Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IR-112: Pruner should be aware of OCI image configs #617

Merged
merged 2 commits into from
Nov 11, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ require (
github.com/moby/buildkit v0.0.0-20181107081847-c3a857e3fca0
github.com/mtrmac/gpgme v0.1.2 // indirect
github.com/opencontainers/go-digest v1.0.0-rc1
github.com/opencontainers/image-spec v1.0.2-0.20190823105129-775207bd45b6
github.com/openshift/api v0.0.0-20201019163320-c6a5ec25f267
github.com/openshift/build-machinery-go v0.0.0-20200917070002-f171684f77ab
github.com/openshift/client-go v0.0.0-20201020074620-f8fd44879f7c
Expand Down
6 changes: 5 additions & 1 deletion pkg/cli/admin/prune/imageprune/prune.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (

"github.com/docker/distribution/manifest/schema2"
"github.com/docker/distribution/registry/api/errcode"
imagespecv1 "github.com/opencontainers/image-spec/specs-go/v1"
"k8s.io/klog/v2"

kappsv1 "k8s.io/api/apps/v1"
Expand Down Expand Up @@ -749,7 +750,10 @@ func getImageBlobs(image *imagev1.Image) ([]string, error) {
return blobs, fmt.Errorf("failed to read metadata for image %s", image.Name)
}

if image.DockerImageManifestMediaType == schema2.MediaTypeManifest && len(dockerImage.ID) > 0 {
mediaTypeHasConfig := image.DockerImageManifestMediaType == schema2.MediaTypeManifest ||
image.DockerImageManifestMediaType == imagespecv1.MediaTypeImageManifest

if mediaTypeHasConfig && len(dockerImage.ID) > 0 {
configName := dockerImage.ID
blobs = append(blobs, configName)
}
Expand Down
87 changes: 87 additions & 0 deletions pkg/cli/admin/prune/imageprune/prune_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1554,6 +1554,93 @@ func TestImagePruning(t *testing.T) {
`buildconfig/bc1 namespace=foo: invalid ImageStreamImage reference "bad:isi":` +
` expected exactly one @ in the isimage name "bad:isi"]`,
},

{
name: "schema 2 image blobs are pruned",
keepTagRevisions: keepTagRevisions(0),
images: Images(imagetest.ImageWithLayers("sha256:0000000000000000000000000000000000000000000000000000000000000000", registryHost+"/foo/bar@sha256:0000000000000000000000000000000000000000000000000000000000000000", &imagetest.Config1, "layer1", "layer2")),
streams: Streams(
imagetest.Stream(registryHost, "foo", "bar", []imagev1.NamedTagEventList{
imagetest.Tag("latest",
imagetest.TagEvent("sha256:0000000000000000000000000000000000000000000000000000000000000000", registryHost+"/foo/bar@sha256:0000000000000000000000000000000000000000000000000000000000000000"),
),
}),
),
expectedImageDeletions: []string{"sha256:0000000000000000000000000000000000000000000000000000000000000000"},
expectedLayerLinkDeletions: []string{
"foo/bar|layer1",
"foo/bar|layer2",
"foo/bar|" + imagetest.Config1,
},
expectedManifestLinkDeletions: []string{
"foo/bar|sha256:0000000000000000000000000000000000000000000000000000000000000000",
},
expectedBlobDeletions: []string{
"sha256:0000000000000000000000000000000000000000000000000000000000000000",
"layer1",
"layer2",
imagetest.Config1,
},
expectedStreamUpdates: []string{
"foo/bar:latest",
"foo/bar|latest|0|sha256:0000000000000000000000000000000000000000000000000000000000000000",
},
},

{
name: "oci image blobs are pruned",
keepTagRevisions: keepTagRevisions(0),
images: Images(imagetest.OCIImageWithLayers("sha256:0000000000000000000000000000000000000000000000000000000000000000", registryHost+"/foo/bar@sha256:0000000000000000000000000000000000000000000000000000000000000000", imagetest.Config1, "layer1", "layer2")),
streams: Streams(
imagetest.Stream(registryHost, "foo", "bar", []imagev1.NamedTagEventList{
imagetest.Tag("latest",
imagetest.TagEvent("sha256:0000000000000000000000000000000000000000000000000000000000000000", registryHost+"/foo/bar@sha256:0000000000000000000000000000000000000000000000000000000000000000"),
),
}),
),
expectedImageDeletions: []string{"sha256:0000000000000000000000000000000000000000000000000000000000000000"},
expectedLayerLinkDeletions: []string{
"foo/bar|layer1",
"foo/bar|layer2",
"foo/bar|" + imagetest.Config1,
},
expectedManifestLinkDeletions: []string{
"foo/bar|sha256:0000000000000000000000000000000000000000000000000000000000000000",
},
expectedBlobDeletions: []string{
"sha256:0000000000000000000000000000000000000000000000000000000000000000",
"layer1",
"layer2",
imagetest.Config1,
},
expectedStreamUpdates: []string{
"foo/bar:latest",
"foo/bar|latest|0|sha256:0000000000000000000000000000000000000000000000000000000000000000",
},
},

{
name: "blobs are not deleted if there are oci images that still use them",
keepTagRevisions: keepTagRevisions(1),
images: Images(
imagetest.OCIImageWithLayers("sha256:0000000000000000000000000000000000000000000000000000000000000001", registryHost+"/foo/bar@sha256:0000000000000000000000000000000000000000000000000000000000000001", imagetest.Config1, "layer1", "layer2"),
imagetest.ImageWithLayers("sha256:0000000000000000000000000000000000000000000000000000000000000000", registryHost+"/foo/bar@sha256:0000000000000000000000000000000000000000000000000000000000000000", &imagetest.Config1, "layer1", "layer2"),
),
streams: Streams(
imagetest.Stream(registryHost, "foo", "bar", []imagev1.NamedTagEventList{
imagetest.Tag("latest",
imagetest.TagEvent("sha256:0000000000000000000000000000000000000000000000000000000000000001", registryHost+"/foo/bar@sha256:0000000000000000000000000000000000000000000000000000000000000001"),
imagetest.TagEvent("sha256:0000000000000000000000000000000000000000000000000000000000000000", registryHost+"/foo/bar@sha256:0000000000000000000000000000000000000000000000000000000000000000"),
),
}),
),
expectedImageDeletions: []string{"sha256:0000000000000000000000000000000000000000000000000000000000000000"},
expectedManifestLinkDeletions: []string{"foo/bar|sha256:0000000000000000000000000000000000000000000000000000000000000000"},
expectedBlobDeletions: []string{"sha256:0000000000000000000000000000000000000000000000000000000000000000"},
expectedStreamUpdates: []string{
"foo/bar|latest|1|sha256:0000000000000000000000000000000000000000000000000000000000000000",
},
},
}

// we need to install OpenShift API types to kubectl's scheme for GetReference to work
Expand Down
10 changes: 9 additions & 1 deletion pkg/helpers/image/test/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (

"github.com/docker/distribution/manifest/schema1"
"github.com/docker/distribution/manifest/schema2"
imagespecv1 "github.com/opencontainers/image-spec/specs-go/v1"

kappsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
Expand Down Expand Up @@ -69,7 +70,7 @@ func Image(id, ref string) imagev1.Image {
return AgedImage(id, ref, 120)
}

// Image returns a default test image referencing the given layers.
// ImageWithLayers returns a default test image referencing the given layers.
func ImageWithLayers(id, ref string, configName *string, layers ...string) imagev1.Image {
image := imagev1.Image{
ObjectMeta: metav1.ObjectMeta{
Expand Down Expand Up @@ -103,6 +104,13 @@ func ImageWithLayers(id, ref string, configName *string, layers ...string) image
return image
}

// OCIImageWithLayers returns an OCI image referencing the given layers.
func OCIImageWithLayers(id, ref string, configName string, layers ...string) imagev1.Image {
image := ImageWithLayers(id, ref, &configName, layers...)
image.DockerImageManifestMediaType = imagespecv1.MediaTypeImageManifest
return image
}

// UnmanagedImage creates a test image object lacking managed by OpenShift annotation.
func UnmanagedImage(id, ref string, hasAnnotations bool, annotation, value string) imagev1.Image {
image := ImageWithLayers(id, ref, nil)
Expand Down
1 change: 1 addition & 0 deletions vendor/modules.txt
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,7 @@ github.com/onsi/gomega/types
## explicit
github.com/opencontainers/go-digest
# github.com/opencontainers/image-spec v1.0.2-0.20190823105129-775207bd45b6
## explicit
github.com/opencontainers/image-spec/specs-go
github.com/opencontainers/image-spec/specs-go/v1
# github.com/opencontainers/runc v1.0.0-rc91.0.20200707015106-819fcc687efb
Expand Down