Skip to content

Commit 7ef3ba3

Browse files
author
Oleg Bulatov
committed
Make registry extended tests dockerless
1 parent 45c74af commit 7ef3ba3

File tree

2 files changed

+139
-65
lines changed

2 files changed

+139
-65
lines changed

test/extended/imageapis/limitrange_admission.go

+18-53
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,16 @@ import (
1616
quotautil "github.com/openshift/origin/pkg/quota/util"
1717
imagesutil "github.com/openshift/origin/test/extended/images"
1818
exutil "github.com/openshift/origin/test/extended/util"
19-
testutil "github.com/openshift/origin/test/util"
2019
)
2120

2221
const limitRangeName = "limits"
2322

24-
var _ = g.Describe("[Feature:ImageQuota][registry][Serial][Suite:openshift/registry/serial][local] Image limit range", func() {
23+
var _ = g.Describe("[Feature:ImageQuota][registry][Serial][Suite:openshift/registry/serial] Image limit range", func() {
2524
defer g.GinkgoRecover()
25+
2626
var oc = exutil.NewCLI("limitrange-admission", exutil.KubeConfigPath())
2727

28-
g.JustBeforeEach(func() {
28+
g.BeforeEach(func() {
2929
g.By("waiting for default service account")
3030
err := exutil.WaitForServiceAccount(oc.KubeClient().Core().ServiceAccounts(oc.Namespace()), "default")
3131
o.Expect(err).NotTo(o.HaveOccurred())
@@ -34,102 +34,77 @@ var _ = g.Describe("[Feature:ImageQuota][registry][Serial][Suite:openshift/regis
3434
o.Expect(err).NotTo(o.HaveOccurred())
3535
})
3636

37-
// needs to be run at the of of each It; cannot be run in AfterEach which is run after the project
38-
// is destroyed
39-
tearDown := func(oc *exutil.CLI) {
40-
g.By(fmt.Sprintf("Deleting limit range %s", limitRangeName))
41-
oc.AdminKubeClient().Core().LimitRanges(oc.Namespace()).Delete(limitRangeName, nil)
42-
43-
deleteTestImagesAndStreams(oc)
44-
}
45-
46-
g.It(fmt.Sprintf("[Skipped] should deny a push of built image exceeding %s limit", imageapi.LimitTypeImage), func() {
47-
g.Skip("FIXME: fill image metadata for schema1 in the registry")
48-
49-
defer tearDown(oc)
50-
51-
dClient, err := testutil.NewDockerClient()
52-
o.Expect(err).NotTo(o.HaveOccurred())
53-
54-
_, err = createLimitRangeOfType(oc, imageapi.LimitTypeImage, kapi.ResourceList{
37+
g.It(fmt.Sprintf("should deny a push of built image exceeding %s limit", imageapi.LimitTypeImage), func() {
38+
_, err := createLimitRangeOfType(oc, imageapi.LimitTypeImage, kapi.ResourceList{
5539
kapi.ResourceStorage: resource.MustParse("10Ki"),
5640
})
5741
o.Expect(err).NotTo(o.HaveOccurred())
5842

5943
g.By(fmt.Sprintf("trying to push an image exceeding size limit with just 1 layer"))
60-
err = imagesutil.BuildAndPushImageOfSizeWithBuilder(oc, dClient, oc.Namespace(), "sized", "middle", 16000, 1, false)
44+
err = imagesutil.BuildAndPushImageOfSizeWithBuilder(oc, nil, oc.Namespace(), "sized", "middle", 16000, 1, false)
6145
o.Expect(err).NotTo(o.HaveOccurred())
6246

6347
g.By(fmt.Sprintf("trying to push an image exceeding size limit in total"))
64-
err = imagesutil.BuildAndPushImageOfSizeWithBuilder(oc, dClient, oc.Namespace(), "sized", "middle", 16000, 5, false)
48+
err = imagesutil.BuildAndPushImageOfSizeWithBuilder(oc, nil, oc.Namespace(), "sized", "middle", 16000, 5, false)
6549
o.Expect(err).NotTo(o.HaveOccurred())
6650

6751
g.By(fmt.Sprintf("trying to push an image with one big layer below size limit"))
68-
err = imagesutil.BuildAndPushImageOfSizeWithBuilder(oc, dClient, oc.Namespace(), "sized", "small", 8000, 1, true)
52+
err = imagesutil.BuildAndPushImageOfSizeWithBuilder(oc, nil, oc.Namespace(), "sized", "small", 8000, 1, true)
6953
o.Expect(err).NotTo(o.HaveOccurred())
7054

7155
g.By(fmt.Sprintf("trying to push an image below size limit"))
72-
err = imagesutil.BuildAndPushImageOfSizeWithBuilder(oc, dClient, oc.Namespace(), "sized", "small", 8000, 2, true)
56+
err = imagesutil.BuildAndPushImageOfSizeWithBuilder(oc, nil, oc.Namespace(), "sized", "small", 8000, 2, true)
7357
o.Expect(err).NotTo(o.HaveOccurred())
7458
})
7559

7660
g.It(fmt.Sprintf("should deny a push of built image exceeding limit on %s resource", imageapi.ResourceImageStreamImages), func() {
77-
78-
defer tearDown(oc)
79-
8061
limits := kapi.ResourceList{
8162
imageapi.ResourceImageStreamTags: resource.MustParse("0"),
8263
imageapi.ResourceImageStreamImages: resource.MustParse("0"),
8364
}
8465
_, err := createLimitRangeOfType(oc, imageapi.LimitTypeImageStream, limits)
8566
o.Expect(err).NotTo(o.HaveOccurred())
8667

87-
dClient, err := testutil.NewDockerClient()
88-
o.Expect(err).NotTo(o.HaveOccurred())
89-
9068
g.By(fmt.Sprintf("trying to push image exceeding limits %v", limits))
91-
err = imagesutil.BuildAndPushImageOfSizeWithBuilder(oc, dClient, oc.Namespace(), "sized", "refused", imageSize, 1, false)
69+
err = imagesutil.BuildAndPushImageOfSizeWithBuilder(oc, nil, oc.Namespace(), "sized", "refused", imageSize, 1, false)
9270
o.Expect(err).NotTo(o.HaveOccurred())
9371

9472
limits, err = bumpLimit(oc, imageapi.ResourceImageStreamImages, "1")
9573
o.Expect(err).NotTo(o.HaveOccurred())
9674

9775
g.By(fmt.Sprintf("trying to push image below limits %v", limits))
98-
err = imagesutil.BuildAndPushImageOfSizeWithBuilder(oc, dClient, oc.Namespace(), "sized", "first", imageSize, 2, true)
76+
err = imagesutil.BuildAndPushImageOfSizeWithBuilder(oc, nil, oc.Namespace(), "sized", "first", imageSize, 2, true)
9977
o.Expect(err).NotTo(o.HaveOccurred())
10078

10179
g.By(fmt.Sprintf("trying to push image exceeding limits %v", limits))
102-
err = imagesutil.BuildAndPushImageOfSizeWithBuilder(oc, dClient, oc.Namespace(), "sized", "second", imageSize, 2, false)
80+
err = imagesutil.BuildAndPushImageOfSizeWithBuilder(oc, nil, oc.Namespace(), "sized", "second", imageSize, 2, false)
10381
o.Expect(err).NotTo(o.HaveOccurred())
10482

10583
g.By(fmt.Sprintf("trying to push image below limits %v to another image stream", limits))
106-
err = imagesutil.BuildAndPushImageOfSizeWithBuilder(oc, dClient, oc.Namespace(), "another", "second", imageSize, 1, true)
84+
err = imagesutil.BuildAndPushImageOfSizeWithBuilder(oc, nil, oc.Namespace(), "another", "second", imageSize, 1, true)
10785
o.Expect(err).NotTo(o.HaveOccurred())
10886

10987
limits, err = bumpLimit(oc, imageapi.ResourceImageStreamImages, "2")
11088
o.Expect(err).NotTo(o.HaveOccurred())
11189

11290
g.By(fmt.Sprintf("trying to push image below limits %v", limits))
113-
err = imagesutil.BuildAndPushImageOfSizeWithBuilder(oc, dClient, oc.Namespace(), "another", "third", imageSize, 1, true)
91+
err = imagesutil.BuildAndPushImageOfSizeWithBuilder(oc, nil, oc.Namespace(), "another", "third", imageSize, 1, true)
11492
o.Expect(err).NotTo(o.HaveOccurred())
11593

11694
g.By(fmt.Sprintf("trying to push image exceeding limits %v", limits))
117-
err = imagesutil.BuildAndPushImageOfSizeWithBuilder(oc, dClient, oc.Namespace(), "another", "fourth", imageSize, 1, false)
95+
err = imagesutil.BuildAndPushImageOfSizeWithBuilder(oc, nil, oc.Namespace(), "another", "fourth", imageSize, 1, false)
11896
o.Expect(err).NotTo(o.HaveOccurred())
11997

12098
g.By(`removing tag "second" from "another" image stream`)
12199
err = oc.ImageClient().Image().ImageStreamTags(oc.Namespace()).Delete("another:second", nil)
122100
o.Expect(err).NotTo(o.HaveOccurred())
123101

124102
g.By(fmt.Sprintf("trying to push image below limits %v", limits))
125-
err = imagesutil.BuildAndPushImageOfSizeWithBuilder(oc, dClient, oc.Namespace(), "another", "replenish", imageSize, 1, true)
103+
err = imagesutil.BuildAndPushImageOfSizeWithBuilder(oc, nil, oc.Namespace(), "another", "replenish", imageSize, 1, true)
126104
o.Expect(err).NotTo(o.HaveOccurred())
127105
})
128106

129107
g.It(fmt.Sprintf("should deny a docker image reference exceeding limit on %s resource", imageapi.ResourceImageStreamTags), func() {
130-
131-
defer tearDown(oc)
132-
133108
tag2Image, err := buildAndPushTestImagesTo(oc, "src", "tag", 2)
134109
o.Expect(err).NotTo(o.HaveOccurred())
135110

@@ -187,15 +162,12 @@ var _ = g.Describe("[Feature:ImageQuota][registry][Serial][Suite:openshift/regis
187162
})
188163

189164
g.It(fmt.Sprintf("should deny an import of a repository exceeding limit on %s resource", imageapi.ResourceImageStreamTags), func() {
190-
191165
maxBulkImport, err := getMaxImagesBulkImportedPerRepository()
192166
if err != nil {
193167
g.Skip(err.Error())
194168
return
195169
}
196170

197-
defer tearDown(oc)
198-
199171
s1tag2Image, err := buildAndPushTestImagesTo(oc, "src1st", "tag", maxBulkImport+1)
200172
s2tag2Image, err := buildAndPushTestImagesTo(oc, "src2nd", "t", 2)
201173
o.Expect(err).NotTo(o.HaveOccurred())
@@ -234,25 +206,18 @@ var _ = g.Describe("[Feature:ImageQuota][registry][Serial][Suite:openshift/regis
234206
// buildAndPushTestImagesTo builds a given number of test images. The images are pushed to a new image stream
235207
// of given name under <tagPrefix><X> where X is a number of image starting from 1.
236208
func buildAndPushTestImagesTo(oc *exutil.CLI, isName string, tagPrefix string, numberOfImages int) (tag2Image map[string]imageapi.Image, err error) {
237-
dClient, err := testutil.NewDockerClient()
238-
if err != nil {
239-
return
240-
}
241209
tag2Image = make(map[string]imageapi.Image)
242210

243211
for i := 1; i <= numberOfImages; i++ {
244212
tag := fmt.Sprintf("%s%d", tagPrefix, i)
245-
dgst, _, err := imagesutil.BuildAndPushImageOfSizeWithDocker(oc, dClient, isName, tag, imageSize, 2, g.GinkgoWriter, true, true)
213+
err = imagesutil.BuildAndPushImageOfSizeWithBuilder(oc, nil, oc.Namespace(), isName, tag, imageSize, 2, true)
246214
if err != nil {
247215
return nil, err
248216
}
249217
ist, err := oc.ImageClient().Image().ImageStreamTags(oc.Namespace()).Get(isName+":"+tag, metav1.GetOptions{})
250218
if err != nil {
251219
return nil, err
252220
}
253-
if dgst != ist.Image.Name {
254-
return nil, fmt.Errorf("digest of built image does not match stored: %s != %s", dgst, ist.Image.Name)
255-
}
256221
tag2Image[tag] = ist.Image
257222
}
258223

@@ -316,7 +281,7 @@ func bumpLimit(oc *exutil.CLI, resourceName kapi.ResourceName, limit string) (ka
316281
func getMaxImagesBulkImportedPerRepository() (int, error) {
317282
max := os.Getenv("MAX_IMAGES_BULK_IMPORTED_PER_REPOSITORY")
318283
if len(max) == 0 {
319-
return 0, fmt.Errorf("MAX_IMAGES_BULK_IMAGES_IMPORTED_PER_REPOSITORY is not set")
284+
return 0, fmt.Errorf("MAX_IMAGES_BULK_IMPORTED_PER_REPOSITORY is not set")
320285
}
321286
return strconv.Atoi(max)
322287
}

test/extended/images/helper.go

+121-12
Original file line numberDiff line numberDiff line change
@@ -2,40 +2,45 @@ package images
22

33
import (
44
"bytes"
5+
"context"
56
cryptorand "crypto/rand"
67
"crypto/tls"
78
"fmt"
89
"io"
910
"io/ioutil"
1011
"net/http"
12+
"net/url"
1113
"os"
1214
"path"
1315
"regexp"
1416
"strconv"
1517
"strings"
1618
"time"
1719

20+
distribution "github.com/docker/distribution"
21+
"github.com/docker/distribution/manifest/schema2"
1822
dockerclient "github.com/fsouza/go-dockerclient"
1923
g "github.com/onsi/ginkgo"
20-
2124
godigest "github.com/opencontainers/go-digest"
2225

2326
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2427
kerrors "k8s.io/apimachinery/pkg/util/errors"
2528
knet "k8s.io/apimachinery/pkg/util/net"
2629
"k8s.io/apimachinery/pkg/util/sets"
2730
"k8s.io/apimachinery/pkg/util/wait"
31+
"k8s.io/client-go/rest"
2832
"k8s.io/client-go/util/retry"
33+
e2e "k8s.io/kubernetes/test/e2e/framework"
2934

3035
imageapi "github.com/openshift/origin/pkg/image/apis/image"
3136
imagetypedclientset "github.com/openshift/origin/pkg/image/generated/internalclientset/typed/image/internalversion"
37+
"github.com/openshift/origin/pkg/image/registryclient"
3238
exutil "github.com/openshift/origin/test/extended/util"
3339
testutil "github.com/openshift/origin/test/util"
3440
)
3541

3642
const (
3743
// There are coefficients used to multiply layer data size to get a rough size of uploaded blob.
38-
layerSizeMultiplierForDocker18 = 2.0
3944
layerSizeMultiplierForLatestDocker = 0.8
4045
defaultLayerSize = 1024
4146
digestSHA256GzippedEmptyTar = godigest.Digest("sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4")
@@ -214,8 +219,10 @@ func BuildAndPushImageOfSizeWithBuilder(
214219
}
215220
buildLog, logsErr := br.Logs()
216221

217-
if match := reSuccessfulBuild.FindStringSubmatch(buildLog); len(match) > 1 {
218-
defer dClient.RemoveImageExtended(match[1], dockerclient.RemoveImageOptions{Force: true})
222+
if dClient != nil {
223+
if match := reSuccessfulBuild.FindStringSubmatch(buildLog); len(match) > 1 {
224+
defer dClient.RemoveImageExtended(match[1], dockerclient.RemoveImageOptions{Force: true})
225+
}
219226
}
220227

221228
if !shouldSucceed {
@@ -431,26 +438,35 @@ func pushImageWithDocker(
431438
return imageDigest, nil
432439
}
433440

441+
func newRandomBlob(size uint64) ([]byte, error) {
442+
var letters = []byte("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
443+
444+
data := make([]byte, size)
445+
if _, err := cryptorand.Read(data); err != nil {
446+
return nil, err
447+
}
448+
449+
for i := range data {
450+
data[i] = letters[uint(data[i])%uint(len(letters))]
451+
}
452+
453+
return data, nil
454+
}
455+
434456
// createRandomBlob creates a random data with bytes from `letters` in order to let docker take advantage of
435457
// compression. Resulting layer size will be different due to file metadata overhead and compression.
436458
func createRandomBlob(dest string, size uint64) error {
437-
var letters = []byte("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
438-
439459
f, err := os.Create(dest)
440460
if err != nil {
441461
return err
442462
}
443463
defer f.Close()
444464

445-
data := make([]byte, size)
446-
if _, err = cryptorand.Read(data); err != nil {
465+
data, err := newRandomBlob(size)
466+
if err != nil {
447467
return err
448468
}
449469

450-
for i := range data {
451-
data[i] = letters[uint(data[i])%uint(len(letters))]
452-
}
453-
454470
f.Write(data)
455471
return nil
456472
}
@@ -815,3 +831,96 @@ func (c *CleanUpContainer) Run() {
815831
}
816832
}
817833
}
834+
835+
func uploadBlob(ctx context.Context, repo distribution.Repository, blob []byte) (distribution.Descriptor, error) {
836+
bs := repo.Blobs(ctx)
837+
fmt.Fprintf(g.GinkgoWriter, "uploading blob (%d bytes)...\n", len(blob))
838+
return bs.Put(ctx, "", blob)
839+
}
840+
841+
func uploadManifest(ctx context.Context, repo distribution.Repository, tag string, config distribution.Descriptor, layers []distribution.Descriptor) (godigest.Digest, error) {
842+
ms, err := repo.Manifests(ctx)
843+
if err != nil {
844+
return "", err
845+
}
846+
manifest, err := schema2.FromStruct(schema2.Manifest{
847+
Versioned: schema2.SchemaVersion,
848+
Config: config,
849+
Layers: layers,
850+
})
851+
if err != nil {
852+
return "", err
853+
}
854+
fmt.Fprintf(g.GinkgoWriter, "uploading manifest...\n")
855+
return ms.Put(ctx, manifest, distribution.WithTag(tag))
856+
}
857+
858+
// BuildAndPushMockImage tries to build a fake image of wanted size and number
859+
// of layers. Built image is stored as an image stream tag <name>:<tag>. If
860+
// shouldSucceed is false, a push is expected to fail with a denied error.
861+
// Returned is an image digest, and an error if any.
862+
func BuildAndPushMockImage(
863+
oc *exutil.CLI,
864+
name, tag string,
865+
size uint64,
866+
numberOfLayers int,
867+
) (godigest.Digest, error) {
868+
e2e.Logf("Uploading mock image to %s:%s (~%d bytes, %d layers)...", name, tag, size, numberOfLayers)
869+
870+
layerSize := (size + uint64(numberOfLayers) - 1) / uint64(numberOfLayers) // round up
871+
872+
rt, err := rest.TransportFor(&rest.Config{})
873+
if err != nil {
874+
return "", err
875+
}
876+
insecureRT, err := rest.TransportFor(&rest.Config{TLSClientConfig: rest.TLSClientConfig{Insecure: true}})
877+
if err != nil {
878+
return "", err
879+
}
880+
881+
registryHost, err := GetDockerRegistryURL(oc)
882+
if err != nil {
883+
return "", err
884+
}
885+
registryURL, err := url.Parse(fmt.Sprintf("http://%s/", registryHost))
886+
if err != nil {
887+
return "", err
888+
}
889+
890+
out, err := oc.Run("whoami").Args("-t").Output()
891+
if err != nil {
892+
return "", err
893+
}
894+
token := strings.TrimSpace(out)
895+
896+
creds := registryclient.NewBasicCredentials()
897+
creds.Add(&url.URL{Host: registryHost}, "unused", token)
898+
registryContext := registryclient.NewContext(rt, insecureRT).WithCredentials(creds)
899+
900+
ctx := context.Background()
901+
insecure := true
902+
repo, err := registryContext.Repository(ctx, registryURL, name, insecure)
903+
if err != nil {
904+
return "", err
905+
}
906+
907+
configDesc, err := uploadBlob(ctx, repo, []byte("{}"))
908+
if err != nil {
909+
return "", fmt.Errorf("unable to upload dummy config: %v", err)
910+
}
911+
912+
var layers []distribution.Descriptor
913+
for i := 0; i < numberOfLayers; i++ {
914+
blob, err := newRandomBlob(layerSize)
915+
if err != nil {
916+
return "", err
917+
}
918+
desc, err := uploadBlob(ctx, repo, blob)
919+
if err != nil {
920+
return "", fmt.Errorf("unable to upload random blob: %v", err)
921+
}
922+
layers = append(layers, desc)
923+
}
924+
925+
return uploadManifest(ctx, repo, tag, configDesc, layers)
926+
}

0 commit comments

Comments
 (0)