From 91558cd79f6f7d8a76ce494503519dab51d283d1 Mon Sep 17 00:00:00 2001 From: Luke Yang Date: Wed, 9 Aug 2023 12:03:39 -0400 Subject: [PATCH] Add `container upgrade --check` function Previously, OS based on native containers could not retrieve the manifest difference between the current system container image and its corresponding remote container image without performing an actual upgrade. This PR solves this issue by allowing the manifest difference to be outputted when using the `rpm-ostree upgrade --check` command. A `ManifestDiff` struct needed to be retrieved using `ostree-rs-ext`, requring several new functions in both Rust and C that were bridged through CXX Bridge. The `cached_update` object also needed to be modifed and updated with the `ManifestDiff` in order to extend compatibility with other products using rpm-ostree. However, a notable difference between how the `--upgrade --check` function works for ostree based system and a native container based system is that native containers skip over the use of `checksums`. This is because rebasing to locally stored container images (as opposed to a remote repository) does not create a valid ostree refspec. A Rust unit test was implemented to confirm that a difference between two manifests (stored locally in the rust/test folder) can be successfully retrieved. A `kola` test was also implemented to confirm that running `rpm-ostree upgrade --check` returns the correct manifest difference for a potential upgrade. --- Cargo.lock | 2 - Cargo.toml | 3 + rpmostree-cxxrs.cxx | 55 +++++++++ rpmostree-cxxrs.h | 31 +++++ rust/src/deployment_utils.rs | 23 +++- rust/src/lib.rs | 26 +++- rust/src/sysroot_upgrade.rs | 95 ++++++++++++++- rust/test/manifest1.json | 1 + rust/test/manifest2.json | 1 + src/app/rpmostree-clientlib.cxx | 65 ++++++++++ src/app/rpmostree-clientlib.h | 2 + src/daemon/rpmostree-sysroot-upgrader.cxx | 21 +++- src/daemon/rpmostreed-deployment-utils.cxx | 67 ++++++++-- .../destructive/container-rebase-upgrade | 6 +- .../destructive/container-update-check | 114 ++++++++++++++++++ 15 files changed, 482 insertions(+), 30 deletions(-) create mode 100644 rust/test/manifest1.json create mode 100644 rust/test/manifest2.json create mode 100755 tests/kolainst/destructive/container-update-check diff --git a/Cargo.lock b/Cargo.lock index ce8d2a73f8..4e8355ca02 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2180,8 +2180,6 @@ dependencies = [ [[package]] name = "ostree-ext" version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ba95e8a8a7120e39607eb8c8b90a7081705618cd21064f5344a162c65c1825" dependencies = [ "anyhow", "async-compression 0.3.15", diff --git a/Cargo.toml b/Cargo.toml index 135ae9cbb9..8242b2dda3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -129,3 +129,6 @@ bin-unit-tests = [] sanitizers = [] default = [] + +[patch.crates-io] +ostree-ext = { path = "../../ostreedev/ostree-rs-ext/lib" } diff --git a/rpmostree-cxxrs.cxx b/rpmostree-cxxrs.cxx index 42b1de545f..abe6ea20cd 100644 --- a/rpmostree-cxxrs.cxx +++ b/rpmostree-cxxrs.cxx @@ -1293,6 +1293,7 @@ enum class SystemHostType : ::std::uint8_t; enum class BubblewrapMutability : ::std::uint8_t; struct Bubblewrap; struct ContainerImageState; +struct ExportedManifestDiff; enum class RefspecType : ::std::uint8_t; struct TempEtcGuard; struct FilesystemScriptPrep; @@ -1396,6 +1397,29 @@ struct Bubblewrap final : public ::rust::Opaque }; #endif // CXXBRIDGE1_STRUCT_rpmostreecxx$Bubblewrap +#ifndef CXXBRIDGE1_STRUCT_rpmostreecxx$ExportedManifestDiff +#define CXXBRIDGE1_STRUCT_rpmostreecxx$ExportedManifestDiff +struct ExportedManifestDiff final +{ + // Check if the struct is initialized + bool initialized; + // The total number of packages in the next upgrade + ::std::uint64_t total; + // The size of the total number of packages in the next upgrade + ::std::uint64_t total_size; + // The total number of removed packages in the next upgrade + ::std::uint64_t n_removed; + // The size of total number of removed packages in the next upgrade + ::std::uint64_t removed_size; + // The total number of added packages in the next upgrade + ::std::uint64_t n_added; + // The size of total number of added packages in the next upgrade + ::std::uint64_t added_size; + + using IsRelocatable = ::std::true_type; +}; +#endif // CXXBRIDGE1_STRUCT_rpmostreecxx$ExportedManifestDiff + #ifndef CXXBRIDGE1_STRUCT_rpmostreecxx$ContainerImageState #define CXXBRIDGE1_STRUCT_rpmostreecxx$ContainerImageState // `ContainerImageState` is currently identical to ostree-rs-ext's `LayeredImageState` struct, @@ -1408,6 +1432,7 @@ struct ContainerImageState final bool is_layered; ::rust::String image_digest; ::rust::String version; + ::rpmostreecxx::ExportedManifestDiff cached_update_diff; using IsRelocatable = ::std::true_type; }; @@ -2073,6 +2098,11 @@ extern "C" ::rust::repr::PtrLen rpmostreecxx$cxxbridge1$purge_refspec (::rpmostreecxx::OstreeRepo const &repo, ::rust::Str refspec) noexcept; + + ::rust::repr::PtrLen + rpmostreecxx$cxxbridge1$check_container_update (::rpmostreecxx::OstreeRepo const &repo, + ::rpmostreecxx::GCancellable const &cancellable, + ::rust::Str imgref, bool *return$) noexcept; ::std::size_t rpmostreecxx$cxxbridge1$TempEtcGuard$operator$sizeof () noexcept; ::std::size_t rpmostreecxx$cxxbridge1$TempEtcGuard$operator$alignof () noexcept; ::std::size_t rpmostreecxx$cxxbridge1$FilesystemScriptPrep$operator$sizeof () noexcept; @@ -2197,6 +2227,10 @@ extern "C" ::rust::Str opt_deploy_id, ::rust::Str opt_os_name, ::rpmostreecxx::OstreeDeployment **return$) noexcept; + bool rpmostreecxx$cxxbridge1$deployment_add_manifest_diff ( + ::rpmostreecxx::GVariantDict const &dict, + ::rpmostreecxx::ExportedManifestDiff const &diff) noexcept; + ::rust::repr::PtrLen rpmostreecxx$cxxbridge1$daemon_sanitycheck_environment ( ::rpmostreecxx::OstreeSysroot const &sysroot) noexcept; @@ -3690,6 +3724,20 @@ purge_refspec (::rpmostreecxx::OstreeRepo const &repo, ::rust::Str refspec) } } +bool +check_container_update (::rpmostreecxx::OstreeRepo const &repo, + ::rpmostreecxx::GCancellable const &cancellable, ::rust::Str imgref) +{ + ::rust::MaybeUninit return$; + ::rust::repr::PtrLen error$ + = rpmostreecxx$cxxbridge1$check_container_update (repo, cancellable, imgref, &return$.value); + if (error$.ptr) + { + throw ::rust::impl< ::rust::Error>::error (error$); + } + return ::std::move (return$.value); +} + ::std::size_t TempEtcGuard::layout::size () noexcept { @@ -4049,6 +4097,13 @@ deployment_get_base (::rpmostreecxx::OstreeSysroot &sysroot, ::rust::Str opt_dep return ::std::move (return$.value); } +bool +deployment_add_manifest_diff (::rpmostreecxx::GVariantDict const &dict, + ::rpmostreecxx::ExportedManifestDiff const &diff) noexcept +{ + return rpmostreecxx$cxxbridge1$deployment_add_manifest_diff (dict, diff); +} + void daemon_sanitycheck_environment (::rpmostreecxx::OstreeSysroot const &sysroot) { diff --git a/rpmostree-cxxrs.h b/rpmostree-cxxrs.h index 488776a899..74ec7634f6 100644 --- a/rpmostree-cxxrs.h +++ b/rpmostree-cxxrs.h @@ -1075,6 +1075,7 @@ enum class SystemHostType : ::std::uint8_t; enum class BubblewrapMutability : ::std::uint8_t; struct Bubblewrap; struct ContainerImageState; +struct ExportedManifestDiff; enum class RefspecType : ::std::uint8_t; struct TempEtcGuard; struct FilesystemScriptPrep; @@ -1178,6 +1179,29 @@ struct Bubblewrap final : public ::rust::Opaque }; #endif // CXXBRIDGE1_STRUCT_rpmostreecxx$Bubblewrap +#ifndef CXXBRIDGE1_STRUCT_rpmostreecxx$ExportedManifestDiff +#define CXXBRIDGE1_STRUCT_rpmostreecxx$ExportedManifestDiff +struct ExportedManifestDiff final +{ + // Check if the struct is initialized + bool initialized; + // The total number of packages in the next upgrade + ::std::uint64_t total; + // The size of the total number of packages in the next upgrade + ::std::uint64_t total_size; + // The total number of removed packages in the next upgrade + ::std::uint64_t n_removed; + // The size of total number of removed packages in the next upgrade + ::std::uint64_t removed_size; + // The total number of added packages in the next upgrade + ::std::uint64_t n_added; + // The size of total number of added packages in the next upgrade + ::std::uint64_t added_size; + + using IsRelocatable = ::std::true_type; +}; +#endif // CXXBRIDGE1_STRUCT_rpmostreecxx$ExportedManifestDiff + #ifndef CXXBRIDGE1_STRUCT_rpmostreecxx$ContainerImageState #define CXXBRIDGE1_STRUCT_rpmostreecxx$ContainerImageState // `ContainerImageState` is currently identical to ostree-rs-ext's `LayeredImageState` struct, @@ -1190,6 +1214,7 @@ struct ContainerImageState final bool is_layered; ::rust::String image_digest; ::rust::String version; + ::rpmostreecxx::ExportedManifestDiff cached_update_diff; using IsRelocatable = ::std::true_type; }; @@ -1774,6 +1799,9 @@ query_container_image_commit (::rpmostreecxx::OstreeRepo const &repo, ::rust::St void purge_refspec (::rpmostreecxx::OstreeRepo const &repo, ::rust::Str refspec); +bool check_container_update (::rpmostreecxx::OstreeRepo const &repo, + ::rpmostreecxx::GCancellable const &cancellable, ::rust::Str imgref); + ::rust::Box< ::rpmostreecxx::TempEtcGuard> prepare_tempetc_guard (::std::int32_t rootfs); ::rust::Box< ::rpmostreecxx::FilesystemScriptPrep> @@ -1844,6 +1872,9 @@ ::rpmostreecxx::OstreeDeployment *deployment_get_base (::rpmostreecxx::OstreeSys ::rust::Str opt_deploy_id, ::rust::Str opt_os_name); +bool deployment_add_manifest_diff (::rpmostreecxx::GVariantDict const &dict, + ::rpmostreecxx::ExportedManifestDiff const &diff) noexcept; + void daemon_sanitycheck_environment (::rpmostreecxx::OstreeSysroot const &sysroot); ::rust::String deployment_generate_id (::rpmostreecxx::OstreeDeployment const &deployment) noexcept; diff --git a/rust/src/deployment_utils.rs b/rust/src/deployment_utils.rs index b284469d4a..f4663341e3 100644 --- a/rust/src/deployment_utils.rs +++ b/rust/src/deployment_utils.rs @@ -5,7 +5,7 @@ use crate::cxxrsutil::*; use anyhow::{anyhow, format_err, Result}; use ostree_ext::glib::translate::*; -use ostree_ext::ostree; +use ostree_ext::{glib, ostree}; use std::pin::Pin; /// Get a currently unique (for this host) identifier for the deployment. @@ -96,3 +96,24 @@ fn deployment_get_base_impl( }), } } + +// Insert the pending manifest diff, if any. Returns true iff the layers changed. +pub fn deployment_add_manifest_diff( + dict: &crate::ffi::GVariantDict, + diff: &crate::ffi::ExportedManifestDiff, +) -> bool { + if diff.n_removed == 0 && diff.n_added == 0 { + return false; + } + let dict = &dict.glib_reborrow(); + // Add a child dict + let diffv = glib::VariantDict::new(None); + diffv.insert("total", diff.total); + diffv.insert("total-size", diff.total_size); + diffv.insert("n-removed", diff.n_removed); + diffv.insert("removed-size", diff.removed_size); + diffv.insert("n-added", diff.n_added); + diffv.insert("added-size", diff.added_size); + dict.insert("manifest-diff", diffv); + return true; +} diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 1bd877a620..0ddd310967 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -187,6 +187,25 @@ pub mod ffi { pub is_layered: bool, pub image_digest: String, pub version: String, + pub cached_update_diff: ExportedManifestDiff, + } + + #[derive(Debug, Default)] + pub(crate) struct ExportedManifestDiff { + /// Check if the struct is initialized + pub initialized: bool, + /// The total number of packages in the next upgrade + pub total: u64, + /// The size of the total number of packages in the next upgrade + pub total_size: u64, + /// The total number of removed packages in the next upgrade + pub n_removed: u64, + /// The size of total number of removed packages in the next upgrade + pub removed_size: u64, + /// The total number of added packages in the next upgrade + pub n_added: u64, + /// The size of total number of added packages in the next upgrade + pub added_size: u64, } // sysroot_upgrade.rs @@ -202,6 +221,11 @@ pub mod ffi { c: &str, ) -> Result>; fn purge_refspec(repo: &OstreeRepo, refspec: &str) -> Result<()>; + fn check_container_update( + repo: &OstreeRepo, + cancellable: &GCancellable, + imgref: &str, + ) -> Result; } // core.rs @@ -303,7 +327,7 @@ pub mod ffi { opt_deploy_id: &str, opt_os_name: &str, ) -> Result<*mut OstreeDeployment>; - + fn deployment_add_manifest_diff(dict: &GVariantDict, diff: &ExportedManifestDiff) -> bool; } // A grab-bag of metadata from the deployment's ostree commit diff --git a/rust/src/sysroot_upgrade.rs b/rust/src/sysroot_upgrade.rs index e4a483f9a5..eea8554e34 100644 --- a/rust/src/sysroot_upgrade.rs +++ b/rust/src/sysroot_upgrade.rs @@ -3,6 +3,7 @@ // SPDX-License-Identifier: Apache-2.0 OR MIT use crate::cxxrsutil::*; +use crate::ffi::ExportedManifestDiff; use crate::ffi::{output_message, ContainerImageState}; use anyhow::{Context, Result}; use ostree::glib; @@ -10,7 +11,7 @@ use ostree_container::store::{ ImageImporter, ImageProxyConfig, ImportProgress, ManifestLayerState, PrepareResult, }; use ostree_container::OstreeImageReference; -use ostree_ext::container as ostree_container; +use ostree_ext::container::{self as ostree_container, ManifestDiff}; use ostree_ext::ostree; use tokio::runtime::Handle; use tokio::sync::mpsc::Receiver; @@ -23,12 +24,20 @@ impl From> for crate::ffi::Conta .and_then(|c| ostree_container::version_for_config(c)) .map(ToOwned::to_owned) .unwrap_or_default(); + let cached_update_diff = s + .cached_update + .map(|c| { + let diff = ManifestDiff::new(&s.manifest, &c.manifest); + export_diff(&diff) + }) + .unwrap_or_default(); crate::ffi::ContainerImageState { base_commit: s.base_commit, merge_commit: s.merge_commit, is_layered: s.is_layered, image_digest: s.manifest_digest, version, + cached_update_diff, } } } @@ -72,14 +81,20 @@ fn default_container_pull_config(imgref: &OstreeImageReference) -> Result Result { + let config = default_container_pull_config(imgref)?; + let mut imp = ImageImporter::new(repo, imgref, config).await?; + imp.require_bootable(); + Ok(imp) +} + async fn pull_container_async( repo: &ostree::Repo, imgref: &OstreeImageReference, ) -> Result { output_message(&format!("Pulling manifest: {}", &imgref)); - let config = default_container_pull_config(imgref)?; - let mut imp = ImageImporter::new(repo, imgref, config).await?; - imp.require_bootable(); + let mut imp = new_importer(repo, imgref).await?; let layer_progress = imp.request_progress(); let prep = match imp.prepare().await? { PrepareResult::AlreadyPresent(r) => return Ok(r.into()), @@ -187,3 +202,75 @@ pub(crate) fn purge_refspec(repo: &crate::FFIOstreeRepo, imgref: &str) -> CxxRes } Ok(()) } + +/// Check for an updated manifest for the given container image reference, and return a diff. +pub(crate) fn check_container_update( + repo: &crate::FFIOstreeRepo, + cancellable: &crate::FFIGCancellable, + imgref: &str, +) -> CxxResult { + let repo = &repo.glib_reborrow(); + let cancellable = cancellable.glib_reborrow(); + let imgref = &OstreeImageReference::try_from(imgref)?; + Handle::current() + .block_on(async { + crate::utils::run_with_cancellable( + async { impl_check_container_update(repo, imgref).await }, + &cancellable, + ) + .await + }) + .map_err(Into::into) +} + +/// Unfortunately we can't export external types into our C++ bridge, so manually copy things +/// to another copy of the struct. +fn export_diff(diff: &ManifestDiff) -> ExportedManifestDiff { + ExportedManifestDiff { + initialized: true, + total: diff.total, + total_size: diff.total_size, + n_removed: diff.n_removed, + removed_size: diff.removed_size, + n_added: diff.n_added, + added_size: diff.added_size, + } +} + +/// Implementation of fetching a container manifest diff. +async fn impl_check_container_update( + repo: &ostree::Repo, + imgref: &OstreeImageReference, +) -> Result { + let mut imp = new_importer(repo, imgref).await?; + let have_update = match imp.prepare().await? { + PrepareResult::AlreadyPresent(_) => false, + PrepareResult::Ready(_) => true, + }; + Ok(have_update) +} + +#[test] +fn test_container_manifest_diff() -> Result<()> { + use ostree_ext::container::ManifestDiff; + use ostree_ext::oci_spec::image::ImageManifest; + let a: ImageManifest = serde_json::from_str(include_str!("../test/manifest1.json")).unwrap(); + let b: ImageManifest = serde_json::from_str(include_str!("../test/manifest2.json")).unwrap(); + let diff = ManifestDiff::new(&a, &b); + + let cmp_total = diff.total; + let cmp_total_size = diff.total_size; + let cmp_removed = diff.n_removed; + let cmp_removed_size = diff.removed_size; + let cmp_added = diff.n_added; + let cmp_added_size = diff.added_size; + + assert_eq!(cmp_total, 51 as u64); + assert_eq!(cmp_total_size, 697035490 as u64); + assert_eq!(cmp_removed, 4 as u64); + assert_eq!(cmp_removed_size, 170473141 as u64); + assert_eq!(cmp_added, 4 as u64); + assert_eq!(cmp_added_size, 170472856 as u64); + + Ok(()) +} diff --git a/rust/test/manifest1.json b/rust/test/manifest1.json new file mode 100644 index 0000000000..c9528d6d5b --- /dev/null +++ b/rust/test/manifest1.json @@ -0,0 +1 @@ +{"schemaVersion":2,"config":{"mediaType":"application/vnd.oci.image.config.v1+json","digest":"sha256:f3b50d0849a19894aa27ca2346a78efdacf2c56bdc2a3493672d2a819990fedf","size":9301},"layers":[{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:75f4abe8518ec55cb8bf0d358a737084f38e2c030a28651d698c0b7569d680a6","size":1387849},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:777cb841d2803f775a36fba62bcbfe84b2a1e0abc27cf995961b63c3d218a410","size":48676116},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:1179dc1e2994ec0466787ec43967db9016b4b93c602bb9675d7fe4c0993366ba","size":124705297},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:74555b3730c4c0f77529ead433db58e038070666b93a5cc0da262d7b8debff0e","size":38743650},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:0ff8b1fdd38e5cfb6390024de23ba4b947cd872055f62e70f2c21dad5c928925","size":77161948},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:76b83eea62b7b93200a056b5e0201ef486c67f1eeebcf2c7678ced4d614cece2","size":21970157},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:d85c742f69904cb8dbf98abca4724d364d91792fcf8b5f5634ab36dda162bfc4","size":59797135},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:167e5df36d0fcbed876ca90c1ed1e6c79b5e2bdaba5eae74ab86444654b19eff","size":49410348},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:b34384ba76fa1e335cc8d75522508d977854f2b423f8aceb50ca6dfc2f609a99","size":21714783},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:7bf2d65ebf222ee10115284abf6909b1a3da0f3bd6d8d849e30723636b7145cb","size":15264848},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:a75bbf55d8de4dbd54e429e16fbd46688717faf4ea823c94676529cc2525fd5f","size":14373701},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:cf728677fa8c84bfcfd71e17953062421538d492d7fbfdd0dbce8eb1e5f6eec3","size":8400473},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:caff60c1ef085fb500c94230ccab9338e531578635070230b1413b439fd53f8f","size":6914489},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:65ca8f9bddaa720b74c5a7401bf273e93eba6b3b855a62422a8258373e0b1ae0","size":8294965},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:387bab4fcb713e9691617a645b6af2b7ad29fe5e009b0b0d3215645ef315481c","size":6600369},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:f63dcde5a664dad3eb3321bbcf2913d9644d16561a67c86ab61d814c1462583d","size":16869027},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:8bcd90242651342fbd2ed5ca3e60d03de90fdd28c3a9f634329f6e1c21c79718","size":5735283},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:cb65c21a0659b5b826881280556995a7ca4818c2b9b7a89e31d816a996fa8640","size":4528663},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:5187f51b62f4a2e82198a75afcc623a0323d4804fa7848e2e0acb30d77b8d9ab","size":5266030},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:bfef79d6d35378fba9093083ff6bd7b5ed9f443f87517785e6ff134dc8d08c6a","size":4316135},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:1cf332fd50b382af7941d6416994f270c894e9d60fb5c6cecf25de887673bbcb","size":3914655},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:e0d80be6e71bfae398f06f7a7e3b224290f3dde7544c8413f922934abeb1f599","size":2441858},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:48ff87e7a7af41d7139c5230e2e939aa97cafb1f62a114825bda5f5904e04a0e","size":3818782},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:8bcc652ccaa27638bd5bd2d7188053f1736586afbae87b3952e9211c773e3563","size":3885971},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:d83d9388b8c8c1e7c97b6b18f5107b74354700ebce9da161ccb73156a2c54a2e","size":3442642},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:efc465ae44a18ee395e542eb97c8d1fc21bf9d5fb49244ba4738e9bf48bfd3dc","size":3066348},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:c5c471cce08aa9cc7d96884a9e1981b7bb67ee43524af47533f50a8ddde7a83d","size":909923},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:8956cd951abc481ba364cf8ef5deca7cc9185b59ed95ae40b52e42afdc271d8e","size":3553645},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:5b0963a6c89d595b5c4786e2f3ce0bc168a262efab74dfce3d7c8d1063482c60","size":1495301},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:bf2df295da2716291f9dd4707158bca218b4a7920965955a4808b824c1bee2b6","size":3063142},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:19b2ea8d63794b8249960d581216ae1ccb80f8cfe518ff8dd1f12d65d19527a5","size":8109718},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:420636df561ccc835ef9665f41d4bc91c5f00614a61dca266af2bcd7bee2cc25","size":3003935},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:5ae67caf0978d82848d47ff932eee83a1e5d2581382c9c47335f69c9d7acc180","size":2468557},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:4f4b8bb8463dc74bb7f32eee78d02b71f61a322967b6d6cbb29829d262376f74","size":2427605},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:69373f86b83e6e5a962de07f40ff780a031b42d2568ffbb8b3c36de42cc90dec","size":2991782},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:2d05c2f993f9761946701da37f45fc573a2db8467f92b3f0d356f5f7adaf229e","size":3085765},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:41925843e5c965165bedc9c8124b96038f08a89c95ba94603a5f782dc813f0a8","size":2724309},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:a8c39f2998073e0e8b55fb88ccd68d2621a0fb6e31a528fd4790a1c90f8508a9","size":2512079},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:b905f801d092faba0c155597dd1303fa8c0540116af59c111ed7744e486ed63b","size":2341122},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:4f46b58b37828fa71fa5d7417a8ca7a62761cc6a72eb1592943572fc2446b054","size":2759344},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:3fbae92ecc64cf253b643a0e75b56514dc694451f163b47fb4e15af373238e10","size":2539288},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:744dd4a3ec521668942661cf1f184eb8f07f44025ce1aa35d5072ad9d72946fe","size":2415870},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:6c74c0a05a36bddabef1fdfae365ff87a9c5dd1ec7345d9e20f7f8ab04b39fc6","size":2145078},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:910ff6f93303ebedde3459f599b06d7b70d8f0674e3fe1d6623e3af809245cc4","size":5098511},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:2752e2f62f38fea3a390f111d673d2529dbf929f6c67ec7ef4359731d1a7edd8","size":1051999},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:5065c3aac5fcc3c1bde50a19d776974353301f269a936dd2933a67711af3b703","size":2713694},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:8bf6993eea50bbd8b448e6fd719f83c82d1d40b623f2c415f7727e766587ea83","size":1686714},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:630221744f0f9632f4f34f74241e65f79e78f938100266a119113af1ce10a1c5","size":2061581},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:e7e2eae322bca0ffa01bb2cae72288507bef1a11ad51f99d0a4faba1b1e000b9","size":2079706},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:bb6374635385b0c2539c284b137d831bd45fbe64b5e49aee8ad92d14c156a41b","size":3142398},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:40493ecd0f9ab499a2bec715415c3a98774ea6d1c9c01eb30a6b56793204a02d","size":69953187}]} diff --git a/rust/test/manifest2.json b/rust/test/manifest2.json new file mode 100644 index 0000000000..76b1b1bd59 --- /dev/null +++ b/rust/test/manifest2.json @@ -0,0 +1 @@ +{"schemaVersion":2,"config":{"mediaType":"application/vnd.oci.image.config.v1+json","digest":"sha256:ca0f7e342503b45a1110aba49177e386242e9192ab1742a95998b6b99c2a0150","size":9301},"layers":[{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:bca674ffe2ebe92b9e952bc807b9f1cd0d559c057e95ac81f3bae12a9b96b53e","size":1387854},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:777cb841d2803f775a36fba62bcbfe84b2a1e0abc27cf995961b63c3d218a410","size":48676116},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:1179dc1e2994ec0466787ec43967db9016b4b93c602bb9675d7fe4c0993366ba","size":124705297},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:74555b3730c4c0f77529ead433db58e038070666b93a5cc0da262d7b8debff0e","size":38743650},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:0b5d930ffc92d444b0a7b39beed322945a3038603fbe2a56415a6d02d598df1f","size":77162517},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:8d12d20c2d1c8f05c533a2a1b27a457f25add8ad38382523660c4093f180887b","size":21970100},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:d85c742f69904cb8dbf98abca4724d364d91792fcf8b5f5634ab36dda162bfc4","size":59797135},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:167e5df36d0fcbed876ca90c1ed1e6c79b5e2bdaba5eae74ab86444654b19eff","size":49410348},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:b34384ba76fa1e335cc8d75522508d977854f2b423f8aceb50ca6dfc2f609a99","size":21714783},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:7bf2d65ebf222ee10115284abf6909b1a3da0f3bd6d8d849e30723636b7145cb","size":15264848},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:a75bbf55d8de4dbd54e429e16fbd46688717faf4ea823c94676529cc2525fd5f","size":14373701},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:cf728677fa8c84bfcfd71e17953062421538d492d7fbfdd0dbce8eb1e5f6eec3","size":8400473},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:caff60c1ef085fb500c94230ccab9338e531578635070230b1413b439fd53f8f","size":6914489},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:65ca8f9bddaa720b74c5a7401bf273e93eba6b3b855a62422a8258373e0b1ae0","size":8294965},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:387bab4fcb713e9691617a645b6af2b7ad29fe5e009b0b0d3215645ef315481c","size":6600369},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:f63dcde5a664dad3eb3321bbcf2913d9644d16561a67c86ab61d814c1462583d","size":16869027},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:8bcd90242651342fbd2ed5ca3e60d03de90fdd28c3a9f634329f6e1c21c79718","size":5735283},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:cb65c21a0659b5b826881280556995a7ca4818c2b9b7a89e31d816a996fa8640","size":4528663},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:5187f51b62f4a2e82198a75afcc623a0323d4804fa7848e2e0acb30d77b8d9ab","size":5266030},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:bfef79d6d35378fba9093083ff6bd7b5ed9f443f87517785e6ff134dc8d08c6a","size":4316135},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:1cf332fd50b382af7941d6416994f270c894e9d60fb5c6cecf25de887673bbcb","size":3914655},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:e0d80be6e71bfae398f06f7a7e3b224290f3dde7544c8413f922934abeb1f599","size":2441858},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:48ff87e7a7af41d7139c5230e2e939aa97cafb1f62a114825bda5f5904e04a0e","size":3818782},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:8bcc652ccaa27638bd5bd2d7188053f1736586afbae87b3952e9211c773e3563","size":3885971},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:d83d9388b8c8c1e7c97b6b18f5107b74354700ebce9da161ccb73156a2c54a2e","size":3442642},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:efc465ae44a18ee395e542eb97c8d1fc21bf9d5fb49244ba4738e9bf48bfd3dc","size":3066348},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:c5c471cce08aa9cc7d96884a9e1981b7bb67ee43524af47533f50a8ddde7a83d","size":909923},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:8956cd951abc481ba364cf8ef5deca7cc9185b59ed95ae40b52e42afdc271d8e","size":3553645},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:5b0963a6c89d595b5c4786e2f3ce0bc168a262efab74dfce3d7c8d1063482c60","size":1495301},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:bf2df295da2716291f9dd4707158bca218b4a7920965955a4808b824c1bee2b6","size":3063142},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:19b2ea8d63794b8249960d581216ae1ccb80f8cfe518ff8dd1f12d65d19527a5","size":8109718},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:420636df561ccc835ef9665f41d4bc91c5f00614a61dca266af2bcd7bee2cc25","size":3003935},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:5ae67caf0978d82848d47ff932eee83a1e5d2581382c9c47335f69c9d7acc180","size":2468557},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:4f4b8bb8463dc74bb7f32eee78d02b71f61a322967b6d6cbb29829d262376f74","size":2427605},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:69373f86b83e6e5a962de07f40ff780a031b42d2568ffbb8b3c36de42cc90dec","size":2991782},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:2d05c2f993f9761946701da37f45fc573a2db8467f92b3f0d356f5f7adaf229e","size":3085765},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:41925843e5c965165bedc9c8124b96038f08a89c95ba94603a5f782dc813f0a8","size":2724309},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:a8c39f2998073e0e8b55fb88ccd68d2621a0fb6e31a528fd4790a1c90f8508a9","size":2512079},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:b905f801d092faba0c155597dd1303fa8c0540116af59c111ed7744e486ed63b","size":2341122},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:4f46b58b37828fa71fa5d7417a8ca7a62761cc6a72eb1592943572fc2446b054","size":2759344},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:3fbae92ecc64cf253b643a0e75b56514dc694451f163b47fb4e15af373238e10","size":2539288},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:744dd4a3ec521668942661cf1f184eb8f07f44025ce1aa35d5072ad9d72946fe","size":2415870},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:6c74c0a05a36bddabef1fdfae365ff87a9c5dd1ec7345d9e20f7f8ab04b39fc6","size":2145078},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:910ff6f93303ebedde3459f599b06d7b70d8f0674e3fe1d6623e3af809245cc4","size":5098511},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:2752e2f62f38fea3a390f111d673d2529dbf929f6c67ec7ef4359731d1a7edd8","size":1051999},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:5065c3aac5fcc3c1bde50a19d776974353301f269a936dd2933a67711af3b703","size":2713694},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:8bf6993eea50bbd8b448e6fd719f83c82d1d40b623f2c415f7727e766587ea83","size":1686714},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:630221744f0f9632f4f34f74241e65f79e78f938100266a119113af1ce10a1c5","size":2061581},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:e7e2eae322bca0ffa01bb2cae72288507bef1a11ad51f99d0a4faba1b1e000b9","size":2079706},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:bb6374635385b0c2539c284b137d831bd45fbe64b5e49aee8ad92d14c156a41b","size":3142398},{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:cb9b8a4ac4a8df62df79e6f0348a14b3ec239816d42985631c88e76d4e3ff815","size":69952385}]} diff --git a/src/app/rpmostree-clientlib.cxx b/src/app/rpmostree-clientlib.cxx index 9545a4df5a..dd0357efe4 100644 --- a/src/app/rpmostree-clientlib.cxx +++ b/src/app/rpmostree-clientlib.cxx @@ -1244,6 +1244,65 @@ rpmostree_print_diff_advisories (GVariant *rpm_diff, GVariant *advisories, gbool return TRUE; } +/* print "manifest-diff" */ +gboolean +rpmostree_print_manifest_diff (GVariant *manifest_diff, guint maxkeylen, GError **error) +{ + if (!manifest_diff) + return TRUE; /* Nothing to 🖨️ */ + + g_auto (GVariantDict) manifest_diff_dict; + g_variant_dict_init (&manifest_diff_dict, manifest_diff); + + guint64 total = 0; + if (!g_variant_dict_lookup (&manifest_diff_dict, "total", "t", &total)) + return glnx_throw (error, "Missing \"total\" key"); + + printf (" %*s%s %" G_GUINT64_FORMAT "\n", maxkeylen, "Total layers", + strlen ("Total layers") ? ":" : " ", total); + + { + guint64 total_size = 0; + if (!g_variant_dict_lookup (&manifest_diff_dict, "total-size", "t", &total_size)) + return glnx_throw (error, "Missing \"total_size\" key"); + g_autofree char *formatted = g_format_size (total_size); + printf (" %*s%s %s", maxkeylen, "Size", strlen ("Size") ? ":" : " ", formatted); + printf ("\n"); + } + + guint64 total_removed = 0; + if (!g_variant_dict_lookup (&manifest_diff_dict, "n-removed", "t", &total_removed)) + return glnx_throw (error, "Missing \"total_removed\" key"); + + printf (" %*s%s %" G_GUINT64_FORMAT "\n", maxkeylen, "Removed layers", + strlen ("Removed layers") ? ":" : " ", total_removed); + + { + guint64 removed_size = 0; + if (!g_variant_dict_lookup (&manifest_diff_dict, "removed-size", "t", &removed_size)) + return glnx_throw (error, "Missing \"removed_size\" key"); + g_autofree char *formatted = g_format_size (removed_size); + printf (" %*s%s %s\n", maxkeylen, "Size", strlen ("Size") ? ":" : " ", formatted); + } + + guint64 total_added = 0; + if (!g_variant_dict_lookup (&manifest_diff_dict, "n-added", "t", &total_added)) + return glnx_throw (error, "Missing \"total_added\" key"); + printf (" %*s%s %" G_GUINT64_FORMAT "\n", maxkeylen, "Added layers", + strlen ("Added layers") ? ":" : " ", total_added); + + { + guint64 added_size = 0; + if (!g_variant_dict_lookup (&manifest_diff_dict, "added_size", "t", &added_size)) + return glnx_throw (error, "Missing \"added_size\" key"); + + g_autofree char *formatted = g_format_size (added_size); + printf (" %*s%s %s\n", maxkeylen, "Size", strlen ("Size") ? ":" : " ", formatted); + } + + return TRUE; +} + /* this is used by both `status` and `upgrade --check/--preview` */ gboolean rpmostree_print_cached_update (GVariant *cached_update, gboolean verbose, @@ -1286,6 +1345,9 @@ rpmostree_print_cached_update (GVariant *cached_update, gboolean verbose, g_autoptr (GVariant) rpm_diff = g_variant_dict_lookup_value (&dict, "rpm-diff", G_VARIANT_TYPE ("a{sv}")); + g_autoptr (GVariant) manifest_diff + = g_variant_dict_lookup_value (&dict, "manifest-diff", G_VARIANT_TYPE ("a{sv}")); + g_autoptr (GVariant) advisories = g_variant_dict_lookup_value (&dict, "advisories", G_VARIANT_TYPE ("a(suuasa{sv})")); @@ -1308,6 +1370,9 @@ rpmostree_print_cached_update (GVariant *cached_update, gboolean verbose, max_key_len, error)) return FALSE; + if (!rpmostree_print_manifest_diff (manifest_diff, max_key_len, error)) + return FALSE; + return TRUE; } diff --git a/src/app/rpmostree-clientlib.h b/src/app/rpmostree-clientlib.h index dd4f22c4c8..a47e672d62 100644 --- a/src/app/rpmostree-clientlib.h +++ b/src/app/rpmostree-clientlib.h @@ -111,6 +111,8 @@ gboolean rpmostree_print_diff_advisories (GVariant *rpm_diff, GVariant *advisori gboolean verbose, gboolean verbose_advisories, guint max_key_len, GError **error); +gboolean rpmostree_print_manifest_diff (GVariant *manifest_diff, guint maxkeylen, GError **error); + gboolean rpmostree_print_cached_update (GVariant *cached_update, gboolean verbose, gboolean verbose_advisories, GCancellable *cancellable, GError **error); diff --git a/src/daemon/rpmostree-sysroot-upgrader.cxx b/src/daemon/rpmostree-sysroot-upgrader.cxx index 2beb3aee3b..4a24b0ed45 100644 --- a/src/daemon/rpmostree-sysroot-upgrader.cxx +++ b/src/daemon/rpmostree-sysroot-upgrader.cxx @@ -434,12 +434,23 @@ rpmostree_sysroot_upgrader_pull_base (RpmOstreeSysrootUpgrader *self, const char return glnx_throw (error, "Specifying commit overrides for container-image-reference " "type refspecs is not supported"); if (check) - return glnx_throw (error, "Cannot currently check for updates without downloading"); + { + CXX_TRY_VAR ( + changed, + rpmostreecxx::check_container_update (*self->repo, *cancellable, r.refspec.c_str ()), + error); + *out_changed = changed; + return TRUE; + } + else + { + CXX_TRY_VAR ( + import, + rpmostreecxx::pull_container (*self->repo, *cancellable, r.refspec.c_str ()), + error); - CXX_TRY_VAR (import, - rpmostreecxx::pull_container (*self->repo, *cancellable, r.refspec.c_str ()), - error); - new_base_rev = g_strdup (import->merge_commit.c_str ()); + new_base_rev = g_strdup (import->merge_commit.c_str ()); + } break; } case rpmostreecxx::RefspecType::Checksum: diff --git a/src/daemon/rpmostreed-deployment-utils.cxx b/src/daemon/rpmostreed-deployment-utils.cxx index 4848050942..ea860f654e 100644 --- a/src/daemon/rpmostreed-deployment-utils.cxx +++ b/src/daemon/rpmostreed-deployment-utils.cxx @@ -677,6 +677,8 @@ rpmostreed_update_generate_variant (OstreeDeployment *booted_deployment, const char *new_checksum = NULL; const char *new_base_checksum = NULL; g_autofree char *new_base_checksum_owned = NULL; + auto refspectype = rpmostreecxx::refspec_classify (r.refspec); + if (staged_deployment) { new_checksum = ostree_deployment_get_csum (staged_deployment); @@ -687,13 +689,18 @@ rpmostreed_update_generate_variant (OstreeDeployment *booted_deployment, } else { - if (!ostree_repo_resolve_rev_ext (repo, r.refspec.c_str (), TRUE, - static_cast (0), - &new_base_checksum_owned, error)) - return FALSE; - new_base_checksum = new_base_checksum_owned; - /* just assume that the hypothetical new deployment would also be layered if we are */ - is_new_layered = (current_base_checksum_owned != NULL); + if (refspectype != rpmostreecxx::RefspecType::Container) + { + if (!ostree_repo_resolve_rev_ext (repo, r.refspec.c_str (), TRUE, + static_cast (0), + &new_base_checksum_owned, error)) + { + return FALSE; + } + new_base_checksum = new_base_checksum_owned; + /* just assume that the hypothetical new deployment would also be layered if we are */ + is_new_layered = (current_base_checksum_owned != NULL); + } } /* Graciously handle rev no longer in repo; e.g. mucking around with rebase/rollback; we @@ -725,12 +732,15 @@ rpmostreed_update_generate_variant (OstreeDeployment *booted_deployment, }; rpm_diff_init (&rpm_diff); - /* we'll need these later for advisories, so just keep them around */ g_autoptr (GPtrArray) ostree_modified_new = NULL; g_autoptr (GPtrArray) rpmmd_modified_new = NULL; + bool container_changed = false; + if (staged_deployment) { + g_debug ("Computing diff with staged deployment"); + /* ok we have a staged deployment; we just need to do a simple diff and BOOM done! */ /* XXX: we're marking all pkgs as BASE right now even though there could be layered * pkgs too -- we can tease those out in the future if needed */ @@ -744,15 +754,41 @@ rpmostreed_update_generate_variant (OstreeDeployment *booted_deployment, * - if a new base checksum was pulled, do a db diff of the old and new bases * - if there are currently any layered pkgs, lookup in sack for newer versions */ - if (is_new_checksum) + + if (is_new_checksum && refspectype != rpmostreecxx::RefspecType::Container) { if (!rpm_diff_add_db_diff (&rpm_diff, repo, RPM_OSTREE_PKG_TYPE_BASE, current_base_checksum, new_base_checksum, &ostree_modified_new, cancellable, error)) - return FALSE; + { + return FALSE; + } } /* now we look at the rpm-md/layering side */ + g_autofree char *origin_remote = NULL; + g_autofree char *origin_ref = NULL; + + if (refspectype != rpmostreecxx::RefspecType::Container) + { + if (!ostree_parse_refspec (r.refspec.c_str (), &origin_remote, &origin_ref, error)) + return FALSE; + } + else + { + // Make this an operation we allow to fail, see the other call + try + { + auto state = rpmostreecxx::query_container_image_commit (*repo, current_checksum); + container_changed = rpmostreecxx::deployment_add_manifest_diff (*dict, state->cached_update_diff); + g_debug ("container changed: %d", container_changed); + } + catch (std::exception &e) + { + sd_journal_print (LOG_ERR, "failed to query container image base metadata: %s", + e.what ()); + } + } /* check that it's actually layered (i.e. the requests are not all just dormant) */ if (sack && is_new_layered && rpmostree_origin_has_packages (origin)) @@ -767,8 +803,8 @@ rpmostreed_update_generate_variant (OstreeDeployment *booted_deployment, if (!rpm_diff_is_empty (&rpm_diff)) g_variant_dict_insert (dict, "rpm-diff", "@a{sv}", rpm_diff_variant_new (&rpm_diff)); - /* now we look for advisories */ + /* now we look for advisories */ if (sack && (ostree_modified_new || rpmmd_modified_new)) { /* let's just merge the two now for convenience */ @@ -802,8 +838,10 @@ rpmostreed_update_generate_variant (OstreeDeployment *booted_deployment, } /* but if there are no updates, then just ditch the whole thing and return NULL */ - if (is_new_checksum || rpmmd_modified_new) + refspectype = rpmostreecxx::refspec_classify (r.refspec); + if (is_new_checksum || rpmmd_modified_new || container_changed) { + g_debug ("Recomputed cached update"); /* include a "state" checksum for cache invalidation; for now this is just the * checksum of the deployment against which we ran, though we could base it off more * things later if needed */ @@ -811,7 +849,10 @@ rpmostreed_update_generate_variant (OstreeDeployment *booted_deployment, *out_update = g_variant_ref_sink (g_variant_dict_end (dict)); } else - *out_update = NULL; + { + g_debug ("No cached update"); + *out_update = NULL; + } return TRUE; } diff --git a/tests/kolainst/destructive/container-rebase-upgrade b/tests/kolainst/destructive/container-rebase-upgrade index ee463b5db8..8c60700805 100755 --- a/tests/kolainst/destructive/container-rebase-upgrade +++ b/tests/kolainst/destructive/container-rebase-upgrade @@ -40,10 +40,8 @@ rpm-ostree upgrade podman image rm -f shouldnotexist || true test -d /run/containers # https://github.com/coreos/rpm-ostree/issues/4176 -if rpm-ostree upgrade --check 2>err.txt; then - fatal "expected upgrade --check not to work yet" -fi -assert_file_has_content_literal err.txt "Cannot currently check for updates without downloading" +rpm-ostree upgrade --check > err.txt || true +assert_file_has_content_literal err.txt 'No updates available.' rpm-ostree upgrade echo "ok upgrade after podman" diff --git a/tests/kolainst/destructive/container-update-check b/tests/kolainst/destructive/container-update-check new file mode 100755 index 0000000000..dd021d9997 --- /dev/null +++ b/tests/kolainst/destructive/container-update-check @@ -0,0 +1,114 @@ +#!/bin/bash +## kola: +## # Increase timeout since this test has a lot of I/O and involves rebasing +## timeoutMin: 30 +## # This test only runs on FCOS due to a problem with skopeo copy on +## # RHCOS. See: https://github.com/containers/skopeo/issues/1846 +## distros: fcos +## # Needs internet access as we fetch files from koji +## tags: "needs-internet platform-independent" +## minMemory: 2048 +# +# Copyright (C) 2023 Red Hat, Inc. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. ${KOLA_EXT_DATA}/libtest.sh + +set -x + +libtest_prepare_offline +cd "$(mktemp -d)" + +# TODO: It'd be much better to test this via a registry +image_dir=/var/tmp/fcos +image=oci:$image_dir + +case "${AUTOPKGTEST_REBOOT_MARK:-}" in + "") + checksum=$(rpm-ostree status --json | jq -r '.deployments[0].checksum') + rm ${image_dir} -rf + # Since we're switching OS update stream, turn off zincati + systemctl mask --now zincati + ostree container encapsulate --repo=/ostree/repo ${checksum} "${image}" --label ostree.bootable=TRUE + + skopeo copy $image containers-storage:localhost/fcos + rm "${image_dir}" -rf + td=$(mktemp -d) + cd ${td} +cat > Containerfile << EOF +FROM localhost/fcos +# RUN rpm-ostree install man +EOF + + touched_resolv_conf=0 + if test '!' -f /etc/resolv.conf; then + podmanv=$(podman --version) + case "${podmanv#podman version }" in + 3.*) touched_resolv_conf=1; touch /etc/resolv.conf;; + esac + fi + podman build --net=host -t localhost/fcos-derived --squash . + if test "${touched_resolv_conf}" -eq 1; then + rm -vf /etc/resolv.conf + fi + + rpm-ostree rebase ostree-unverified-image:containers-storage:localhost/fcos-derived + rm $image_dir -rf + + /tmp/autopkgtest-reboot 1 + ;; + 1) + rpm-ostree status + rpm-ostree upgrade --check > out.txt || true + assert_file_has_content_literal out.txt 'No updates available.' + + checksum=$(rpm-ostree status --json | jq -r '.deployments[0].checksum') + rm ${image_dir} -rf + systemctl mask --now zincati + ostree container encapsulate --repo=/ostree/repo ${checksum} "${image}" --label ostree.bootable=TRUE + + skopeo copy $image containers-storage:localhost/fcos + rm "${image_dir}" -rf + td=$(mktemp -d) + cd ${td} +cat > Containerfile << EOF +FROM localhost/fcos +RUN rpm-ostree install man +EOF + + touched_resolv_conf=0 + if test '!' -f /etc/resolv.conf; then + podmanv=$(podman --version) + case "${podmanv#podman version }" in + 3.*) touched_resolv_conf=1; touch /etc/resolv.conf;; + esac + fi + podman build --net=host -t localhost/fcos-derived --squash . + if test "${touched_resolv_conf}" -eq 1; then + rm -vf /etc/resolv.conf + fi + + rpm-ostree upgrade --check > out.txt || true + assert_file_has_content_literal out.txt 'AvailableUpdate:' + assert_file_has_content_literal out.txt 'Total layers:' + assert_file_has_content_literal out.txt 'Size:' + assert_file_has_content_literal out.txt 'Removed layers:' + assert_file_has_content_literal out.txt 'Added layers:' + +esac