apt: allow changelog retrieval from enterprise repo
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@proxmox.com>
This commit is contained in:
parent
ed1329ecf7
commit
137a6ebcad
|
@ -1,12 +1,13 @@
|
||||||
use anyhow::{Error, bail, format_err};
|
use anyhow::{Error, bail, format_err};
|
||||||
use serde_json::{json, Value};
|
use serde_json::{json, Value};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use proxmox::list_subdirs_api_method;
|
use proxmox::list_subdirs_api_method;
|
||||||
use proxmox::api::{api, RpcEnvironment, RpcEnvironmentType, Permission};
|
use proxmox::api::{api, RpcEnvironment, RpcEnvironmentType, Permission};
|
||||||
use proxmox::api::router::{Router, SubdirMap};
|
use proxmox::api::router::{Router, SubdirMap};
|
||||||
|
|
||||||
use crate::server::WorkerTask;
|
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::config::acl::{PRIV_SYS_AUDIT, PRIV_SYS_MODIFY};
|
||||||
use crate::api2::types::{Authid, APTUpdateInfo, NODE_SCHEMA, UPID_SCHEMA};
|
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;
|
let changelog_url = &pkg_info[0].change_log_url;
|
||||||
// FIXME: use 'apt-get changelog' for proxmox packages as well, once repo supports it
|
// FIXME: use 'apt-get changelog' for proxmox packages as well, once repo supports it
|
||||||
if changelog_url.starts_with("http://download.proxmox.com/") {
|
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))?;
|
.map_err(|err| format_err!("Error downloading changelog from '{}': {}", changelog_url, err))?;
|
||||||
return Ok(json!(changelog));
|
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 {
|
} else {
|
||||||
let mut command = std::process::Command::new("apt-get");
|
let mut command = std::process::Command::new("apt-get");
|
||||||
command.arg("changelog");
|
command.arg("changelog");
|
||||||
|
|
|
@ -128,9 +128,14 @@ fn get_changelog_url(
|
||||||
None => bail!("incompatible filename, doesn't match regex")
|
None => bail!("incompatible filename, doesn't match regex")
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if component == "pbs-enterprise" {
|
||||||
|
return Ok(format!("https://enterprise.proxmox.com/{}/{}_{}.changelog",
|
||||||
|
base, package, version));
|
||||||
|
} else {
|
||||||
return Ok(format!("http://download.proxmox.com/{}/{}_{}.changelog",
|
return Ok(format!("http://download.proxmox.com/{}/{}_{}.changelog",
|
||||||
base, package, version));
|
base, package, version));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bail!("unknown origin ({}) or component ({})", origin, component)
|
bail!("unknown origin ({}) or component ({})", origin, component)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ use anyhow::{Error, format_err, bail};
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use std::task::{Context, Poll};
|
use std::task::{Context, Poll};
|
||||||
use std::os::unix::io::AsRawFd;
|
use std::os::unix::io::AsRawFd;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use hyper::{Uri, Body};
|
use hyper::{Uri, Body};
|
||||||
use hyper::client::{Client, HttpConnector};
|
use hyper::client::{Client, HttpConnector};
|
||||||
|
@ -26,8 +27,21 @@ lazy_static! {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_string(uri: &str) -> Result<String, Error> {
|
pub async fn get_string(uri: &str, extra_headers: Option<&HashMap<String, String>>) -> Result<String, Error> {
|
||||||
let res = HTTP_CLIENT.get(uri.parse()?).await?;
|
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();
|
let status = res.status();
|
||||||
if !status.is_success() {
|
if !status.is_success() {
|
||||||
|
|
Loading…
Reference in New Issue