From 4a55da55b6589bcb4de36d04cfce9a063123f0ed Mon Sep 17 00:00:00 2001 From: Samuel Mendoza-Jonas Date: Mon, 18 Nov 2019 16:15:21 -0800 Subject: [PATCH] updog: Add support for query parameters in TUF requests Implement a new tough transport 'Bark', which allows Updog to add extra query parameters to requests to the TUF repository. Updog now uses this to append the current image version to all requests. Signed-off-by: Samuel Mendoza-Jonas --- workspaces/Cargo.lock | 1 + workspaces/updater/updog/Cargo.toml | 1 + workspaces/updater/updog/src/error.rs | 6 +++ workspaces/updater/updog/src/main.rs | 27 +++++++++----- workspaces/updater/updog/src/transport.rs | 45 +++++++++++++++++++++++ 5 files changed, 70 insertions(+), 10 deletions(-) create mode 100644 workspaces/updater/updog/src/transport.rs diff --git a/workspaces/Cargo.lock b/workspaces/Cargo.lock index bb38885c8fd..c22a03b44df 100644 --- a/workspaces/Cargo.lock +++ b/workspaces/Cargo.lock @@ -2862,6 +2862,7 @@ dependencies = [ "toml 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "tough 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "update_metadata 0.1.0", + "url 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/workspaces/updater/updog/Cargo.toml b/workspaces/updater/updog/Cargo.toml index 303f8f339f0..ad4d0fe5d1b 100644 --- a/workspaces/updater/updog/Cargo.toml +++ b/workspaces/updater/updog/Cargo.toml @@ -26,6 +26,7 @@ tough = { version = "0.1.0", features = ["http"] } update_metadata = { path = "../update_metadata" } structopt = "0.3" migrator = { path = "../../api/migration/migrator" } +url = "2.1.0" [dev-dependencies] tempfile = "3.1.0" diff --git a/workspaces/updater/updog/src/error.rs b/workspaces/updater/updog/src/error.rs index e5a975c7d4c..8011a42d4fc 100644 --- a/workspaces/updater/updog/src/error.rs +++ b/workspaces/updater/updog/src/error.rs @@ -274,6 +274,12 @@ pub(crate) enum Error { source: std::io::Error, }, + #[snafu(display("2Borrow2Fast"))] + TransportBorrow { + backtrace: Backtrace, + source: std::cell::BorrowMutError, + }, + #[snafu(display("Failed to serialize update information: {}", source))] UpdateSerialize { source: serde_json::Error, diff --git a/workspaces/updater/updog/src/main.rs b/workspaces/updater/updog/src/main.rs index 978e099d2f4..212ce42cec9 100644 --- a/workspaces/updater/updog/src/main.rs +++ b/workspaces/updater/updog/src/main.rs @@ -2,8 +2,10 @@ #![warn(clippy::pedantic)] mod error; +mod transport; use crate::error::Result; +use crate::transport::{HttpQueryRepo, HttpQueryTransport}; use chrono::{DateTime, Utc}; use data_store_version::Version as DataVersion; use semver::Version as SemVer; @@ -17,11 +19,9 @@ use std::os::unix::fs::PermissionsExt; use std::path::Path; use std::process; use std::str::FromStr; -use tough::{HttpTransport, Limits, Repository, Settings}; +use tough::{Limits, Repository, Settings}; use update_metadata::{Manifest, Update}; -type HttpRepo<'a> = Repository<'a, HttpTransport>; - #[cfg(target_arch = "x86_64")] const TARGET_ARCH: &str = "x86_64"; #[cfg(target_arch = "aarch64")] @@ -96,7 +96,10 @@ fn load_config() -> Result { Ok(config) } -fn load_repository<'a>(transport: &'a HttpTransport, config: &'a Config) -> Result> { +fn load_repository<'a>( + transport: &'a HttpQueryTransport, + config: &'a Config, +) -> Result> { fs::create_dir_all("/var/lib/thar/updog").context(error::CreateMetadataCache)?; Repository::load( transport, @@ -118,7 +121,7 @@ fn load_repository<'a>(transport: &'a HttpTransport, config: &'a Config) -> Resu .context(error::Metadata) } -fn load_manifest(repository: &HttpRepo<'_>) -> Result { +fn load_manifest(repository: &HttpQueryRepo<'_>) -> Result { let target = "manifest.json"; serde_json::from_reader( repository @@ -201,7 +204,7 @@ fn update_required<'a>( } fn write_target_to_disk>( - repository: &HttpRepo<'_>, + repository: &HttpQueryRepo<'_>, target: &str, disk_path: P, ) -> Result<()> { @@ -261,7 +264,7 @@ fn migration_targets( /// storage. All intermediate migrations between the current version and the /// target version must be retrieved. fn retrieve_migrations( - repository: &HttpRepo<'_>, + repository: &HttpQueryRepo<'_>, manifest: &Manifest, update: &Update, ) -> Result<()> { @@ -309,7 +312,7 @@ fn retrieve_migrations( Ok(()) } -fn update_image(update: &Update, repository: &HttpRepo<'_>) -> Result<()> { +fn update_image(update: &Update, repository: &HttpQueryRepo<'_>) -> Result<()> { let mut gpt_state = State::load().context(error::PartitionTableRead)?; gpt_state.clear_inactive(); // Write out the clearing of the inactive partition immediately, because we're about to @@ -444,10 +447,14 @@ fn main_inner() -> Result<()> { serde_plain::from_str::(&arguments.subcommand).unwrap_or_else(|_| usage()); let config = load_config()?; - let transport = HttpTransport::new(); + let (current_version, flavor) = running_version()?; + let transport = HttpQueryTransport::new(); + transport + .queries_get_mut() + .context(error::TransportBorrow)? + .push((String::from("version"), current_version.to_string())); let repository = load_repository(&transport, &config)?; let manifest = load_manifest(&repository)?; - let (current_version, flavor) = running_version().unwrap(); match command { Command::CheckUpdate | Command::Whats => { diff --git a/workspaces/updater/updog/src/transport.rs b/workspaces/updater/updog/src/transport.rs new file mode 100644 index 00000000000..e58d9d60bfe --- /dev/null +++ b/workspaces/updater/updog/src/transport.rs @@ -0,0 +1,45 @@ +use std::cell::{BorrowMutError, RefCell}; +use tough::{HttpTransport, Repository, Transport}; +use url::Url; + +#[derive(Debug)] +#[allow(clippy::module_name_repetitions)] +pub struct HttpQueryTransport { + pub inner: HttpTransport, + parameters: RefCell>, +} + +impl HttpQueryTransport { + pub fn new() -> Self { + Self { + inner: HttpTransport::new(), + parameters: RefCell::new(vec![]), + } + } + + /// Try to borrow a mutable reference to parameters; returns an error if + /// a borrow is already active + pub fn queries_get_mut( + &self, + ) -> Result>, BorrowMutError> { + self.parameters.try_borrow_mut() + } + + fn set_query_string(&self, mut url: Url) -> Url { + for (key, val) in self.parameters.borrow().iter() { + url.query_pairs_mut().append_pair(&key, &val); + } + url + } +} + +pub type HttpQueryRepo<'a> = Repository<'a, HttpQueryTransport>; + +impl Transport for HttpQueryTransport { + type Stream = reqwest::Response; + type Error = reqwest::Error; + + fn fetch(&self, url: Url) -> Result { + self.inner.fetch(self.set_query_string(url)) + } +}