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};
}
}
+fn get_group_list(
+ param: Value,
+ _info: &ApiMethod,
+ _rpcenv: &mut RpcEnvironment,
+) -> Result<Value, Error> {
+
+ 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,
pub fn router() -> Router {
+ let store_schema: Arc<Schema> = 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",
.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()
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()
Ok(Value::Null)
}
+fn list_backup_groups(
+ param: Value,
+ _info: &ApiMethod,
+ _rpcenv: &mut RpcEnvironment,
+) -> Result<Value, Error> {
+
+ 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,
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"]);