Skip to content
118 changes: 87 additions & 31 deletions test/extended/quota/resourcequota.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ package quota
import (
"context"
"fmt"
"sort"
"time"

g "github.com/onsi/ginkgo/v2"
o "github.com/onsi/gomega"

imagev1 "github.com/openshift/api/image/v1"
"github.com/openshift/library-go/pkg/image/imageutil"
exutil "github.com/openshift/origin/test/extended/util"

corev1 "k8s.io/api/core/v1"
Expand Down Expand Up @@ -217,8 +219,8 @@ var _ = g.Describe("[sig-api-machinery][Feature:ResourceQuota]", func() {
o.Expect(err).NotTo(o.HaveOccurred())
})

g.It("when exceed openshift.io/image-tags will ban to create new image references in the project [Skipped:Disconnected]", func() {
testProject := oc.Namespace()
g.It("when exceed openshift.io/image-tags will ban to create new image references in the project", func() {
testProject := oc.SetupProject()
testResourceQuotaName := "my-image-tag-quota"
clusterAdminKubeClient := oc.AdminKubeClient()

Expand Down Expand Up @@ -257,44 +259,98 @@ var _ = g.Describe("[sig-api-machinery][Feature:ResourceQuota]", func() {
})
o.Expect(err).NotTo(o.HaveOccurred())

images := []struct {
Image string
Tag string
}{
{
Image: "quay.io/openshifttest/hello-openshift@sha256:4200f438cf2e9446f6bcff9d67ceea1f69ed07a2f83363b7fb52529f7ddd8a83",
Tag: "v1",
},
{
Image: "quay.io/openshifttest/base-alpine@sha256:3126e4eed4a3ebd8bf972b2453fa838200988ee07c01b2251e3ea47e4b1f245c",
Tag: "v2",
},
{
Image: "openshift/hello-openshift",
Tag: "v3",
},
sourceISTags, ok := pickOpenshiftSourceISTagsForTagQuota(oc)
if !ok {
g.Skip("need three openshift ImageStreams with at least one resolved tag each for oc tag --source=istag; skipping image-tag quota enforcement check")
}

for _, u := range images {
g.By("trying to tag a container image with " + u.Tag)
err = oc.Run("tag").Args(u.Image, "--source=docker", "mystream:"+u.Tag, "-n", testProject).Execute()
if u.Tag != "v3" {
o.Expect(err).NotTo(o.HaveOccurred())
err = exutil.WaitForAnImageStreamTag(oc, testProject, "mystream", u.Tag)
o.Expect(err).NotTo(o.HaveOccurred())
} else {
o.Expect(err).To(o.HaveOccurred())
o.Expect(err.Error()).To(o.MatchRegexp(`.*forbidden.*[Ee]xceed`))
}
tags := []string{"v1", "v2", "v3"}
for i := range 2 {
g.By("trying to tag a container image with " + tags[i] + " from " + sourceISTags[i])
err = oc.Run("tag").Args(sourceISTags[i], "--source=istag", "mystream:"+tags[i], "-n", testProject).Execute()
o.Expect(err).NotTo(o.HaveOccurred())
err = exutil.WaitForAnImageStreamTag(oc, testProject, "mystream", tags[i])
o.Expect(err).NotTo(o.HaveOccurred())
}

g.By("waiting until mystream records both tags so limit enforcement sees tag count before v3")
err = waitForImageStreamStatusTagsPopulated(oc, testProject, "mystream", tags[:2])
o.Expect(err).NotTo(o.HaveOccurred())

g.By("trying to tag a container image with v3 from " + sourceISTags[2])
err = oc.Run("tag").Args(sourceISTags[2], "--source=istag", "mystream:v3", "-n", testProject).Execute()
o.Expect(err).To(o.HaveOccurred())
o.Expect(err.Error()).To(o.MatchRegexp(`.*forbidden.*[Ee]xceed`))
})
})
})

func pickOpenshiftSourceISTagsForTagQuota(oc *exutil.CLI) ([]string, bool) {
const ns = "openshift"
list, err := oc.AdminImageClient().ImageV1().ImageStreams(ns).List(context.Background(), metav1.ListOptions{})
if err != nil {
return nil, false
}
sort.Slice(list.Items, func(i, j int) bool { return list.Items[i].Name < list.Items[j].Name })

var refs []string
for i := range list.Items {
is := &list.Items[i]
if len(is.Spec.Tags) == 0 {
continue
}
names := make([]string, len(is.Spec.Tags))
for j := range is.Spec.Tags {
names[j] = is.Spec.Tags[j].Name
}
sort.Slice(names, func(i, j int) bool {
a, b := names[i], names[j]
aLatest, bLatest := a == imagev1.DefaultImageTag, b == imagev1.DefaultImageTag
if aLatest != bLatest {
return aLatest
}
return a < b
})
tag := ""
for _, n := range names {
ev, ok := imageutil.StatusHasTag(is, n)
if ok && len(ev.Items) > 0 {
tag = n
break
}
}
if tag == "" {
continue
}
refs = append(refs, fmt.Sprintf("%s/%s:%s", ns, is.Name, tag))
if len(refs) == 3 {
return refs, true
}
}
return nil, false
}

func waitForImageStreamStatusTagsPopulated(oc *exutil.CLI, namespace, name string, tags []string) error {
streams := oc.AdminImageClient().ImageV1().ImageStreams(namespace)
return utilwait.PollImmediate(200*time.Millisecond, 2*time.Minute, func() (bool, error) {
Comment thread
YamunadeviShanmugam marked this conversation as resolved.
is, err := streams.Get(context.Background(), name, metav1.GetOptions{})
if err != nil {
return false, nil
}
for _, t := range tags {
st, ok := imageutil.StatusHasTag(is, t)
if !ok || len(st.Items) == 0 {
return false, nil
}
}
return true, nil
})
}

func waitForResourceQuotaStatus(clusterAdminKubeClient kubernetes.Interface, name string, namespace string, conditionFn func(*corev1.ResourceQuota) error) error {
var pollErr error
err := utilwait.PollImmediate(100*time.Millisecond, QuotaWaitTimeout, func() (done bool, err error) {
quota, err := clusterAdminKubeClient.CoreV1().ResourceQuotas(namespace).Get(context.Background(), name, metav1.GetOptions{})
err := utilwait.PollUntilContextTimeout(context.Background(), 100*time.Millisecond, QuotaWaitTimeout, true, func(ctx context.Context) (done bool, err error) {
quota, err := clusterAdminKubeClient.CoreV1().ResourceQuotas(namespace).Get(ctx, name, metav1.GetOptions{})
if err != nil {
pollErr = err
return false, nil
Expand Down