public inbox for pbs-devel@lists.proxmox.com
 help / color / mirror / Atom feed
* [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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal