mirror of
git://git.proxmox.com/git/proxmox-backup.git
synced 2025-01-06 13:18:00 +03:00
api: implement apt pkg cache
based on the idea of PVE Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
This commit is contained in:
parent
b282557563
commit
33508b1237
@ -26,17 +26,26 @@ use crate::api2::types::{Authid, APTUpdateInfo, NODE_SCHEMA, UPID_SCHEMA};
|
|||||||
type: APTUpdateInfo
|
type: APTUpdateInfo
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
protected: true,
|
||||||
access: {
|
access: {
|
||||||
permission: &Permission::Privilege(&[], PRIV_SYS_AUDIT, false),
|
permission: &Permission::Privilege(&[], PRIV_SYS_AUDIT, false),
|
||||||
},
|
},
|
||||||
)]
|
)]
|
||||||
/// List available APT updates
|
/// List available APT updates
|
||||||
fn apt_update_available(_param: Value) -> Result<Value, Error> {
|
fn apt_update_available(_param: Value) -> Result<Value, Error> {
|
||||||
let all_upgradeable = apt::list_installed_apt_packages(|data| {
|
|
||||||
data.candidate_version == data.active_version &&
|
match apt::pkg_cache_expired() {
|
||||||
data.installed_version != Some(data.candidate_version)
|
Ok(false) => {
|
||||||
}, None);
|
if let Ok(Some(cache)) = apt::read_pkg_state() {
|
||||||
Ok(json!(all_upgradeable))
|
return Ok(json!(cache.package_status));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
|
||||||
|
let cache = apt::update_cache()?;
|
||||||
|
|
||||||
|
return Ok(json!(cache.package_status));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn do_apt_update(worker: &WorkerTask, quiet: bool) -> Result<(), Error> {
|
fn do_apt_update(worker: &WorkerTask, quiet: bool) -> Result<(), Error> {
|
||||||
|
@ -1,12 +1,77 @@
|
|||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
use anyhow::{Error, bail};
|
use anyhow::{Error, bail, format_err};
|
||||||
use apt_pkg_native::Cache;
|
use apt_pkg_native::Cache;
|
||||||
|
|
||||||
use proxmox::const_regex;
|
use proxmox::const_regex;
|
||||||
|
use proxmox::tools::fs::{file_read_optional_string, replace_file, CreateOptions};
|
||||||
|
|
||||||
use crate::api2::types::APTUpdateInfo;
|
use crate::api2::types::APTUpdateInfo;
|
||||||
|
|
||||||
|
const APT_PKG_STATE_FN: &str = "/var/lib/proxmox-backup/pkg-state.json";
|
||||||
|
|
||||||
|
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
||||||
|
/// Some information we cache about the package (update) state
|
||||||
|
pub struct PkgState {
|
||||||
|
/// A list of pending updates
|
||||||
|
pub package_status: Vec<APTUpdateInfo>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write_pkg_cache(state: &PkgState) -> Result<(), Error> {
|
||||||
|
let serialized_state = serde_json::to_string(state)?;
|
||||||
|
|
||||||
|
replace_file(APT_PKG_STATE_FN, &serialized_state.as_bytes(), CreateOptions::new())
|
||||||
|
.map_err(|err| format_err!("Error writing package cache - {}", err))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_pkg_state() -> Result<Option<PkgState>, Error> {
|
||||||
|
let serialized_state = match file_read_optional_string(&APT_PKG_STATE_FN) {
|
||||||
|
Ok(Some(raw)) => raw,
|
||||||
|
Ok(None) => return Ok(None),
|
||||||
|
Err(err) => bail!("could not read cached package state file - {}", err),
|
||||||
|
};
|
||||||
|
|
||||||
|
serde_json::from_str(&serialized_state)
|
||||||
|
.map(|s| Some(s))
|
||||||
|
.map_err(|err| format_err!("could not parse cached package status - {}", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pkg_cache_expired () -> Result<bool, Error> {
|
||||||
|
if let Ok(pbs_cache) = std::fs::metadata(APT_PKG_STATE_FN) {
|
||||||
|
let apt_pkgcache = std::fs::metadata("/var/cache/apt/pkgcache.bin")?;
|
||||||
|
let dpkg_status = std::fs::metadata("/var/lib/dpkg/status")?;
|
||||||
|
|
||||||
|
let mtime = pbs_cache.modified()?;
|
||||||
|
|
||||||
|
if apt_pkgcache.modified()? <= mtime && dpkg_status.modified()? <= mtime {
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_cache() -> Result<PkgState, Error> {
|
||||||
|
// update our cache
|
||||||
|
let all_upgradeable = list_installed_apt_packages(|data| {
|
||||||
|
data.candidate_version == data.active_version &&
|
||||||
|
data.installed_version != Some(data.candidate_version)
|
||||||
|
}, None);
|
||||||
|
|
||||||
|
let cache = match read_pkg_state() {
|
||||||
|
Ok(Some(mut cache)) => {
|
||||||
|
cache.package_status = all_upgradeable;
|
||||||
|
cache
|
||||||
|
},
|
||||||
|
_ => PkgState {
|
||||||
|
package_status: all_upgradeable,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
write_pkg_cache(&cache)?;
|
||||||
|
Ok(cache)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const_regex! {
|
const_regex! {
|
||||||
VERSION_EPOCH_REGEX = r"^\d+:";
|
VERSION_EPOCH_REGEX = r"^\d+:";
|
||||||
FILENAME_EXTRACT_REGEX = r"^.*/.*?_(.*)_Packages$";
|
FILENAME_EXTRACT_REGEX = r"^.*/.*?_(.*)_Packages$";
|
||||||
|
Loading…
Reference in New Issue
Block a user