From 9894469e89d7b74d623b708d24dd930ca3e4c9f2 Mon Sep 17 00:00:00 2001 From: Dietmar Maurer Date: Thu, 30 Jan 2020 13:29:39 +0100 Subject: [PATCH] src/bin/proxmox-backup-manager.rs: use new texdt table formatter --- Cargo.toml | 2 +- src/bin/proxmox-backup-manager.rs | 120 +++++++++++++++++++++++------- 2 files changed, 93 insertions(+), 29 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f824038b..b946f679 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,7 +34,7 @@ pam = "0.7" pam-sys = "0.5" percent-encoding = "2.1" pin-utils = "0.1.0-alpha" -proxmox = { version = "0.1.9", features = [ "sortable-macro", "api-macro" ] } +proxmox = { version = "0.1.10", features = [ "sortable-macro", "api-macro" ] } #proxmox = { git = "ssh://gitolite3@proxdev.maurer-it.com/rust/proxmox", version = "0.1.2", features = [ "sortable-macro", "api-macro" ] } #proxmox = { path = "../proxmox/proxmox", features = [ "sortable-macro", "api-macro" ] } regex = "1.2" diff --git a/src/bin/proxmox-backup-manager.rs b/src/bin/proxmox-backup-manager.rs index fac88cc4..11ceaa27 100644 --- a/src/bin/proxmox-backup-manager.rs +++ b/src/bin/proxmox-backup-manager.rs @@ -1,18 +1,41 @@ -use failure::*; -use serde_json::{json, Value}; use std::path::PathBuf; use std::collections::HashMap; +use failure::*; +use serde_json::{json, Value}; +use chrono::{Local, TimeZone}; + use proxmox::api::{api, cli::*}; use proxmox_backup::configdir; use proxmox_backup::tools; use proxmox_backup::config::{self, remote::{self, Remote}}; -use proxmox_backup::api2::types::*; +use proxmox_backup::api2::{self, types::* }; use proxmox_backup::client::*; use proxmox_backup::tools::ticket::*; use proxmox_backup::auth_helpers::*; +fn render_epoch(value: &Value, _record: &Value) -> Result { + if value.is_null() { return Ok(String::new()); } + let text = match value.as_i64() { + Some(epoch) => { + Local.timestamp(epoch, 0).format("%c").to_string() + } + None => { + value.to_string() + } + }; + Ok(text) +} + +fn render_status(value: &Value, record: &Value) -> Result { + if record["endtime"].is_null() { + Ok(value.as_str().unwrap_or("running").to_string()) + } else { + Ok(value.as_str().unwrap_or("unknown").to_string()) + } +} + async fn view_task_result( client: HttpClient, result: Value, @@ -50,12 +73,51 @@ fn connect() -> Result { Ok(client) } +#[api( + input: { + properties: { + "output-format": { + schema: OUTPUT_FORMAT, + optional: true, + }, + } + } +)] +/// List configured remotes. +async fn list_remotes(param: Value) -> Result { + + let output_format = param["output-format"].as_str().unwrap_or("text").to_owned(); + + let client = connect()?; + + let mut result = client.get("api2/json/config/remote", None).await?; + + let mut data = result["data"].take(); + let schema = api2::config::remote::API_RETURN_SCHEMA_LIST_REMOTES; + + let mut column_config = Vec::new(); + column_config.push(ColumnConfig::new("name")); + column_config.push(ColumnConfig::new("host")); + column_config.push(ColumnConfig::new("userid")); + column_config.push(ColumnConfig::new("fingerprint")); + column_config.push(ColumnConfig::new("comment")); + + let options = TableFormatOptions::new() + .noborder(false) + .noheader(false) + .column_config(column_config); + + + format_and_print_result_full(&mut data, schema, &output_format, &options); + + Ok(Value::Null) +} + fn remote_commands() -> CommandLineInterface { - use proxmox_backup::api2; - let cmd_def = CliCommandMap::new() - .insert("list", CliCommand::new(&api2::config::remote::API_METHOD_LIST_REMOTES)) + //.insert("list", CliCommand::new(&api2::config::remote::API_METHOD_LIST_REMOTES)) + .insert("list", CliCommand::new(&&API_METHOD_LIST_REMOTES)) .insert( "create", // fixme: howto handle password parameter? @@ -80,8 +142,6 @@ fn remote_commands() -> CommandLineInterface { fn datastore_commands() -> CommandLineInterface { - use proxmox_backup::api2; - let cmd_def = CliCommandMap::new() .insert("list", CliCommand::new(&api2::config::datastore::API_METHOD_LIST_DATASTORES)) .insert("create", @@ -158,13 +218,15 @@ async fn garbage_collection_status(param: Value) -> Result { let path = format!("api2/json/admin/datastore/{}/gc", store); - let result = client.get(&path, None).await?; - let data = &result["data"]; - if output_format == "text" { - format_and_print_result(&data, "json-pretty"); - } else { - format_and_print_result(&data, &output_format); - } + let mut result = client.get(&path, None).await?; + let mut data = result["data"].take(); + let schema = api2::admin::datastore::API_RETURN_SCHEMA_GARBAGE_COLLECTION_STATUS; + + let options = TableFormatOptions::new() + .noborder(false) + .noheader(false); + + format_and_print_result_full(&mut data, schema, &output_format, &options); Ok(Value::Null) } @@ -223,21 +285,23 @@ async fn task_list(param: Value) -> Result { "start": 0, "limit": limit, }); - let result = client.get("api2/json/nodes/localhost/tasks", Some(args)).await?; + let mut result = client.get("api2/json/nodes/localhost/tasks", Some(args)).await?; - let data = &result["data"]; + let mut data = result["data"].take(); + let schema = api2::node::tasks::API_RETURN_SCHEMA_LIST_TASKS; - if output_format == "text" { - for item in data.as_array().unwrap() { - println!( - "{} {}", - item["upid"].as_str().unwrap(), - item["status"].as_str().unwrap_or("running"), - ); - } - } else { - format_and_print_result(data, &output_format); - } + let mut column_config = Vec::new(); + column_config.push(ColumnConfig::new("starttime").right_align(false).renderer(render_epoch)); + column_config.push(ColumnConfig::new("endtime").right_align(false).renderer(render_epoch)); + column_config.push(ColumnConfig::new("upid")); + column_config.push(ColumnConfig::new("status").renderer(render_status)); + + let options = TableFormatOptions::new() + .noborder(false) + .noheader(false) + .column_config(column_config); + + format_and_print_result_full(&mut data, schema, &output_format, &options); Ok(Value::Null) }