all lists on lists.proxmox.com
 help / color / mirror / Atom feed
* [pbs-devel] [PATCH backup 1/2] move subscription API path to /nodes
@ 2020-07-21 11:41 Stefan Reiter
  2020-07-21 11:41 ` [pbs-devel] [PATCH v2 backup 2/2] add .../apt/update API call Stefan Reiter
  2020-07-21 17:36 ` [pbs-devel] applied: [PATCH backup 1/2] move subscription API path to /nodes Thomas Lamprecht
  0 siblings, 2 replies; 4+ messages in thread
From: Stefan Reiter @ 2020-07-21 11:41 UTC (permalink / raw)
  To: pbs-devel

This aligns it with PVE and allows the widget toolkit's update window
"refresh" to work without modifications once POST /apt/update is
implemented.

Signed-off-by: Stefan Reiter <s.reiter@proxmox.com>
---

I believe it makes more sense here in general, it is certainly node specific.

 src/api2.rs                         | 2 --
 src/api2/node.rs                    | 2 ++
 src/api2/{ => node}/subscription.rs | 8 ++++++++
 www/Dashboard.js                    | 2 +-
 www/Subscription.js                 | 2 +-
 5 files changed, 12 insertions(+), 4 deletions(-)
 rename src/api2/{ => node}/subscription.rs (88%)

diff --git a/src/api2.rs b/src/api2.rs
index 178f3f45..85d29ed2 100644
--- a/src/api2.rs
+++ b/src/api2.rs
@@ -4,7 +4,6 @@ pub mod backup;
 pub mod config;
 pub mod node;
 pub mod reader;
-mod subscription;
 pub mod status;
 pub mod types;
 pub mod version;
@@ -26,7 +25,6 @@ pub const SUBDIRS: SubdirMap = &[
     ("pull", &pull::ROUTER),
     ("reader", &reader::ROUTER),
     ("status", &status::ROUTER),
-    ("subscription", &subscription::ROUTER),
     ("version", &version::ROUTER),
 ];
 
diff --git a/src/api2/node.rs b/src/api2/node.rs
index 13ff282c..e67cab4e 100644
--- a/src/api2/node.rs
+++ b/src/api2/node.rs
@@ -9,6 +9,7 @@ mod syslog;
 mod journal;
 mod services;
 mod status;
+mod subscription;
 pub(crate) mod rrd;
 pub mod disks;
 
