From: Lukas Wagner <l.wagner@proxmox.com>
To: pdm-devel@lists.proxmox.com
Subject: [PATCH datacenter-manager 4/4] remote-updates: switch over to new api_cache
Date: Wed, 13 May 2026 15:54:57 +0200 [thread overview]
Message-ID: <20260513135457.573414-5-l.wagner@proxmox.com> (raw)
In-Reply-To: <20260513135457.573414-1-l.wagner@proxmox.com>
Use the new, centralized API cache for caching remote update summaries.
Add some cleanup logic to remove the old cachefile, which can be removed
at some point in the future.
Signed-off-by: Lukas Wagner <l.wagner@proxmox.com>
---
Notes:
Changes since the RFC:
- use new async cache interface
- clean up old cachefile automatically
server/src/api/pve/mod.rs | 4 +-
server/src/api/remotes/updates.rs | 4 +-
server/src/remote_updates.rs | 87 ++++++++++++++++---------------
3 files changed, 49 insertions(+), 46 deletions(-)
diff --git a/server/src/api/pve/mod.rs b/server/src/api/pve/mod.rs
index 20892f38..649ab624 100644
--- a/server/src/api/pve/mod.rs
+++ b/server/src/api/pve/mod.rs
@@ -588,8 +588,8 @@ pub async fn get_options(remote: String) -> Result<serde_json::Value, Error> {
},
)]
/// Return the cached update information about a remote.
-pub fn get_updates(remote: String) -> Result<RemoteUpdateSummary, Error> {
- let update_summary = get_available_updates_for_remote(&remote)?;
+pub async fn get_updates(remote: String) -> Result<RemoteUpdateSummary, Error> {
+ let update_summary = get_available_updates_for_remote(&remote).await?;
Ok(update_summary)
}
diff --git a/server/src/api/remotes/updates.rs b/server/src/api/remotes/updates.rs
index 365ffc19..0ca78214 100644
--- a/server/src/api/remotes/updates.rs
+++ b/server/src/api/remotes/updates.rs
@@ -42,7 +42,7 @@ const SUBDIRS: SubdirMap = &sorted!([
returns: { type: UpdateSummary }
)]
/// Return available update summary for managed remote nodes.
-pub fn update_summary(rpcenv: &mut dyn RpcEnvironment) -> Result<UpdateSummary, Error> {
+pub async fn update_summary(rpcenv: &mut dyn RpcEnvironment) -> Result<UpdateSummary, Error> {
let auth_id = rpcenv
.get_auth_id()
.context("no authid available")?
@@ -53,7 +53,7 @@ pub fn update_summary(rpcenv: &mut dyn RpcEnvironment) -> Result<UpdateSummary,
http_bail!(FORBIDDEN, "user has no access to resources");
}
- let mut update_summary = remote_updates::get_available_updates_summary()?;
+ let mut update_summary = remote_updates::get_available_updates_summary().await?;
update_summary.remotes.retain(|remote_name, _| {
user_info
diff --git a/server/src/remote_updates.rs b/server/src/remote_updates.rs
index 7aaacc46..0129a563 100644
--- a/server/src/remote_updates.rs
+++ b/server/src/remote_updates.rs
@@ -1,6 +1,3 @@
-use std::fs::File;
-use std::io::ErrorKind;
-
use anyhow::{bail, Error};
use serde::{Deserialize, Serialize};
@@ -12,12 +9,13 @@ use pdm_api_types::remote_updates::{
};
use pdm_api_types::remotes::{Remote, RemoteType};
use pdm_api_types::RemoteUpid;
-use pdm_buildcfg::PDM_CACHE_DIR_M;
-use crate::connection;
use crate::parallel_fetcher::ParallelFetcher;
+use crate::{api_cache, connection};
-pub const UPDATE_CACHE: &str = concat!(PDM_CACHE_DIR_M!(), "/remote-updates.json");
+const OLD_CACHEFILE: &str = concat!(pdm_buildcfg::PDM_CACHE_DIR_M!(), "/remote-updates.json");
+
+const UPDATE_SUMMARY_CACHE_KEY: &str = "remote-updates";
#[derive(Clone, Default, Debug, Deserialize, Serialize)]
#[serde(rename_all = "kebab-case")]
@@ -106,10 +104,10 @@ pub async fn get_changelog(remote: &Remote, node: &str, package: String) -> Resu
}
/// Get update summary for all managed remotes.
-pub fn get_available_updates_summary() -> Result<UpdateSummary, Error> {
+pub async fn get_available_updates_summary() -> Result<UpdateSummary, Error> {
let (config, _digest) = pdm_config::remotes::config()?;
- let cache_content = get_cached_summary_or_default()?;
+ let cache_content = get_cached_summary_or_default().await?;
let mut summary = UpdateSummary::default();
@@ -137,11 +135,11 @@ pub fn get_available_updates_summary() -> Result<UpdateSummary, Error> {
}
/// Return cached update information from specific remote
-pub fn get_available_updates_for_remote(remote: &str) -> Result<RemoteUpdateSummary, Error> {
+pub async fn get_available_updates_for_remote(remote: &str) -> Result<RemoteUpdateSummary, Error> {
let (config, _digest) = pdm_config::remotes::config()?;
if let Some(remote) = config.get(remote) {
- let cache_content = get_cached_summary_or_default()?;
+ let cache_content = get_cached_summary_or_default().await?;
Ok(cache_content
.remotes
.get(&remote.id)
@@ -156,22 +154,12 @@ pub fn get_available_updates_for_remote(remote: &str) -> Result<RemoteUpdateSumm
}
}
-fn get_cached_summary_or_default() -> Result<UpdateSummary, Error> {
- match File::open(UPDATE_CACHE) {
- Ok(file) => {
- let content = match serde_json::from_reader(file) {
- Ok(cache_content) => cache_content,
- Err(err) => {
- log::error!("failed to deserialize remote update cache: {err:#}");
- Default::default()
- }
- };
-
- Ok(content)
- }
- Err(err) if err.kind() == ErrorKind::NotFound => Ok(Default::default()),
- Err(err) => Err(err.into()),
- }
+async fn get_cached_summary_or_default() -> Result<UpdateSummary, Error> {
+ Ok(api_cache::read_global()
+ .await?
+ .get::<UpdateSummary>(UPDATE_SUMMARY_CACHE_KEY)
+ .await?
+ .unwrap_or_default())
}
async fn update_cached_summary_for_node(
@@ -179,10 +167,11 @@ async fn update_cached_summary_for_node(
node: String,
node_data: NodeUpdateSummary,
) -> Result<(), Error> {
- let mut file = File::open(UPDATE_CACHE)?;
- let mut cache_content: UpdateSummary = serde_json::from_reader(&mut file)?;
- let remote_entry =
- cache_content
+ let cache = api_cache::write_global().await?;
+ let cache_content = cache.get::<UpdateSummary>(UPDATE_SUMMARY_CACHE_KEY).await?;
+
+ if let Some(mut entry) = cache_content {
+ let remote_entry = entry
.remotes
.entry(remote.id)
.or_insert_with(|| RemoteUpdateSummary {
@@ -191,15 +180,9 @@ async fn update_cached_summary_for_node(
status: RemoteUpdateStatus::Success,
});
- remote_entry.nodes.insert(node, node_data);
-
- let options = proxmox_product_config::default_create_options();
- proxmox_sys::fs::replace_file(
- UPDATE_CACHE,
- &serde_json::to_vec(&cache_content)?,
- options,
- true,
- )?;
+ remote_entry.nodes.insert(node, node_data);
+ cache.set(UPDATE_SUMMARY_CACHE_KEY, entry).await?;
+ }
Ok(())
}
@@ -212,7 +195,7 @@ pub async fn refresh_update_summary_cache(remotes: Vec<Remote>) -> Result<(), Er
.do_for_all_remote_nodes(remotes.clone().into_iter(), fetch_available_updates)
.await;
- let mut content = get_cached_summary_or_default()?;
+ let mut content = get_cached_summary_or_default().await?;
// Clean out any remotes that might have been removed from the remote config in the meanwhile.
content
@@ -275,8 +258,28 @@ pub async fn refresh_update_summary_cache(remotes: Vec<Remote>) -> Result<(), Er
}
}
- let options = proxmox_product_config::default_create_options();
- proxmox_sys::fs::replace_file(UPDATE_CACHE, &serde_json::to_vec(&content)?, options, true)?;
+ cleanup_old_cachefile().await?;
+
+ let cache = api_cache::write_global().await?;
+ cache.set(UPDATE_SUMMARY_CACHE_KEY, content).await?;
+
+ Ok(())
+}
+
+// FIXME: We can remove this pretty soon.
+async fn cleanup_old_cachefile() -> Result<(), Error> {
+ tokio::task::spawn_blocking(|| {
+ if let Err(err) = std::fs::remove_file(OLD_CACHEFILE) {
+ if err.kind() != std::io::ErrorKind::NotFound {
+ log::error!(
+ "could not clean up old remote update cache file {OLD_CACHEFILE}: {err}"
+ );
+ }
+ } else {
+ log::info!("removed obsolete remote update cachefile {OLD_CACHEFILE}")
+ }
+ })
+ .await?;
Ok(())
}
--
2.47.3
next prev parent reply other threads:[~2026-05-13 13:55 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-13 13:54 [PATCH datacenter-manager 0/4] add generic, per-remote (and global) cache for remote API responses Lukas Wagner
2026-05-13 13:54 ` [PATCH datacenter-manager 1/4] add persistent, generic, namespaced key-value cache implementation Lukas Wagner
2026-05-15 9:06 ` Thomas Lamprecht
2026-05-15 9:19 ` Lukas Wagner
2026-05-13 13:54 ` [PATCH datacenter-manager 2/4] add api_cache as a specialized wrapper around the namespaced cache Lukas Wagner
2026-05-15 9:06 ` Thomas Lamprecht
2026-05-15 9:22 ` Lukas Wagner
2026-05-13 13:54 ` [PATCH datacenter-manager 3/4] api: resources: subscriptions: switch over to api_cache Lukas Wagner
2026-05-15 9:06 ` Thomas Lamprecht
2026-05-15 9:49 ` Lukas Wagner
2026-05-13 13:54 ` Lukas Wagner [this message]
2026-05-15 9:06 ` [PATCH datacenter-manager 4/4] remote-updates: switch over to new api_cache Thomas Lamprecht
2026-05-15 12:56 ` Lukas Wagner
2026-05-15 8:30 ` superseded: [PATCH datacenter-manager 0/4] add generic, per-remote (and global) cache for remote API responses Lukas Wagner
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260513135457.573414-5-l.wagner@proxmox.com \
--to=l.wagner@proxmox.com \
--cc=pdm-devel@lists.proxmox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.