From 812c6f8716469579daae4a7aad02015d113c52ff Mon Sep 17 00:00:00 2001 From: Dietmar Maurer Date: Sat, 2 Mar 2019 11:29:05 +0100 Subject: [PATCH] src/api2/admin/datastore.rs: impl list_backup_groups --- src/api2/admin/datastore.rs | 50 ++++++++++++++++++++++++++++++-- src/bin/proxmox-backup-client.rs | 43 +++++++++++++++++++++++++-- 2 files changed, 89 insertions(+), 4 deletions(-) diff --git a/src/api2/admin/datastore.rs b/src/api2/admin/datastore.rs index 041597fd..dccbed74 100644 --- a/src/api2/admin/datastore.rs +++ b/src/api2/admin/datastore.rs @@ -7,6 +7,7 @@ use serde_json::{json, Value}; use std::collections::{HashSet, HashMap}; use chrono::{DateTime, Datelike, Local}; use std::path::PathBuf; +use std::sync::Arc; //use hyper::StatusCode; //use hyper::rt::{Future, Stream}; @@ -50,6 +51,39 @@ fn mark_selections, &BackupInfo) -> String> ( } } +fn get_group_list( + param: Value, + _info: &ApiMethod, + _rpcenv: &mut RpcEnvironment, +) -> Result { + + let store = param["store"].as_str().unwrap(); + + let datastore = DataStore::lookup_datastore(store)?; + + let backup_list = datastore.list_backups()?; + + let group_hash = group_backups(backup_list); + + let mut groups = vec![]; + + for (_group_id, mut list) in group_hash { + + list.sort_unstable_by(|a, b| b.backup_dir.backup_time.cmp(&a.backup_dir.backup_time)); // new backups first + + let info = &list[0]; + let group = &info.backup_dir.group; + + groups.push(json!({ + "backup_type": group.backup_type, + "backup_id": group.backup_id, + "last_backup": info.backup_dir.backup_time.timestamp(), + "num_backups": list.len() as u64, + })); + } + + Ok(json!(groups)) +} fn prune( param: Value, @@ -249,17 +283,22 @@ fn get_datastore_list( pub fn router() -> Router { + let store_schema: Arc = Arc::new( + StringSchema::new("Datastore name.").into() + ); + let datastore_info = Router::new() .get(ApiMethod::new( |_,_,_| Ok(json!([ {"subdir": "backups" }, {"subdir": "catar" }, {"subdir": "gc" }, + {"subdir": "groups" }, {"subdir": "status" }, {"subdir": "prune" }, ])), ObjectSchema::new("Directory index.") - .required("store", StringSchema::new("Datastore name."))) + .required("store", store_schema.clone())) ) .subdir( "backups", @@ -267,7 +306,7 @@ pub fn router() -> Router { .get(ApiMethod::new( get_backup_list, ObjectSchema::new("List backups.") - .required("store", StringSchema::new("Datastore name."))))) + .required("store", store_schema.clone())))) .subdir( "catar", Router::new() @@ -278,6 +317,13 @@ pub fn router() -> Router { Router::new() .get(api_method_garbage_collection_status()) .post(api_method_start_garbage_collection())) + .subdir( + "groups", + Router::new() + .get(ApiMethod::new( + get_group_list, + ObjectSchema::new("List backup groups.") + .required("store", store_schema.clone())))) .subdir( "prune", Router::new() diff --git a/src/bin/proxmox-backup-client.rs b/src/bin/proxmox-backup-client.rs index c48e22b4..a0d8c271 100644 --- a/src/bin/proxmox-backup-client.rs +++ b/src/bin/proxmox-backup-client.rs @@ -135,6 +135,45 @@ fn list_backups( Ok(Value::Null) } +fn list_backup_groups( + param: Value, + _info: &ApiMethod, + _rpcenv: &mut RpcEnvironment, +) -> Result { + + let repo_url = tools::required_string_param(¶m, "repository")?; + let repo = BackupRepository::parse(repo_url)?; + + let mut client = HttpClient::new(&repo.host, &repo.user); + + let path = format!("api2/json/admin/datastore/{}/groups", repo.store); + + let result = client.get(&path)?; + + // fixme: implement and use output formatter instead .. + let list = result["data"].as_array().unwrap(); + + for item in list { + + let id = item["backup_id"].as_str().unwrap(); + let btype = item["backup_type"].as_str().unwrap(); + let epoch = item["last_backup"].as_i64().unwrap(); + let last_backup = Local.timestamp(epoch, 0); + let num_backups = item["num_backups"].as_u64().unwrap(); + + let group = BackupGroup { + backup_type: btype.to_string(), + backup_id: id.to_string(), + }; + + let path = group.group_path().to_str().unwrap().to_owned(); + println!("{} | {} | {}", path, last_backup.format("%c"), num_backups); + } + + //Ok(result) + Ok(Value::Null) +} + fn start_garbage_collection( param: Value, _info: &ApiMethod, @@ -318,8 +357,8 @@ fn main() { let list_cmd_def = CliCommand::new( ApiMethod::new( - list_backups, - ObjectSchema::new("List backups.") + list_backup_groups, + ObjectSchema::new("List backup groups.") .required("repository", repo_url_schema.clone()) )) .arg_param(vec!["repository"]);