@@ -20,6 +21,7 @@ pub const SUBDIRS: SubdirMap = &[
     ("rrd", &rrd::ROUTER),
     ("services", &services::ROUTER),
     ("status", &status::ROUTER),
+    ("subscription", &subscription::ROUTER),
     ("syslog", &syslog::ROUTER),
     ("tasks", &tasks::ROUTER),
     ("time", &time::ROUTER),
diff --git a/src/api2/subscription.rs b/src/api2/node/subscription.rs
similarity index 88%
rename from src/api2/subscription.rs
rename to src/api2/node/subscription.rs
index 7d1b0237..186019cb 100644
--- a/src/api2/subscription.rs
+++ b/src/api2/node/subscription.rs
@@ -5,8 +5,16 @@ use proxmox::api::{api, Router, Permission};
 
 use crate::tools;
 use crate::config::acl::PRIV_SYS_AUDIT;
+use crate::api2::types::NODE_SCHEMA;
 
 #[api(
+    input: {
+        properties: {
+            node: {
+                schema: NODE_SCHEMA,
+            },
+        },
+    },
     returns: {
         description: "Subscription status.",
         properties: {
diff --git a/www/Dashboard.js b/www/Dashboard.js
index 7f699d93..d6dc40d2 100644
--- a/www/Dashboard.js
+++ b/www/Dashboard.js
@@ -209,7 +209,7 @@ Ext.define('PBS.Dashboard', {
 		autoDestroy: true,
 		proxy: {
 		    type: 'proxmox',
-		    url: '/api2/json/subscription'
+		    url: '/api2/json/nodes/localhost/subscription'
 		},
 		listeners: {
 		    load: 'updateSubscription'
diff --git a/www/Subscription.js b/www/Subscription.js
index f5a64459..8746091f 100644
--- a/www/Subscription.js
+++ b/www/Subscription.js
@@ -37,7 +37,7 @@ Ext.define('PBS.Subscription', {
 	    me.rstore.load();
 	};
 
-	var baseurl = '/subscription';
+	var baseurl = '/nodes/localhost/subscription';
 
 	var render_status = function(value) {
 
-- 
2.20.1





^ permalink raw reply	[flat|nested] 4+ messages in thread

* [pbs-devel] [PATCH v2 backup 2/2] add .../apt/update API call
  2020-07-21 11:41 [pbs-devel] [PATCH backup 1/2] move subscription API path to /nodes Stefan Reiter
@ 2020-07-21 11:41 ` Stefan Reiter
  2020-07-23  8:42   ` [pbs-devel] applied: " Thomas Lamprecht
  2020-07-21 17:36 ` [pbs-devel] applied: [PATCH backup 1/2] move subscription API path to /nodes Thomas Lamprecht
  1 sibling, 1 reply; 4+ messages in thread
From: Stefan Reiter @ 2020-07-21 11:41 UTC (permalink / raw)
  To: pbs-devel

Depends on patched apt-pkg-native-rs. Changelog-URL detection is
inspired by PVE perl code for now, though marked with fixme to use 'apt
changelog' later on, if/when our repos have APT-compatible changelogs
set up.

list_installed_apt_packages iterates all packages and creates an
APTUpdateInfo with detailed information for every package matched by the
given filter Fn.

Sadly, libapt-pkg has some questionable design choices regarding their
use of 'iterators', which means quite a bit of nesting...

Signed-off-by: Stefan Reiter <s.reiter@proxmox.com>
---

v2:
* Include feedback from Fabian:
** Update Cargo.toml with now packaged apt-pkg-native (still no update on my PR)
** Use proxmox.com changelog logic for all origin=Proxmox packages, not just pbs
** Change serde naming to PascalCase for APTUpdateInfo
** Add FIXME to changelog detection
** Update comments


 Cargo.toml           |   1 +
 src/api2/node.rs     |   2 +
 src/api2/node/apt.rs | 211 +++++++++++++++++++++++++++++++++++++++++++
 src/api2/types.rs    |  27 ++++++
 4 files changed, 241 insertions(+)
 create mode 100644 src/api2/node/apt.rs

diff --git a/Cargo.toml b/Cargo.toml
index 355217eb..b0881319 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -14,6 +14,7 @@ name = "proxmox_backup"
 path = "src/lib.rs"
 
 [dependencies]
+apt-pkg-native = "0.3.1" # custom patched version
 base64 = "0.12"
 bitflags = "1.2.1"
 bytes = "0.5"
diff --git a/src/api2/node.rs b/src/api2/node.rs
index e67cab4e..e8800e4c 100644
--- a/src/api2/node.rs
+++ b/src/api2/node.rs
@@ -12,8 +12,10 @@ mod status;
 mod subscription;
 pub(crate) mod rrd;
 pub mod disks;
+mod apt;
 
 pub const SUBDIRS: SubdirMap = &[
+    ("apt", &apt::ROUTER),
     ("disks", &disks::ROUTER),
     ("dns", &dns::ROUTER),
     ("journal", &journal::ROUTER),
diff --git a/src/api2/node/apt.rs b/src/api2/node/apt.rs
new file mode 100644
index 00000000..55d360fe
--- /dev/null
+++ b/src/api2/node/apt.rs
@@ -0,0 +1,211 @@
+use apt_pkg_native::Cache;
+use anyhow::{Error, bail};
+use serde_json::{json, Value};
+
+use proxmox::{list_subdirs_api_method, const_regex};
+use proxmox::api::{api, Router, Permission, SubdirMap};
+
+use crate::config::acl::PRIV_SYS_AUDIT;
+use crate::api2::types::{APTUpdateInfo, NODE_SCHEMA};
+
+const_regex! {
+    VERSION_EPOCH_REGEX = r"^\d+:";
+    FILENAME_EXTRACT_REGEX = r"^.*/.*?_(.*)_Packages$";
+}
+
+// FIXME: Replace with call to 'apt changelog <pkg> --print-uris'. Currently
+// not possible as our packages do not have a URI set in their Release file
+fn get_changelog_url(
+    package: &str,
+    filename: &str,
+    source_pkg: &str,
+    version: &str,
+    source_version: &str,
+    origin: &str,
+    component: &str,
+) -> Result<String, Error> {
+    if origin == "" {
+        bail!("no origin available for package {}", package);
+    }
+
+    if origin == "Debian" {
+        let source_version = (VERSION_EPOCH_REGEX.regex_obj)().replace_all(source_version, "");
+
+        let prefix = if source_pkg.starts_with("lib") {
+            source_pkg.get(0..4)
+        } else {
+            source_pkg.get(0..1)
+        };
+
+        let prefix = match prefix {
+            Some(p) => p,
+            None => bail!("cannot get starting characters of package name '{}'", package)
+        };
+
+        // note: security updates seem to not always upload a changelog for
+        // their package version, so this only works *most* of the time
+        return Ok(format!("https://metadata.ftp-master.debian.org/changelogs/main/{}/{}/{}_{}_changelog",
+                          prefix, source_pkg, source_pkg, source_version));
+
+    } else if origin == "Proxmox" {
+        let version = (VERSION_EPOCH_REGEX.regex_obj)().replace_all(version, "");
+
+        let base = match (FILENAME_EXTRACT_REGEX.regex_obj)().captures(filename) {
+            Some(captures) => {
+                let base_capture = captures.get(1);
+                match base_capture {
+                    Some(base_underscore) => base_underscore.as_str().replace("_", "/"),
+                    None => bail!("incompatible filename, cannot find regex group")
+                }
+            },
+            None => bail!("incompatible filename, doesn't match regex")
+        };
+
+        return Ok(format!("http://download.proxmox.com/{}/{}_{}.changelog",
+                          base, package, version));
+    }
+
+    bail!("unknown origin ({}) or component ({})", origin, component)
+}
+
+fn list_installed_apt_packages<F: Fn(&str, &str, &str) -> bool>(filter: F)
+    -> Vec<APTUpdateInfo> {
+
+    let mut ret = Vec::new();
+
+    // note: this is not an 'apt update', it just re-reads the cache from disk
+    let mut cache = Cache::get_singleton();
+    cache.reload();
+
+    let mut cache_iter = cache.iter();
+
+    loop {
+        let view = match cache_iter.next() {
+            Some(view) => view,
+            None => break
+        };
+
+        let current_version = match view.current_version() {
+            Some(vers) => vers,
+            None => continue
+        };
+        let candidate_version = match view.candidate_version() {
+            Some(vers) => vers,
+            // if there's no candidate (i.e. no update) get info of currently
+            // installed version instead
+            None => current_version.clone()
+        };
+
+        let package = view.name();
+        if filter(&package, &current_version, &candidate_version) {
+            let mut origin_res = "unknown".to_owned();
+            let mut section_res = "unknown".to_owned();
+            let mut priority_res = "unknown".to_owned();
+            let mut change_log_url = "".to_owned();
+            let mut short_desc = package.clone();
+            let mut long_desc = "".to_owned();
+
+            // get additional information via nested APT 'iterators'
+            let mut view_iter = view.versions();
+            while let Some(ver) = view_iter.next() {
+                if ver.version() == candidate_version {
+                    if let Some(section) = ver.section() {
+                        section_res = section;
+                    }
+
+                    if let Some(prio) = ver.priority_type() {
+                        priority_res = prio;
+                    }
+
+                    // assume every package has only one origin file (not
+                    // origin, but origin *file*, for some reason those seem to
+                    // be different concepts in APT)
+                    let mut origin_iter = ver.origin_iter();
+                    let origin = origin_iter.next();
+                    if let Some(origin) = origin {
+
+                        if let Some(sd) = origin.short_desc() {
+                            short_desc = sd;
+                        }
+
+                        if let Some(ld) = origin.long_desc() {
+                            long_desc = ld;
+                        }
+
+                        // the package files appear in priority order, meaning
+                        // the one for the candidate version is first
+                        let mut pkg_iter = origin.file();
+                        let pkg_file = pkg_iter.next();
+                        if let Some(pkg_file) = pkg_file {
+                            if let Some(origin_name) = pkg_file.origin() {
+                                origin_res = origin_name;
+                            }
+
+                            let filename = pkg_file.file_name();
+                            let source_pkg = ver.source_package();
+                            let source_ver = ver.source_version();
+                            let component = pkg_file.component();
+
+                            // build changelog URL from gathered information
+                            // ignore errors, use empty changelog instead
+                            let url = get_changelog_url(&package, &filename, &source_pkg,
+                                &candidate_version, &source_ver, &origin_res, &component);
+                            if let Ok(url) = url {
+                                change_log_url = url;
+                            }
+                        }
+                    }
+
+                    break;
+                }
+            }
+
+            let info = APTUpdateInfo {
+                package,
+                title: short_desc,
+                arch: view.arch(),
+                description: long_desc,
+                change_log_url,
+                origin: origin_res,
+                version: candidate_version,
+                old_version: current_version,
+                priority: priority_res,
+                section: section_res,
+            };
+            ret.push(info);
+        }
+    }
+
+    return ret;
+}
+
+#[api(
+    input: {
+        properties: {
+            node: {
+                schema: NODE_SCHEMA,
+            },
+        },
+    },
+    returns: {
+        description: "A list of packages with available updates.",
+        type: Array,
+        items: { type: APTUpdateInfo },
+    },
+    access: {
+        permission: &Permission::Privilege(&[], PRIV_SYS_AUDIT, false),
+    },
+)]
+/// List available APT updates
+fn apt_update_available(_param: Value) -> Result<Value, Error> {
+    let ret = list_installed_apt_packages(|_pkg, cur_ver, can_ver| cur_ver != can_ver);
+    Ok(json!(ret))
+}
+
+const SUBDIRS: SubdirMap = &[
+    ("update", &Router::new().get(&API_METHOD_APT_UPDATE_AVAILABLE)),
+];
+
+pub const ROUTER: Router = Router::new()
+    .get(&list_subdirs_api_method!(SUBDIRS))
+    .subdirs(SUBDIRS);
diff --git a/src/api2/types.rs b/src/api2/types.rs
index 0d0fab3b..f6972c8b 100644
--- a/src/api2/types.rs
+++ b/src/api2/types.rs
@@ -962,3 +962,30 @@ pub enum RRDTimeFrameResolution {
     /// 1 week => last 490 days
     Year = 60*10080,
 }
+
+#[api()]
+#[derive(Serialize, Deserialize)]
+#[serde(rename_all = "PascalCase")]
+/// Describes a package for which an update is available.
+pub struct APTUpdateInfo {
+    /// Package name
+    pub package: String,
+    /// Package title
+    pub title: String,
+    /// Package architecture
+    pub arch: String,
+    /// Human readable package description
+    pub description: String,
+    /// New version to be updated to
+    pub version: String,
+    /// Old version currently installed
+    pub old_version: String,
+    /// Package origin
+    pub origin: String,
+    /// Package priority in human-readable form
+    pub priority: String,
+    /// Package section
+    pub section: String,
+    /// URL under which the package's changelog can be retrieved
+    pub change_log_url: String,
+}
-- 
2.20.1





^ permalink raw reply	[flat|nested] 4+ messages in thread

* [pbs-devel] applied: [PATCH backup 1/2] move subscription API path to /nodes
  2020-07-21 11:41 [pbs-devel] [PATCH backup 1/2] move subscription API path to /nodes Stefan Reiter
  2020-07-21 11:41 ` [pbs-devel] [PATCH v2 backup 2/2] add .../apt/update API call Stefan Reiter
@ 2020-07-21 17:36 ` Thomas Lamprecht
  1 sibling, 0 replies; 4+ messages in thread
From: Thomas Lamprecht @ 2020-07-21 17:36 UTC (permalink / raw)
  To: Proxmox Backup Server development discussion, Stefan Reiter

On 21.07.20 13:41, Stefan Reiter wrote:
> This aligns it with PVE and allows the widget toolkit's update window
> "refresh" to work without modifications once POST /apt/update is
> implemented.
> 
> Signed-off-by: Stefan Reiter <s.reiter@proxmox.com>
> ---
> 
> I believe it makes more sense here in general, it is certainly node specific.
> 
>  src/api2.rs                         | 2 --
>  src/api2/node.rs                    | 2 ++
>  src/api2/{ => node}/subscription.rs | 8 ++++++++
>  www/Dashboard.js                    | 2 +-
>  www/Subscription.js                 | 2 +-
>  5 files changed, 12 insertions(+), 4 deletions(-)
>  rename src/api2/{ => node}/subscription.rs (88%)
> 
>

applied, thanks!




^ permalink raw reply	[flat|nested] 4+ messages in thread

* [pbs-devel] applied: [PATCH v2 backup 2/2] add .../apt/update API call
  2020-07-21 11:41 ` [pbs-devel] [PATCH v2 backup 2/2] add .../apt/update API call Stefan Reiter
@ 2020-07-23  8:42   ` Thomas Lamprecht
  0 siblings, 0 replies; 4+ messages in thread
From: Thomas Lamprecht @ 2020-07-23  8:42 UTC (permalink / raw)
  To: Proxmox Backup Server development discussion, Stefan Reiter

On 21.07.20 13:41, Stefan Reiter wrote:
> Depends on patched apt-pkg-native-rs. Changelog-URL detection is
> inspired by PVE perl code for now, though marked with fixme to use 'apt
> changelog' later on, if/when our repos have APT-compatible changelogs
> set up.
> 
> list_installed_apt_packages iterates all packages and creates an
> APTUpdateInfo with detailed information for every package matched by the
> given filter Fn.
> 
> Sadly, libapt-pkg has some questionable design choices regarding their
> use of 'iterators', which means quite a bit of nesting...
> 
> Signed-off-by: Stefan Reiter <s.reiter@proxmox.com>
> ---
> 
> v2:
> * Include feedback from Fabian:
> ** Update Cargo.toml with now packaged apt-pkg-native (still no update on my PR)
> ** Use proxmox.com changelog logic for all origin=Proxmox packages, not just pbs
> ** Change serde naming to PascalCase for APTUpdateInfo
> ** Add FIXME to changelog detection
> ** Update comments
> 
> 
>  Cargo.toml           |   1 +
>  src/api2/node.rs     |   2 +
>  src/api2/node/apt.rs | 211 +++++++++++++++++++++++++++++++++++++++++++
>  src/api2/types.rs    |  27 ++++++
>  4 files changed, 241 insertions(+)
>  create mode 100644 src/api2/node/apt.rs
> 
>

applied, thanks! Adding additionally the POST call on it for `apt-get update` wouldn't
have been really more work ;)




^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2020-07-23  8:42 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-07-21 11:41 [pbs-devel] [PATCH backup 1/2] move subscription API path to /nodes Stefan Reiter
2020-07-21 11:41 ` [pbs-devel] [PATCH v2 backup 2/2] add .../apt/update API call Stefan Reiter
2020-07-23  8:42   ` [pbs-devel] applied: " Thomas Lamprecht
2020-07-21 17:36 ` [pbs-devel] applied: [PATCH backup 1/2] move subscription API path to /nodes Thomas Lamprecht

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