forked from TrueCloudLab/distribution
Add API unit testing for schema2 manifest
Signed-off-by: Aaron Lehmann <aaron.lehmann@docker.com>
This commit is contained in:
parent
f14c6a4814
commit
66a33baa36
2 changed files with 383 additions and 44 deletions
|
@ -18,11 +18,13 @@ import (
|
|||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/distribution"
|
||||
"github.com/docker/distribution/configuration"
|
||||
"github.com/docker/distribution/context"
|
||||
"github.com/docker/distribution/digest"
|
||||
"github.com/docker/distribution/manifest"
|
||||
"github.com/docker/distribution/manifest/schema1"
|
||||
"github.com/docker/distribution/manifest/schema2"
|
||||
"github.com/docker/distribution/registry/api/errcode"
|
||||
"github.com/docker/distribution/registry/api/v2"
|
||||
_ "github.com/docker/distribution/registry/storage/driver/inmemory"
|
||||
|
@ -690,48 +692,40 @@ func httpDelete(url string) (*http.Response, error) {
|
|||
}
|
||||
|
||||
type manifestArgs struct {
|
||||
imageName string
|
||||
signedManifest *schema1.SignedManifest
|
||||
dgst digest.Digest
|
||||
}
|
||||
|
||||
func makeManifestArgs(t *testing.T) manifestArgs {
|
||||
args := manifestArgs{
|
||||
imageName: "foo/bar",
|
||||
}
|
||||
|
||||
return args
|
||||
imageName string
|
||||
mediaType string
|
||||
manifest distribution.Manifest
|
||||
dgst digest.Digest
|
||||
}
|
||||
|
||||
func TestManifestAPI(t *testing.T) {
|
||||
deleteEnabled := false
|
||||
env := newTestEnv(t, deleteEnabled)
|
||||
args := makeManifestArgs(t)
|
||||
testManifestAPI(t, env, args)
|
||||
testManifestAPISchema1(t, env, "foo/schema1")
|
||||
testManifestAPISchema2(t, env, "foo/schema2")
|
||||
|
||||
deleteEnabled = true
|
||||
env = newTestEnv(t, deleteEnabled)
|
||||
args = makeManifestArgs(t)
|
||||
testManifestAPI(t, env, args)
|
||||
testManifestAPISchema1(t, env, "foo/schema1")
|
||||
testManifestAPISchema2(t, env, "foo/schema2")
|
||||
}
|
||||
|
||||
func TestManifestDelete(t *testing.T) {
|
||||
deleteEnabled := true
|
||||
env := newTestEnv(t, deleteEnabled)
|
||||
args := makeManifestArgs(t)
|
||||
env, args = testManifestAPI(t, env, args)
|
||||
testManifestDelete(t, env, args)
|
||||
schema1Args := testManifestAPISchema1(t, env, "foo/schema1")
|
||||
testManifestDelete(t, env, schema1Args)
|
||||
schema2Args := testManifestAPISchema2(t, env, "foo/schema2")
|
||||
testManifestDelete(t, env, schema2Args)
|
||||
}
|
||||
|
||||
func TestManifestDeleteDisabled(t *testing.T) {
|
||||
deleteEnabled := false
|
||||
env := newTestEnv(t, deleteEnabled)
|
||||
args := makeManifestArgs(t)
|
||||
testManifestDeleteDisabled(t, env, args)
|
||||
testManifestDeleteDisabled(t, env, "foo/schema1")
|
||||
}
|
||||
|
||||
func testManifestDeleteDisabled(t *testing.T, env *testEnv, args manifestArgs) *testEnv {
|
||||
imageName := args.imageName
|
||||
func testManifestDeleteDisabled(t *testing.T, env *testEnv, imageName string) {
|
||||
manifestURL, err := env.builder.BuildManifestURL(imageName, digest.DigestSha256EmptyTar)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error getting manifest url: %v", err)
|
||||
|
@ -744,12 +738,11 @@ func testManifestDeleteDisabled(t *testing.T, env *testEnv, args manifestArgs) *
|
|||
defer resp.Body.Close()
|
||||
|
||||
checkResponse(t, "status of disabled delete of manifest", resp, http.StatusMethodNotAllowed)
|
||||
return nil
|
||||
}
|
||||
|
||||
func testManifestAPI(t *testing.T, env *testEnv, args manifestArgs) (*testEnv, manifestArgs) {
|
||||
imageName := args.imageName
|
||||
func testManifestAPISchema1(t *testing.T, env *testEnv, imageName string) manifestArgs {
|
||||
tag := "thetag"
|
||||
args := manifestArgs{imageName: imageName}
|
||||
|
||||
manifestURL, err := env.builder.BuildManifestURL(imageName, tag)
|
||||
if err != nil {
|
||||
|
@ -808,10 +801,10 @@ func testManifestAPI(t *testing.T, env *testEnv, args manifestArgs) (*testEnv, m
|
|||
},
|
||||
}
|
||||
|
||||
resp = putManifest(t, "putting unsigned manifest", manifestURL, unsignedManifest)
|
||||
resp = putManifest(t, "putting unsigned manifest", manifestURL, "", unsignedManifest)
|
||||
defer resp.Body.Close()
|
||||
checkResponse(t, "putting unsigned manifest", resp, http.StatusBadRequest)
|
||||
_, p, counts := checkBodyHasErrorCodes(t, "getting unknown manifest tags", resp, v2.ErrorCodeManifestInvalid)
|
||||
_, p, counts := checkBodyHasErrorCodes(t, "putting unsigned manifest", resp, v2.ErrorCodeManifestInvalid)
|
||||
|
||||
expectedCounts := map[errcode.ErrorCode]int{
|
||||
v2.ErrorCodeManifestInvalid: 1,
|
||||
|
@ -827,7 +820,7 @@ func testManifestAPI(t *testing.T, env *testEnv, args manifestArgs) (*testEnv, m
|
|||
t.Fatalf("error signing manifest: %v", err)
|
||||
}
|
||||
|
||||
resp = putManifest(t, "putting signed manifest with errors", manifestURL, sm)
|
||||
resp = putManifest(t, "putting signed manifest with errors", manifestURL, "", sm)
|
||||
defer resp.Body.Close()
|
||||
checkResponse(t, "putting signed manifest with errors", resp, http.StatusBadRequest)
|
||||
_, p, counts = checkBodyHasErrorCodes(t, "putting signed manifest with errors", resp,
|
||||
|
@ -872,13 +865,13 @@ func testManifestAPI(t *testing.T, env *testEnv, args manifestArgs) (*testEnv, m
|
|||
}
|
||||
|
||||
dgst := digest.FromBytes(signedManifest.Canonical)
|
||||
args.signedManifest = signedManifest
|
||||
args.manifest = signedManifest
|
||||
args.dgst = dgst
|
||||
|
||||
manifestDigestURL, err := env.builder.BuildManifestURL(imageName, dgst.String())
|
||||
checkErr(t, err, "building manifest url")
|
||||
|
||||
resp = putManifest(t, "putting signed manifest no error", manifestURL, signedManifest)
|
||||
resp = putManifest(t, "putting signed manifest no error", manifestURL, "", signedManifest)
|
||||
checkResponse(t, "putting signed manifest no error", resp, http.StatusCreated)
|
||||
checkHeaders(t, resp, http.Header{
|
||||
"Location": []string{manifestDigestURL},
|
||||
|
@ -887,7 +880,7 @@ func testManifestAPI(t *testing.T, env *testEnv, args manifestArgs) (*testEnv, m
|
|||
|
||||
// --------------------
|
||||
// Push by digest -- should get same result
|
||||
resp = putManifest(t, "putting signed manifest", manifestDigestURL, signedManifest)
|
||||
resp = putManifest(t, "putting signed manifest", manifestDigestURL, "", signedManifest)
|
||||
checkResponse(t, "putting signed manifest", resp, http.StatusCreated)
|
||||
checkHeaders(t, resp, http.Header{
|
||||
"Location": []string{manifestDigestURL},
|
||||
|
@ -958,7 +951,7 @@ func testManifestAPI(t *testing.T, env *testEnv, args manifestArgs) (*testEnv, m
|
|||
|
||||
}
|
||||
|
||||
resp = putManifest(t, "re-putting signed manifest", manifestDigestURL, sm2)
|
||||
resp = putManifest(t, "re-putting signed manifest", manifestDigestURL, "", sm2)
|
||||
checkResponse(t, "re-putting signed manifest", resp, http.StatusCreated)
|
||||
|
||||
resp, err = http.Get(manifestDigestURL)
|
||||
|
@ -1020,8 +1013,7 @@ func testManifestAPI(t *testing.T, env *testEnv, args manifestArgs) (*testEnv, m
|
|||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// Check that we get an unknown repository error when asking for tags
|
||||
checkResponse(t, "getting unknown manifest tags", resp, http.StatusOK)
|
||||
checkResponse(t, "getting tags", resp, http.StatusOK)
|
||||
dec = json.NewDecoder(resp.Body)
|
||||
|
||||
var tagsResponse tagsAPIResponse
|
||||
|
@ -1052,16 +1044,359 @@ func testManifestAPI(t *testing.T, env *testEnv, args manifestArgs) (*testEnv, m
|
|||
t.Fatalf("error signing manifest")
|
||||
}
|
||||
|
||||
resp = putManifest(t, "putting invalid signed manifest", manifestDigestURL, invalidSigned)
|
||||
resp = putManifest(t, "putting invalid signed manifest", manifestDigestURL, "", invalidSigned)
|
||||
checkResponse(t, "putting invalid signed manifest", resp, http.StatusBadRequest)
|
||||
|
||||
return env, args
|
||||
return args
|
||||
}
|
||||
|
||||
func testManifestAPISchema2(t *testing.T, env *testEnv, imageName string) manifestArgs {
|
||||
tag := "schema2tag"
|
||||
args := manifestArgs{
|
||||
imageName: imageName,
|
||||
mediaType: schema2.MediaTypeManifest,
|
||||
}
|
||||
|
||||
manifestURL, err := env.builder.BuildManifestURL(imageName, tag)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error getting manifest url: %v", err)
|
||||
}
|
||||
|
||||
// -----------------------------
|
||||
// Attempt to fetch the manifest
|
||||
resp, err := http.Get(manifestURL)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error getting manifest: %v", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
checkResponse(t, "getting non-existent manifest", resp, http.StatusNotFound)
|
||||
checkBodyHasErrorCodes(t, "getting non-existent manifest", resp, v2.ErrorCodeManifestUnknown)
|
||||
|
||||
tagsURL, err := env.builder.BuildTagsURL(imageName)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error building tags url: %v", err)
|
||||
}
|
||||
|
||||
resp, err = http.Get(tagsURL)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error getting unknown tags: %v", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// Check that we get an unknown repository error when asking for tags
|
||||
checkResponse(t, "getting unknown manifest tags", resp, http.StatusNotFound)
|
||||
checkBodyHasErrorCodes(t, "getting unknown manifest tags", resp, v2.ErrorCodeNameUnknown)
|
||||
|
||||
// --------------------------------
|
||||
// Attempt to push manifest with missing config and missing layers
|
||||
manifest := &schema2.Manifest{
|
||||
Versioned: manifest.Versioned{
|
||||
SchemaVersion: 2,
|
||||
},
|
||||
MediaType: schema2.MediaTypeManifest,
|
||||
Config: distribution.Descriptor{
|
||||
Digest: "sha256:1a9ec845ee94c202b2d5da74a24f0ed2058318bfa9879fa541efaecba272e86b",
|
||||
Size: 3253,
|
||||
MediaType: schema2.MediaTypeConfig,
|
||||
},
|
||||
Layers: []distribution.Descriptor{
|
||||
{
|
||||
Digest: "sha256:463434349086340864309863409683460843608348608934092322395278926a",
|
||||
Size: 6323,
|
||||
MediaType: schema2.MediaTypeLayer,
|
||||
},
|
||||
{
|
||||
Digest: "sha256:630923423623623423352523525237238023652897356239852383652aaaaaaa",
|
||||
Size: 6863,
|
||||
MediaType: schema2.MediaTypeLayer,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
resp = putManifest(t, "putting missing config manifest", manifestURL, schema2.MediaTypeManifest, manifest)
|
||||
defer resp.Body.Close()
|
||||
checkResponse(t, "putting missing config manifest", resp, http.StatusBadRequest)
|
||||
_, p, counts := checkBodyHasErrorCodes(t, "putting missing config manifest", resp, v2.ErrorCodeManifestBlobUnknown)
|
||||
|
||||
expectedCounts := map[errcode.ErrorCode]int{
|
||||
v2.ErrorCodeManifestBlobUnknown: 3,
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(counts, expectedCounts) {
|
||||
t.Fatalf("unexpected number of error codes encountered: %v\n!=\n%v\n---\n%s", counts, expectedCounts, string(p))
|
||||
}
|
||||
|
||||
// Push a config, and reference it in the manifest
|
||||
sampleConfig := []byte(`{
|
||||
"architecture": "amd64",
|
||||
"history": [
|
||||
{
|
||||
"created": "2015-10-31T22:22:54.690851953Z",
|
||||
"created_by": "/bin/sh -c #(nop) ADD file:a3bc1e842b69636f9df5256c49c5374fb4eef1e281fe3f282c65fb853ee171c5 in /"
|
||||
},
|
||||
{
|
||||
"created": "2015-10-31T22:22:55.613815829Z",
|
||||
"created_by": "/bin/sh -c #(nop) CMD [\"sh\"]"
|
||||
}
|
||||
],
|
||||
"rootfs": {
|
||||
"diff_ids": [
|
||||
"sha256:c6f988f4874bb0add23a778f753c65efe992244e148a1d2ec2a8b664fb66bbd1",
|
||||
"sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef"
|
||||
],
|
||||
"type": "layers"
|
||||
}
|
||||
}`)
|
||||
sampleConfigDigest := digest.FromBytes(sampleConfig)
|
||||
|
||||
uploadURLBase, _ := startPushLayer(t, env.builder, imageName)
|
||||
pushLayer(t, env.builder, imageName, sampleConfigDigest, uploadURLBase, bytes.NewReader(sampleConfig))
|
||||
manifest.Config.Digest = sampleConfigDigest
|
||||
manifest.Config.Size = int64(len(sampleConfig))
|
||||
|
||||
// The manifest should still be invalid, because its layer doesnt exist
|
||||
resp = putManifest(t, "putting missing layer manifest", manifestURL, schema2.MediaTypeManifest, manifest)
|
||||
defer resp.Body.Close()
|
||||
checkResponse(t, "putting missing layer manifest", resp, http.StatusBadRequest)
|
||||
_, p, counts = checkBodyHasErrorCodes(t, "getting unknown manifest tags", resp, v2.ErrorCodeManifestBlobUnknown)
|
||||
|
||||
expectedCounts = map[errcode.ErrorCode]int{
|
||||
v2.ErrorCodeManifestBlobUnknown: 2,
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(counts, expectedCounts) {
|
||||
t.Fatalf("unexpected number of error codes encountered: %v\n!=\n%v\n---\n%s", counts, expectedCounts, string(p))
|
||||
}
|
||||
|
||||
// Push 2 random layers
|
||||
expectedLayers := make(map[digest.Digest]io.ReadSeeker)
|
||||
|
||||
for i := range manifest.Layers {
|
||||
rs, dgstStr, err := testutil.CreateRandomTarFile()
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("error creating random layer %d: %v", i, err)
|
||||
}
|
||||
dgst := digest.Digest(dgstStr)
|
||||
|
||||
expectedLayers[dgst] = rs
|
||||
manifest.Layers[i].Digest = dgst
|
||||
|
||||
uploadURLBase, _ := startPushLayer(t, env.builder, imageName)
|
||||
pushLayer(t, env.builder, imageName, dgst, uploadURLBase, rs)
|
||||
}
|
||||
|
||||
// -------------------
|
||||
// Push the manifest with all layers pushed.
|
||||
deserializedManifest, err := schema2.FromStruct(*manifest)
|
||||
if err != nil {
|
||||
t.Fatalf("could not create DeserializedManifest: %v", err)
|
||||
}
|
||||
_, canonical, err := deserializedManifest.Payload()
|
||||
if err != nil {
|
||||
t.Fatalf("could not get manifest payload: %v", err)
|
||||
}
|
||||
dgst := digest.FromBytes(canonical)
|
||||
args.dgst = dgst
|
||||
args.manifest = deserializedManifest
|
||||
|
||||
manifestDigestURL, err := env.builder.BuildManifestURL(imageName, dgst.String())
|
||||
checkErr(t, err, "building manifest url")
|
||||
|
||||
resp = putManifest(t, "putting manifest no error", manifestURL, schema2.MediaTypeManifest, manifest)
|
||||
checkResponse(t, "putting manifest no error", resp, http.StatusCreated)
|
||||
checkHeaders(t, resp, http.Header{
|
||||
"Location": []string{manifestDigestURL},
|
||||
"Docker-Content-Digest": []string{dgst.String()},
|
||||
})
|
||||
|
||||
// --------------------
|
||||
// Push by digest -- should get same result
|
||||
resp = putManifest(t, "putting manifest by digest", manifestDigestURL, schema2.MediaTypeManifest, manifest)
|
||||
checkResponse(t, "putting manifest by digest", resp, http.StatusCreated)
|
||||
checkHeaders(t, resp, http.Header{
|
||||
"Location": []string{manifestDigestURL},
|
||||
"Docker-Content-Digest": []string{dgst.String()},
|
||||
})
|
||||
|
||||
// ------------------
|
||||
// Fetch by tag name
|
||||
req, err := http.NewRequest("GET", manifestURL, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Error constructing request: %s", err)
|
||||
}
|
||||
req.Header.Set("Accept", schema2.MediaTypeManifest)
|
||||
resp, err = http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error fetching manifest: %v", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
checkResponse(t, "fetching uploaded manifest", resp, http.StatusOK)
|
||||
checkHeaders(t, resp, http.Header{
|
||||
"Docker-Content-Digest": []string{dgst.String()},
|
||||
"ETag": []string{fmt.Sprintf(`"%s"`, dgst)},
|
||||
})
|
||||
|
||||
var fetchedManifest schema2.DeserializedManifest
|
||||
dec := json.NewDecoder(resp.Body)
|
||||
|
||||
if err := dec.Decode(&fetchedManifest); err != nil {
|
||||
t.Fatalf("error decoding fetched manifest: %v", err)
|
||||
}
|
||||
|
||||
_, fetchedCanonical, err := fetchedManifest.Payload()
|
||||
if err != nil {
|
||||
t.Fatalf("error getting manifest payload: %v", err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(fetchedCanonical, canonical) {
|
||||
t.Fatalf("manifests do not match")
|
||||
}
|
||||
|
||||
// ---------------
|
||||
// Fetch by digest
|
||||
req, err = http.NewRequest("GET", manifestDigestURL, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Error constructing request: %s", err)
|
||||
}
|
||||
req.Header.Set("Accept", schema2.MediaTypeManifest)
|
||||
resp, err = http.DefaultClient.Do(req)
|
||||
checkErr(t, err, "fetching manifest by digest")
|
||||
defer resp.Body.Close()
|
||||
|
||||
checkResponse(t, "fetching uploaded manifest", resp, http.StatusOK)
|
||||
checkHeaders(t, resp, http.Header{
|
||||
"Docker-Content-Digest": []string{dgst.String()},
|
||||
"ETag": []string{fmt.Sprintf(`"%s"`, dgst)},
|
||||
})
|
||||
|
||||
var fetchedManifestByDigest schema2.DeserializedManifest
|
||||
dec = json.NewDecoder(resp.Body)
|
||||
if err := dec.Decode(&fetchedManifestByDigest); err != nil {
|
||||
t.Fatalf("error decoding fetched manifest: %v", err)
|
||||
}
|
||||
|
||||
_, fetchedCanonical, err = fetchedManifest.Payload()
|
||||
if err != nil {
|
||||
t.Fatalf("error getting manifest payload: %v", err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(fetchedCanonical, canonical) {
|
||||
t.Fatalf("manifests do not match")
|
||||
}
|
||||
|
||||
// Get by name with etag, gives 304
|
||||
etag := resp.Header.Get("Etag")
|
||||
req, err = http.NewRequest("GET", manifestURL, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Error constructing request: %s", err)
|
||||
}
|
||||
req.Header.Set("If-None-Match", etag)
|
||||
resp, err = http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
t.Fatalf("Error constructing request: %s", err)
|
||||
}
|
||||
|
||||
checkResponse(t, "fetching manifest by name with etag", resp, http.StatusNotModified)
|
||||
|
||||
// Get by digest with etag, gives 304
|
||||
req, err = http.NewRequest("GET", manifestDigestURL, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Error constructing request: %s", err)
|
||||
}
|
||||
req.Header.Set("If-None-Match", etag)
|
||||
resp, err = http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
t.Fatalf("Error constructing request: %s", err)
|
||||
}
|
||||
|
||||
checkResponse(t, "fetching manifest by dgst with etag", resp, http.StatusNotModified)
|
||||
|
||||
// Ensure that the tag is listed.
|
||||
resp, err = http.Get(tagsURL)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error getting unknown tags: %v", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
checkResponse(t, "getting unknown manifest tags", resp, http.StatusOK)
|
||||
dec = json.NewDecoder(resp.Body)
|
||||
|
||||
var tagsResponse tagsAPIResponse
|
||||
|
||||
if err := dec.Decode(&tagsResponse); err != nil {
|
||||
t.Fatalf("unexpected error decoding error response: %v", err)
|
||||
}
|
||||
|
||||
if tagsResponse.Name != imageName {
|
||||
t.Fatalf("tags name should match image name: %v != %v", tagsResponse.Name, imageName)
|
||||
}
|
||||
|
||||
if len(tagsResponse.Tags) != 1 {
|
||||
t.Fatalf("expected some tags in response: %v", tagsResponse.Tags)
|
||||
}
|
||||
|
||||
if tagsResponse.Tags[0] != tag {
|
||||
t.Fatalf("tag not as expected: %q != %q", tagsResponse.Tags[0], tag)
|
||||
}
|
||||
|
||||
// ------------------
|
||||
// Fetch as a schema1 manifest
|
||||
resp, err = http.Get(manifestURL)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error fetching manifest as schema1: %v", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
checkResponse(t, "fetching uploaded manifest as schema1", resp, http.StatusOK)
|
||||
checkHeaders(t, resp, http.Header{
|
||||
"Docker-Content-Digest": []string{dgst.String()},
|
||||
"ETag": []string{fmt.Sprintf(`"%s"`, dgst)},
|
||||
})
|
||||
|
||||
var fetchedSchema1Manifest schema1.SignedManifest
|
||||
dec = json.NewDecoder(resp.Body)
|
||||
|
||||
if err := dec.Decode(&fetchedSchema1Manifest); err != nil {
|
||||
t.Fatalf("error decoding fetched schema1 manifest: %v", err)
|
||||
}
|
||||
|
||||
if fetchedSchema1Manifest.Manifest.SchemaVersion != 1 {
|
||||
t.Fatal("wrong schema version")
|
||||
}
|
||||
if fetchedSchema1Manifest.Architecture != "amd64" {
|
||||
t.Fatal("wrong architecture")
|
||||
}
|
||||
if fetchedSchema1Manifest.Name != imageName {
|
||||
t.Fatal("wrong image name")
|
||||
}
|
||||
if fetchedSchema1Manifest.Tag != tag {
|
||||
t.Fatal("wrong tag")
|
||||
}
|
||||
if len(fetchedSchema1Manifest.FSLayers) != 2 {
|
||||
t.Fatal("wrong number of FSLayers")
|
||||
}
|
||||
for i := range manifest.Layers {
|
||||
if fetchedSchema1Manifest.FSLayers[i].BlobSum != manifest.Layers[len(manifest.Layers)-i-1].Digest {
|
||||
t.Fatalf("blob digest mismatch in schema1 manifest for layer %d", i)
|
||||
}
|
||||
}
|
||||
if len(fetchedSchema1Manifest.History) != 2 {
|
||||
t.Fatal("wrong number of History entries")
|
||||
}
|
||||
|
||||
// Don't check V1Compatibility fields becuase we're using randomly-generated
|
||||
// layers.
|
||||
|
||||
return args
|
||||
}
|
||||
|
||||
func testManifestDelete(t *testing.T, env *testEnv, args manifestArgs) {
|
||||
imageName := args.imageName
|
||||
dgst := args.dgst
|
||||
signedManifest := args.signedManifest
|
||||
manifest := args.manifest
|
||||
manifestDigestURL, err := env.builder.BuildManifestURL(imageName, dgst.String())
|
||||
// ---------------
|
||||
// Delete by digest
|
||||
|
@ -1090,8 +1425,8 @@ func testManifestDelete(t *testing.T, env *testEnv, args manifestArgs) {
|
|||
|
||||
// --------------------
|
||||
// Re-upload manifest by digest
|
||||
resp = putManifest(t, "putting signed manifest", manifestDigestURL, signedManifest)
|
||||
checkResponse(t, "putting signed manifest", resp, http.StatusCreated)
|
||||
resp = putManifest(t, "putting manifest", manifestDigestURL, args.mediaType, manifest)
|
||||
checkResponse(t, "putting manifest", resp, http.StatusCreated)
|
||||
checkHeaders(t, resp, http.Header{
|
||||
"Location": []string{manifestDigestURL},
|
||||
"Docker-Content-Digest": []string{dgst.String()},
|
||||
|
@ -1183,7 +1518,7 @@ func newTestEnvWithConfig(t *testing.T, config *configuration.Configuration) *te
|
|||
}
|
||||
}
|
||||
|
||||
func putManifest(t *testing.T, msg, url string, v interface{}) *http.Response {
|
||||
func putManifest(t *testing.T, msg, url, contentType string, v interface{}) *http.Response {
|
||||
var body []byte
|
||||
|
||||
if sm, ok := v.(*schema1.SignedManifest); ok {
|
||||
|
@ -1205,6 +1540,10 @@ func putManifest(t *testing.T, msg, url string, v interface{}) *http.Response {
|
|||
t.Fatalf("error creating request for %s: %v", msg, err)
|
||||
}
|
||||
|
||||
if contentType != "" {
|
||||
req.Header.Set("Content-Type", contentType)
|
||||
}
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
t.Fatalf("error doing put request while %s: %v", msg, err)
|
||||
|
@ -1532,7 +1871,7 @@ func createRepository(env *testEnv, t *testing.T, imageName string, tag string)
|
|||
location, err := env.builder.BuildManifestURL(imageName, dgst.String())
|
||||
checkErr(t, err, "building location URL")
|
||||
|
||||
resp := putManifest(t, "putting signed manifest", manifestDigestURL, signedManifest)
|
||||
resp := putManifest(t, "putting signed manifest", manifestDigestURL, "", signedManifest)
|
||||
checkResponse(t, "putting signed manifest", resp, http.StatusCreated)
|
||||
checkHeaders(t, resp, http.Header{
|
||||
"Location": []string{location},
|
||||
|
@ -1570,7 +1909,7 @@ func TestRegistryAsCacheMutationAPIs(t *testing.T) {
|
|||
t.Fatalf("error signing manifest: %v", err)
|
||||
}
|
||||
|
||||
resp := putManifest(t, "putting unsigned manifest", manifestURL, sm)
|
||||
resp := putManifest(t, "putting unsigned manifest", manifestURL, "", sm)
|
||||
checkResponse(t, "putting signed manifest to cache", resp, errcode.ErrorCodeUnsupported.Descriptor().HTTPStatusCode)
|
||||
|
||||
// Manifest Delete
|
||||
|
|
|
@ -86,7 +86,7 @@ func (imh *imageManifestHandler) GetImageManifest(w http.ResponseWriter, r *http
|
|||
// Only rewrite schema2 manifests when they are being fetched by tag.
|
||||
// If they are being fetched by digest, we can't return something not
|
||||
// matching the digest.
|
||||
if _, isSchema2 := manifest.(*schema2.DeserializedManifest); imh.Tag != "" && isSchema2 {
|
||||
if schema2Manifest, isSchema2 := manifest.(*schema2.DeserializedManifest); imh.Tag != "" && isSchema2 {
|
||||
supportsSchema2 := false
|
||||
if acceptHeaders, ok := r.Header["Accept"]; ok {
|
||||
for _, mediaType := range acceptHeaders {
|
||||
|
@ -101,7 +101,7 @@ func (imh *imageManifestHandler) GetImageManifest(w http.ResponseWriter, r *http
|
|||
// Rewrite manifest in schema1 format
|
||||
ctxu.GetLogger(imh).Infof("rewriting manifest %s in schema1 format to support old client", imh.Digest.String())
|
||||
|
||||
targetDescriptor := manifest.Target()
|
||||
targetDescriptor := schema2Manifest.Target()
|
||||
blobs := imh.Repository.Blobs(imh)
|
||||
configJSON, err := blobs.Get(imh, targetDescriptor.Digest)
|
||||
if err != nil {
|
||||
|
|
Loading…
Reference in a new issue