From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by lists.proxmox.com (Postfix) with ESMTPS id 0575C63D22 for ; Thu, 27 Jan 2022 11:56:39 +0100 (CET) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 615932173B for ; Thu, 27 Jan 2022 11:56:08 +0100 (CET) Received: from proxmox-new.maurer-it.com (proxmox-new.maurer-it.com [94.136.29.106]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by firstgate.proxmox.com (Proxmox) with ESMTPS id 2CB8D21591 for ; Thu, 27 Jan 2022 11:56:03 +0100 (CET) Received: from proxmox-new.maurer-it.com (localhost.localdomain [127.0.0.1]) by proxmox-new.maurer-it.com (Proxmox) with ESMTP id F407746CC7 for ; Thu, 27 Jan 2022 11:56:02 +0100 (CET) From: Dominik Csapak To: pve-devel@lists.proxmox.com Date: Thu, 27 Jan 2022 11:55:58 +0100 Message-Id: <20220127105601.2741602-6-d.csapak@proxmox.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220127105601.2741602-1-d.csapak@proxmox.com> References: <20220127105601.2741602-1-d.csapak@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-SPAM-LEVEL: Spam detection results: 0 AWL 0.160 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Subject: [pve-devel] [PATCH proxmox-backup 5/5] file-restore: add 'timeout' and 'json-error' parameter X-BeenThere: pve-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox VE development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 27 Jan 2022 10:56:39 -0000 timeout limits the code with the given timeout in seconds, and 'json-error' return json to stdout when the call returns an error like this: { "msg": "error message", "error": true, "code": , // if it was an http error } with both options set, a client can more easily determine if the call ran into a timeout (since it will return a 503 error), and can poll it again both is done behind new parameters, so that we can stay backwards-compatible Signed-off-by: Dominik Csapak --- proxmox-file-restore/src/main.rs | 53 ++++++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/proxmox-file-restore/src/main.rs b/proxmox-file-restore/src/main.rs index cbf79802..16c197a9 100644 --- a/proxmox-file-restore/src/main.rs +++ b/proxmox-file-restore/src/main.rs @@ -7,6 +7,7 @@ use anyhow::{bail, format_err, Error}; use serde_json::{json, Value}; use proxmox_sys::fs::{create_path, CreateOptions}; +use proxmox_router::{http_err, HttpError}; use proxmox_router::cli::{ complete_file_name, default_table_format_options, format_and_print_result_full, get_output_format, @@ -213,6 +214,18 @@ async fn list_files( schema: OUTPUT_FORMAT, optional: true, }, + "json-error": { + type: Boolean, + description: "If set, errors are returned as json instead of writing to stderr", + optional: true, + default: false, + }, + "timeout": { + type: Integer, + description: "Defines the maximum time the call can should take.", + minimum: 1, + optional: true, + }, } }, returns: { @@ -228,6 +241,8 @@ async fn list( snapshot: String, path: String, base64: bool, + json_error: bool, + timeout: Option, param: Value, ) -> Result<(), Error> { let repo = extract_repository_from_value(¶m)?; @@ -253,10 +268,44 @@ async fn list( None => None, }; - let result = list_files(repo, snapshot, path, crypt_config, keyfile, driver).await?; + let result = if let Some(timeout) = timeout { + match tokio::time::timeout( + std::time::Duration::from_secs(timeout), + list_files(repo, snapshot, path, crypt_config, keyfile, driver), + ) + .await + { + Ok(res) => res, + Err(_) => Err(http_err!(SERVICE_UNAVAILABLE, "list not finished in time")), + } + } else { + list_files(repo, snapshot, path, crypt_config, keyfile, driver).await + }; let output_format = get_output_format(¶m); + if let Err(err) = result { + if !json_error { + return Err(err); + } + let (msg, code) = match err.downcast_ref::() { + Some(HttpError { code, message }) => (message.clone(), Some(code)), + None => (err.to_string(), None), + }; + let mut json_err = json!({ + "error": true, + "message": msg, + }); + if let Some(code) = code { + json_err["code"] = Value::from(code.as_u16()); + } + match output_format.as_ref() { + "json-pretty" => println!("{}", serde_json::to_string_pretty(&json_err)?), + _ => println!("{}", serde_json::to_string(&json_err)?), + } + return Ok(()); + } + let options = default_table_format_options() .sortby("type", false) .sortby("text", false) @@ -266,7 +315,7 @@ async fn list( .column(ColumnConfig::new("size")); format_and_print_result_full( - &mut json!(result), + &mut json!(result.unwrap()), &API_METHOD_LIST.returns, &output_format, &options, -- 2.30.2