[pbs-devel] [PATCH proxmox-backup] apt: allow changelog retrieval from enterprise repo

Stefan Reiter s.reiter at proxmox.com
Mon Nov 9 10:35:28 CET 2020


If a package is or will be installed from the enterprise repo, retrieve
the changelog from there as well (securely via HTTPS and authenticated
with the subcription key).

Extends the get_string method to take additional headers, in this case
used for 'Authorization'. Hyper does not have built-in basic auth
support AFAICT but it's simple enough to just build the header manually.

Take the opportunity and also set the User-Agent sensibly for GET
requests, just like for POST.

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

Note: If you configure the enterprise repo together with pbstest/staging, the
latter will take precedence, i.e. for testing this only configure the enterprise
repo, otherwise the old code path will be taken for packages found in both.

 src/api2/node/apt.rs | 30 ++++++++++++++++++++++++++++--
 src/tools/apt.rs     |  9 +++++++--
 src/tools/http.rs    | 18 ++++++++++++++++--
 3 files changed, 51 insertions(+), 6 deletions(-)

diff --git a/src/api2/node/apt.rs b/src/api2/node/apt.rs
index 05c6b7ee..cb1e454a 100644
--- a/src/api2/node/apt.rs
+++ b/src/api2/node/apt.rs
@@ -1,12 +1,13 @@
 use anyhow::{Error, bail, format_err};
 use serde_json::{json, Value};
+use std::collections::HashMap;
 
 use proxmox::list_subdirs_api_method;
 use proxmox::api::{api, RpcEnvironment, RpcEnvironmentType, Permission};
 use proxmox::api::router::{Router, SubdirMap};
 
 use crate::server::WorkerTask;
-use crate::tools::{apt, http};
+use crate::tools::{apt, http, subscription};
 
 use crate::config::acl::{PRIV_SYS_AUDIT, PRIV_SYS_MODIFY};
 use crate::api2::types::{Authid, APTUpdateInfo, NODE_SCHEMA, UPID_SCHEMA};
@@ -202,9 +203,34 @@ fn apt_get_changelog(
     let changelog_url = &pkg_info[0].change_log_url;
     // FIXME: use 'apt-get changelog' for proxmox packages as well, once repo supports it
     if changelog_url.starts_with("http://download.proxmox.com/") {
-        let changelog = crate::tools::runtime::block_on(http::get_string(changelog_url))
+        let changelog = crate::tools::runtime::block_on(http::get_string(changelog_url, None))
             .map_err(|err| format_err!("Error downloading changelog from '{}': {}", changelog_url, err))?;
         return Ok(json!(changelog));
+
+    } else if changelog_url.starts_with("https://enterprise.proxmox.com/") {
+        let sub = match subscription::read_subscription()? {
+            Some(sub) => sub,
+            None => bail!("cannot retrieve changelog from enterprise repo: no subscription info found")
+        };
+        let (key, id) = match sub.key {
+            Some(key) => {
+                match sub.serverid {
+                    Some(id) => (key, id),
+                    None =>
+                        bail!("cannot retrieve changelog from enterprise repo: no server id found")
+                }
+            },
+            None => bail!("cannot retrieve changelog from enterprise repo: no subscription key found")
+        };
+
+        let mut auth_header = HashMap::new();
+        auth_header.insert("Authorization".to_owned(),
+            format!("Basic {}", base64::encode(format!("{}:{}", key, id))));
+
+        let changelog = crate::tools::runtime::block_on(http::get_string(changelog_url, Some(&auth_header)))
+            .map_err(|err| format_err!("Error downloading changelog from '{}': {}", changelog_url, err))?;
+        return Ok(json!(changelog));
+
     } else {
         let mut command = std::process::Command::new("apt-get");
         command.arg("changelog");
diff --git a/src/tools/apt.rs b/src/tools/apt.rs
index 5800e0a2..3dbc5e23 100644
--- a/src/tools/apt.rs
+++ b/src/tools/apt.rs
@@ -128,8 +128,13 @@ fn get_changelog_url(
             None => bail!("incompatible filename, doesn't match regex")
         };
 
-        return Ok(format!("http://download.proxmox.com/{}/{}_{}.changelog",
-                          base, package, version));
+        if component == "pbs-enterprise" {
+            return Ok(format!("https://enterprise.proxmox.com/{}/{}_{}.changelog",
+                              base, package, version));
+        } else {
+            return Ok(format!("http://download.proxmox.com/{}/{}_{}.changelog",
+                              base, package, version));
+        }
     }
 
     bail!("unknown origin ({}) or component ({})", origin, component)
diff --git a/src/tools/http.rs b/src/tools/http.rs
index 168bb107..d8603fe5 100644
--- a/src/tools/http.rs
+++ b/src/tools/http.rs
@@ -2,6 +2,7 @@ use anyhow::{Error, format_err, bail};
 use lazy_static::lazy_static;
 use std::task::{Context, Poll};
 use std::os::unix::io::AsRawFd;
+use std::collections::HashMap;
 
 use hyper::{Uri, Body};
 use hyper::client::{Client, HttpConnector};
@@ -26,8 +27,21 @@ lazy_static! {
     };
 }
 
-pub async fn get_string(uri: &str) -> Result<String, Error> {
-    let res = HTTP_CLIENT.get(uri.parse()?).await?;
+pub async fn get_string(uri: &str, extra_headers: Option<&HashMap<String, String>>) -> Result<String, Error> {
+    let mut request = Request::builder()
+        .method("GET")
+        .uri(uri)
+        .header("User-Agent", "proxmox-backup-client/1.0");
+
+    if let Some(hs) = extra_headers {
+        for (h, v) in hs.iter() {
+            request = request.header(h, v);
+        }
+    }
+
+    let request = request.body(Body::empty())?;
+
+    let res = HTTP_CLIENT.request(request).await?;
 
     let status = res.status();
     if !status.is_success() {
-- 
2.20.1






More information about the pbs-devel mailing list