* [pbs-devel] [PATCH v2 proxmox-backup] add version API call
@ 2020-11-05 9:41 Mira Limbeck
2020-11-05 9:46 ` Mira Limbeck
0 siblings, 1 reply; 2+ messages in thread
From: Mira Limbeck @ 2020-11-05 9:41 UTC (permalink / raw)
To: pbs-devel
Adds an API call that returns all relevant packages, same as the version
API call in PVE.
In addition extens proxmox-backup-manager with the 'version' command
that prints the packages in a format similar to pveversion.
Signed-off-by: Mira Limbeck <m.limbeck@proxmox.com>
---
v2:
- renamed api call to 'versions' from 'version'
- incorporated stefan's suggestions:
- changed the filter to include all packages, but only installed
versions
- fixed looping over the cache multiple times
- fixed use of wrong version
- removed unnecessary version checks
src/api2/node.rs | 147 +++++++++++++++++++++++++++++-
src/api2/types/mod.rs | 15 ++-
src/bin/proxmox-backup-manager.rs | 39 ++++++++
src/tools/apt.rs | 3 +
4 files changed, 202 insertions(+), 2 deletions(-)
diff --git a/src/api2/node.rs b/src/api2/node.rs
index a19bea7e..7888cd24 100644
--- a/src/api2/node.rs
+++ b/src/api2/node.rs
@@ -19,7 +19,7 @@ use proxmox::tools::websocket::WebSocket;
use proxmox::{identity, sortable};
use crate::api2::types::*;
-use crate::config::acl::PRIV_SYS_CONSOLE;
+use crate::config::acl::{PRIV_SYS_AUDIT, PRIV_SYS_CONSOLE};
use crate::server::WorkerTask;
use crate::tools;
use crate::tools::ticket::{self, Empty, Ticket};
@@ -305,6 +305,150 @@ fn upgrade_to_websocket(
.boxed()
}
+#[api(
+ input: {
+ properties: {
+ node: {
+ schema: NODE_SCHEMA,
+ },
+ verbose: {
+ description: "Enable verbose output.",
+ type: Boolean,
+ optional: true,
+ default: false,
+ },
+ },
+ },
+ returns: {
+ description: "List of packages and their installed version.",
+ type: Array,
+ items: {
+ type: PackageInfo,
+ },
+ },
+ access: {
+ permission: &Permission::Privilege(&[], PRIV_SYS_AUDIT, false),
+ },
+)]
+/// Get package information for important Proxmox packages.
+pub fn get_versions(verbose: bool) -> Result<Value, Error> {
+ const PACKAGES: [&str; 11] = [
+ "ifupdown2",
+ "libjs-extjs",
+ "proxmox-backup",
+ "proxmox-backup-docs",
+ "proxmox-backup-client",
+ "proxmox-backup-server",
+ "proxmox-mini-journalreader",
+ "proxmox-widget-toolkit",
+ "pve-xtermjs",
+ "smartmontools",
+ "zfsutils-linux",
+ ];
+
+ let running_kernel = nix::sys::utsname::uname().release().to_owned();
+ let mut packages: Vec<PackageInfo> = Vec::new();
+ let pbs_packages = tools::apt::list_installed_apt_packages(
+ |fd| {
+ (fd.installed_version.is_some() && fd.installed_version.unwrap() == fd.active_version)
+ && (fd.package.starts_with("pve-kernel-") || PACKAGES.contains(&fd.package))
+ },
+ None,
+ );
+ if let Some(proxmox_backup) = pbs_packages
+ .iter()
+ .find(|pkg| pkg.package == "proxmox-backup")
+ {
+ packages.push(PackageInfo {
+ name: proxmox_backup.package.clone(),
+ version: proxmox_backup.old_version.clone(),
+ comment: Some(format!("running kernel: {}", &running_kernel)),
+ });
+ } else {
+ packages.push(PackageInfo {
+ name: "proxmox-backup".to_owned(),
+ version: "not correctly installed".to_owned(),
+ comment: Some(format!("running kernel: {}", &running_kernel)),
+ });
+ }
+
+ if !verbose {
+ return Ok(json!(packages));
+ }
+
+ if let Some(proxmox_backup_server) = pbs_packages
+ .iter()
+ .find(|pkg| pkg.package == "proxmox-backup-server")
+ {
+ packages.push(PackageInfo {
+ name: proxmox_backup_server.package.clone(),
+ version: proxmox_backup_server.old_version.clone(),
+ comment: Some(format!(
+ "running version: {}.{}",
+ crate::api2::version::PROXMOX_PKG_VERSION,
+ crate::api2::version::PROXMOX_PKG_RELEASE
+ )),
+ });
+ } else {
+ packages.push(PackageInfo {
+ name: "proxmox-backup-server".to_owned(),
+ version: "not correctly installed".to_owned(),
+ comment: Some(format!(
+ "running version: {}.{}",
+ crate::api2::version::PROXMOX_PKG_VERSION,
+ crate::api2::version::PROXMOX_PKG_RELEASE
+ )),
+ });
+ }
+
+ let mut pve_kernel_pkgs: Vec<APTUpdateInfo> = pbs_packages
+ .iter()
+ .filter(|pkg| pkg.package.starts_with("pve-kernel-"))
+ .cloned()
+ .collect();
+ {
+ let cache = apt_pkg_native::Cache::get_singleton();
+ pve_kernel_pkgs.sort_by(|left, right| {
+ cache
+ .compare_versions(&left.old_version, &right.old_version)
+ .reverse()
+ });
+ }
+
+ for pkg in pve_kernel_pkgs.iter().map(|pkg| PackageInfo {
+ name: pkg.package.clone(),
+ version: pkg.old_version.clone(),
+ comment: None,
+ }) {
+ packages.push(pkg);
+ }
+
+ // add packages we're interested in, but are not installed
+ // and the installed ones returned by list_installed_apt_packages
+ for pkg in PACKAGES.iter() {
+ if pkg == &"proxmox-backup" || pkg == &"proxmox-backup-server" {
+ continue;
+ }
+ let apt_pkg = pbs_packages.iter().find(|item| &item.package == pkg);
+ if apt_pkg.is_some() {
+ let apt_pkg = apt_pkg.unwrap();
+ packages.push(PackageInfo {
+ name: apt_pkg.package.clone(),
+ version: apt_pkg.old_version.clone(),
+ comment: None,
+ });
+ } else {
+ packages.push(PackageInfo {
+ name: pkg.to_string(),
+ version: "not installed".to_owned(),
+ comment: None,
+ });
+ }
+ }
+
+ Ok(json!(packages))
+}
+
pub const SUBDIRS: SubdirMap = &[
("apt", &apt::ROUTER),
("disks", &disks::ROUTER),
@@ -320,6 +464,7 @@ pub const SUBDIRS: SubdirMap = &[
("tasks", &tasks::ROUTER),
("termproxy", &Router::new().post(&API_METHOD_TERMPROXY)),
("time", &time::ROUTER),
+ ("versions", &Router::new().get(&API_METHOD_GET_VERSIONS)),
(
"vncwebsocket",
&Router::new().upgrade(&API_METHOD_WEBSOCKET),
diff --git a/src/api2/types/mod.rs b/src/api2/types/mod.rs
index 7ee89f57..707f1a9a 100644
--- a/src/api2/types/mod.rs
+++ b/src/api2/types/mod.rs
@@ -1129,7 +1129,7 @@ pub enum RRDTimeFrameResolution {
}
#[api()]
-#[derive(Debug, Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "PascalCase")]
/// Describes a package for which an update is available.
pub struct APTUpdateInfo {
@@ -1155,6 +1155,19 @@ pub struct APTUpdateInfo {
pub change_log_url: String,
}
+#[api()]
+#[derive(Serialize, Deserialize)]
+#[serde(rename_all = "PascalCase")]
+/// Pair of package name and version with optional comment.
+pub struct PackageInfo {
+ /// Package name
+ pub name: String,
+ /// Package version
+ pub version: String,
+ /// Optional comment
+ pub comment: Option<String>,
+}
+
#[api()]
#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
diff --git a/src/bin/proxmox-backup-manager.rs b/src/bin/proxmox-backup-manager.rs
index 7499446b..273bed81 100644
--- a/src/bin/proxmox-backup-manager.rs
+++ b/src/bin/proxmox-backup-manager.rs
@@ -363,6 +363,42 @@ async fn report() -> Result<Value, Error> {
Ok(Value::Null)
}
+#[api(
+ input: {
+ properties: {
+ verbose: {
+ description: "Enable verbose output.",
+ type: Boolean,
+ optional: true,
+ default: false,
+ },
+ },
+ },
+)]
+/// Get package information for important Proxmox packages.
+async fn get_versions(param: Value) -> Result<Value, Error> {
+ let client = connect()?;
+
+ let node = proxmox::tools::nodename();
+
+ let path = format!("api2/json/nodes/{}/versions", node);
+
+ let mut result = client.get(&path, Some(param)).await?;
+
+ let data = result["data"].take();
+ let packages: Vec<PackageInfo> = serde_json::from_value(data)?;
+
+ for pkg in packages {
+ if pkg.comment.is_some() {
+ println!("{}: {} ({})", pkg.name, pkg.version, pkg.comment.unwrap());
+ } else {
+ println!("{}: {}", pkg.name, pkg.version);
+ }
+ }
+
+ Ok(Value::Null)
+}
+
fn main() {
proxmox_backup::tools::setup_safe_path_env();
@@ -396,6 +432,9 @@ fn main() {
)
.insert("report",
CliCommand::new(&API_METHOD_REPORT)
+ )
+ .insert("versions",
+ CliCommand::new(&API_METHOD_GET_VERSIONS)
);
diff --git a/src/tools/apt.rs b/src/tools/apt.rs
index 5800e0a2..fab8f998 100644
--- a/src/tools/apt.rs
+++ b/src/tools/apt.rs
@@ -136,6 +136,8 @@ fn get_changelog_url(
}
pub struct FilterData<'a> {
+ // package name
+ pub package: &'a str,
// this is version info returned by APT
pub installed_version: Option<&'a str>,
pub candidate_version: &'a str,
@@ -270,6 +272,7 @@ where
let mut long_desc = "".to_owned();
let fd = FilterData {
+ package: package.as_str(),
installed_version: current_version.as_deref(),
candidate_version: &candidate_version,
active_version: &version,
--
2.20.1
^ permalink raw reply [flat|nested] 2+ messages in thread
* Re: [pbs-devel] [PATCH v2 proxmox-backup] add version API call
2020-11-05 9:41 [pbs-devel] [PATCH v2 proxmox-backup] add version API call Mira Limbeck
@ 2020-11-05 9:46 ` Mira Limbeck
0 siblings, 0 replies; 2+ messages in thread
From: Mira Limbeck @ 2020-11-05 9:46 UTC (permalink / raw)
To: pbs-devel
I changed the API call to 'versions' in the code, but not in the commit
message. Will send a v3 with this fixed.
On 11/5/20 10:41 AM, Mira Limbeck wrote:
> Adds an API call that returns all relevant packages, same as the version
> API call in PVE.
>
> In addition extens proxmox-backup-manager with the 'version' command
> that prints the packages in a format similar to pveversion.
>
> Signed-off-by: Mira Limbeck <m.limbeck@proxmox.com>
> ---
> v2:
> - renamed api call to 'versions' from 'version'
> - incorporated stefan's suggestions:
> - changed the filter to include all packages, but only installed
> versions
> - fixed looping over the cache multiple times
> - fixed use of wrong version
> - removed unnecessary version checks
>
> src/api2/node.rs | 147 +++++++++++++++++++++++++++++-
> src/api2/types/mod.rs | 15 ++-
> src/bin/proxmox-backup-manager.rs | 39 ++++++++
> src/tools/apt.rs | 3 +
> 4 files changed, 202 insertions(+), 2 deletions(-)
>
> diff --git a/src/api2/node.rs b/src/api2/node.rs
> index a19bea7e..7888cd24 100644
> --- a/src/api2/node.rs
> +++ b/src/api2/node.rs
> @@ -19,7 +19,7 @@ use proxmox::tools::websocket::WebSocket;
> use proxmox::{identity, sortable};
>
> use crate::api2::types::*;
> -use crate::config::acl::PRIV_SYS_CONSOLE;
> +use crate::config::acl::{PRIV_SYS_AUDIT, PRIV_SYS_CONSOLE};
> use crate::server::WorkerTask;
> use crate::tools;
> use crate::tools::ticket::{self, Empty, Ticket};
> @@ -305,6 +305,150 @@ fn upgrade_to_websocket(
> .boxed()
> }
>
> +#[api(
> + input: {
> + properties: {
> + node: {
> + schema: NODE_SCHEMA,
> + },
> + verbose: {
> + description: "Enable verbose output.",
> + type: Boolean,
> + optional: true,
> + default: false,
> + },
> + },
> + },
> + returns: {
> + description: "List of packages and their installed version.",
> + type: Array,
> + items: {
> + type: PackageInfo,
> + },
> + },
> + access: {
> + permission: &Permission::Privilege(&[], PRIV_SYS_AUDIT, false),
> + },
> +)]
> +/// Get package information for important Proxmox packages.
> +pub fn get_versions(verbose: bool) -> Result<Value, Error> {
> + const PACKAGES: [&str; 11] = [
> + "ifupdown2",
> + "libjs-extjs",
> + "proxmox-backup",
> + "proxmox-backup-docs",
> + "proxmox-backup-client",
> + "proxmox-backup-server",
> + "proxmox-mini-journalreader",
> + "proxmox-widget-toolkit",
> + "pve-xtermjs",
> + "smartmontools",
> + "zfsutils-linux",
> + ];
> +
> + let running_kernel = nix::sys::utsname::uname().release().to_owned();
> + let mut packages: Vec<PackageInfo> = Vec::new();
> + let pbs_packages = tools::apt::list_installed_apt_packages(
> + |fd| {
> + (fd.installed_version.is_some() && fd.installed_version.unwrap() == fd.active_version)
> + && (fd.package.starts_with("pve-kernel-") || PACKAGES.contains(&fd.package))
> + },
> + None,
> + );
> + if let Some(proxmox_backup) = pbs_packages
> + .iter()
> + .find(|pkg| pkg.package == "proxmox-backup")
> + {
> + packages.push(PackageInfo {
> + name: proxmox_backup.package.clone(),
> + version: proxmox_backup.old_version.clone(),
> + comment: Some(format!("running kernel: {}", &running_kernel)),
> + });
> + } else {
> + packages.push(PackageInfo {
> + name: "proxmox-backup".to_owned(),
> + version: "not correctly installed".to_owned(),
> + comment: Some(format!("running kernel: {}", &running_kernel)),
> + });
> + }
> +
> + if !verbose {
> + return Ok(json!(packages));
> + }
> +
> + if let Some(proxmox_backup_server) = pbs_packages
> + .iter()
> + .find(|pkg| pkg.package == "proxmox-backup-server")
> + {
> + packages.push(PackageInfo {
> + name: proxmox_backup_server.package.clone(),
> + version: proxmox_backup_server.old_version.clone(),
> + comment: Some(format!(
> + "running version: {}.{}",
> + crate::api2::version::PROXMOX_PKG_VERSION,
> + crate::api2::version::PROXMOX_PKG_RELEASE
> + )),
> + });
> + } else {
> + packages.push(PackageInfo {
> + name: "proxmox-backup-server".to_owned(),
> + version: "not correctly installed".to_owned(),
> + comment: Some(format!(
> + "running version: {}.{}",
> + crate::api2::version::PROXMOX_PKG_VERSION,
> + crate::api2::version::PROXMOX_PKG_RELEASE
> + )),
> + });
> + }
> +
> + let mut pve_kernel_pkgs: Vec<APTUpdateInfo> = pbs_packages
> + .iter()
> + .filter(|pkg| pkg.package.starts_with("pve-kernel-"))
> + .cloned()
> + .collect();
> + {
> + let cache = apt_pkg_native::Cache::get_singleton();
> + pve_kernel_pkgs.sort_by(|left, right| {
> + cache
> + .compare_versions(&left.old_version, &right.old_version)
> + .reverse()
> + });
> + }
> +
> + for pkg in pve_kernel_pkgs.iter().map(|pkg| PackageInfo {
> + name: pkg.package.clone(),
> + version: pkg.old_version.clone(),
> + comment: None,
> + }) {
> + packages.push(pkg);
> + }
> +
> + // add packages we're interested in, but are not installed
> + // and the installed ones returned by list_installed_apt_packages
> + for pkg in PACKAGES.iter() {
> + if pkg == &"proxmox-backup" || pkg == &"proxmox-backup-server" {
> + continue;
> + }
> + let apt_pkg = pbs_packages.iter().find(|item| &item.package == pkg);
> + if apt_pkg.is_some() {
> + let apt_pkg = apt_pkg.unwrap();
> + packages.push(PackageInfo {
> + name: apt_pkg.package.clone(),
> + version: apt_pkg.old_version.clone(),
> + comment: None,
> + });
> + } else {
> + packages.push(PackageInfo {
> + name: pkg.to_string(),
> + version: "not installed".to_owned(),
> + comment: None,
> + });
> + }
> + }
> +
> + Ok(json!(packages))
> +}
> +
> pub const SUBDIRS: SubdirMap = &[
> ("apt", &apt::ROUTER),
> ("disks", &disks::ROUTER),
> @@ -320,6 +464,7 @@ pub const SUBDIRS: SubdirMap = &[
> ("tasks", &tasks::ROUTER),
> ("termproxy", &Router::new().post(&API_METHOD_TERMPROXY)),
> ("time", &time::ROUTER),
> + ("versions", &Router::new().get(&API_METHOD_GET_VERSIONS)),
> (
> "vncwebsocket",
> &Router::new().upgrade(&API_METHOD_WEBSOCKET),
> diff --git a/src/api2/types/mod.rs b/src/api2/types/mod.rs
> index 7ee89f57..707f1a9a 100644
> --- a/src/api2/types/mod.rs
> +++ b/src/api2/types/mod.rs
> @@ -1129,7 +1129,7 @@ pub enum RRDTimeFrameResolution {
> }
>
> #[api()]
> -#[derive(Debug, Serialize, Deserialize)]
> +#[derive(Debug, Clone, Serialize, Deserialize)]
> #[serde(rename_all = "PascalCase")]
> /// Describes a package for which an update is available.
> pub struct APTUpdateInfo {
> @@ -1155,6 +1155,19 @@ pub struct APTUpdateInfo {
> pub change_log_url: String,
> }
>
> +#[api()]
> +#[derive(Serialize, Deserialize)]
> +#[serde(rename_all = "PascalCase")]
> +/// Pair of package name and version with optional comment.
> +pub struct PackageInfo {
> + /// Package name
> + pub name: String,
> + /// Package version
> + pub version: String,
> + /// Optional comment
> + pub comment: Option<String>,
> +}
> +
> #[api()]
> #[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
> #[serde(rename_all = "lowercase")]
> diff --git a/src/bin/proxmox-backup-manager.rs b/src/bin/proxmox-backup-manager.rs
> index 7499446b..273bed81 100644
> --- a/src/bin/proxmox-backup-manager.rs
> +++ b/src/bin/proxmox-backup-manager.rs
> @@ -363,6 +363,42 @@ async fn report() -> Result<Value, Error> {
> Ok(Value::Null)
> }
>
> +#[api(
> + input: {
> + properties: {
> + verbose: {
> + description: "Enable verbose output.",
> + type: Boolean,
> + optional: true,
> + default: false,
> + },
> + },
> + },
> +)]
> +/// Get package information for important Proxmox packages.
> +async fn get_versions(param: Value) -> Result<Value, Error> {
> + let client = connect()?;
> +
> + let node = proxmox::tools::nodename();
> +
> + let path = format!("api2/json/nodes/{}/versions", node);
> +
> + let mut result = client.get(&path, Some(param)).await?;
> +
> + let data = result["data"].take();
> + let packages: Vec<PackageInfo> = serde_json::from_value(data)?;
> +
> + for pkg in packages {
> + if pkg.comment.is_some() {
> + println!("{}: {} ({})", pkg.name, pkg.version, pkg.comment.unwrap());
> + } else {
> + println!("{}: {}", pkg.name, pkg.version);
> + }
> + }
> +
> + Ok(Value::Null)
> +}
> +
> fn main() {
>
> proxmox_backup::tools::setup_safe_path_env();
> @@ -396,6 +432,9 @@ fn main() {
> )
> .insert("report",
> CliCommand::new(&API_METHOD_REPORT)
> + )
> + .insert("versions",
> + CliCommand::new(&API_METHOD_GET_VERSIONS)
> );
>
>
> diff --git a/src/tools/apt.rs b/src/tools/apt.rs
> index 5800e0a2..fab8f998 100644
> --- a/src/tools/apt.rs
> +++ b/src/tools/apt.rs
> @@ -136,6 +136,8 @@ fn get_changelog_url(
> }
>
> pub struct FilterData<'a> {
> + // package name
> + pub package: &'a str,
> // this is version info returned by APT
> pub installed_version: Option<&'a str>,
> pub candidate_version: &'a str,
> @@ -270,6 +272,7 @@ where
> let mut long_desc = "".to_owned();
>
> let fd = FilterData {
> + package: package.as_str(),
> installed_version: current_version.as_deref(),
> candidate_version: &candidate_version,
> active_version: &version,
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2020-11-05 9:46 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-11-05 9:41 [pbs-devel] [PATCH v2 proxmox-backup] add version API call Mira Limbeck
2020-11-05 9:46 ` Mira Limbeck
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.
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal