From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from gate001.proxmox.com (gate001.proxmox.com [IPv6:2a0f:8001:1:32::40]) by lore.proxmox.com (Postfix) with ESMTPS id 57FB61FF0E1 for ; Thu, 27 Aug 2026 13:43:22 +0200 (CEST) Received: from gate001.proxmox.com (localhost.localdomain [127.0.0.1]) by gate001.proxmox.com (Proxmox) with ESMTP id CD5E3215EA; Thu, 27 Aug 2026 13:43:12 +0200 (CEST) From: Lukas Wagner To: pdm-devel@lists.proxmox.com Subject: [PATCH datacenter-manager v3 18/21] context: provide api-cache on the app object Date: Thu, 27 Aug 2026 13:42:41 +0200 Message-ID: <20260827114244.424784-19-l.wagner@proxmox.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260827114244.424784-1-l.wagner@proxmox.com> References: <20260827114244.424784-1-l.wagner@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Bm-Milter-Handled: 55990f41-d878-4baa-be0a-ee34c49e34d2 X-Bm-Transport-Timestamp: 1787830961880 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.572 Adjusted score from AWL reputation of From: address DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment (newer systems) RCVD_IN_DNSWL_MED -2.3 Sender listed at https://www.dnswl.org/, medium trust SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Message-ID-Hash: GRQP76KETXOHPJSW3ZGTJSEKZ2B7O7TC X-Message-ID-Hash: GRQP76KETXOHPJSW3ZGTJSEKZ2B7O7TC X-MailFrom: l.wagner@proxmox.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.10 Precedence: list List-Id: Proxmox Datacenter Manager development discussion List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: Move the ApiCache instance from the global CACHE static onto PdmApplication, built from the product config's cache directory instead of the hardcoded PDM_API_CACHE_PATH. The free functions in api_cache now fetch it via context::pdm_application() instead of the static. Add default_file_create_options()/default_dir_create_options() to ProductConfig so the cache's directory and file permissions can be derived the same way in both the real application and tests. Signed-off-by: Lukas Wagner --- server/src/api_cache.rs | 45 ++++++++++--------- .../bin/proxmox-datacenter-privileged-api.rs | 7 ++- server/src/context/mod.rs | 20 ++++++++- server/tests/common/test_application.rs | 2 + 4 files changed, 52 insertions(+), 22 deletions(-) diff --git a/server/src/api_cache.rs b/server/src/api_cache.rs index 6dc8a043..fed66483 100644 --- a/server/src/api_cache.rs +++ b/server/src/api_cache.rs @@ -54,31 +54,22 @@ //! ``` use std::path::PathBuf; -use std::sync::LazyLock; use std::time::Duration; -use nix::sys::stat::Mode; - use proxmox_sys::fs::CreateOptions; +use crate::context; use crate::namespaced_cache::{ BlockingReadableCacheNamespace, BlockingWritableCacheNamespace, CacheError, NamespacedCache, ReadableCacheNamespace, WritableCacheNamespace, }; -/// Path at which API responses are cached. -pub const PDM_API_CACHE_PATH: &str = concat!(pdm_buildcfg::PDM_RUN_DIR_M!(), "/api-cache"); +/// Subdirectory at which API responses are cached. +pub const PDM_API_CACHE_SUBDIR: &str = "api-cache"; const GLOBAL_NAMESPACE: &str = "global"; const LOCK_TIMEOUT: Duration = Duration::from_secs(10); -static CACHE: LazyLock = LazyLock::new(|| { - let file_options = proxmox_product_config::default_create_options(); - let dir_options = file_options.perm(Mode::from_bits_truncate(0o750)); - - ApiCache::new(PathBuf::from(PDM_API_CACHE_PATH), dir_options, file_options) -}); - fn format_remote_namespace(remote: &str) -> String { format!("remote-{remote}") } @@ -157,40 +148,54 @@ impl ApiCache { /// Lock the cache for reading remote-specific data (blocking interface). pub fn read_remote_blocking(remote: &str) -> Result { - CACHE.read_remote_blocking(remote) + context::pdm_application() + .api_cache() + .read_remote_blocking(remote) } /// Lock the cache for writing remote-specific data (blocking interface). pub fn write_remote_blocking(remote: &str) -> Result { - CACHE.write_remote_blocking(remote) + context::pdm_application() + .api_cache() + .write_remote_blocking(remote) } /// Lock the cache for reading global data (blocking interface). pub fn read_global_blocking() -> Result { - CACHE.read_global_blocking() + context::pdm_application() + .api_cache() + .read_global_blocking() } /// Lock the cache for writing global data (blocking interface). pub fn write_global_blocking() -> Result { - CACHE.write_global_blocking() + context::pdm_application() + .api_cache() + .write_global_blocking() } /// Lock the cache for reading remote-specific data (async interface). pub async fn read_remote(remote: &str) -> Result { - CACHE.read_remote(remote).await + context::pdm_application() + .api_cache() + .read_remote(remote) + .await } /// Lock the cache for writing remote-specific data (async interface). pub async fn write_remote(remote: &str) -> Result { - CACHE.write_remote(remote).await + context::pdm_application() + .api_cache() + .write_remote(remote) + .await } /// Lock the cache for reading global data (async interface). pub async fn read_global() -> Result { - CACHE.read_global().await + context::pdm_application().api_cache().read_global().await } /// Lock the cache for writing global data (async interface). pub async fn write_global() -> Result { - CACHE.write_global().await + context::pdm_application().api_cache().write_global().await } diff --git a/server/src/bin/proxmox-datacenter-privileged-api.rs b/server/src/bin/proxmox-datacenter-privileged-api.rs index 3815ab03..d32e10c5 100644 --- a/server/src/bin/proxmox-datacenter-privileged-api.rs +++ b/server/src/bin/proxmox-datacenter-privileged-api.rs @@ -2,6 +2,7 @@ use std::path::Path; use std::pin::pin; use anyhow::{Context as _, Error, bail, format_err}; +use const_format::concatcp; use futures::*; use hyper_util::server::graceful::GracefulShutdown; use nix::fcntl::AtFlags; @@ -104,7 +105,11 @@ fn create_directories() -> Result<(), Error> { )?; pdm_config::setup::mkdir_perms( - api_cache::PDM_API_CACHE_PATH, + concatcp!( + pdm_buildcfg::PDM_RUN_DIR_M!(), + "/", + api_cache::PDM_API_CACHE_SUBDIR, + ), api_user.uid, api_user.gid, 0o750, diff --git a/server/src/context/mod.rs b/server/src/context/mod.rs index f0853d65..082ab8de 100644 --- a/server/src/context/mod.rs +++ b/server/src/context/mod.rs @@ -10,6 +10,7 @@ use proxmox_product_config::{ProductConfig, ProductConfigParams}; use pdm_config::{remotes::RemoteConfig, subscriptions::SubscriptionKeyConfig}; +use crate::api_cache::ApiCache; use crate::connection::{self, ClientFactory}; #[cfg(remote_config = "faked")] @@ -78,12 +79,22 @@ pub trait ContextFactory { } fn make_pdm_application(&self) -> Result { + let product_config = self.make_product_config()?; + + let api_cache = ApiCache::new( + product_config.run_dir().join("api-cache"), + product_config.default_dir_create_options(), + product_config.default_file_create_options(), + ); + Ok(PdmApplication { inner: Arc::new(PdmApplicationInner { client_factory: self.make_client_factory()?, remote_config: self.make_remote_config()?, subscription_key_config: self.make_subscription_key_config()?, - product_config: self.make_product_config()?, + product_config, + + api_cache, }), }) } @@ -138,6 +149,11 @@ impl PdmApplication { pub fn product_config(&self) -> &ProductConfig { &self.inner.product_config } + + /// Get a reference to the [`ApiCache`]. + pub fn api_cache(&self) -> &ApiCache { + &self.inner.api_cache + } } struct PdmApplicationInner { @@ -145,4 +161,6 @@ struct PdmApplicationInner { remote_config: Box, subscription_key_config: Box, product_config: ProductConfig, + + api_cache: ApiCache, } diff --git a/server/tests/common/test_application.rs b/server/tests/common/test_application.rs index bba5e5f0..83b35bf6 100644 --- a/server/tests/common/test_application.rs +++ b/server/tests/common/test_application.rs @@ -155,6 +155,8 @@ impl ContextFactory for TestApplication { std::fs::create_dir(&run_dir)?; std::fs::create_dir(&cache_dir)?; + std::fs::create_dir(run_dir.join("api-cache"))?; + Ok(ProductConfig::new(ProductConfigParams { api_user: user.clone(), priv_user: user, -- 2.47.3