From b10baa658186d4cccf1969f149efa16235fcabca Mon Sep 17 00:00:00 2001 From: Oleg Bulatov Date: Fri, 2 Nov 2018 16:50:35 +0100 Subject: [PATCH] Make image API admission extended tests dockerless --- .../imageapis/limitrange_admission.go | 76 ++++------- test/extended/imageapis/quota_admission.go | 121 ++++++++---------- test/extended/images/helper.go | 8 +- test/extended/images/prune.go | 99 +++++++++----- 4 files changed, 147 insertions(+), 157 deletions(-) diff --git a/test/extended/imageapis/limitrange_admission.go b/test/extended/imageapis/limitrange_admission.go index 56dd45bec5f0..7948630738ad 100644 --- a/test/extended/imageapis/limitrange_admission.go +++ b/test/extended/imageapis/limitrange_admission.go @@ -16,16 +16,19 @@ import ( quotautil "github.com/openshift/origin/pkg/quota/util" imagesutil "github.com/openshift/origin/test/extended/images" exutil "github.com/openshift/origin/test/extended/util" - testutil "github.com/openshift/origin/test/util" ) -const limitRangeName = "limits" +const ( + limitRangeName = "limits" + imageSize = 100 +) -var _ = g.Describe("[Feature:ImageQuota][registry][Serial][Suite:openshift/registry/serial][local] Image limit range", func() { +var _ = g.Describe("[Feature:ImageQuota][registry][Serial][Suite:openshift/registry/serial] Image limit range", func() { defer g.GinkgoRecover() + var oc = exutil.NewCLI("limitrange-admission", exutil.KubeConfigPath()) - g.JustBeforeEach(func() { + g.BeforeEach(func() { g.By("waiting for default service account") err := exutil.WaitForServiceAccount(oc.KubeClient().Core().ServiceAccounts(oc.Namespace()), "default") o.Expect(err).NotTo(o.HaveOccurred()) @@ -34,49 +37,30 @@ var _ = g.Describe("[Feature:ImageQuota][registry][Serial][Suite:openshift/regis o.Expect(err).NotTo(o.HaveOccurred()) }) - // needs to be run at the of of each It; cannot be run in AfterEach which is run after the project - // is destroyed - tearDown := func(oc *exutil.CLI) { - g.By(fmt.Sprintf("Deleting limit range %s", limitRangeName)) - oc.AdminKubeClient().Core().LimitRanges(oc.Namespace()).Delete(limitRangeName, nil) - - deleteTestImagesAndStreams(oc) - } - - g.It(fmt.Sprintf("[Skipped] should deny a push of built image exceeding %s limit", imageapi.LimitTypeImage), func() { - g.Skip("FIXME: fill image metadata for schema1 in the registry") - - defer tearDown(oc) - - dClient, err := testutil.NewDockerClient() - o.Expect(err).NotTo(o.HaveOccurred()) - - _, err = createLimitRangeOfType(oc, imageapi.LimitTypeImage, kapi.ResourceList{ + g.It(fmt.Sprintf("should deny a push of built image exceeding %s limit", imageapi.LimitTypeImage), func() { + _, err := createLimitRangeOfType(oc, imageapi.LimitTypeImage, kapi.ResourceList{ kapi.ResourceStorage: resource.MustParse("10Ki"), }) o.Expect(err).NotTo(o.HaveOccurred()) g.By(fmt.Sprintf("trying to push an image exceeding size limit with just 1 layer")) - err = imagesutil.BuildAndPushImageOfSizeWithBuilder(oc, dClient, oc.Namespace(), "sized", "middle", 16000, 1, false) + err = imagesutil.BuildAndPushImageOfSizeWithBuilder(oc, nil, oc.Namespace(), "sized", "middle", 16000, 1, false) o.Expect(err).NotTo(o.HaveOccurred()) g.By(fmt.Sprintf("trying to push an image exceeding size limit in total")) - err = imagesutil.BuildAndPushImageOfSizeWithBuilder(oc, dClient, oc.Namespace(), "sized", "middle", 16000, 5, false) + err = imagesutil.BuildAndPushImageOfSizeWithBuilder(oc, nil, oc.Namespace(), "sized", "middle", 16000, 5, false) o.Expect(err).NotTo(o.HaveOccurred()) g.By(fmt.Sprintf("trying to push an image with one big layer below size limit")) - err = imagesutil.BuildAndPushImageOfSizeWithBuilder(oc, dClient, oc.Namespace(), "sized", "small", 8000, 1, true) + err = imagesutil.BuildAndPushImageOfSizeWithBuilder(oc, nil, oc.Namespace(), "sized", "small", 8000, 1, true) o.Expect(err).NotTo(o.HaveOccurred()) g.By(fmt.Sprintf("trying to push an image below size limit")) - err = imagesutil.BuildAndPushImageOfSizeWithBuilder(oc, dClient, oc.Namespace(), "sized", "small", 8000, 2, true) + err = imagesutil.BuildAndPushImageOfSizeWithBuilder(oc, nil, oc.Namespace(), "sized", "small", 8000, 2, true) o.Expect(err).NotTo(o.HaveOccurred()) }) g.It(fmt.Sprintf("should deny a push of built image exceeding limit on %s resource", imageapi.ResourceImageStreamImages), func() { - - defer tearDown(oc) - limits := kapi.ResourceList{ imageapi.ResourceImageStreamTags: resource.MustParse("0"), imageapi.ResourceImageStreamImages: resource.MustParse("0"), @@ -84,37 +68,34 @@ var _ = g.Describe("[Feature:ImageQuota][registry][Serial][Suite:openshift/regis _, err := createLimitRangeOfType(oc, imageapi.LimitTypeImageStream, limits) o.Expect(err).NotTo(o.HaveOccurred()) - dClient, err := testutil.NewDockerClient() - o.Expect(err).NotTo(o.HaveOccurred()) - g.By(fmt.Sprintf("trying to push image exceeding limits %v", limits)) - err = imagesutil.BuildAndPushImageOfSizeWithBuilder(oc, dClient, oc.Namespace(), "sized", "refused", imageSize, 1, false) + err = imagesutil.BuildAndPushImageOfSizeWithBuilder(oc, nil, oc.Namespace(), "sized", "refused", imageSize, 1, false) o.Expect(err).NotTo(o.HaveOccurred()) limits, err = bumpLimit(oc, imageapi.ResourceImageStreamImages, "1") o.Expect(err).NotTo(o.HaveOccurred()) g.By(fmt.Sprintf("trying to push image below limits %v", limits)) - err = imagesutil.BuildAndPushImageOfSizeWithBuilder(oc, dClient, oc.Namespace(), "sized", "first", imageSize, 2, true) + err = imagesutil.BuildAndPushImageOfSizeWithBuilder(oc, nil, oc.Namespace(), "sized", "first", imageSize, 2, true) o.Expect(err).NotTo(o.HaveOccurred()) g.By(fmt.Sprintf("trying to push image exceeding limits %v", limits)) - err = imagesutil.BuildAndPushImageOfSizeWithBuilder(oc, dClient, oc.Namespace(), "sized", "second", imageSize, 2, false) + err = imagesutil.BuildAndPushImageOfSizeWithBuilder(oc, nil, oc.Namespace(), "sized", "second", imageSize, 2, false) o.Expect(err).NotTo(o.HaveOccurred()) g.By(fmt.Sprintf("trying to push image below limits %v to another image stream", limits)) - err = imagesutil.BuildAndPushImageOfSizeWithBuilder(oc, dClient, oc.Namespace(), "another", "second", imageSize, 1, true) + err = imagesutil.BuildAndPushImageOfSizeWithBuilder(oc, nil, oc.Namespace(), "another", "second", imageSize, 1, true) o.Expect(err).NotTo(o.HaveOccurred()) limits, err = bumpLimit(oc, imageapi.ResourceImageStreamImages, "2") o.Expect(err).NotTo(o.HaveOccurred()) g.By(fmt.Sprintf("trying to push image below limits %v", limits)) - err = imagesutil.BuildAndPushImageOfSizeWithBuilder(oc, dClient, oc.Namespace(), "another", "third", imageSize, 1, true) + err = imagesutil.BuildAndPushImageOfSizeWithBuilder(oc, nil, oc.Namespace(), "another", "third", imageSize, 1, true) o.Expect(err).NotTo(o.HaveOccurred()) g.By(fmt.Sprintf("trying to push image exceeding limits %v", limits)) - err = imagesutil.BuildAndPushImageOfSizeWithBuilder(oc, dClient, oc.Namespace(), "another", "fourth", imageSize, 1, false) + err = imagesutil.BuildAndPushImageOfSizeWithBuilder(oc, nil, oc.Namespace(), "another", "fourth", imageSize, 1, false) o.Expect(err).NotTo(o.HaveOccurred()) g.By(`removing tag "second" from "another" image stream`) @@ -122,14 +103,11 @@ var _ = g.Describe("[Feature:ImageQuota][registry][Serial][Suite:openshift/regis o.Expect(err).NotTo(o.HaveOccurred()) g.By(fmt.Sprintf("trying to push image below limits %v", limits)) - err = imagesutil.BuildAndPushImageOfSizeWithBuilder(oc, dClient, oc.Namespace(), "another", "replenish", imageSize, 1, true) + err = imagesutil.BuildAndPushImageOfSizeWithBuilder(oc, nil, oc.Namespace(), "another", "replenish", imageSize, 1, true) o.Expect(err).NotTo(o.HaveOccurred()) }) g.It(fmt.Sprintf("should deny a docker image reference exceeding limit on %s resource", imageapi.ResourceImageStreamTags), func() { - - defer tearDown(oc) - tag2Image, err := buildAndPushTestImagesTo(oc, "src", "tag", 2) o.Expect(err).NotTo(o.HaveOccurred()) @@ -187,15 +165,12 @@ var _ = g.Describe("[Feature:ImageQuota][registry][Serial][Suite:openshift/regis }) g.It(fmt.Sprintf("should deny an import of a repository exceeding limit on %s resource", imageapi.ResourceImageStreamTags), func() { - maxBulkImport, err := getMaxImagesBulkImportedPerRepository() if err != nil { g.Skip(err.Error()) return } - defer tearDown(oc) - s1tag2Image, err := buildAndPushTestImagesTo(oc, "src1st", "tag", maxBulkImport+1) s2tag2Image, err := buildAndPushTestImagesTo(oc, "src2nd", "t", 2) o.Expect(err).NotTo(o.HaveOccurred()) @@ -234,15 +209,11 @@ var _ = g.Describe("[Feature:ImageQuota][registry][Serial][Suite:openshift/regis // buildAndPushTestImagesTo builds a given number of test images. The images are pushed to a new image stream // of given name under where X is a number of image starting from 1. func buildAndPushTestImagesTo(oc *exutil.CLI, isName string, tagPrefix string, numberOfImages int) (tag2Image map[string]imageapi.Image, err error) { - dClient, err := testutil.NewDockerClient() - if err != nil { - return - } tag2Image = make(map[string]imageapi.Image) for i := 1; i <= numberOfImages; i++ { tag := fmt.Sprintf("%s%d", tagPrefix, i) - dgst, _, err := imagesutil.BuildAndPushImageOfSizeWithDocker(oc, dClient, isName, tag, imageSize, 2, g.GinkgoWriter, true, true) + err = imagesutil.BuildAndPushImageOfSizeWithBuilder(oc, nil, oc.Namespace(), isName, tag, imageSize, 2, true) if err != nil { return nil, err } @@ -250,9 +221,6 @@ func buildAndPushTestImagesTo(oc *exutil.CLI, isName string, tagPrefix string, n if err != nil { return nil, err } - if dgst != ist.Image.Name { - return nil, fmt.Errorf("digest of built image does not match stored: %s != %s", dgst, ist.Image.Name) - } tag2Image[tag] = ist.Image } @@ -316,7 +284,7 @@ func bumpLimit(oc *exutil.CLI, resourceName kapi.ResourceName, limit string) (ka func getMaxImagesBulkImportedPerRepository() (int, error) { max := os.Getenv("MAX_IMAGES_BULK_IMPORTED_PER_REPOSITORY") if len(max) == 0 { - return 0, fmt.Errorf("MAX_IMAGES_BULK_IMAGES_IMPORTED_PER_REPOSITORY is not set") + return 0, fmt.Errorf("MAX_IMAGES_BULK_IMPORTED_PER_REPOSITORY is not set") } return strconv.Atoi(max) } diff --git a/test/extended/imageapis/quota_admission.go b/test/extended/imageapis/quota_admission.go index 289c047a8977..9c5f1be3dd20 100644 --- a/test/extended/imageapis/quota_admission.go +++ b/test/extended/imageapis/quota_admission.go @@ -4,33 +4,32 @@ import ( "fmt" "time" + kerrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" kutilerrors "k8s.io/apimachinery/pkg/util/errors" kapi "k8s.io/kubernetes/pkg/apis/core" + e2e "k8s.io/kubernetes/test/e2e/framework" g "github.com/onsi/ginkgo" o "github.com/onsi/gomega" + imageapiv1 "github.com/openshift/api/image/v1" imageapi "github.com/openshift/origin/pkg/image/apis/image" - imagesutil "github.com/openshift/origin/test/extended/images" exutil "github.com/openshift/origin/test/extended/util" testutil "github.com/openshift/origin/test/util" ) const ( - imageSize = 100 - - quotaName = "isquota" - + quotaName = "isquota" waitTimeout = time.Second * 600 ) -var _ = g.Describe("[Feature:ImageQuota][registry][Serial][Suite:openshift/registry/serial][local] Image resource quota", func() { +var _ = g.Describe("[Feature:ImageQuota][registry][Serial][Suite:openshift/registry/serial] Image resource quota", func() { defer g.GinkgoRecover() var oc = exutil.NewCLI("resourcequota-admission", exutil.KubeConfigPath()) - g.JustBeforeEach(func() { + g.BeforeEach(func() { g.By("waiting for default service account") err := exutil.WaitForServiceAccount(oc.KubeClient().Core().ServiceAccounts(oc.Namespace()), "default") o.Expect(err).NotTo(o.HaveOccurred()) @@ -39,49 +38,37 @@ var _ = g.Describe("[Feature:ImageQuota][registry][Serial][Suite:openshift/regis o.Expect(err).NotTo(o.HaveOccurred()) }) - // needs to be run at the of of each It; cannot be run in AfterEach which is run after the project - // is destroyed - tearDown := func(oc *exutil.CLI) { - g.By(fmt.Sprintf("Deleting quota %s", quotaName)) - oc.AdminKubeClient().Core().ResourceQuotas(oc.Namespace()).Delete(quotaName, nil) - - deleteTestImagesAndStreams(oc) - } - g.It(fmt.Sprintf("should deny a push of built image exceeding %s quota", imageapi.ResourceImageStreams), func() { - - defer tearDown(oc) - dClient, err := testutil.NewDockerClient() - o.Expect(err).NotTo(o.HaveOccurred()) - - outSink := g.GinkgoWriter - quota := kapi.ResourceList{ imageapi.ResourceImageStreams: resource.MustParse("0"), } - _, err = createResourceQuota(oc, quota) + _, err := createResourceQuota(oc, quota) + o.Expect(err).NotTo(o.HaveOccurred()) + used, err := waitForResourceQuotaSync(oc, quotaName, quota) o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(assertQuotasEqual(used, quota)).NotTo(o.HaveOccurred()) g.By(fmt.Sprintf("trying to push image exceeding quota %v", quota)) - _, _, err = imagesutil.BuildAndPushImageOfSizeWithDocker(oc, dClient, "first", "refused", imageSize, 1, outSink, false, true) - o.Expect(err).NotTo(o.HaveOccurred()) + err = createImageStreamMapping(oc, oc.Namespace(), "first", "refused") + assertQuotaExceeded(err) quota, err = bumpQuota(oc, imageapi.ResourceImageStreams, 1) o.Expect(err).NotTo(o.HaveOccurred()) g.By(fmt.Sprintf("trying to push image below quota %v", quota)) - _, _, err = imagesutil.BuildAndPushImageOfSizeWithDocker(oc, dClient, "first", "tag1", imageSize, 1, outSink, true, true) + err = createImageStreamMapping(oc, oc.Namespace(), "first", "tag1") o.Expect(err).NotTo(o.HaveOccurred()) - used, err := waitForResourceQuotaSync(oc, quotaName, quota) + used, err = waitForResourceQuotaSync(oc, quotaName, quota) o.Expect(err).NotTo(o.HaveOccurred()) o.Expect(assertQuotasEqual(used, quota)).NotTo(o.HaveOccurred()) g.By(fmt.Sprintf("trying to push image to existing image stream %v", quota)) - _, _, err = imagesutil.BuildAndPushImageOfSizeWithDocker(oc, dClient, "first", "tag2", imageSize, 1, outSink, true, true) + err = createImageStreamMapping(oc, oc.Namespace(), "first", "tag2") o.Expect(err).NotTo(o.HaveOccurred()) g.By(fmt.Sprintf("trying to push image exceeding quota %v", quota)) - _, _, err = imagesutil.BuildAndPushImageOfSizeWithDocker(oc, dClient, "second", "refused", imageSize, 1, outSink, false, true) + err = createImageStreamMapping(oc, oc.Namespace(), "second", "refused") + assertQuotaExceeded(err) quota, err = bumpQuota(oc, imageapi.ResourceImageStreams, 2) o.Expect(err).NotTo(o.HaveOccurred()) @@ -89,15 +76,15 @@ var _ = g.Describe("[Feature:ImageQuota][registry][Serial][Suite:openshift/regis o.Expect(err).NotTo(o.HaveOccurred()) g.By(fmt.Sprintf("trying to push image below quota %v", quota)) - _, _, err = imagesutil.BuildAndPushImageOfSizeWithDocker(oc, dClient, "second", "tag1", imageSize, 1, outSink, true, true) + err = createImageStreamMapping(oc, oc.Namespace(), "second", "tag1") o.Expect(err).NotTo(o.HaveOccurred()) used, err = waitForResourceQuotaSync(oc, quotaName, quota) o.Expect(err).NotTo(o.HaveOccurred()) o.Expect(assertQuotasEqual(used, quota)).NotTo(o.HaveOccurred()) g.By(fmt.Sprintf("trying to push image exceeding quota %v", quota)) - _, _, err = imagesutil.BuildAndPushImageOfSizeWithDocker(oc, dClient, "third", "refused", imageSize, 1, outSink, false, true) - o.Expect(err).NotTo(o.HaveOccurred()) + err = createImageStreamMapping(oc, oc.Namespace(), "third", "refused") + assertQuotaExceeded(err) g.By("deleting first image stream") err = oc.ImageClient().Image().ImageStreams(oc.Namespace()).Delete("first", nil) @@ -113,7 +100,7 @@ var _ = g.Describe("[Feature:ImageQuota][registry][Serial][Suite:openshift/regis o.Expect(assertQuotasEqual(used, kapi.ResourceList{imageapi.ResourceImageStreams: resource.MustParse("1")})).NotTo(o.HaveOccurred()) g.By(fmt.Sprintf("trying to push image below quota %v", quota)) - _, _, err = imagesutil.BuildAndPushImageOfSizeWithDocker(oc, dClient, "third", "tag", imageSize, 1, outSink, true, true) + err = createImageStreamMapping(oc, oc.Namespace(), "third", "tag") o.Expect(err).NotTo(o.HaveOccurred()) used, err = waitForResourceQuotaSync(oc, quotaName, quota) o.Expect(err).NotTo(o.HaveOccurred()) @@ -213,42 +200,38 @@ func waitForLimitSync(oc *exutil.CLI, hardLimit kapi.ResourceList) error { waitTimeout) } -// deleteTestImagesAndStreams deletes test images built in current and shared -// namespaces. It also deletes shared projects. -func deleteTestImagesAndStreams(oc *exutil.CLI) { - for _, projectName := range []string{ - oc.Namespace() + "-s2", - oc.Namespace() + "-s1", - oc.Namespace() + "-shared", - oc.Namespace(), - } { - g.By(fmt.Sprintf("Deleting images and image streams in project %q", projectName)) - iss, err := oc.AdminInternalImageClient().Image().ImageStreams(projectName).List(metav1.ListOptions{}) +func createImageStreamMapping(oc *exutil.CLI, namespace, name, tag string) error { + e2e.Logf("Creating image stream mapping for %s/%s:%s...", namespace, name, tag) + _, err := oc.AdminImageClient().Image().ImageStreams(namespace).Get(name, metav1.GetOptions{}) + if kerrors.IsNotFound(err) { + _, err = oc.AdminImageClient().Image().ImageStreams(namespace).Create(&imageapiv1.ImageStream{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + }, + }) if err != nil { - continue - } - for _, is := range iss.Items { - for _, history := range is.Status.Tags { - for i := range history.Items { - oc.AdminInternalImageClient().Image().Images().Delete(history.Items[i].Image, nil) - } - } - for _, tagRef := range is.Spec.Tags { - switch tagRef.From.Kind { - case "ImageStreamImage": - _, id, err := imageapi.ParseImageStreamImageName(tagRef.From.Name) - if err != nil { - continue - } - oc.AdminInternalImageClient().Image().Images().Delete(id, nil) - } - } - } - - // let the extended framework take care of the current namespace - if projectName != oc.Namespace() { - g.By(fmt.Sprintf("Deleting project %q", projectName)) - oc.AdminProjectClient().Project().Projects().Delete(projectName, nil) + return err } + } else if err != nil { + return err } + _, err = oc.AdminImageClient().Image().ImageStreamMappings(namespace).Create(&imageapiv1.ImageStreamMapping{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + }, + Image: imageapiv1.Image{ + ObjectMeta: metav1.ObjectMeta{ + Name: "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + }, + }, + Tag: tag, + }) + return err +} + +func assertQuotaExceeded(err error) { + o.Expect(kerrors.ReasonForError(err)).To(o.Equal(metav1.StatusReasonForbidden)) + o.Expect(err.Error()).To(o.ContainSubstring("exceeded quota")) } diff --git a/test/extended/images/helper.go b/test/extended/images/helper.go index 7133520a86c8..255adf0cf394 100644 --- a/test/extended/images/helper.go +++ b/test/extended/images/helper.go @@ -17,7 +17,6 @@ import ( dockerclient "github.com/fsouza/go-dockerclient" g "github.com/onsi/ginkgo" - godigest "github.com/opencontainers/go-digest" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -35,7 +34,6 @@ import ( const ( // There are coefficients used to multiply layer data size to get a rough size of uploaded blob. - layerSizeMultiplierForDocker18 = 2.0 layerSizeMultiplierForLatestDocker = 0.8 defaultLayerSize = 1024 digestSHA256GzippedEmptyTar = godigest.Digest("sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4") @@ -214,8 +212,10 @@ func BuildAndPushImageOfSizeWithBuilder( } buildLog, logsErr := br.Logs() - if match := reSuccessfulBuild.FindStringSubmatch(buildLog); len(match) > 1 { - defer dClient.RemoveImageExtended(match[1], dockerclient.RemoveImageOptions{Force: true}) + if dClient != nil { + if match := reSuccessfulBuild.FindStringSubmatch(buildLog); len(match) > 1 { + defer dClient.RemoveImageExtended(match[1], dockerclient.RemoveImageOptions{Force: true}) + } } if !shouldSucceed { diff --git a/test/extended/images/prune.go b/test/extended/images/prune.go index aedb6114e548..6fba4c9212f4 100644 --- a/test/extended/images/prune.go +++ b/test/extended/images/prune.go @@ -14,10 +14,11 @@ import ( godigest "github.com/opencontainers/go-digest" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + e2e "k8s.io/kubernetes/test/e2e/framework" imageapi "github.com/openshift/origin/pkg/image/apis/image" + "github.com/openshift/origin/pkg/image/dockerlayer" exutil "github.com/openshift/origin/test/extended/util" - testutil "github.com/openshift/origin/test/util" ) const ( @@ -33,6 +34,10 @@ var _ = g.Describe("[Feature:ImagePrune][registry][Serial][Suite:openshift/regis var originalAcceptSchema2 *bool + var startTime time.Time + g.JustBeforeEach(func() { + startTime = time.Now() + }) g.JustBeforeEach(func() { if originalAcceptSchema2 == nil { accepts, err := DoesRegistryAcceptSchema2(oc) @@ -68,6 +73,9 @@ var _ = g.Describe("[Feature:ImagePrune][registry][Serial][Suite:openshift/regis }) g.AfterEach(func() { + if g.CurrentGinkgoTestDescription().Failed { + dumpRegistryLogs(oc, startTime) + } if *originalAcceptSchema2 { _, err := EnsureRegistryAcceptsSchema2(oc, true) o.Expect(err).NotTo(o.HaveOccurred()) @@ -93,6 +101,9 @@ var _ = g.Describe("[Feature:ImagePrune][registry][Serial][Suite:openshift/regis }) g.AfterEach(func() { + if g.CurrentGinkgoTestDescription().Failed { + dumpRegistryLogs(oc, startTime) + } if !*originalAcceptSchema2 { _, err := EnsureRegistryAcceptsSchema2(oc, false) o.Expect(err).NotTo(o.HaveOccurred()) @@ -118,6 +129,9 @@ var _ = g.Describe("[Feature:ImagePrune][registry][Serial][Suite:openshift/regis }) g.AfterEach(func() { + if g.CurrentGinkgoTestDescription().Failed { + dumpRegistryLogs(oc, startTime) + } if !*originalAcceptSchema2 { _, err := EnsureRegistryAcceptsSchema2(oc, false) o.Expect(err).NotTo(o.HaveOccurred()) @@ -143,6 +157,9 @@ var _ = g.Describe("[Feature:ImagePrune][registry][Serial][Suite:openshift/regis }) g.AfterEach(func() { + if g.CurrentGinkgoTestDescription().Failed { + dumpRegistryLogs(oc, startTime) + } if !*originalAcceptSchema2 { _, err := EnsureRegistryAcceptsSchema2(oc, false) o.Expect(err).NotTo(o.HaveOccurred()) @@ -168,6 +185,9 @@ var _ = g.Describe("[Feature:ImagePrune][registry][Serial][Suite:openshift/regis }) g.AfterEach(func() { + if g.CurrentGinkgoTestDescription().Failed { + dumpRegistryLogs(oc, startTime) + } if !*originalAcceptSchema2 { _, err := EnsureRegistryAcceptsSchema2(oc, false) o.Expect(err).NotTo(o.HaveOccurred()) @@ -178,6 +198,14 @@ var _ = g.Describe("[Feature:ImagePrune][registry][Serial][Suite:openshift/regis }) }) +func getImageName(oc *exutil.CLI, namespace, name, tag string) (string, error) { + istag, err := oc.AdminImageClient().Image().ImageStreamTags(namespace).Get(fmt.Sprintf("%s:%s", name, tag), metav1.GetOptions{}) + if err != nil { + return "", err + } + return istag.Image.Name, nil +} + func testPruneImages(oc *exutil.CLI, schemaVersion int) { var mediaType string switch schemaVersion { @@ -192,22 +220,21 @@ func testPruneImages(oc *exutil.CLI, schemaVersion int) { isName := "prune" repoName := oc.Namespace() + "/" + isName - outSink := g.GinkgoWriter - cleanUp := NewCleanUpContainer(oc) defer cleanUp.Run() - dClient, err := testutil.NewDockerClient() + g.By(fmt.Sprintf("build two images and push them as schema %d", schemaVersion)) + err := BuildAndPushImageOfSizeWithBuilder(oc, nil, oc.Namespace(), isName, "latest", testImageSize, 2, true) o.Expect(err).NotTo(o.HaveOccurred()) - - g.By(fmt.Sprintf("build two images using Docker and push them as schema %d", schemaVersion)) - imgPruneName, _, err := BuildAndPushImageOfSizeWithDocker(oc, dClient, isName, "latest", testImageSize, 2, outSink, true, true) + imgPruneName, err := getImageName(oc, oc.Namespace(), isName, "latest") o.Expect(err).NotTo(o.HaveOccurred()) cleanUp.AddImage(imgPruneName, "", "") cleanUp.AddImageStream(isName) pruneSize, err := GetRegistryStorageSize(oc) o.Expect(err).NotTo(o.HaveOccurred()) - imgKeepName, _, err := BuildAndPushImageOfSizeWithDocker(oc, dClient, isName, "latest", testImageSize, 2, outSink, true, true) + err = BuildAndPushImageOfSizeWithBuilder(oc, nil, oc.Namespace(), isName, "latest", testImageSize, 2, true) + o.Expect(err).NotTo(o.HaveOccurred()) + imgKeepName, err := getImageName(oc, oc.Namespace(), isName, "latest") o.Expect(err).NotTo(o.HaveOccurred()) cleanUp.AddImage(imgKeepName, "", "") keepSize, err := GetRegistryStorageSize(oc) @@ -224,6 +251,8 @@ func testPruneImages(oc *exutil.CLI, schemaVersion int) { g.By("prune the first image uploaded (dry-run)") output, err := oc.WithoutNamespace().Run("adm").Args("prune", "images", "--keep-tag-revisions=1", "--keep-younger-than=0").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + e2e.Logf("Prune Images Output:\n%s", output) g.By("verify images, layers and configs about to be pruned") o.Expect(output).To(o.ContainSubstring(imgPruneName)) @@ -233,17 +262,17 @@ func testPruneImages(oc *exutil.CLI, schemaVersion int) { o.Expect(output).To(o.ContainSubstring(imgPrune.DockerImageMetadata.ID)) } for _, layer := range imgPrune.DockerImageLayers { - if !strings.Contains(output, layer.Name) { - o.Expect(output).To(o.ContainSubstring(layer.Name)) + if layer.Name == dockerlayer.GzippedEmptyLayerDigest { + // Schema 1 manifests are known to have the widespread layer. + continue } + o.Expect(output).To(o.ContainSubstring(layer.Name)) } o.Expect(output).NotTo(o.ContainSubstring(imgKeepName)) o.Expect(output).NotTo(o.ContainSubstring(imgKeep.DockerImageMetadata.ID)) for _, layer := range imgKeep.DockerImageLayers { - if !strings.Contains(output, layer.Name) { - o.Expect(output).NotTo(o.ContainSubstring(layer.Name)) - } + o.Expect(output).NotTo(o.ContainSubstring(layer.Name)) } noConfirmSize, err := GetRegistryStorageSize(oc) @@ -252,6 +281,8 @@ func testPruneImages(oc *exutil.CLI, schemaVersion int) { g.By("prune the first image uploaded (confirm)") output, err = oc.WithoutNamespace().Run("adm").Args("prune", "images", "--keep-tag-revisions=1", "--keep-younger-than=0", "--confirm").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + e2e.Logf("Prune Images Output:\n%s", output) g.By("verify images, layers and configs about to be pruned") o.Expect(output).To(o.ContainSubstring(imgPruneName)) @@ -261,9 +292,13 @@ func testPruneImages(oc *exutil.CLI, schemaVersion int) { o.Expect(output).To(o.ContainSubstring(imgPrune.DockerImageMetadata.ID)) } for _, layer := range imgPrune.DockerImageLayers { - if !strings.Contains(output, layer.Name) { - o.Expect(output).To(o.ContainSubstring(layer.Name)) + if layer.Name == dockerlayer.GzippedEmptyLayerDigest { + // Schema 1 manifests are known to have the widespread layer. + continue } + + o.Expect(output).To(o.ContainSubstring(layer.Name)) + globally, inRepository, err := IsBlobStoredInRegistry(oc, godigest.Digest(layer.Name), repoName) o.Expect(err).NotTo(o.HaveOccurred()) o.Expect(globally).To(o.BeFalse()) @@ -273,9 +308,8 @@ func testPruneImages(oc *exutil.CLI, schemaVersion int) { o.Expect(output).NotTo(o.ContainSubstring(imgKeepName)) o.Expect(output).NotTo(o.ContainSubstring(imgKeep.DockerImageMetadata.ID)) for _, layer := range imgKeep.DockerImageLayers { - if !strings.Contains(output, layer.Name) { - o.Expect(output).NotTo(o.ContainSubstring(layer.Name)) - } + o.Expect(output).NotTo(o.ContainSubstring(layer.Name)) + globally, inRepository, err := IsBlobStoredInRegistry(oc, godigest.Digest(layer.Name), repoName) o.Expect(err).NotTo(o.HaveOccurred()) o.Expect(globally).To(o.BeTrue()) @@ -294,16 +328,13 @@ func testPruneImages(oc *exutil.CLI, schemaVersion int) { func testSoftPruneImages(oc *exutil.CLI) { isName := "prune" - outSink := g.GinkgoWriter - cleanUp := NewCleanUpContainer(oc) defer cleanUp.Run() - dClient, err := testutil.NewDockerClient() + g.By("build two images and push them") + err := BuildAndPushImageOfSizeWithBuilder(oc, nil, oc.Namespace(), isName, "latest", testImageSize, 2, true) o.Expect(err).NotTo(o.HaveOccurred()) - - g.By("build two images using Docker and push them") - imgPruneName, _, err := BuildAndPushImageOfSizeWithDocker(oc, dClient, isName, "latest", testImageSize, 2, outSink, true, true) + imgPruneName, err := getImageName(oc, oc.Namespace(), isName, "latest") o.Expect(err).NotTo(o.HaveOccurred()) cleanUp.AddImage(imgPruneName, "", "") cleanUp.AddImageStream(isName) @@ -328,16 +359,13 @@ func testPruneAllImages(oc *exutil.CLI, setAllImagesToFalse bool, schemaVersion isName := fmt.Sprintf("prune-schema%d-all-images-%t", schemaVersion, setAllImagesToFalse) repository := oc.Namespace() + "/" + isName - outSink := g.GinkgoWriter - cleanUp := NewCleanUpContainer(oc) defer cleanUp.Run() - dClient, err := testutil.NewDockerClient() + g.By("build one image and push it") + err := BuildAndPushImageOfSizeWithBuilder(oc, nil, oc.Namespace(), isName, "latest", testImageSize, 2, true) o.Expect(err).NotTo(o.HaveOccurred()) - - g.By("build one image using Docker and push it") - managedImageName, _, err := BuildAndPushImageOfSizeWithDocker(oc, dClient, isName, "latest", testImageSize, 2, outSink, true, true) + managedImageName, err := getImageName(oc, oc.Namespace(), isName, "latest") o.Expect(err).NotTo(o.HaveOccurred()) cleanUp.AddImage(managedImageName, "", "") cleanUp.AddImageStream(isName) @@ -464,3 +492,14 @@ func importImageAndMirrorItsSmallestBlob(oc *exutil.CLI, imageReference, destIST return &istag.Image, godigest.Digest(tmpLayers[0].Name), nil } + +func dumpRegistryLogs(oc *exutil.CLI, since time.Time) { + oadm := oc.AsAdmin() + oadm.SetNamespace("default") + out, err := oadm.Run("logs").Args("dc/docker-registry", "--since-time="+since.Format(time.RFC3339)).Output() + if err != nil { + e2e.Logf("Error during retrieval of registry logs: %v", err) + } else { + e2e.Logf("Registry Logs (since %s)\n%s:", since, out) + } +}