Skip to content

WRKLDS-1599: Drop support for image manifest schema 1 #528

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 0 additions & 7 deletions pkg/image/apis/image/docker10/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,6 @@ type DockerImageManifest struct {
SchemaVersion int `json:"schemaVersion"`
MediaType string `json:"mediaType,omitempty"`

// schema1
Name string `json:"name"`
Tag string `json:"tag"`
Architecture string `json:"architecture"`
FSLayers []DockerFSLayer `json:"fsLayers"`
History []DockerHistory `json:"history"`

// schema2
Layers []Descriptor `json:"layers"`
Config Descriptor `json:"config"`
Expand Down
5 changes: 3 additions & 2 deletions pkg/image/apiserver/admission/limitrange/admission_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import (
imagev1 "github.com/openshift/api/image/v1"
"github.com/openshift/openshift-apiserver/pkg/api/legacy"
imageapi "github.com/openshift/openshift-apiserver/pkg/image/apis/image"
"github.com/openshift/openshift-apiserver/pkg/image/apiserver/testutil"
"github.com/openshift/openshift-apiserver/pkg/image/apiserver/internal/testutil"
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just moved this package around, feels more consistent.

)

func TestAdmitImageStreamMapping(t *testing.T) {
Expand All @@ -36,7 +36,7 @@ func TestAdmitImageStreamMapping(t *testing.T) {
},
"new ism, under limit range": {
imageStreamMapping: getImageStreamMapping(),
limitRange: getLimitRange("1Ki"),
limitRange: getLimitRange("2Mi"),
operation: admission.Create,
shouldAdmit: true,
},
Expand Down Expand Up @@ -246,6 +246,7 @@ func getBaseImageWith1Layer() imageapi.Image {
},
DockerImageReference: fmt.Sprintf("registry.example.org/%s/%s", "test", testutil.BaseImageWith1LayerDigest),
DockerImageManifest: testutil.BaseImageWith1Layer,
DockerImageConfig: testutil.BaseImageWith1LayerConfig,
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
"github.com/openshift/library-go/pkg/quota/quotautil"

imageapi "github.com/openshift/openshift-apiserver/pkg/image/apis/image"
imagetest "github.com/openshift/openshift-apiserver/pkg/image/apiserver/testutil"
imagetest "github.com/openshift/openshift-apiserver/pkg/image/apiserver/internal/testutil"
)

func TestGetMaxLimits(t *testing.T) {
Expand Down
2 changes: 1 addition & 1 deletion pkg/image/apiserver/admission/limitrange/usage_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
imagev1 "github.com/openshift/api/image/v1"
"github.com/openshift/library-go/pkg/image/imageutil"
imageapi "github.com/openshift/openshift-apiserver/pkg/image/apis/image"
imagetest "github.com/openshift/openshift-apiserver/pkg/image/apiserver/testutil"
imagetest "github.com/openshift/openshift-apiserver/pkg/image/apiserver/internal/testutil"
)

func TestGetImageReferenceForObjectReference(t *testing.T) {
Expand Down
36 changes: 0 additions & 36 deletions pkg/image/apiserver/importer/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (

"github.com/distribution/distribution/v3"
"github.com/distribution/distribution/v3/manifest/manifestlist"
"github.com/distribution/distribution/v3/manifest/schema1"
"github.com/distribution/distribution/v3/registry/api/errcode"
godigest "github.com/opencontainers/go-digest"

Expand All @@ -18,41 +17,6 @@ import (
imagedockerpre012 "github.com/openshift/openshift-apiserver/pkg/image/apis/image/dockerpre012"
)

func schema1ToImage(manifest *schema1.SignedManifest, d godigest.Digest) (*imageapi.Image, error) {
if len(manifest.History) == 0 {
return nil, fmt.Errorf("image has no v1Compatibility history and cannot be used")
}
dockerImage, err := unmarshalDockerImage([]byte(manifest.History[0].V1Compatibility))
if err != nil {
return nil, err
}
mediatype, payload, err := manifest.Payload()
if err != nil {
return nil, err
}

if len(manifest.Canonical) == 0 {
return nil, fmt.Errorf("unable to load canonical representation from schema1 manifest")
}
payloadDigest := godigest.FromBytes(manifest.Canonical)
if len(d) > 0 && payloadDigest != d {
return nil, fmt.Errorf("content integrity error: the schema 1 manifest retrieved with digest %s does not match the digest calculated from the content %s", d, payloadDigest)
}
dockerImage.ID = payloadDigest.String()

image := &imageapi.Image{
ObjectMeta: metav1.ObjectMeta{
Name: dockerImage.ID,
},
DockerImageMetadata: *dockerImage,
DockerImageManifest: string(payload),
DockerImageManifestMediaType: mediatype,
DockerImageMetadataVersion: "1.0",
}

return image, nil
}

// schema2OrOCIToImage converts a docker schema 2 or an oci schema manifest into an Image.
func schema2OrOCIToImage(manifest distribution.Manifest, imageConfig []byte, d godigest.Digest) (*imageapi.Image, error) {
mediatype, payload, err := manifest.Payload()
Expand Down
3 changes: 0 additions & 3 deletions pkg/image/apiserver/importer/importer.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import (
"github.com/distribution/distribution/v3"
"github.com/distribution/distribution/v3/manifest/manifestlist"
"github.com/distribution/distribution/v3/manifest/ocischema"
"github.com/distribution/distribution/v3/manifest/schema1"
"github.com/distribution/distribution/v3/manifest/schema2"
"github.com/distribution/distribution/v3/reference"
"github.com/distribution/distribution/v3/registry/api/errcode"
Expand Down Expand Up @@ -743,8 +742,6 @@ func (imp *ImageStreamImporter) importManifest(
if isManifestList && !legacyManifestListImport {
image, err = manifestListToImage(manifestList, d)
return
} else if signedManifest, isSchema1 := manifest.(*schema1.SignedManifest); isSchema1 {
image, err = schema1ToImage(signedManifest, d)
} else if deserializedManifest, isSchema2 := manifest.(*schema2.DeserializedManifest); isSchema2 {
imageConfig, getImportConfigErr := b.Get(ctx, deserializedManifest.Config.Digest)
if getImportConfigErr != nil {
Expand Down
118 changes: 30 additions & 88 deletions pkg/image/apiserver/importer/importer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package importer

import (
"context"
"encoding/json"
"fmt"
"net/http"
"net/url"
Expand All @@ -11,7 +10,6 @@ import (

"github.com/containers/image/v5/pkg/sysregistriesv2"
"github.com/distribution/distribution/v3"
"github.com/distribution/distribution/v3/manifest/schema1"
"github.com/distribution/distribution/v3/manifest/schema2"
"github.com/distribution/distribution/v3/reference"
godigest "github.com/opencontainers/go-digest"
Expand Down Expand Up @@ -169,20 +167,6 @@ func (r *mockTagService) Lookup(ctx context.Context, digest distribution.Descrip
return nil, fmt.Errorf("not implemented")
}

func TestSchema1ToImage(t *testing.T) {
m := &schema1.SignedManifest{}
if err := json.Unmarshal([]byte(etcdManifest), m); err != nil {
t.Fatal(err)
}
image, err := schema1ToImage(m, godigest.Digest("sha256:958608f8ecc1dc62c93b6c610f3a834dae4220c9642e6e8b4e0f2b3ad7cbd238"))
if err != nil {
t.Fatal(err)
}
if image.DockerImageMetadata.ID != "sha256:958608f8ecc1dc62c93b6c610f3a834dae4220c9642e6e8b4e0f2b3ad7cbd238" {
t.Errorf("unexpected image: %#v", image.DockerImageMetadata.ID)
}
}

func TestImportNothing(t *testing.T) {
ctx := NewStaticCredentialsContext(
http.DefaultTransport, http.DefaultTransport, nil,
Expand All @@ -202,11 +186,6 @@ func expectStatusError(status metav1.Status, message string) bool {
}

func TestImport(t *testing.T) {
etcdManifestSchema1 := &schema1.SignedManifest{}
if err := json.Unmarshal([]byte(etcdManifest), etcdManifestSchema1); err != nil {
t.Fatal(err)
}
t.Logf("etcd manifest schema 1 digest: %q", godigest.FromBytes([]byte(etcdManifest)))
busyboxManifestSchema2 := &schema2.DeserializedManifest{}
if err := busyboxManifestSchema2.UnmarshalJSON([]byte(busyboxManifest)); err != nil {
t.Fatal(err)
Expand Down Expand Up @@ -312,12 +291,21 @@ func TestImport(t *testing.T) {
},
},
{
name: "successfull import by tag and digest",
retriever: &mockRetriever{repo: &mockRepository{manifest: etcdManifestSchema1}},
name: "successful import by tag and digest",
retriever: &mockRetriever{
repo: &mockRepository{
blobs: &mockBlobStore{
blobs: map[godigest.Digest][]byte{
busyboxConfigDigest: []byte(busyboxManifestConfig),
},
},
manifest: busyboxManifestSchema2,
},
},
isi: imageapi.ImageStreamImport{
Spec: imageapi.ImageStreamImportSpec{
Images: []imageapi.ImageImportSpec{
{From: kapi.ObjectReference{Kind: "DockerImage", Name: "test@sha256:958608f8ecc1dc62c93b6c610f3a834dae4220c9642e6e8b4e0f2b3ad7cbd238"}},
{From: kapi.ObjectReference{Kind: "DockerImage", Name: "test@" + busyboxDigest}},
{From: kapi.ObjectReference{Kind: "DockerImage", Name: "test:tag"}},
},
},
Expand All @@ -331,13 +319,17 @@ func TestImport(t *testing.T) {
if image.Status.Status != metav1.StatusSuccess {
t.Errorf("unexpected status %d: %#v", i, image.Status)
}
// the image name is always the sha256, and size is calculated
if image.Image == nil || image.Image.Name != "sha256:958608f8ecc1dc62c93b6c610f3a834dae4220c9642e6e8b4e0f2b3ad7cbd238" || image.Image.DockerImageMetadata.Size != 28643712 {
t.Errorf("unexpected image %d: %#v", i, image.Image.Name)
}
// the most specific reference is returned
if image.Image.DockerImageReference != "test@sha256:958608f8ecc1dc62c93b6c610f3a834dae4220c9642e6e8b4e0f2b3ad7cbd238" {
t.Errorf("unexpected ref %d: %#v", i, image.Image.DockerImageReference)
if image.Image == nil {
t.Errorf("unexpected nil image: %#v", image)
} else {
// the image name is always the sha256, and size is calculated
if image.Image.Name != busyboxDigest || image.Image.DockerImageMetadata.Size != 669049 {
t.Errorf("unexpected image %d: %#v (size %d)", i, image.Image.Name, image.Image.DockerImageMetadata.Size)
}
// the most specific reference is returned
if image.Image.DockerImageReference != "test@"+busyboxDigest {
t.Errorf("unexpected ref %d: %#v", i, image.Image.DockerImageReference)
}
}
if image.Tag != expectedTags[i] {
t.Errorf("unexpected tag of status %d (%s != %s)", i, image.Tag, expectedTags[i])
Expand Down Expand Up @@ -392,14 +384,14 @@ func TestImport(t *testing.T) {
name: "import repository with additional tags",
retriever: &mockRetriever{
repo: &mockRepository{
manifest: etcdManifestSchema1,
manifest: busyboxManifestSchema2,
tags: map[string]string{
"v1": "sha256:958608f8ecc1dc62c93b6c610f3a834dae4220c9642e6e8b4e0f2b3ad7cbd238",
"other": "sha256:958608f8ecc1dc62c93b6c610f3a834dae4220c9642e6e8b4e0f2b3ad7cbd238",
"v2": "sha256:958608f8ecc1dc62c93b6c610f3a834dae4220c9642e6e8b4e0f2b3ad7cbd238",
"3": "sha256:958608f8ecc1dc62c93b6c610f3a834dae4220c9642e6e8b4e0f2b3ad7cbd238",
"3.1": "sha256:958608f8ecc1dc62c93b6c610f3a834dae4220c9642e6e8b4e0f2b3ad7cbd238",
"abc": "sha256:958608f8ecc1dc62c93b6c610f3a834dae4220c9642e6e8b4e0f2b3ad7cbd238",
"v1": busyboxDigest,
"other": busyboxDigest,
"v2": busyboxDigest,
"3": busyboxDigest,
"3.1": busyboxDigest,
"abc": busyboxDigest,
},
getTagErr: fmt.Errorf("no such tag"),
getByTagErr: fmt.Errorf("no such manifest tag"),
Expand Down Expand Up @@ -640,56 +632,6 @@ func TestImportFromMirror(t *testing.T) {
})
}

const etcdManifest = `
{
"schemaVersion": 1,
"tag": "latest",
"name": "coreos/etcd",
"architecture": "amd64",
"fsLayers": [
{
"blobSum": "sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4"
},
{
"blobSum": "sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4"
},
{
"blobSum": "sha256:2560187847cadddef806eaf244b7755af247a9dbabb90ca953dd2703cf423766"
},
{
"blobSum": "sha256:744b46d0ac8636c45870a03830d8d82c20b75fbfb9bc937d5e61005d23ad4cfe"
}
],
"history": [
{
"v1Compatibility": "{\"id\":\"fe50ac14986497fa6b5d2cc24feb4a561d01767bc64413752c0988cb70b0b8b9\",\"parent\":\"a5a18474fa96a3c6e240bc88e41de2afd236520caf904356ad9d5f8d875c3481\",\"created\":\"2015-12-30T22:29:13.967754365Z\",\"container\":\"c8d0f1a274b5f52fa5beb280775ef07cf18ec0f95e5ae42fbad01157e2614d42\",\"container_config\":{\"Hostname\":\"1b97abade59e\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"ExposedPorts\":{\"2379/tcp\":{},\"2380/tcp\":{},\"4001/tcp\":{},\"7001/tcp\":{}},\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":null,\"Cmd\":[\"/bin/sh\",\"-c\",\"#(nop) ENTRYPOINT \\u0026{[\\\"/etcd\\\"]}\"],\"Image\":\"a5a18474fa96a3c6e240bc88e41de2afd236520caf904356ad9d5f8d875c3481\",\"Volumes\":null,\"WorkingDir\":\"\",\"Entrypoint\":[\"/etcd\"],\"OnBuild\":null,\"Labels\":{}},\"docker_version\":\"1.9.1\",\"config\":{\"Hostname\":\"1b97abade59e\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"ExposedPorts\":{\"2379/tcp\":{},\"2380/tcp\":{},\"4001/tcp\":{},\"7001/tcp\":{}},\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":null,\"Cmd\":null,\"Image\":\"a5a18474fa96a3c6e240bc88e41de2afd236520caf904356ad9d5f8d875c3481\",\"Volumes\":null,\"WorkingDir\":\"\",\"Entrypoint\":[\"/etcd\"],\"OnBuild\":null,\"Labels\":{}},\"architecture\":\"amd64\",\"os\":\"linux\"}"
},
{
"v1Compatibility": "{\"id\":\"a5a18474fa96a3c6e240bc88e41de2afd236520caf904356ad9d5f8d875c3481\",\"parent\":\"796d581500e960cc02095dcdeccf55db215b8e54c57e3a0b11392145ffe60cf6\",\"created\":\"2015-12-30T22:29:13.504159783Z\",\"container\":\"080708d544f85052a46fab72e701b4358c1b96cb4b805a5b2d66276fc2aaf85d\",\"container_config\":{\"Hostname\":\"1b97abade59e\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"ExposedPorts\":{\"2379/tcp\":{},\"2380/tcp\":{},\"4001/tcp\":{},\"7001/tcp\":{}},\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":null,\"Cmd\":[\"/bin/sh\",\"-c\",\"#(nop) EXPOSE 2379/tcp 2380/tcp 4001/tcp 7001/tcp\"],\"Image\":\"796d581500e960cc02095dcdeccf55db215b8e54c57e3a0b11392145ffe60cf6\",\"Volumes\":null,\"WorkingDir\":\"\",\"Entrypoint\":null,\"OnBuild\":null,\"Labels\":{}},\"docker_version\":\"1.9.1\",\"config\":{\"Hostname\":\"1b97abade59e\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"ExposedPorts\":{\"2379/tcp\":{},\"2380/tcp\":{},\"4001/tcp\":{},\"7001/tcp\":{}},\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":null,\"Cmd\":null,\"Image\":\"796d581500e960cc02095dcdeccf55db215b8e54c57e3a0b11392145ffe60cf6\",\"Volumes\":null,\"WorkingDir\":\"\",\"Entrypoint\":null,\"OnBuild\":null,\"Labels\":{}},\"architecture\":\"amd64\",\"os\":\"linux\"}"
},
{
"v1Compatibility": "{\"id\":\"796d581500e960cc02095dcdeccf55db215b8e54c57e3a0b11392145ffe60cf6\",\"parent\":\"309c960c7f875411ae2ee2bfb97b86eee5058f3dad77206dd0df4f97df8a77fa\",\"created\":\"2015-12-30T22:29:12.912813629Z\",\"container\":\"f28be899c9b8680d4cf8585e663ad20b35019db062526844e7cfef117ce9037f\",\"container_config\":{\"Hostname\":\"1b97abade59e\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":null,\"Cmd\":[\"/bin/sh\",\"-c\",\"#(nop) ADD file:e330b1da49d993059975e46560b3bd360691498b0f2f6e00f39fc160cf8d4ec3 in /\"],\"Image\":\"309c960c7f875411ae2ee2bfb97b86eee5058f3dad77206dd0df4f97df8a77fa\",\"Volumes\":null,\"WorkingDir\":\"\",\"Entrypoint\":null,\"OnBuild\":null,\"Labels\":{}},\"docker_version\":\"1.9.1\",\"config\":{\"Hostname\":\"1b97abade59e\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":null,\"Cmd\":null,\"Image\":\"309c960c7f875411ae2ee2bfb97b86eee5058f3dad77206dd0df4f97df8a77fa\",\"Volumes\":null,\"WorkingDir\":\"\",\"Entrypoint\":null,\"OnBuild\":null,\"Labels\":{}},\"architecture\":\"amd64\",\"os\":\"linux\",\"Size\":13502144}"
},
{
"v1Compatibility": "{\"id\":\"309c960c7f875411ae2ee2bfb97b86eee5058f3dad77206dd0df4f97df8a77fa\",\"created\":\"2015-12-30T22:29:12.346834862Z\",\"container\":\"1b97abade59e4b5b935aede236980a54fb500cd9ee5bd4323c832c6d7b3ffc6e\",\"container_config\":{\"Hostname\":\"1b97abade59e\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":null,\"Cmd\":[\"/bin/sh\",\"-c\",\"#(nop) ADD file:74912593c6783292c4520514f5cc9313acbd1da0f46edee0fdbed2a24a264d6f in /\"],\"Image\":\"\",\"Volumes\":null,\"WorkingDir\":\"\",\"Entrypoint\":null,\"OnBuild\":null,\"Labels\":null},\"docker_version\":\"1.9.1\",\"config\":{\"Hostname\":\"1b97abade59e\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":null,\"Cmd\":null,\"Image\":\"\",\"Volumes\":null,\"WorkingDir\":\"\",\"Entrypoint\":null,\"OnBuild\":null,\"Labels\":null},\"architecture\":\"amd64\",\"os\":\"linux\",\"Size\":15141568}"
}
],
"signatures": [
{
"header": {
"alg": "RS256",
"jwk": {
"e": "AQAB",
"kty": "RSA",
"n": "yB40ou1GMvIxYs1jhxWaeoDiw3oa0_Q2UJThUPtArvO0tRzaun9FnSphhOEHIGcezfq95jy-3MN-FIjmsWgbPHY8lVDS38fF75aCw6qkholwqjmMtUIgPNYoMrg0rLUE5RRyJ84-hKf9Fk7V3fItp1mvCTGKaS3ze-y5dTTrfbNGE7qG638Dla2Fuz-9CNgRQj0JH54o547WkKJC-pG-j0jTDr8lzsXhrZC7lJas4yc-vpt3D60iG4cW_mkdtIj52ZFEgHZ56sUj7AhnNVly0ZP9W1hmw4xEHDn9WLjlt7ivwARVeb2qzsNdguUitcI5hUQNwpOVZ_O3f1rUIL_kRw"
}
},
"protected": "eyJmb3JtYXRUYWlsIjogIkNuMCIsICJmb3JtYXRMZW5ndGgiOiA1OTI2LCAidGltZSI6ICIyMDE2LTAxLTAyVDAyOjAxOjMzWiJ9",
"signature": "DrQ43UWeit-thDoRGTCP0Gd2wL5K2ecyPhHo_au0FoXwuKODja0tfwHexB9ypvFWngk-ijXuwO02x3aRIZqkWpvKLxxzxwkrZnPSje4o_VrFU4z5zwmN8sJw52ODkQlW38PURIVksOxCrb0zRl87yTAAsUAJ_4UUPNltZSLnhwy-qPb2NQ8ghgsONcBxRQrhPFiWNkxDKZ3kjvzYyrXDxTcvwK3Kk_YagZ4rCOhH1B7mAdVSiSHIvvNV5grPshw_ipAoqL2iNMsxWxLjYZl9xSJQI2asaq3fvh8G8cZ7T-OahDUos_GyhnIj39C-9ouqdJqMUYFETqbzRCR6d36CpQ"
}
]
}`

const busyboxDigest = "sha256:a59906e33509d14c036c8678d687bd4eec81ed7c4b8ce907b888c607f6a1e0e6"

const busyboxManifest = `{
Expand Down
Loading