From c7ae1a01f0263dadf5a6e008cd1f9416344e38fa Mon Sep 17 00:00:00 2001 From: Luke Yang Date: Mon, 10 Jul 2023 13:21:33 -0400 Subject: [PATCH] Add previous container state manifest This commit is a prerequisite to issue #4176 in the rpm-ostree repo, implementing the `rpm-ostree upgrade --check` feature for ostree native containers. A previous_state `LayeredImageState` object is added to the `PreparedImport` object, used to store the previous container state when importing a container image. A `export_as_string()` function is added to the `ManifestDiff` object to allow rpm-ostree to print the manifest diff on the client side. The code is exactly the same as the existing `print()` function for `ManifestDiff`, except it returns a string instead of printing out the diff in the terminal. --- lib/src/cli.rs | 6 ++++- lib/src/container/mod.rs | 51 +++++++++++++++++++++++++++----------- lib/src/container/store.rs | 12 +++++---- 3 files changed, 49 insertions(+), 20 deletions(-) diff --git a/lib/src/cli.rs b/lib/src/cli.rs index acbc973a..eb2f8120 100644 --- a/lib/src/cli.rs +++ b/lib/src/cli.rs @@ -16,7 +16,7 @@ use tokio::sync::mpsc::Receiver; use crate::commit::container_commit; use crate::container::store::{ImportProgress, LayerProgress, PreparedImport}; -use crate::container::{self as ostree_container}; +use crate::container::{self as ostree_container, ManifestDiff}; use crate::container::{Config, ImageReference, OstreeImageReference}; use ostree_container::store::{ImageImporter, PrepareResult}; @@ -613,6 +613,10 @@ async fn container_store( if let Some(warning) = prep.deprecated_warning() { print_deprecated_warning(warning).await; } + if let Some(previous_state) = prep.previous_state.as_ref() { + let diff = ManifestDiff::new(&previous_state.manifest, &prep.manifest); + diff.print(); + } print_layer_status(&prep); let printer = (!quiet).then(|| { let layer_progress = imp.request_progress(); diff --git a/lib/src/container/mod.rs b/lib/src/container/mod.rs index 239d7529..3896aceb 100644 --- a/lib/src/container/mod.rs +++ b/lib/src/container/mod.rs @@ -265,6 +265,18 @@ pub struct ManifestDiff<'a> { pub removed: Vec<&'a oci_spec::image::Descriptor>, /// Layers which are present in the new image but not the old image. pub added: Vec<&'a oci_spec::image::Descriptor>, + /// Total number of packages + pub total: u64, + /// Size of total number of packages. + pub total_size: u64, + /// Number of packages removed + pub n_removed: u64, + /// Size of the number of packages removed + pub removed_size: u64, + /// Number of packages added + pub n_added: u64, + /// Size of the number of packages added + pub added_size: u64, } impl<'a> ManifestDiff<'a> { @@ -297,11 +309,27 @@ impl<'a> ManifestDiff<'a> { } } added.sort_by(|a, b| a.digest().cmp(b.digest())); + + fn layersum<'a, I: Iterator>(layers: I) -> u64 { + layers.map(|layer| layer.size() as u64).sum() + } + let total = dest_layers.len() as u64; + let total_size = layersum(dest.layers().iter()); + let n_removed = removed.len() as u64; + let n_added = added.len() as u64; + let removed_size = layersum(removed.iter().copied()); + let added_size = layersum(added.iter().copied()); ManifestDiff { from: src, to: dest, removed, added, + total, + total_size, + n_removed, + removed_size, + n_added, + added_size, } } } @@ -309,20 +337,15 @@ impl<'a> ManifestDiff<'a> { impl<'a> ManifestDiff<'a> { /// Prints the total, removed and added content between two OCI images pub fn print(&self) { - fn layersum<'a, I: Iterator>(layers: I) -> u64 { - layers.map(|layer| layer.size() as u64).sum() - } - let new_total = self.to.layers().len(); - let new_total_size = glib::format_size(layersum(self.to.layers().iter())); - let n_removed = self.removed.len(); - let n_added = self.added.len(); - let removed_size = layersum(self.removed.iter().copied()); - let removed_size_str = glib::format_size(removed_size); - let added_size = layersum(self.added.iter().copied()); - let added_size_str = glib::format_size(added_size); - println!("Total new layers: {new_total:<4} Size: {new_total_size}"); - println!("Removed layers: {n_removed:<4} Size: {removed_size_str}"); - println!("Added layers: {n_added:<4} Size: {added_size_str}"); + let print_total = self.total; + let print_total_size = glib::format_size(self.total_size); + let print_n_removed = self.n_removed; + let print_removed_size = glib::format_size(self.removed_size); + let print_n_added = self.n_added; + let print_added_size = glib::format_size(self.added_size); + println!("Total new layers: {print_total:<4} Size: {print_total_size}"); + println!("Removed layers: {print_n_removed:<4} Size: {print_removed_size}"); + println!("Added layers: {print_n_added:<4} Size: {print_added_size}"); } } diff --git a/lib/src/container/store.rs b/lib/src/container/store.rs index 3b72c29a..4279417c 100644 --- a/lib/src/container/store.rs +++ b/lib/src/container/store.rs @@ -191,6 +191,8 @@ pub struct PreparedImport { pub manifest: oci_image::ImageManifest, /// The deserialized configuration. pub config: oci_image::ImageConfiguration, + /// The previous manifest + pub previous_state: Option>, /// The previously stored manifest digest. pub previous_manifest_digest: Option, /// The previously stored image ID. @@ -532,7 +534,7 @@ impl ImageImporter { // Query for previous stored state - let (previous_manifest_digest, previous_imageid) = + let (previous_state, previous_imageid) = if let Some(previous_state) = try_query_image_ref(&self.repo, &self.imgref.imgref)? { // If the manifest digests match, we're done. if previous_state.manifest_digest == manifest_digest { @@ -543,10 +545,8 @@ impl ImageImporter { if previous_imageid == new_imageid { return Ok(PrepareResult::AlreadyPresent(previous_state)); } - ( - Some(previous_state.manifest_digest), - Some(previous_imageid.to_string()), - ) + let previous_imageid = previous_imageid.to_string(); + (Some(previous_state), Some(previous_imageid)) } else { (None, None) }; @@ -567,10 +567,12 @@ impl ImageImporter { .map(query) .collect::>>()?; + let previous_manifest_digest = previous_state.as_ref().map(|s| s.manifest_digest.clone()); let imp = PreparedImport { manifest, manifest_digest, config, + previous_state, previous_manifest_digest, previous_imageid, ostree_layers: component_layers,