src/bin/proxmox-backup-client.rs: use #[api] macro
This commit is contained in:
		| @ -10,7 +10,7 @@ use std::os::unix::fs::OpenOptionsExt; | ||||
|  | ||||
| use proxmox::{sortable, identity}; | ||||
| use proxmox::tools::fs::{file_get_contents, file_get_json, file_set_contents, image_size}; | ||||
| use proxmox::api::{ApiFuture, ApiHandler, ApiMethod, RpcEnvironment}; | ||||
| use proxmox::api::{ApiHandler, ApiMethod, RpcEnvironment}; | ||||
| use proxmox::api::schema::*; | ||||
| use proxmox::api::cli::*; | ||||
| use proxmox::api::api; | ||||
| @ -44,6 +44,22 @@ const REPO_URL_SCHEMA: Schema = StringSchema::new("Repository URL.") | ||||
|     .max_length(256) | ||||
|     .schema(); | ||||
|  | ||||
| const BACKUP_SOURCE_SCHEMA: Schema = StringSchema::new( | ||||
|     "Backup source specification ([<label>:<path>]).") | ||||
|     .format(&ApiStringFormat::Pattern(&BACKUPSPEC_REGEX)) | ||||
|     .schema(); | ||||
|  | ||||
| const KEYFILE_SCHEMA: Schema = StringSchema::new( | ||||
|     "Path to encryption key. All data will be encrypted using this key.") | ||||
|     .schema(); | ||||
|  | ||||
| const CHUNK_SIZE_SCHEMA: Schema = IntegerSchema::new( | ||||
|     "Chunk size in KB. Must be a power of 2.") | ||||
|     .minimum(64) | ||||
|     .maximum(4096) | ||||
|     .default(4096) | ||||
|     .schema(); | ||||
|  | ||||
| fn get_default_repository() -> Option<String> { | ||||
|     std::env::var("PBS_REPOSITORY").ok() | ||||
| } | ||||
| @ -233,18 +249,22 @@ fn strip_server_file_expenstion(name: &str) -> String { | ||||
|     } | ||||
| } | ||||
|  | ||||
| fn list_backup_groups<'a>( | ||||
|     param: Value, | ||||
|     _info: &ApiMethod, | ||||
|     _rpcenv: &'a mut dyn RpcEnvironment, | ||||
| ) -> ApiFuture<'a> { | ||||
|  | ||||
|     async move { | ||||
|         list_backup_groups_async(param).await | ||||
|     }.boxed() | ||||
| } | ||||
|  | ||||
| async fn list_backup_groups_async(param: Value) -> Result<Value, Error> { | ||||
| #[api( | ||||
|    input: { | ||||
|         properties: { | ||||
|             repository: { | ||||
|                 schema: REPO_URL_SCHEMA, | ||||
|                 optional: true, | ||||
|             }, | ||||
|             "output-format": { | ||||
|                 schema: OUTPUT_FORMAT, | ||||
|                 optional: true, | ||||
|             }, | ||||
|         } | ||||
|    } | ||||
| )] | ||||
| /// List backup groups. | ||||
| async fn list_backup_groups(param: Value) -> Result<Value, Error> { | ||||
|  | ||||
|     let repo = extract_repository_from_value(¶m)?; | ||||
|  | ||||
| @ -316,18 +336,27 @@ async fn list_backup_groups_async(param: Value) -> Result<Value, Error> { | ||||
|     Ok(Value::Null) | ||||
| } | ||||
|  | ||||
| fn list_snapshots<'a>( | ||||
|     param: Value, | ||||
|     _info: &ApiMethod, | ||||
|     _rpcenv: &'a mut dyn RpcEnvironment, | ||||
| ) -> ApiFuture<'a> { | ||||
|  | ||||
|     async move { | ||||
|         list_snapshots_async(param).await | ||||
|     }.boxed() | ||||
| } | ||||
|  | ||||
| async fn list_snapshots_async(param: Value) -> Result<Value, Error> { | ||||
| #[api( | ||||
|    input: { | ||||
|         properties: { | ||||
|             repository: { | ||||
|                 schema: REPO_URL_SCHEMA, | ||||
|                 optional: true, | ||||
|             }, | ||||
|             group: { | ||||
|                 type: String, | ||||
|                 description: "Backup group.", | ||||
|                 optional: true, | ||||
|             }, | ||||
|             "output-format": { | ||||
|                 schema: OUTPUT_FORMAT, | ||||
|                 optional: true, | ||||
|             }, | ||||
|         } | ||||
|    } | ||||
| )] | ||||
| /// List backup snapshots. | ||||
| async fn list_snapshots(param: Value) -> Result<Value, Error> { | ||||
|  | ||||
|     let repo = extract_repository_from_value(¶m)?; | ||||
|  | ||||
| @ -391,18 +420,22 @@ async fn list_snapshots_async(param: Value) -> Result<Value, Error> { | ||||
|     Ok(Value::Null) | ||||
| } | ||||
|  | ||||
| fn forget_snapshots<'a>( | ||||
|     param: Value, | ||||
|     _info: &ApiMethod, | ||||
|     _rpcenv: &'a mut dyn RpcEnvironment, | ||||
| ) -> ApiFuture<'a> { | ||||
|  | ||||
|     async move { | ||||
|         forget_snapshots_async(param).await | ||||
|     }.boxed() | ||||
| } | ||||
|  | ||||
| async fn forget_snapshots_async(param: Value) -> Result<Value, Error> { | ||||
| #[api( | ||||
|    input: { | ||||
|         properties: { | ||||
|             repository: { | ||||
|                 schema: REPO_URL_SCHEMA, | ||||
|                 optional: true, | ||||
|             }, | ||||
|             snapshot: { | ||||
|                 type: String, | ||||
|                 description: "Snapshot path.", | ||||
|              }, | ||||
|         } | ||||
|    } | ||||
| )] | ||||
| /// Forget (remove) backup snapshots. | ||||
| async fn forget_snapshots(param: Value) -> Result<Value, Error> { | ||||
|  | ||||
|     let repo = extract_repository_from_value(¶m)?; | ||||
|  | ||||
| @ -424,18 +457,18 @@ async fn forget_snapshots_async(param: Value) -> Result<Value, Error> { | ||||
|     Ok(result) | ||||
| } | ||||
|  | ||||
| fn api_login<'a>( | ||||
|     param: Value, | ||||
|     _info: &ApiMethod, | ||||
|     _rpcenv: &'a mut dyn RpcEnvironment, | ||||
| ) -> ApiFuture<'a> { | ||||
|  | ||||
|     async move { | ||||
|         api_login_async(param).await | ||||
|     }.boxed() | ||||
| } | ||||
|  | ||||
| async fn api_login_async(param: Value) -> Result<Value, Error> { | ||||
| #[api( | ||||
|    input: { | ||||
|         properties: { | ||||
|             repository: { | ||||
|                 schema: REPO_URL_SCHEMA, | ||||
|                 optional: true, | ||||
|             }, | ||||
|         } | ||||
|    } | ||||
| )] | ||||
| /// Try to login. If successful, store ticket. | ||||
| async fn api_login(param: Value) -> Result<Value, Error> { | ||||
|  | ||||
|     let repo = extract_repository_from_value(¶m)?; | ||||
|  | ||||
| @ -447,11 +480,18 @@ async fn api_login_async(param: Value) -> Result<Value, Error> { | ||||
|     Ok(Value::Null) | ||||
| } | ||||
|  | ||||
| fn api_logout( | ||||
|     param: Value, | ||||
|     _info: &ApiMethod, | ||||
|     _rpcenv: &mut dyn RpcEnvironment, | ||||
| ) -> Result<Value, Error> { | ||||
| #[api( | ||||
|    input: { | ||||
|         properties: { | ||||
|             repository: { | ||||
|                 schema: REPO_URL_SCHEMA, | ||||
|                 optional: true, | ||||
|             }, | ||||
|         } | ||||
|    } | ||||
| )] | ||||
| /// Logout (delete stored ticket). | ||||
| fn api_logout(param: Value) -> Result<Value, Error> { | ||||
|  | ||||
|     let repo = extract_repository_from_value(¶m)?; | ||||
|  | ||||
| @ -460,18 +500,22 @@ fn api_logout( | ||||
|     Ok(Value::Null) | ||||
| } | ||||
|  | ||||
| fn dump_catalog<'a>( | ||||
|     param: Value, | ||||
|     _info: &ApiMethod, | ||||
|     _rpcenv: &'a mut dyn RpcEnvironment, | ||||
| ) -> ApiFuture<'a> { | ||||
|  | ||||
|     async move { | ||||
|         dump_catalog_async(param).await | ||||
|     }.boxed() | ||||
| } | ||||
|  | ||||
| async fn dump_catalog_async(param: Value) -> Result<Value, Error> { | ||||
| #[api( | ||||
|    input: { | ||||
|         properties: { | ||||
|             repository: { | ||||
|                 schema: REPO_URL_SCHEMA, | ||||
|                 optional: true, | ||||
|             }, | ||||
|             snapshot: { | ||||
|                 type: String, | ||||
|                 description: "Snapshot path.", | ||||
|              }, | ||||
|         } | ||||
|    } | ||||
| )] | ||||
| /// Dump catalog. | ||||
| async fn dump_catalog(param: Value) -> Result<Value, Error> { | ||||
|  | ||||
|     let repo = extract_repository_from_value(¶m)?; | ||||
|  | ||||
| @ -530,18 +574,26 @@ async fn dump_catalog_async(param: Value) -> Result<Value, Error> { | ||||
|     Ok(Value::Null) | ||||
| } | ||||
|  | ||||
| fn list_snapshot_files<'a>( | ||||
|     param: Value, | ||||
|     _info: &ApiMethod, | ||||
|     _rpcenv: &'a mut dyn RpcEnvironment, | ||||
| ) -> ApiFuture<'a> { | ||||
|  | ||||
|     async move { | ||||
|         list_snapshot_files_async(param).await | ||||
|     }.boxed() | ||||
| } | ||||
|  | ||||
| async fn list_snapshot_files_async(param: Value) -> Result<Value, Error> { | ||||
| #[api( | ||||
|    input: { | ||||
|         properties: { | ||||
|             repository: { | ||||
|                 schema: REPO_URL_SCHEMA, | ||||
|                 optional: true, | ||||
|             }, | ||||
|             snapshot: { | ||||
|                 type: String, | ||||
|                 description: "Snapshot path.", | ||||
|              }, | ||||
|             "output-format": { | ||||
|                 schema: OUTPUT_FORMAT, | ||||
|                 optional: true, | ||||
|             }, | ||||
|         } | ||||
|    } | ||||
| )] | ||||
| /// List snapshot files. | ||||
| async fn list_snapshot_files(param: Value) -> Result<Value, Error> { | ||||
|  | ||||
|     let repo = extract_repository_from_value(¶m)?; | ||||
|  | ||||
| @ -579,22 +631,18 @@ async fn list_snapshot_files_async(param: Value) -> Result<Value, Error> { | ||||
|     Ok(Value::Null) | ||||
| } | ||||
|  | ||||
| fn start_garbage_collection<'a>( | ||||
|     param: Value, | ||||
|     info: &'static ApiMethod, | ||||
|     rpcenv: &'a mut dyn RpcEnvironment, | ||||
| ) -> ApiFuture<'a> { | ||||
|  | ||||
|     async move { | ||||
|         start_garbage_collection_async(param, info, rpcenv).await | ||||
|     }.boxed() | ||||
| } | ||||
|  | ||||
| async fn start_garbage_collection_async( | ||||
|     param: Value, | ||||
|     _info: &ApiMethod, | ||||
|     _rpcenv: &mut dyn RpcEnvironment, | ||||
| ) -> Result<Value, Error> { | ||||
| #[api( | ||||
|    input: { | ||||
|         properties: { | ||||
|             repository: { | ||||
|                 schema: REPO_URL_SCHEMA, | ||||
|                 optional: true, | ||||
|             }, | ||||
|         } | ||||
|    } | ||||
| )] | ||||
| /// Start garbage collection for a specific repository. | ||||
| async fn start_garbage_collection(param: Value) -> Result<Value, Error> { | ||||
|  | ||||
|     let repo = extract_repository_from_value(¶m)?; | ||||
|     let output_format = param["output-format"].as_str().unwrap_or("text").to_owned(); | ||||
| @ -654,18 +702,58 @@ fn spawn_catalog_upload( | ||||
|     Ok((catalog, catalog_result_rx)) | ||||
| } | ||||
|  | ||||
| fn create_backup<'a>( | ||||
|     param: Value, | ||||
|     info: &'static ApiMethod, | ||||
|     rpcenv: &'a mut dyn RpcEnvironment, | ||||
| ) -> ApiFuture<'a> { | ||||
|  | ||||
|     async move { | ||||
|         create_backup_async(param, info, rpcenv).await | ||||
|     }.boxed() | ||||
| } | ||||
|  | ||||
| async fn create_backup_async( | ||||
| #[api( | ||||
|    input: { | ||||
|        properties: { | ||||
|            backupspec: { | ||||
|                type: Array, | ||||
|                description: "List of backup source specifications ([<label.ext>:<path>] ...)", | ||||
|                items: { | ||||
|                    schema: BACKUP_SOURCE_SCHEMA, | ||||
|                } | ||||
|            }, | ||||
|            repository: { | ||||
|                schema: REPO_URL_SCHEMA, | ||||
|                optional: true, | ||||
|            }, | ||||
|            "include-dev": { | ||||
|                description: "Include mountpoints with same st_dev number (see ``man fstat``) as specified files.", | ||||
|                optional: true, | ||||
|                items: { | ||||
|                    type: String, | ||||
|                    description: "Path to file.", | ||||
|                } | ||||
|            }, | ||||
|            keyfile: { | ||||
|                schema: KEYFILE_SCHEMA, | ||||
|                optional: true, | ||||
|            }, | ||||
|            "skip-lost-and-found": { | ||||
|                type: Boolean, | ||||
|                description: "Skip lost+found directory.", | ||||
|                optional: true, | ||||
|            }, | ||||
|            "backup-type": { | ||||
|                schema: BACKUP_TYPE_SCHEMA, | ||||
|                optional: true, | ||||
|            }, | ||||
|            "backup-id": { | ||||
|                schema: BACKUP_ID_SCHEMA, | ||||
|                optional: true, | ||||
|            }, | ||||
|            "backup-time": { | ||||
|                schema: BACKUP_TIME_SCHEMA, | ||||
|                optional: true, | ||||
|            }, | ||||
|            "chunk-size": { | ||||
|                schema: CHUNK_SIZE_SCHEMA, | ||||
|                optional: true, | ||||
|            }, | ||||
|        } | ||||
|    } | ||||
| )] | ||||
| /// Create (host) backup. | ||||
| async fn create_backup( | ||||
|     param: Value, | ||||
|     _info: &ApiMethod, | ||||
|     _rpcenv: &mut dyn RpcEnvironment, | ||||
| @ -984,18 +1072,43 @@ fn dump_image<W: Write>( | ||||
|     Ok(()) | ||||
| } | ||||
|  | ||||
| fn restore<'a>( | ||||
|     param: Value, | ||||
|     _info: &ApiMethod, | ||||
|     _rpcenv: &'a mut dyn RpcEnvironment, | ||||
| ) -> ApiFuture<'a> { | ||||
| #[api( | ||||
|    input: { | ||||
|        properties: { | ||||
|            repository: { | ||||
|                schema: REPO_URL_SCHEMA, | ||||
|                optional: true, | ||||
|            }, | ||||
|            snapshot: { | ||||
|                type: String, | ||||
|                description: "Group/Snapshot path.", | ||||
|            }, | ||||
|            "archive-name": { | ||||
|                description: "Backup archive name.", | ||||
|                type: String, | ||||
|            }, | ||||
|            target: { | ||||
|                type: String, | ||||
|                description: r###"Target directory path. Use '-' to write to stdandard output. | ||||
|  | ||||
|     async move { | ||||
|         restore_do(param).await | ||||
|     }.boxed() | ||||
| } | ||||
| We do not extraxt '.pxar' archives when writing to stdandard output. | ||||
|  | ||||
| async fn restore_do(param: Value) -> Result<Value, Error> { | ||||
| "### | ||||
|            }, | ||||
|            "allow-existing-dirs": { | ||||
|                type: Boolean, | ||||
|                description: "Do not fail if directories already exists.", | ||||
|                optional: true, | ||||
|            }, | ||||
|            keyfile: { | ||||
|                schema: KEYFILE_SCHEMA, | ||||
|                optional: true, | ||||
|            }, | ||||
|        } | ||||
|    } | ||||
| )] | ||||
| /// Restore backup repository. | ||||
| async fn restore(param: Value) -> Result<Value, Error> { | ||||
|     let repo = extract_repository_from_value(¶m)?; | ||||
|  | ||||
|     let verbose = param["verbose"].as_bool().unwrap_or(false); | ||||
| @ -1154,17 +1267,30 @@ async fn restore_do(param: Value) -> Result<Value, Error> { | ||||
|     Ok(Value::Null) | ||||
| } | ||||
|  | ||||
| fn upload_log<'a>( | ||||
|     param: Value, | ||||
|     _info: &ApiMethod, | ||||
|     _rpcenv: &'a mut dyn RpcEnvironment, | ||||
| ) -> ApiFuture<'a> { | ||||
|     async move { | ||||
|         upload_log_async(param).await | ||||
|     }.boxed() | ||||
| } | ||||
|  | ||||
| async fn upload_log_async(param: Value) -> Result<Value, Error> { | ||||
| #[api( | ||||
|    input: { | ||||
|        properties: { | ||||
|            repository: { | ||||
|                schema: REPO_URL_SCHEMA, | ||||
|                optional: true, | ||||
|            }, | ||||
|            snapshot: { | ||||
|                type: String, | ||||
|                description: "Group/Snapshot path.", | ||||
|            }, | ||||
|            logfile: { | ||||
|                type: String, | ||||
|                description: "The path to the log file you want to upload.", | ||||
|            }, | ||||
|            keyfile: { | ||||
|                schema: KEYFILE_SCHEMA, | ||||
|                optional: true, | ||||
|            }, | ||||
|        } | ||||
|    } | ||||
| )] | ||||
| /// Upload backup log file. | ||||
| async fn upload_log(param: Value) -> Result<Value, Error> { | ||||
|  | ||||
|     let logfile = tools::required_string_param(¶m, "logfile")?; | ||||
|     let repo = extract_repository_from_value(¶m)?; | ||||
| @ -1204,17 +1330,31 @@ async fn upload_log_async(param: Value) -> Result<Value, Error> { | ||||
|     client.upload("application/octet-stream", body, &path, Some(args)).await | ||||
| } | ||||
|  | ||||
| fn prune<'a>( | ||||
|     param: Value, | ||||
|     _info: &ApiMethod, | ||||
|     _rpcenv: &'a mut dyn RpcEnvironment, | ||||
| ) -> ApiFuture<'a> { | ||||
|     async move { | ||||
|         prune_async(param).await | ||||
|     }.boxed() | ||||
| } | ||||
|  | ||||
| async fn prune_async(mut param: Value) -> Result<Value, Error> { | ||||
| #[api( | ||||
|    input: { | ||||
|        properties: { | ||||
|            repository: { | ||||
|                schema: REPO_URL_SCHEMA, | ||||
|                optional: true, | ||||
|            }, | ||||
|            group: { | ||||
|                type: String, | ||||
|                description: "Backup group.", | ||||
|            }, | ||||
|            "output-format": { | ||||
|                schema: OUTPUT_FORMAT, | ||||
|                optional: true, | ||||
|            }, | ||||
|            "dry-run": { | ||||
|                type: Boolean, | ||||
|                description: "Just show what prune would do, but do not delete anything.", | ||||
|                optional: true, | ||||
|            }, | ||||
|        } | ||||
|    } | ||||
| )] | ||||
| /// Prune a backup repository. | ||||
| async fn prune(mut param: Value) -> Result<Value, Error> { | ||||
|  | ||||
|     let repo = extract_repository_from_value(¶m)?; | ||||
|  | ||||
| @ -1242,17 +1382,22 @@ async fn prune_async(mut param: Value) -> Result<Value, Error> { | ||||
|     Ok(Value::Null) | ||||
| } | ||||
|  | ||||
| fn status<'a>( | ||||
|     param: Value, | ||||
|     _info: &ApiMethod, | ||||
|     _rpcenv: &'a mut dyn RpcEnvironment, | ||||
| ) -> ApiFuture<'a> { | ||||
|     async move { | ||||
|         status_async(param).await | ||||
|     }.boxed() | ||||
| } | ||||
|  | ||||
| async fn status_async(param: Value) -> Result<Value, Error> { | ||||
| #[api( | ||||
|    input: { | ||||
|        properties: { | ||||
|            repository: { | ||||
|                schema: REPO_URL_SCHEMA, | ||||
|                optional: true, | ||||
|            }, | ||||
|            "output-format": { | ||||
|                schema: OUTPUT_FORMAT, | ||||
|                optional: true, | ||||
|            }, | ||||
|        } | ||||
|    } | ||||
| )] | ||||
| /// Get repository status. | ||||
| async fn status(param: Value) -> Result<Value, Error> { | ||||
|  | ||||
|     let repo = extract_repository_from_value(¶m)?; | ||||
|  | ||||
| @ -1994,18 +2139,6 @@ fn catalog_mgmt_cli() -> CliCommandMap { | ||||
|         .completion_cb("archive-name", complete_pxar_archive_name) | ||||
|         .completion_cb("snapshot", complete_group_or_snapshot); | ||||
|  | ||||
|     #[sortable] | ||||
|     const API_METHOD_DUMP_CATALOG: ApiMethod = ApiMethod::new( | ||||
|         &ApiHandler::Async(&dump_catalog), | ||||
|         &ObjectSchema::new( | ||||
|             "Dump catalog.", | ||||
|             &sorted!([ | ||||
|                 ("snapshot", false, &StringSchema::new("Snapshot path.").schema()), | ||||
|                 ("repository", true, &REPO_URL_SCHEMA), | ||||
|             ]), | ||||
|         ) | ||||
|     ); | ||||
|  | ||||
|     let catalog_dump_cmd_def = CliCommand::new(&API_METHOD_DUMP_CATALOG) | ||||
|         .arg_param(&["snapshot"]) | ||||
|         .completion_cb("repository", complete_repository) | ||||
| @ -2157,84 +2290,6 @@ fn task_mgmt_cli() -> CliCommandMap { | ||||
|  | ||||
| fn main() { | ||||
|  | ||||
|     const BACKUP_SOURCE_SCHEMA: Schema = StringSchema::new("Backup source specification ([<label>:<path>]).") | ||||
|         .format(&ApiStringFormat::Pattern(&BACKUPSPEC_REGEX)) | ||||
|         .schema(); | ||||
|  | ||||
|     #[sortable] | ||||
|     const API_METHOD_CREATE_BACKUP: ApiMethod = ApiMethod::new( | ||||
|         &ApiHandler::Async(&create_backup), | ||||
|         &ObjectSchema::new( | ||||
|             "Create (host) backup.", | ||||
|             &sorted!([ | ||||
|                 ( | ||||
|                     "backupspec", | ||||
|                     false, | ||||
|                     &ArraySchema::new( | ||||
|                         "List of backup source specifications ([<label.ext>:<path>] ...)", | ||||
|                         &BACKUP_SOURCE_SCHEMA, | ||||
|                     ).min_length(1).schema() | ||||
|                 ), | ||||
|                 ( | ||||
|                     "repository", | ||||
|                     true, | ||||
|                     &REPO_URL_SCHEMA | ||||
|                 ), | ||||
|                 ( | ||||
|                     "include-dev", | ||||
|                     true, | ||||
|                     &ArraySchema::new( | ||||
|                         "Include mountpoints with same st_dev number (see ``man fstat``) as specified files.", | ||||
|                         &StringSchema::new("Path to file.").schema() | ||||
|                     ).schema() | ||||
|                 ), | ||||
|                 ( | ||||
|                     "keyfile", | ||||
|                     true, | ||||
|                     &StringSchema::new("Path to encryption key. All data will be encrypted using this key.").schema() | ||||
|                 ), | ||||
|                 ( | ||||
|                     "verbose", | ||||
|                     true, | ||||
|                     &BooleanSchema::new("Verbose output.") | ||||
|                         .default(false) | ||||
|                         .schema() | ||||
|                 ), | ||||
|                 ( | ||||
|                     "skip-lost-and-found", | ||||
|                     true, | ||||
|                     &BooleanSchema::new("Skip lost+found directory") | ||||
|                         .default(false) | ||||
|                         .schema() | ||||
|                 ), | ||||
|                 ( | ||||
|                     "backup-type", | ||||
|                     true, | ||||
|                     &BACKUP_TYPE_SCHEMA, | ||||
|                 ), | ||||
|                 ( | ||||
|                     "backup-id", | ||||
|                     true, | ||||
|                     &BACKUP_ID_SCHEMA | ||||
|                 ), | ||||
|                 ( | ||||
|                     "backup-time", | ||||
|                     true, | ||||
|                     &BACKUP_TIME_SCHEMA | ||||
|                 ), | ||||
|                 ( | ||||
|                     "chunk-size", | ||||
|                     true, | ||||
|                     &IntegerSchema::new("Chunk size in KB. Must be a power of 2.") | ||||
|                         .minimum(64) | ||||
|                         .maximum(4096) | ||||
|                         .default(4096) | ||||
|                         .schema() | ||||
|                 ), | ||||
|             ]), | ||||
|         ) | ||||
|     ); | ||||
|  | ||||
|     let backup_cmd_def = CliCommand::new(&API_METHOD_CREATE_BACKUP) | ||||
|         .arg_param(&["backupspec"]) | ||||
|         .completion_cb("repository", complete_repository) | ||||
| @ -2242,36 +2297,6 @@ fn main() { | ||||
|         .completion_cb("keyfile", tools::complete_file_name) | ||||
|         .completion_cb("chunk-size", complete_chunk_size); | ||||
|  | ||||
|     #[sortable] | ||||
|     const API_METHOD_UPLOAD_LOG: ApiMethod = ApiMethod::new( | ||||
|         &ApiHandler::Async(&upload_log), | ||||
|         &ObjectSchema::new( | ||||
|             "Upload backup log file.", | ||||
|             &sorted!([ | ||||
|                 ( | ||||
|                     "snapshot", | ||||
|                     false, | ||||
|                     &StringSchema::new("Snapshot path.").schema() | ||||
|                 ), | ||||
|                 ( | ||||
|                     "logfile", | ||||
|                     false, | ||||
|                     &StringSchema::new("The path to the log file you want to upload.").schema() | ||||
|                 ), | ||||
|                 ( | ||||
|                     "repository", | ||||
|                     true, | ||||
|                     &REPO_URL_SCHEMA | ||||
|                 ), | ||||
|                 ( | ||||
|                     "keyfile", | ||||
|                     true, | ||||
|                     &StringSchema::new("Path to encryption key. All data will be encrypted using this key.").schema() | ||||
|                 ), | ||||
|             ]), | ||||
|         ) | ||||
|     ); | ||||
|  | ||||
|     let upload_log_cmd_def = CliCommand::new(&API_METHOD_UPLOAD_LOG) | ||||
|         .arg_param(&["snapshot", "logfile"]) | ||||
|         .completion_cb("snapshot", complete_backup_snapshot) | ||||
| @ -2279,107 +2304,22 @@ fn main() { | ||||
|         .completion_cb("keyfile", tools::complete_file_name) | ||||
|         .completion_cb("repository", complete_repository); | ||||
|  | ||||
|     #[sortable] | ||||
|     const API_METHOD_LIST_BACKUP_GROUPS: ApiMethod = ApiMethod::new( | ||||
|         &ApiHandler::Async(&list_backup_groups), | ||||
|         &ObjectSchema::new( | ||||
|             "List backup groups.", | ||||
|             &sorted!([ | ||||
|                 ("repository", true, &REPO_URL_SCHEMA), | ||||
|                 ("output-format", true, &OUTPUT_FORMAT), | ||||
|             ]), | ||||
|         ) | ||||
|     ); | ||||
|  | ||||
|     let list_cmd_def = CliCommand::new(&API_METHOD_LIST_BACKUP_GROUPS) | ||||
|         .completion_cb("repository", complete_repository); | ||||
|  | ||||
|     #[sortable] | ||||
|     const API_METHOD_LIST_SNAPSHOTS: ApiMethod = ApiMethod::new( | ||||
|         &ApiHandler::Async(&list_snapshots), | ||||
|         &ObjectSchema::new( | ||||
|             "List backup snapshots.", | ||||
|             &sorted!([ | ||||
|                 ("group", true, &StringSchema::new("Backup group.").schema()), | ||||
|                 ("repository", true, &REPO_URL_SCHEMA), | ||||
|                 ("output-format", true, &OUTPUT_FORMAT), | ||||
|             ]), | ||||
|         ) | ||||
|     ); | ||||
|  | ||||
|     let snapshots_cmd_def = CliCommand::new(&API_METHOD_LIST_SNAPSHOTS) | ||||
|         .arg_param(&["group"]) | ||||
|         .completion_cb("group", complete_backup_group) | ||||
|         .completion_cb("repository", complete_repository); | ||||
|  | ||||
|     #[sortable] | ||||
|     const API_METHOD_FORGET_SNAPSHOTS: ApiMethod = ApiMethod::new( | ||||
|         &ApiHandler::Async(&forget_snapshots), | ||||
|         &ObjectSchema::new( | ||||
|             "Forget (remove) backup snapshots.", | ||||
|             &sorted!([ | ||||
|                 ("snapshot", false, &StringSchema::new("Snapshot path.").schema()), | ||||
|                 ("repository", true, &REPO_URL_SCHEMA), | ||||
|             ]), | ||||
|         ) | ||||
|     ); | ||||
|  | ||||
|     let forget_cmd_def = CliCommand::new(&API_METHOD_FORGET_SNAPSHOTS) | ||||
|         .arg_param(&["snapshot"]) | ||||
|         .completion_cb("repository", complete_repository) | ||||
|         .completion_cb("snapshot", complete_backup_snapshot); | ||||
|  | ||||
|     #[sortable] | ||||
|     const API_METHOD_START_GARBAGE_COLLECTION: ApiMethod = ApiMethod::new( | ||||
|         &ApiHandler::Async(&start_garbage_collection), | ||||
|         &ObjectSchema::new( | ||||
|             "Start garbage collection for a specific repository.", | ||||
|             &sorted!([ ("repository", true, &REPO_URL_SCHEMA) ]), | ||||
|         ) | ||||
|     ); | ||||
|  | ||||
|     let garbage_collect_cmd_def = CliCommand::new(&API_METHOD_START_GARBAGE_COLLECTION) | ||||
|         .completion_cb("repository", complete_repository); | ||||
|  | ||||
|     #[sortable] | ||||
|     const API_METHOD_RESTORE: ApiMethod = ApiMethod::new( | ||||
|         &ApiHandler::Async(&restore), | ||||
|         &ObjectSchema::new( | ||||
|             "Restore backup repository.", | ||||
|             &sorted!([ | ||||
|                 ("snapshot", false, &StringSchema::new("Group/Snapshot path.").schema()), | ||||
|                 ("archive-name", false, &StringSchema::new("Backup archive name.").schema()), | ||||
|                 ( | ||||
|                     "target", | ||||
|                     false, | ||||
|                     &StringSchema::new( | ||||
|                         r###"Target directory path. Use '-' to write to stdandard output. | ||||
|  | ||||
| We do not extraxt '.pxar' archives when writing to stdandard output. | ||||
|  | ||||
| "### | ||||
|                     ).schema() | ||||
|                 ), | ||||
|                 ( | ||||
|                     "allow-existing-dirs", | ||||
|                     true, | ||||
|                     &BooleanSchema::new("Do not fail if directories already exists.") | ||||
|                         .default(false) | ||||
|                         .schema() | ||||
|                 ), | ||||
|                 ("repository", true, &REPO_URL_SCHEMA), | ||||
|                 ("keyfile", true, &StringSchema::new("Path to encryption key.").schema()), | ||||
|                 ( | ||||
|                     "verbose", | ||||
|                     true, | ||||
|                     &BooleanSchema::new("Verbose output.") | ||||
|                         .default(false) | ||||
|                         .schema() | ||||
|                 ), | ||||
|             ]), | ||||
|         ) | ||||
|     ); | ||||
|  | ||||
|     let restore_cmd_def = CliCommand::new(&API_METHOD_RESTORE) | ||||
|         .arg_param(&["snapshot", "archive-name", "target"]) | ||||
|         .completion_cb("repository", complete_repository) | ||||
| @ -2387,81 +2327,22 @@ We do not extraxt '.pxar' archives when writing to stdandard output. | ||||
|         .completion_cb("archive-name", complete_archive_name) | ||||
|         .completion_cb("target", tools::complete_file_name); | ||||
|  | ||||
|     #[sortable] | ||||
|     const API_METHOD_LIST_SNAPSHOT_FILES: ApiMethod = ApiMethod::new( | ||||
|         &ApiHandler::Async(&list_snapshot_files), | ||||
|         &ObjectSchema::new( | ||||
|             "List snapshot files.", | ||||
|             &sorted!([ | ||||
|                 ("snapshot", false, &StringSchema::new("Snapshot path.").schema()), | ||||
|                 ("repository", true, &REPO_URL_SCHEMA), | ||||
|                 ("output-format", true, &OUTPUT_FORMAT), | ||||
|             ]), | ||||
|         ) | ||||
|     ); | ||||
|  | ||||
|     let files_cmd_def = CliCommand::new(&API_METHOD_LIST_SNAPSHOT_FILES) | ||||
|         .arg_param(&["snapshot"]) | ||||
|         .completion_cb("repository", complete_repository) | ||||
|         .completion_cb("snapshot", complete_backup_snapshot); | ||||
|  | ||||
|     const API_METHOD_PRUNE: ApiMethod = ApiMethod::new( | ||||
|         &ApiHandler::Async(&prune), | ||||
|         &ObjectSchema::new( | ||||
|             "Prune backup repository.", | ||||
|             &proxmox_backup::add_common_prune_prameters!([ | ||||
|                 ("dry-run", true, &BooleanSchema::new( | ||||
|                     "Just show what prune would do, but do not delete anything.") | ||||
|                  .schema()), | ||||
|                 ("group", false, &StringSchema::new("Backup group.").schema()), | ||||
|             ], [ | ||||
|                 ("output-format", true, &OUTPUT_FORMAT), | ||||
|                 ("repository", true, &REPO_URL_SCHEMA), | ||||
|             ]) | ||||
|         ) | ||||
|     ); | ||||
|  | ||||
|     let prune_cmd_def = CliCommand::new(&API_METHOD_PRUNE) | ||||
|         .arg_param(&["group"]) | ||||
|         .completion_cb("group", complete_backup_group) | ||||
|         .completion_cb("repository", complete_repository); | ||||
|  | ||||
|     #[sortable] | ||||
|     const API_METHOD_STATUS: ApiMethod = ApiMethod::new( | ||||
|         &ApiHandler::Async(&status), | ||||
|         &ObjectSchema::new( | ||||
|             "Get repository status.", | ||||
|             &sorted!([ | ||||
|                 ("repository", true, &REPO_URL_SCHEMA), | ||||
|                 ("output-format", true, &OUTPUT_FORMAT), | ||||
|             ]), | ||||
|         ) | ||||
|     ); | ||||
|  | ||||
|     let status_cmd_def = CliCommand::new(&API_METHOD_STATUS) | ||||
|         .completion_cb("repository", complete_repository); | ||||
|  | ||||
|     #[sortable] | ||||
|     const API_METHOD_API_LOGIN: ApiMethod = ApiMethod::new( | ||||
|         &ApiHandler::Async(&api_login), | ||||
|         &ObjectSchema::new( | ||||
|             "Try to login. If successful, store ticket.", | ||||
|             &sorted!([ ("repository", true, &REPO_URL_SCHEMA) ]), | ||||
|         ) | ||||
|     ); | ||||
|  | ||||
|     let login_cmd_def = CliCommand::new(&API_METHOD_API_LOGIN) | ||||
|         .completion_cb("repository", complete_repository); | ||||
|  | ||||
|     #[sortable] | ||||
|     const API_METHOD_API_LOGOUT: ApiMethod = ApiMethod::new( | ||||
|         &ApiHandler::Sync(&api_logout), | ||||
|         &ObjectSchema::new( | ||||
|             "Logout (delete stored ticket).", | ||||
|             &sorted!([ ("repository", true, &REPO_URL_SCHEMA) ]), | ||||
|         ) | ||||
|     ); | ||||
|  | ||||
|     let logout_cmd_def = CliCommand::new(&API_METHOD_API_LOGOUT) | ||||
|         .completion_cb("repository", complete_repository); | ||||
|  | ||||
|  | ||||
		Reference in New Issue
	
	Block a user