From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: <pdm-devel-bounces@lists.proxmox.com> Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) by lore.proxmox.com (Postfix) with ESMTPS id E1EF21FF15C for <inbox@lore.proxmox.com>; Wed, 5 Mar 2025 16:01:19 +0100 (CET) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id EC51F18D87; Wed, 5 Mar 2025 16:01:13 +0100 (CET) From: Wolfgang Bumiller <w.bumiller@proxmox.com> To: pdm-devel@lists.proxmox.com Date: Wed, 5 Mar 2025 16:01:04 +0100 Message-Id: <20250305150108.245584-4-w.bumiller@proxmox.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20250305150108.245584-1-w.bumiller@proxmox.com> References: <20250305150108.245584-1-w.bumiller@proxmox.com> MIME-Version: 1.0 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.081 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 RCVD_IN_VALIDITY_CERTIFIED_BLOCKED 0.001 ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. RCVD_IN_VALIDITY_RPBL_BLOCKED 0.001 ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. RCVD_IN_VALIDITY_SAFE_BLOCKED 0.001 ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record URIBL_BLOCKED 0.001 ADMINISTRATOR NOTICE: The query to URIBL was blocked. See http://wiki.apache.org/spamassassin/DnsBlocklists#dnsbl-block for more information. [connection.rs] Subject: [pdm-devel] [PATCH v2 datacenter-manager 3/7] server: separate ConnectInfo from client creation X-BeenThere: pdm-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox Datacenter Manager development discussion <pdm-devel.lists.proxmox.com> List-Unsubscribe: <https://lists.proxmox.com/cgi-bin/mailman/options/pdm-devel>, <mailto:pdm-devel-request@lists.proxmox.com?subject=unsubscribe> List-Archive: <http://lists.proxmox.com/pipermail/pdm-devel/> List-Post: <mailto:pdm-devel@lists.proxmox.com> List-Help: <mailto:pdm-devel-request@lists.proxmox.com?subject=help> List-Subscribe: <https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel>, <mailto:pdm-devel-request@lists.proxmox.com?subject=subscribe> Reply-To: Proxmox Datacenter Manager development discussion <pdm-devel@lists.proxmox.com> Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: pdm-devel-bounces@lists.proxmox.com Sender: "pdm-devel" <pdm-devel-bounces@lists.proxmox.com> Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com> Reviewed-by: Lukas Wagner <l.wagner@proxmox.com> --- No changes since v1. server/src/connection.rs | 141 +++++++++++++++++++++++---------------- 1 file changed, 83 insertions(+), 58 deletions(-) diff --git a/server/src/connection.rs b/server/src/connection.rs index 984cd79..35b9462 100644 --- a/server/src/connection.rs +++ b/server/src/connection.rs @@ -29,43 +29,29 @@ static INSTANCE: OnceLock<Box<dyn ClientFactory + Send + Sync>> = OnceLock::new( /// Connection Info returned from [`prepare_connect_client`] struct ConnectInfo { - pub client: Client, - pub prefix: String, - pub perl_compat: bool, + prefix: String, + perl_compat: bool, + pve_compat: bool, + default_port: u16, } -/// Returns a [`proxmox_client::Client`] and a token prefix for the specified -/// [`pdm_api_types::Remote`] -fn prepare_connect_client( - remote: &Remote, - target_endpoint: Option<&str>, -) -> Result<ConnectInfo, Error> { - let node = remote - .nodes - .iter() - .find(|endpoint| match target_endpoint { - Some(target) => target == endpoint.hostname, - None => true, - }) - .ok_or_else(|| match target_endpoint { - Some(endpoint) => format_err!("{endpoint} not configured for remote"), - None => format_err!("no nodes configured for remote"), - })?; +impl ConnectInfo { + fn for_remote(remote: &Remote) -> Self { + let (default_port, prefix, perl_compat, pve_compat) = match remote.ty { + RemoteType::Pve => (8006, "PVEAPIToken".to_string(), true, true), + RemoteType::Pbs => (8007, "PBSAPIToken".to_string(), false, false), + }; - let (default_port, prefix, perl_compat, pve_compat) = match remote.ty { - RemoteType::Pve => (8006, "PVEAPIToken".to_string(), true, true), - RemoteType::Pbs => (8007, "PBSAPIToken".to_string(), false, false), - }; - - let client = prepare_connect_client_to_node(node, default_port, pve_compat)?; - - Ok(ConnectInfo { - client, - prefix, - perl_compat, - }) + ConnectInfo { + prefix, + perl_compat, + pve_compat, + default_port, + } + } } - +/// +/// Returns a [`proxmox_client::Client`] set up to connect to a specific node. fn prepare_connect_client_to_node( node: &NodeUrl, default_port: u16, @@ -92,51 +78,82 @@ fn prepare_connect_client_to_node( Ok(client) } +/// Returns a [`proxmox_client::Client`] and connection info required to set token authentication +/// data for the [`pdm_api_types::Remote`]. +fn prepare_connect_client( + remote: &Remote, + target_endpoint: Option<&str>, +) -> Result<(Client, ConnectInfo), Error> { + let node = remote + .nodes + .iter() + .find(|endpoint| match target_endpoint { + Some(target) => target == endpoint.hostname, + None => true, + }) + .ok_or_else(|| match target_endpoint { + Some(endpoint) => format_err!("{endpoint} not configured for remote"), + None => format_err!("no nodes configured for remote"), + })?; + + let info = ConnectInfo::for_remote(remote); + + let client = prepare_connect_client_to_node(node, info.default_port, info.pve_compat)?; + + Ok((client, info)) +} + /// Constructs a [`Client`] for the given [`Remote`] for an API token /// /// It does not actually opens a connection there, but prepares the client with the correct /// authentication information and settings for the [`RemoteType`] fn connect(remote: &Remote, target_endpoint: Option<&str>) -> Result<Client, anyhow::Error> { - let ConnectInfo { - client, - perl_compat, - prefix, - } = prepare_connect_client(remote, target_endpoint)?; + let (client, info) = prepare_connect_client(remote, target_endpoint)?; client.set_authentication(proxmox_client::Token { userid: remote.authid.to_string(), - prefix, value: remote.token.to_string(), - perl_compat, + prefix: info.prefix, + perl_compat: info.perl_compat, }); - Ok(client) } -/// Like [`connect()`], but for remotes which have multiple clients. -fn multi_connect(remote: &Remote) -> Result<MultiClient, anyhow::Error> { - let (default_port, prefix, perl_compat, pve_compat) = match remote.ty { - RemoteType::Pve => (8006, "PVEAPIToken".to_string(), true, true), - RemoteType::Pbs => (8007, "PBSAPIToken".to_string(), false, false), +/// Returns a [`MultiClient`] and connection info required to set token authentication +/// data for the [`pdm_api_types::Remote`]. +fn prepare_connect_multi_client(remote: &Remote) -> Result<(MultiClient, ConnectInfo), Error> { + if remote.nodes.is_empty() { + bail!("no nodes configured for remote"); }; + let info = ConnectInfo::for_remote(remote); + let mut clients = Vec::new(); for node in &remote.nodes { - let client = prepare_connect_client_to_node(node, default_port, pve_compat)?; + clients.push(Arc::new(prepare_connect_client_to_node( + node, + info.default_port, + info.pve_compat, + )?)); + } + + Ok((MultiClient::new(clients), info)) +} + +/// Like [`connect()`], but with failover support for remotes which can have multiple nodes. +fn multi_connect(remote: &Remote) -> Result<MultiClient, anyhow::Error> { + let (client, info) = prepare_connect_multi_client(remote)?; + + client.for_each_client(|client| { client.set_authentication(proxmox_client::Token { userid: remote.authid.to_string(), - prefix: prefix.clone(), value: remote.token.to_string(), - perl_compat, + prefix: info.prefix.clone(), + perl_compat: info.perl_compat, }); - clients.push(Arc::new(client)); - } - - if clients.is_empty() { - bail!("no nodes configured for remote"); - } + }); - Ok(MultiClient::new(clients)) + Ok(client) } /// Constructs a [`Client`] for the given [`Remote`] for an API token or user @@ -155,8 +172,7 @@ async fn connect_or_login( if remote.authid.is_token() { connect(remote, target_endpoint) } else { - let info = prepare_connect_client(remote, target_endpoint)?; - let client = info.client; + let (client, _info) = prepare_connect_client(remote, target_endpoint)?; match client .login(proxmox_login::Login::new( client.api_url().to_string(), @@ -424,6 +440,15 @@ impl MultiClient { timeout: Duration::from_secs(60), } } + + fn for_each_client<F>(&self, func: F) + where + F: Fn(&Arc<Client>), + { + for client in &self.state.lock().unwrap().clients { + func(client); + } + } } /// Keeps track of which client (iow. which specific node of a remote) we're supposed to be using -- 2.39.5 _______________________________________________ pdm-devel mailing list pdm-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel