Skip to content
This repository has been archived by the owner on Nov 7, 2024. It is now read-only.

Commit

Permalink
container: Add deployed commits into set of GC roots
Browse files Browse the repository at this point in the history
Prep for handling image pruning better.  The way things
are kind of expected to work today is that for a deployed ostree
commit, we have *two* refs which point to it - one like e.g.
`fedora:fedora/x86_64/coreos/stable`, as well as the "deployment ref"
like "ostree/0/1/1" which is a synthetic ref generated by the
sysroot core.

We want to be able to remove the container image refs - but
doing so today subjects the *layer* branches to garbage collection.

Fix this by looking at the deployment refs as well as the set of
images when computing the set of references for container images.
  • Loading branch information
cgwalters committed Nov 10, 2022
1 parent b2e3e56 commit aec69c8
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 0 deletions.
6 changes: 6 additions & 0 deletions ci/priv-integration.sh
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,14 @@ for img in "${image}"; do
ostree-ext-cli container image deploy --sysroot "${sysroot}" \
--stateroot "${stateroot}" --imgref ostree-unverified-registry:"${img}"
ostree admin --sysroot="${sysroot}" status
initial_refs=$(ostree --repo="${sysroot}/ostree/repo" refs | wc -l)
ostree-ext-cli container image remove --repo "${sysroot}/ostree/repo" registry:"${img}"
pruned_refs=$(ostree --repo="${sysroot}/ostree/repo" refs | wc -l)
# Removing the image should only drop the image reference, not its layers
test "$(($initial_refs - 1))" = "$pruned_refs"
ostree admin --sysroot="${sysroot}" undeploy 0
# TODO: when we fold together ostree and ostree-ext, automatically prune layers
ostree-ext-cli container image prune-layers --repo="${sysroot}/ostree/repo"
ostree --repo="${sysroot}/ostree/repo" refs > refs.txt
if test "$(wc -l < refs.txt)" -ne 0; then
echo "found refs"
Expand Down
13 changes: 13 additions & 0 deletions lib/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,13 @@ pub(crate) enum ContainerImageOpts {
skip_gc: bool,
},

/// Garbage collect unreferenced image layer references.
PruneLayers {
/// Path to the repository
#[clap(long, value_parser)]
repo: Utf8PathBuf,
},

/// Perform initial deployment for a container image
Deploy {
/// Path to the system root
Expand Down Expand Up @@ -777,6 +784,12 @@ where
}
Ok(())
}
ContainerImageOpts::PruneLayers { repo } => {
let repo = parse_repo(&repo)?;
let nlayers = crate::container::store::gc_image_layers(&repo)?;
println!("Removed layers: {nlayers}");
Ok(())
}
ContainerImageOpts::Copy {
src_repo,
dest_repo,
Expand Down
36 changes: 36 additions & 0 deletions lib/src/container/store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -983,6 +983,40 @@ pub async fn copy(
Ok(())
}

/// Iterate over deployment commits, returning the manifests from
/// commits which point to a container image.
fn list_container_deployment_manifests(
repo: &ostree::Repo,
cancellable: Option<&gio::Cancellable>,
) -> Result<Vec<ImageManifest>> {
let commits = repo
.list_refs_ext(
Some("ostree/0"),
ostree::RepoListRefsExtFlags::empty(),
cancellable,
)?
.into_iter()
.chain(repo.list_refs_ext(
Some("ostree/1"),
ostree::RepoListRefsExtFlags::empty(),
cancellable,
)?)
.map(|v| v.1);
let mut r = Vec::new();
for commit in commits {
let commit_obj = repo.load_commit(&commit)?.0;
let commit_meta = &glib::VariantDict::new(Some(&commit_obj.child_value(0)));
if commit_meta
.lookup::<String>(META_MANIFEST_DIGEST)?
.is_some()
{
let manifest = manifest_data_from_commitmeta(commit_meta)?.0;
r.push(manifest);
}
}
Ok(r)
}

/// Garbage collect unused image layer references.
///
/// This function assumes no transaction is active on the repository.
Expand All @@ -998,11 +1032,13 @@ fn gc_image_layers_impl(
cancellable: Option<&gio::Cancellable>,
) -> Result<u32> {
let all_images = list_images(repo)?;
let deployment_commits = list_container_deployment_manifests(repo, cancellable)?;
let all_manifests = all_images
.into_iter()
.map(|img| {
ImageReference::try_from(img.as_str()).and_then(|ir| manifest_for_image(repo, &ir))
})
.chain(deployment_commits.into_iter().map(Ok))
.collect::<Result<Vec<_>>>()?;
let mut referenced_layers = BTreeSet::new();
for m in all_manifests.iter() {
Expand Down

0 comments on commit aec69c8

Please sign in to comment.