Skip to content

Commit

Permalink
Make image API admission extended tests dockerless
Browse files Browse the repository at this point in the history
  • Loading branch information
Oleg Bulatov committed Nov 13, 2018
1 parent a7f822d commit b10baa6
Show file tree
Hide file tree
Showing 4 changed files with 147 additions and 157 deletions.
76 changes: 22 additions & 54 deletions test/extended/imageapis/limitrange_admission.go
Original file line number Diff line number Diff line change
Expand Up @@ -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())
Expand All @@ -34,102 +37,77 @@ 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"),
}
_, 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`)
err = oc.ImageClient().Image().ImageStreamTags(oc.Namespace()).Delete("another:second", nil)
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())

Expand Down Expand Up @@ -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())
Expand Down Expand Up @@ -234,25 +209,18 @@ 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 <tagPrefix><X> 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
}
ist, err := oc.ImageClient().Image().ImageStreamTags(oc.Namespace()).Get(isName+":"+tag, metav1.GetOptions{})
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
}

Expand Down Expand Up @@ -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)
}
121 changes: 52 additions & 69 deletions test/extended/imageapis/quota_admission.go
Original file line number Diff line number Diff line change
Expand Up @@ -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())
Expand All @@ -39,65 +38,53 @@ 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())
used, err = waitForResourceQuotaSync(oc, quotaName, used)
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)
Expand All @@ -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())
Expand Down Expand Up @@ -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"))
}
Loading

0 comments on commit b10baa6

Please sign in to comment.