4 use serde_json
::{json, Value}
;
8 tools
::fs
::file_get_contents
,
28 api_datastore_list_snapshots
,
29 complete_backup_snapshot
,
30 complete_backup_group
,
33 extract_repository_from_value
,
42 schema
: REPO_URL_SCHEMA
,
47 description
: "Backup group.",
51 schema
: OUTPUT_FORMAT
,
57 /// List backup snapshots.
58 async
fn list_snapshots(param
: Value
) -> Result
<Value
, Error
> {
60 let repo
= extract_repository_from_value(¶m
)?
;
62 let output_format
= get_output_format(¶m
);
64 let client
= connect(&repo
)?
;
66 let group
: Option
<BackupGroup
> = if let Some(path
) = param
["group"].as_str() {
72 let mut data
= api_datastore_list_snapshots(&client
, repo
.store(), group
).await?
;
74 record_repository(&repo
);
76 let render_snapshot_path
= |_v
: &Value
, record
: &Value
| -> Result
<String
, Error
> {
77 let item
: SnapshotListItem
= serde_json
::from_value(record
.to_owned())?
;
78 let snapshot
= BackupDir
::new(item
.backup_type
, item
.backup_id
, item
.backup_time
)?
;
79 Ok(snapshot
.relative_path().to_str().unwrap().to_owned())
82 let render_files
= |_v
: &Value
, record
: &Value
| -> Result
<String
, Error
> {
83 let item
: SnapshotListItem
= serde_json
::from_value(record
.to_owned())?
;
84 let mut filenames
= Vec
::new();
85 for file
in &item
.files
{
86 filenames
.push(file
.filename
.to_string());
88 Ok(tools
::format
::render_backup_file_list(&filenames
[..]))
91 let options
= default_table_format_options()
92 .sortby("backup-type", false)
93 .sortby("backup-id", false)
94 .sortby("backup-time", false)
95 .column(ColumnConfig
::new("backup-id").renderer(render_snapshot_path
).header("snapshot"))
96 .column(ColumnConfig
::new("size").renderer(tools
::format
::render_bytes_human_readable
))
97 .column(ColumnConfig
::new("files").renderer(render_files
))
100 let return_type
= &proxmox_backup
::api2
::admin
::datastore
::API_METHOD_LIST_SNAPSHOTS
.returns
;
102 format_and_print_result_full(&mut data
, return_type
, &output_format
, &options
);
111 schema
: REPO_URL_SCHEMA
,
116 description
: "Snapshot path.",
119 schema
: OUTPUT_FORMAT
,
125 /// List snapshot files.
126 async
fn list_snapshot_files(param
: Value
) -> Result
<Value
, Error
> {
128 let repo
= extract_repository_from_value(¶m
)?
;
130 let path
= tools
::required_string_param(¶m
, "snapshot")?
;
131 let snapshot
: BackupDir
= path
.parse()?
;
133 let output_format
= get_output_format(¶m
);
135 let client
= connect(&repo
)?
;
137 let path
= format
!("api2/json/admin/datastore/{}/files", repo
.store());
139 let mut result
= client
.get(&path
, Some(json
!({
140 "backup-type": snapshot
.group().backup_type(),
141 "backup-id": snapshot
.group().backup_id(),
142 "backup-time": snapshot
.backup_time(),
145 record_repository(&repo
);
148 &proxmox_backup
::api2
::admin
::datastore
::API_METHOD_LIST_SNAPSHOT_FILES
.returns
;
150 let mut data
: Value
= result
["data"].take();
152 let options
= default_table_format_options();
154 format_and_print_result_full(&mut data
, return_type
, &output_format
, &options
);
163 schema
: REPO_URL_SCHEMA
,
168 description
: "Snapshot path.",
173 /// Forget (remove) backup snapshots.
174 async
fn forget_snapshots(param
: Value
) -> Result
<Value
, Error
> {
176 let repo
= extract_repository_from_value(¶m
)?
;
178 let path
= tools
::required_string_param(¶m
, "snapshot")?
;
179 let snapshot
: BackupDir
= path
.parse()?
;
181 let mut client
= connect(&repo
)?
;
183 let path
= format
!("api2/json/admin/datastore/{}/snapshots", repo
.store());
185 let result
= client
.delete(&path
, Some(json
!({
186 "backup-type": snapshot
.group().backup_type(),
187 "backup-id": snapshot
.group().backup_id(),
188 "backup-time": snapshot
.backup_time(),
191 record_repository(&repo
);
200 schema
: REPO_URL_SCHEMA
,
205 description
: "Group/Snapshot path.",
209 description
: "The path to the log file you want to upload.",
212 schema
: KEYFILE_SCHEMA
,
216 schema
: KEYFD_SCHEMA
,
226 /// Upload backup log file.
227 async
fn upload_log(param
: Value
) -> Result
<Value
, Error
> {
229 let logfile
= tools
::required_string_param(¶m
, "logfile")?
;
230 let repo
= extract_repository_from_value(¶m
)?
;
232 let snapshot
= tools
::required_string_param(¶m
, "snapshot")?
;
233 let snapshot
: BackupDir
= snapshot
.parse()?
;
235 let mut client
= connect(&repo
)?
;
237 let (keydata
, crypt_mode
) = keyfile_parameters(¶m
)?
;
239 let crypt_config
= match keydata
{
242 let (key
, _created
, _
) = decrypt_key(&key
, &crate::key
::get_encryption_key_password
)?
;
243 let crypt_config
= CryptConfig
::new(key
)?
;
244 Some(Arc
::new(crypt_config
))
248 let data
= file_get_contents(logfile
)?
;
250 // fixme: howto sign log?
251 let blob
= match crypt_mode
{
252 CryptMode
::None
| CryptMode
::SignOnly
=> DataBlob
::encode(&data
, None
, true)?
,
253 CryptMode
::Encrypt
=> DataBlob
::encode(&data
, crypt_config
.as_ref().map(Arc
::as_ref
), true)?
,
256 let raw_data
= blob
.into_inner();
258 let path
= format
!("api2/json/admin/datastore/{}/upload-backup-log", repo
.store());
261 "backup-type": snapshot
.group().backup_type(),
262 "backup-id": snapshot
.group().backup_id(),
263 "backup-time": snapshot
.backup_time(),
266 let body
= hyper
::Body
::from(raw_data
);
268 client
.upload("application/octet-stream", body
, &path
, Some(args
)).await
275 schema
: REPO_URL_SCHEMA
,
280 description
: "Snapshot path.",
283 schema
: OUTPUT_FORMAT
,
290 async
fn show_notes(param
: Value
) -> Result
<Value
, Error
> {
291 let repo
= extract_repository_from_value(¶m
)?
;
292 let path
= tools
::required_string_param(¶m
, "snapshot")?
;
294 let snapshot
: BackupDir
= path
.parse()?
;
295 let client
= connect(&repo
)?
;
297 let path
= format
!("api2/json/admin/datastore/{}/notes", repo
.store());
300 "backup-type": snapshot
.group().backup_type(),
301 "backup-id": snapshot
.group().backup_id(),
302 "backup-time": snapshot
.backup_time(),
305 let output_format
= get_output_format(¶m
);
307 let mut result
= client
.get(&path
, Some(args
)).await?
;
309 let notes
= result
["data"].take();
311 if output_format
== "text" {
312 if let Some(notes
) = notes
.as_str() {
313 println
!("{}", notes
);
316 format_and_print_result(
331 schema
: REPO_URL_SCHEMA
,
336 description
: "Snapshot path.",
340 description
: "The Notes.",
346 async
fn update_notes(param
: Value
) -> Result
<Value
, Error
> {
347 let repo
= extract_repository_from_value(¶m
)?
;
348 let path
= tools
::required_string_param(¶m
, "snapshot")?
;
349 let notes
= tools
::required_string_param(¶m
, "notes")?
;
351 let snapshot
: BackupDir
= path
.parse()?
;
352 let mut client
= connect(&repo
)?
;
354 let path
= format
!("api2/json/admin/datastore/{}/notes", repo
.store());
357 "backup-type": snapshot
.group().backup_type(),
358 "backup-id": snapshot
.group().backup_id(),
359 "backup-time": snapshot
.backup_time(),
363 client
.put(&path
, Some(args
)).await?
;
368 fn notes_cli() -> CliCommandMap
{
372 CliCommand
::new(&API_METHOD_SHOW_NOTES
)
373 .arg_param(&["snapshot"])
374 .completion_cb("snapshot", complete_backup_snapshot
),
378 CliCommand
::new(&API_METHOD_UPDATE_NOTES
)
379 .arg_param(&["snapshot", "notes"])
380 .completion_cb("snapshot", complete_backup_snapshot
),
384 pub fn snapshot_mgtm_cli() -> CliCommandMap
{
386 .insert("notes", notes_cli())
389 CliCommand
::new(&API_METHOD_LIST_SNAPSHOTS
)
390 .arg_param(&["group"])
391 .completion_cb("group", complete_backup_group
)
392 .completion_cb("repository", complete_repository
)
396 CliCommand
::new(&API_METHOD_LIST_SNAPSHOT_FILES
)
397 .arg_param(&["snapshot"])
398 .completion_cb("repository", complete_repository
)
399 .completion_cb("snapshot", complete_backup_snapshot
)
403 CliCommand
::new(&API_METHOD_FORGET_SNAPSHOTS
)
404 .arg_param(&["snapshot"])
405 .completion_cb("repository", complete_repository
)
406 .completion_cb("snapshot", complete_backup_snapshot
)
410 CliCommand
::new(&API_METHOD_UPLOAD_LOG
)
411 .arg_param(&["snapshot", "logfile"])
412 .completion_cb("snapshot", complete_backup_snapshot
)
413 .completion_cb("logfile", tools
::complete_file_name
)
414 .completion_cb("keyfile", tools
::complete_file_name
)
415 .completion_cb("repository", complete_repository
)