Skip to content

Commit b101d9d

Browse files
authored
Merge pull request #214 from cgwalters/podman-pull-prep
Podman pull prep
2 parents 17d1fc7 + fde6bdd commit b101d9d

File tree

2 files changed

+96
-70
lines changed

2 files changed

+96
-70
lines changed

lib/src/cli.rs

Lines changed: 9 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,7 @@ use camino::Utf8PathBuf;
77
use clap::Parser;
88
use fn_error_context::context;
99
use ostree::gio;
10-
use ostree_container::store::LayeredImageState;
1110
use ostree_container::store::PrepareResult;
12-
use ostree_container::OstreeImageReference;
1311
use ostree_ext::container as ostree_container;
1412
use ostree_ext::container::SignatureSource;
1513
use ostree_ext::keyfileext::KeyFileExt;
@@ -214,57 +212,6 @@ pub(crate) async fn get_locked_sysroot() -> Result<ostree_ext::sysroot::SysrootL
214212
Ok(sysroot)
215213
}
216214

217-
/// Wrapper for pulling a container image, wiring up status output.
218-
async fn new_importer(
219-
repo: &ostree::Repo,
220-
imgref: &ostree_container::OstreeImageReference,
221-
) -> Result<ostree_container::store::ImageImporter> {
222-
let config = Default::default();
223-
let mut imp = ostree_container::store::ImageImporter::new(repo, imgref, config).await?;
224-
imp.require_bootable();
225-
Ok(imp)
226-
}
227-
228-
/// Wrapper for pulling a container image, wiring up status output.
229-
#[context("Pulling")]
230-
async fn pull(
231-
repo: &ostree::Repo,
232-
imgref: &ImageReference,
233-
quiet: bool,
234-
) -> Result<Box<LayeredImageState>> {
235-
let imgref = &OstreeImageReference::from(imgref.clone());
236-
let mut imp = new_importer(repo, imgref).await?;
237-
let prep = match imp.prepare().await? {
238-
PrepareResult::AlreadyPresent(c) => {
239-
println!("No changes in {} => {}", imgref, c.manifest_digest);
240-
return Ok(c);
241-
}
242-
PrepareResult::Ready(p) => p,
243-
};
244-
if let Some(warning) = prep.deprecated_warning() {
245-
ostree_ext::cli::print_deprecated_warning(warning).await;
246-
}
247-
ostree_ext::cli::print_layer_status(&prep);
248-
let printer = (!quiet).then(|| {
249-
let layer_progress = imp.request_progress();
250-
let layer_byte_progress = imp.request_layer_progress();
251-
tokio::task::spawn(async move {
252-
ostree_ext::cli::handle_layer_progress_print(layer_progress, layer_byte_progress).await
253-
})
254-
});
255-
let import = imp.import(prep).await;
256-
if let Some(printer) = printer {
257-
let _ = printer.await;
258-
}
259-
let import = import?;
260-
if let Some(msg) =
261-
ostree_container::store::image_filtered_content_warning(repo, &imgref.imgref)?
262-
{
263-
eprintln!("{msg}")
264-
}
265-
Ok(import)
266-
}
267-
268215
#[context("Querying root privilege")]
269216
pub(crate) fn require_root() -> Result<()> {
270217
let uid = rustix::process::getuid();
@@ -327,7 +274,7 @@ async fn upgrade(opts: UpgradeOpts) -> Result<()> {
327274
let mut changed = false;
328275
if opts.check {
329276
let imgref = imgref.clone().into();
330-
let mut imp = new_importer(repo, &imgref).await?;
277+
let mut imp = crate::deploy::new_importer(repo, &imgref).await?;
331278
match imp.prepare().await? {
332279
PrepareResult::AlreadyPresent(_) => {
333280
println!("No changes in: {}", imgref);
@@ -347,7 +294,7 @@ async fn upgrade(opts: UpgradeOpts) -> Result<()> {
347294
}
348295
}
349296
} else {
350-
let fetched = pull(&sysroot.repo(), imgref, opts.quiet).await?;
297+
let fetched = crate::deploy::pull(&sysroot, imgref, opts.quiet).await?;
351298
let staged_digest = staged_image.as_ref().map(|s| s.image_digest.as_str());
352299
let fetched_digest = fetched.manifest_digest.as_str();
353300
tracing::debug!("staged: {staged_digest:?}");
@@ -368,8 +315,11 @@ async fn upgrade(opts: UpgradeOpts) -> Result<()> {
368315
crate::deploy::stage(sysroot, &osname, &fetched, &spec).await?;
369316
changed = true;
370317
if let Some(prev) = booted_image.as_ref() {
371-
let diff = ostree_container::ManifestDiff::new(&prev.manifest, &fetched.manifest);
372-
diff.print();
318+
if let Some(fetched_manifest) = fetched.get_manifest(repo)? {
319+
let diff =
320+
ostree_container::ManifestDiff::new(&prev.manifest, &fetched_manifest);
321+
diff.print();
322+
}
373323
}
374324
}
375325
}
@@ -424,7 +374,7 @@ async fn switch(opts: SwitchOpts) -> Result<()> {
424374
}
425375
let new_spec = RequiredHostSpec::from_spec(&new_spec)?;
426376

427-
let fetched = pull(repo, &target, opts.quiet).await?;
377+
let fetched = crate::deploy::pull(sysroot, &target, opts.quiet).await?;
428378

429379
if !opts.retain {
430380
// By default, we prune the previous ostree ref so it will go away after later upgrades
@@ -448,7 +398,6 @@ async fn switch(opts: SwitchOpts) -> Result<()> {
448398
async fn edit(opts: EditOpts) -> Result<()> {
449399
prepare_for_write().await?;
450400
let sysroot = &get_locked_sysroot().await?;
451-
let repo = &sysroot.repo();
452401
let (booted_deployment, _deployments, host) =
453402
crate::status::get_status_require_booted(sysroot)?;
454403
let new_host: Host = if let Some(filename) = opts.filename {
@@ -467,7 +416,7 @@ async fn edit(opts: EditOpts) -> Result<()> {
467416
return Ok(());
468417
}
469418
let new_spec = RequiredHostSpec::from_spec(&new_host.spec)?;
470-
let fetched = pull(repo, new_spec.image, opts.quiet).await?;
419+
let fetched = crate::deploy::pull(sysroot, new_spec.image, opts.quiet).await?;
471420

472421
// TODO gc old layers here
473422

lib/src/deploy.rs

Lines changed: 87 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ use anyhow::{Context, Result};
66

77
use fn_error_context::context;
88
use ostree::{gio, glib};
9-
use ostree_container::store::LayeredImageState;
109
use ostree_container::OstreeImageReference;
1110
use ostree_ext::container as ostree_container;
11+
use ostree_ext::container::store::PrepareResult;
1212
use ostree_ext::ostree;
1313
use ostree_ext::ostree::Deployment;
1414
use ostree_ext::sysroot::SysrootLock;
@@ -27,6 +27,13 @@ pub(crate) struct RequiredHostSpec<'a> {
2727
pub(crate) image: &'a ImageReference,
2828
}
2929

30+
/// State of a locally fetched image
31+
pub(crate) struct ImageState {
32+
pub(crate) manifest_digest: String,
33+
pub(crate) version: Option<String>,
34+
pub(crate) ostree_commit: String,
35+
}
36+
3037
impl<'a> RequiredHostSpec<'a> {
3138
/// Given a (borrowed) host specification, "unwrap" its internal
3239
/// options, giving a spec that is required to have a base container image.
@@ -39,6 +46,81 @@ impl<'a> RequiredHostSpec<'a> {
3946
}
4047
}
4148

49+
impl From<ostree_container::store::LayeredImageState> for ImageState {
50+
fn from(value: ostree_container::store::LayeredImageState) -> Self {
51+
let version = value.version().map(|v| v.to_owned());
52+
let ostree_commit = value.get_commit().to_owned();
53+
Self {
54+
manifest_digest: value.manifest_digest,
55+
version,
56+
ostree_commit,
57+
}
58+
}
59+
}
60+
61+
impl ImageState {
62+
/// Fetch the manifest corresponding to this image. May not be available in all backends.
63+
pub(crate) fn get_manifest(
64+
&self,
65+
repo: &ostree::Repo,
66+
) -> Result<Option<ostree_ext::oci_spec::image::ImageManifest>> {
67+
ostree_container::store::query_image_commit(repo, &self.ostree_commit)
68+
.map(|v| Some(v.manifest))
69+
}
70+
}
71+
72+
/// Wrapper for pulling a container image, wiring up status output.
73+
pub(crate) async fn new_importer(
74+
repo: &ostree::Repo,
75+
imgref: &ostree_container::OstreeImageReference,
76+
) -> Result<ostree_container::store::ImageImporter> {
77+
let config = Default::default();
78+
let mut imp = ostree_container::store::ImageImporter::new(repo, imgref, config).await?;
79+
imp.require_bootable();
80+
Ok(imp)
81+
}
82+
83+
/// Wrapper for pulling a container image, wiring up status output.
84+
#[context("Pulling")]
85+
pub(crate) async fn pull(
86+
sysroot: &SysrootLock,
87+
imgref: &ImageReference,
88+
quiet: bool,
89+
) -> Result<Box<ImageState>> {
90+
let repo = &sysroot.repo();
91+
let imgref = &OstreeImageReference::from(imgref.clone());
92+
let mut imp = new_importer(repo, imgref).await?;
93+
let prep = match imp.prepare().await? {
94+
PrepareResult::AlreadyPresent(c) => {
95+
println!("No changes in {} => {}", imgref, c.manifest_digest);
96+
return Ok(Box::new((*c).into()));
97+
}
98+
PrepareResult::Ready(p) => p,
99+
};
100+
if let Some(warning) = prep.deprecated_warning() {
101+
ostree_ext::cli::print_deprecated_warning(warning).await;
102+
}
103+
ostree_ext::cli::print_layer_status(&prep);
104+
let printer = (!quiet).then(|| {
105+
let layer_progress = imp.request_progress();
106+
let layer_byte_progress = imp.request_layer_progress();
107+
tokio::task::spawn(async move {
108+
ostree_ext::cli::handle_layer_progress_print(layer_progress, layer_byte_progress).await
109+
})
110+
});
111+
let import = imp.import(prep).await;
112+
if let Some(printer) = printer {
113+
let _ = printer.await;
114+
}
115+
let import = import?;
116+
if let Some(msg) =
117+
ostree_container::store::image_filtered_content_warning(repo, &imgref.imgref)?
118+
{
119+
eprintln!("{msg}")
120+
}
121+
Ok(Box::new((*import).into()))
122+
}
123+
42124
pub(crate) async fn cleanup(sysroot: &SysrootLock) -> Result<()> {
43125
let repo = sysroot.repo();
44126
let sysroot = sysroot.sysroot.clone();
@@ -90,16 +172,15 @@ async fn deploy(
90172
sysroot: &SysrootLock,
91173
merge_deployment: Option<&Deployment>,
92174
stateroot: &str,
93-
image: &LayeredImageState,
175+
image: &ImageState,
94176
origin: &glib::KeyFile,
95177
) -> Result<()> {
96178
let stateroot = Some(stateroot);
97179
// Copy to move into thread
98-
let base_commit = image.get_commit().to_owned();
99180
let cancellable = gio::Cancellable::NONE;
100181
let _new_deployment = sysroot.stage_tree_with_options(
101182
stateroot,
102-
&base_commit,
183+
image.ostree_commit.as_str(),
103184
Some(origin),
104185
merge_deployment,
105186
&Default::default(),
@@ -113,7 +194,7 @@ async fn deploy(
113194
pub(crate) async fn stage(
114195
sysroot: &SysrootLock,
115196
stateroot: &str,
116-
image: &LayeredImageState,
197+
image: &ImageState,
117198
spec: &RequiredHostSpec<'_>,
118199
) -> Result<()> {
119200
let merge_deployment = sysroot.merge_deployment(Some(stateroot));
@@ -134,11 +215,7 @@ pub(crate) async fn stage(
134215
.await?;
135216
crate::deploy::cleanup(sysroot).await?;
136217
println!("Queued for next boot: {imgref}");
137-
if let Some(version) = image
138-
.configuration
139-
.as_ref()
140-
.and_then(ostree_container::version_for_config)
141-
{
218+
if let Some(version) = image.version.as_deref() {
142219
println!(" Version: {version}");
143220
}
144221
println!(" Digest: {}", image.manifest_digest);

0 commit comments

Comments
 (0)