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 BC832A0B08 for ; Thu, 9 Nov 2023 16:34:17 +0100 (CET) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 81E0016FEA for ; Thu, 9 Nov 2023 16:34:17 +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 for ; Thu, 9 Nov 2023 16:34:16 +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 EED3547792 for ; Thu, 9 Nov 2023 16:34:15 +0100 (CET) From: Stefan Sterz To: pbs-devel@lists.proxmox.com Date: Thu, 9 Nov 2023 16:34:01 +0100 Message-Id: <20231109153403.529870-5-s.sterz@proxmox.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20231109153403.529870-1-s.sterz@proxmox.com> References: <20231109153403.529870-1-s.sterz@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-SPAM-LEVEL: Spam detection results: 0 AWL -0.087 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy 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 T_SCC_BODY_TEXT_LINE -0.01 - Subject: [pbs-devel] [PATCH proxmox-offline-mirror 4/6] helper: improve handling of multiple keys when activating them X-BeenThere: pbs-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox Backup Server development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 09 Nov 2023 15:34:17 -0000 this commit fixes a behavior where pom would applied any subscription key that matched the provided product. it did not check whether the server id of the activated subscription matched the current system. this commit fixes that and only allows applying subscriptions for the current system. it also adds a couple of ux improvements: - the `offline-key` sub-command now does not require the `--product` parameter anymore. if there are multiple keys with different products for the same server we will try to activate them all. the assumption is that the user added all keys intentionally (e.g. a combo pbs+pve system) and would like to activate them all at once. since this only makes the api more permissive this shouldn't be a breaking change. - if the `offline-key` sub-command encounters multiple subscription keys with the same product and server id, it only activates the one with the due date furthest in the future. this makes sense in a scenario where a user simply adds new subscription keys to their key medium without removing older ones (perhaps older subscriptions haven't even expired just yet). - the interactive `setup` sub-command now only offers keys that have a matching server id. it also orders them in such a way that the top most key for a given product has the next due date furthest in the future. Signed-off-by: Stefan Sterz --- src/bin/proxmox-offline-mirror-helper.rs | 97 ++++++++++++++---------- 1 file changed, 59 insertions(+), 38 deletions(-) diff --git a/src/bin/proxmox-offline-mirror-helper.rs b/src/bin/proxmox-offline-mirror-helper.rs index f1b4bd7..a231e84 100644 --- a/src/bin/proxmox-offline-mirror-helper.rs +++ b/src/bin/proxmox-offline-mirror-helper.rs @@ -24,7 +24,7 @@ use proxmox_offline_mirror::helpers::tty::{ use proxmox_offline_mirror::medium::{self, generate_repo_snippet, MediumState}; fn set_subscription_key( - product: ProductType, + product: &ProductType, subscription: &SubscriptionInfo, ) -> Result { let data = base64::encode(serde_json::to_vec(subscription)?); @@ -218,32 +218,34 @@ async fn setup(_param: Value) -> Result<(), Error> { } Action::UpdateOfflineSubscription => { let server_id = proxmox_subscription::get_hardware_address()?; - let subscriptions: Vec<(&SubscriptionInfo, &str)> = state + let mut subscriptions: Vec<((ProductType, &SubscriptionInfo), &str)> = state .subscriptions .iter() - .filter_map(|s| { - if let Some(key) = s.key.as_ref() { - if let Ok(product) = key[..3].parse::() { - if product == ProductType::Pom { - return None; - } else { - return Some((s, key.as_str())); - } - } - } - None + .filter(|sub| sub.serverid.as_ref() == Some(&server_id)) + .filter_map(|sub| { + sub.get_product_type() + .ok() + .and_then(|prod| Some(((prod, sub), sub.key.as_ref()?.as_str()))) }) + .filter(|((found_product, _), _)| found_product != &ProductType::Pom) .collect(); + subscriptions.sort_by(|((prod_a, sub_a), _), ((prod_b, sub_b), _)| { + if prod_a == prod_b { + return sub_b + .get_next_due_date() + .ok() + .cmp(&sub_a.get_next_due_date().ok()); + } + + prod_a.cmp(prod_b) + }); + if subscriptions.is_empty() { - println!( - "No matching subscription key found for server ID '{}'", - server_id - ); + println!("No matching subscription key found for server ID '{server_id}'"); } else { - let info = read_selection_from_tty("Select key", &subscriptions, None)?; - // safe unwrap, checked above! - let product: ProductType = info.key.as_ref().unwrap()[..3].parse()?; + let (product, info) = + read_selection_from_tty("Select key", &subscriptions, None)?; set_subscription_key(product, info)?; } } @@ -265,6 +267,7 @@ async fn setup(_param: Value) -> Result<(), Error> { }, product: { type: ProductType, + optional: true, }, }, }, @@ -272,10 +275,10 @@ async fn setup(_param: Value) -> Result<(), Error> { /// Configures and offline subscription key async fn setup_offline_key( mountpoint: String, - product: ProductType, + product: Option, _param: Value, ) -> Result<(), Error> { - if product == ProductType::Pom { + if product == Some(ProductType::Pom) { param_bail!( "product", format_err!("Proxmox Offline Mirror does not support offline operations.") @@ -299,27 +302,45 @@ async fn setup_offline_key( ); let server_id = proxmox_subscription::get_hardware_address()?; - let subscription = state.subscriptions.iter().find(|s| { - if let Some(key) = s.key.as_ref() { - if let Ok(found_product) = key[..3].parse::() { - return product == found_product; - } + + let mut subscriptions: Vec<(ProductType, &SubscriptionInfo)> = state + .subscriptions + .iter() + .filter(|sub| sub.serverid.as_ref() == Some(&server_id)) + .filter_map(|sub| sub.get_product_type().ok().map(|prod| (prod, sub))) + .filter(|(found_product, _)| { + (product.is_none() || Some(found_product) == product.as_ref()) + && found_product != &ProductType::Pom + }) + .collect(); + + if subscriptions.is_empty() { + bail!("No matching subscription key found for server ID '{server_id}'"); + } + + subscriptions.sort_by(|(prod_a, sub_a), (prod_b, sub_b)| { + if prod_a == prod_b { + return sub_b + .get_next_due_date() + .ok() + .cmp(&sub_a.get_next_due_date().ok()); } - false + + prod_a.cmp(prod_b) }); - match subscription { - Some(subscription) => { - eprintln!("Setting offline subscription key for {product}.."); - match set_subscription_key(product, subscription) { - Ok(output) if !output.is_empty() => eprintln!("success: {output}"), - Ok(_) => eprintln!("success."), - Err(err) => eprintln!("error: {err}"), - } - Ok(()) + subscriptions.dedup_by(|(prod_a, _), (prod_b, _)| prod_a == prod_b); + + for (product, subscription) in subscriptions { + eprintln!("Setting offline subscription key for {product}..."); + match set_subscription_key(&product, subscription) { + Ok(output) if !output.is_empty() => eprintln!("success: {output}"), + Ok(_) => eprintln!("success."), + Err(err) => eprintln!("error: {err}"), } - None => bail!("No matching subscription key found for product '{product}' and server ID '{server_id}'"), } + + Ok(()) } #[api( -- 2.39.2