Skip to content

Commit

Permalink
Merge pull request #338 from owtaylor/docker-oci-manifests
Browse files Browse the repository at this point in the history
Support pulling/pushing OCI manifests from a docker registry
  • Loading branch information
mtrmac authored Sep 7, 2017
2 parents abb4cd7 + ae52c73 commit 742b329
Show file tree
Hide file tree
Showing 29 changed files with 63 additions and 113 deletions.
6 changes: 2 additions & 4 deletions copy/copy.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,9 +129,7 @@ func Image(policyContext *signature.PolicyContext, destRef, srcRef types.ImageRe
}
}()

destSupportedManifestMIMETypes := dest.SupportedManifestMIMETypes()

rawSource, err := srcRef.NewImageSource(options.SourceCtx, destSupportedManifestMIMETypes)
rawSource, err := srcRef.NewImageSource(options.SourceCtx)
if err != nil {
return errors.Wrapf(err, "Error initializing source %s", transports.ImageName(srcRef))
}
Expand Down Expand Up @@ -195,7 +193,7 @@ func Image(policyContext *signature.PolicyContext, destRef, srcRef types.ImageRe

// We compute preferredManifestMIMEType only to show it in error messages.
// Without having to add this context in an error message, we would be happy enough to know only that no conversion is needed.
preferredManifestMIMEType, otherManifestMIMETypeCandidates, err := determineManifestConversion(&manifestUpdates, src, destSupportedManifestMIMETypes, canModifyManifest)
preferredManifestMIMEType, otherManifestMIMETypeCandidates, err := determineManifestConversion(&manifestUpdates, src, dest.SupportedManifestMIMETypes(), canModifyManifest)
if err != nil {
return err
}
Expand Down
8 changes: 4 additions & 4 deletions directory/directory_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ func TestGetPutManifest(t *testing.T) {
err = dest.Commit()
assert.NoError(t, err)

src, err := ref.NewImageSource(nil, nil)
src, err := ref.NewImageSource(nil)
require.NoError(t, err)
defer src.Close()
m, mt, err := src.GetManifest()
Expand All @@ -64,7 +64,7 @@ func TestGetPutBlob(t *testing.T) {
assert.Equal(t, int64(9), info.Size)
assert.Equal(t, digest.FromBytes(blob), info.Digest)

src, err := ref.NewImageSource(nil, nil)
src, err := ref.NewImageSource(nil)
require.NoError(t, err)
defer src.Close()
rc, size, err := src.GetBlob(info)
Expand Down Expand Up @@ -143,7 +143,7 @@ func TestGetPutSignatures(t *testing.T) {
err = dest.Commit()
assert.NoError(t, err)

src, err := ref.NewImageSource(nil, nil)
src, err := ref.NewImageSource(nil)
require.NoError(t, err)
defer src.Close()
sigs, err := src.GetSignatures(context.Background())
Expand All @@ -155,7 +155,7 @@ func TestSourceReference(t *testing.T) {
ref, tmpDir := refToTempDir(t)
defer os.RemoveAll(tmpDir)

src, err := ref.NewImageSource(nil, nil)
src, err := ref.NewImageSource(nil)
require.NoError(t, err)
defer src.Close()
ref2 := src.Reference()
Expand Down
6 changes: 2 additions & 4 deletions directory/directory_transport.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,11 +143,9 @@ func (ref dirReference) NewImage(ctx *types.SystemContext) (types.Image, error)
return image.FromSource(src)
}

// NewImageSource returns a types.ImageSource for this reference,
// asking the backend to use a manifest from requestedManifestMIMETypes if possible.
// nil requestedManifestMIMETypes means manifest.DefaultRequestedManifestMIMETypes.
// NewImageSource returns a types.ImageSource for this reference.
// The caller must call .Close() on the returned ImageSource.
func (ref dirReference) NewImageSource(ctx *types.SystemContext, requestedManifestMIMETypes []string) (types.ImageSource, error) {
func (ref dirReference) NewImageSource(ctx *types.SystemContext) (types.ImageSource, error) {
return newImageSource(ref), nil
}

Expand Down
2 changes: 1 addition & 1 deletion directory/directory_transport_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ func TestReferenceNewImageNoValidManifest(t *testing.T) {
func TestReferenceNewImageSource(t *testing.T) {
ref, tmpDir := refToTempDir(t)
defer os.RemoveAll(tmpDir)
src, err := ref.NewImageSource(nil, nil)
src, err := ref.NewImageSource(nil)
assert.NoError(t, err)
defer src.Close()
}
Expand Down
6 changes: 2 additions & 4 deletions docker/archive/transport.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,11 +134,9 @@ func (ref archiveReference) NewImage(ctx *types.SystemContext) (types.Image, err
return ctrImage.FromSource(src)
}

// NewImageSource returns a types.ImageSource for this reference,
// asking the backend to use a manifest from requestedManifestMIMETypes if possible.
// nil requestedManifestMIMETypes means manifest.DefaultRequestedManifestMIMETypes.
// NewImageSource returns a types.ImageSource for this reference.
// The caller must call .Close() on the returned ImageSource.
func (ref archiveReference) NewImageSource(ctx *types.SystemContext, requestedManifestMIMETypes []string) (types.ImageSource, error) {
func (ref archiveReference) NewImageSource(ctx *types.SystemContext) (types.ImageSource, error) {
return newImageSource(ctx, ref), nil
}

Expand Down
2 changes: 1 addition & 1 deletion docker/archive/transport_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ func TestReferenceNewImageSource(t *testing.T) {
for _, suffix := range []string{"", ":thisisignoredbutaccepted"} {
ref, err := ParseReference(tarFixture + suffix)
require.NoError(t, err, suffix)
src, err := ref.NewImageSource(nil, nil)
src, err := ref.NewImageSource(nil)
assert.NoError(t, err, suffix)
defer src.Close()
}
Expand Down
6 changes: 2 additions & 4 deletions docker/daemon/daemon_transport.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,11 +161,9 @@ func (ref daemonReference) NewImage(ctx *types.SystemContext) (types.Image, erro
return image.FromSource(src)
}

// NewImageSource returns a types.ImageSource for this reference,
// asking the backend to use a manifest from requestedManifestMIMETypes if possible.
// nil requestedManifestMIMETypes means manifest.DefaultRequestedManifestMIMETypes.
// NewImageSource returns a types.ImageSource for this reference.
// The caller must call .Close() on the returned ImageSource.
func (ref daemonReference) NewImageSource(ctx *types.SystemContext, requestedManifestMIMETypes []string) (types.ImageSource, error) {
func (ref daemonReference) NewImageSource(ctx *types.SystemContext) (types.ImageSource, error) {
return newImageSource(ctx, ref)
}

Expand Down
2 changes: 1 addition & 1 deletion docker/docker_image.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ type Image struct {
// a client to the registry hosting the given image.
// The caller must call .Close() on the returned Image.
func newImage(ctx *types.SystemContext, ref dockerReference) (types.Image, error) {
s, err := newImageSource(ctx, ref, nil)
s, err := newImageSource(ctx, ref)
if err != nil {
return nil, err
}
Expand Down
23 changes: 7 additions & 16 deletions docker/docker_image_dest.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,25 +20,11 @@ import (
"github.com/docker/distribution/registry/api/v2"
"github.com/docker/distribution/registry/client"
"github.com/opencontainers/go-digest"
imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)

var manifestMIMETypes = []string{
// TODO(runcom): we'll add OCI as part of another PR here
manifest.DockerV2Schema2MediaType,
manifest.DockerV2Schema1SignedMediaType,
manifest.DockerV2Schema1MediaType,
}

func supportedManifestMIMETypesMap() map[string]bool {
m := make(map[string]bool, len(manifestMIMETypes))
for _, mt := range manifestMIMETypes {
m[mt] = true
}
return m
}

type dockerImageDestination struct {
ref dockerReference
c *dockerClient
Expand Down Expand Up @@ -70,7 +56,12 @@ func (d *dockerImageDestination) Close() error {
}

func (d *dockerImageDestination) SupportedManifestMIMETypes() []string {
return manifestMIMETypes
return []string{
imgspecv1.MediaTypeImageManifest,
manifest.DockerV2Schema2MediaType,
manifest.DockerV2Schema1SignedMediaType,
manifest.DockerV2Schema1MediaType,
}
}

// SupportsSignatures returns an error (to be displayed to the user) if the destination certainly can't store signatures.
Expand Down
30 changes: 6 additions & 24 deletions docker/docker_image_src.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,41 +21,23 @@ import (
)

type dockerImageSource struct {
ref dockerReference
requestedManifestMIMETypes []string
c *dockerClient
ref dockerReference
c *dockerClient
// State
cachedManifest []byte // nil if not loaded yet
cachedManifestMIMEType string // Only valid if cachedManifest != nil
}

// newImageSource creates a new ImageSource for the specified image reference,
// asking the backend to use a manifest from requestedManifestMIMETypes if possible.
// nil requestedManifestMIMETypes means manifest.DefaultRequestedManifestMIMETypes.
// newImageSource creates a new ImageSource for the specified image reference.
// The caller must call .Close() on the returned ImageSource.
func newImageSource(ctx *types.SystemContext, ref dockerReference, requestedManifestMIMETypes []string) (*dockerImageSource, error) {
func newImageSource(ctx *types.SystemContext, ref dockerReference) (*dockerImageSource, error) {
c, err := newDockerClient(ctx, ref, false, "pull")
if err != nil {
return nil, err
}
if requestedManifestMIMETypes == nil {
requestedManifestMIMETypes = manifest.DefaultRequestedManifestMIMETypes
}
supportedMIMEs := supportedManifestMIMETypesMap()
acceptableRequestedMIMEs := false
for _, mtrequested := range requestedManifestMIMETypes {
if supportedMIMEs[mtrequested] {
acceptableRequestedMIMEs = true
break
}
}
if !acceptableRequestedMIMEs {
requestedManifestMIMETypes = manifest.DefaultRequestedManifestMIMETypes
}
return &dockerImageSource{
ref: ref,
requestedManifestMIMETypes: requestedManifestMIMETypes,
c: c,
c: c,
}, nil
}

Expand Down Expand Up @@ -96,7 +78,7 @@ func (s *dockerImageSource) GetManifest() ([]byte, string, error) {
func (s *dockerImageSource) fetchManifest(ctx context.Context, tagOrDigest string) ([]byte, string, error) {
path := fmt.Sprintf(manifestPath, reference.Path(s.ref.ref), tagOrDigest)
headers := make(map[string][]string)
headers["Accept"] = s.requestedManifestMIMETypes
headers["Accept"] = manifest.DefaultRequestedManifestMIMETypes
res, err := s.c.makeRequest(ctx, "GET", path, headers, nil)
if err != nil {
return nil, "", err
Expand Down
8 changes: 3 additions & 5 deletions docker/docker_transport.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,12 +130,10 @@ func (ref dockerReference) NewImage(ctx *types.SystemContext) (types.Image, erro
return newImage(ctx, ref)
}

// NewImageSource returns a types.ImageSource for this reference,
// asking the backend to use a manifest from requestedManifestMIMETypes if possible.
// nil requestedManifestMIMETypes means manifest.DefaultRequestedManifestMIMETypes.
// NewImageSource returns a types.ImageSource for this reference.
// The caller must call .Close() on the returned ImageSource.
func (ref dockerReference) NewImageSource(ctx *types.SystemContext, requestedManifestMIMETypes []string) (types.ImageSource, error) {
return newImageSource(ctx, ref, requestedManifestMIMETypes)
func (ref dockerReference) NewImageSource(ctx *types.SystemContext) (types.ImageSource, error) {
return newImageSource(ctx, ref)
}

// NewImageDestination returns a types.ImageDestination for this reference.
Expand Down
2 changes: 1 addition & 1 deletion docker/docker_transport_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ func TestReferenceNewImage(t *testing.T) {
func TestReferenceNewImageSource(t *testing.T) {
ref, err := ParseReference("//busybox")
require.NoError(t, err)
src, err := ref.NewImageSource(&types.SystemContext{RegistriesDirPath: "/this/doesnt/exist", DockerPerHostCertDirPath: "/this/doesnt/exist"}, nil)
src, err := ref.NewImageSource(&types.SystemContext{RegistriesDirPath: "/this/doesnt/exist", DockerPerHostCertDirPath: "/this/doesnt/exist"})
assert.NoError(t, err)
defer src.Close()
}
Expand Down
2 changes: 1 addition & 1 deletion image/docker_schema2_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@ func (ref refImageReferenceMock) PolicyConfigurationNamespaces() []string {
func (ref refImageReferenceMock) NewImage(ctx *types.SystemContext) (types.Image, error) {
panic("unexpected call to a mock function")
}
func (ref refImageReferenceMock) NewImageSource(ctx *types.SystemContext, requestedManifestMIMETypes []string) (types.ImageSource, error) {
func (ref refImageReferenceMock) NewImageSource(ctx *types.SystemContext) (types.ImageSource, error) {
panic("unexpected call to a mock function")
}
func (ref refImageReferenceMock) NewImageDestination(ctx *types.SystemContext) (types.ImageDestination, error) {
Expand Down
4 changes: 2 additions & 2 deletions oci/archive/oci_src.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@ type ociArchiveImageSource struct {

// newImageSource returns an ImageSource for reading from an existing directory.
// newImageSource untars the file and saves it in a temp directory
func newImageSource(ctx *types.SystemContext, ref ociArchiveReference, requestedManifestMIMETypes []string) (types.ImageSource, error) {
func newImageSource(ctx *types.SystemContext, ref ociArchiveReference) (types.ImageSource, error) {
tempDirRef, err := createUntarTempDir(ref)
if err != nil {
return nil, errors.Wrap(err, "error creating temp directory")
}

unpackedSrc, err := tempDirRef.ociRefExtracted.NewImageSource(ctx, requestedManifestMIMETypes)
unpackedSrc, err := tempDirRef.ociRefExtracted.NewImageSource(ctx)
if err != nil {
if err := tempDirRef.deleteTempDir(); err != nil {
return nil, errors.Wrapf(err, "error deleting temp directory", tempDirRef.tempDirectory)
Expand Down
9 changes: 4 additions & 5 deletions oci/archive/oci_transport.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,18 +157,17 @@ func (ref ociArchiveReference) PolicyConfigurationNamespaces() []string {
// NewImage returns a types.Image for this reference, possibly specialized for this ImageTransport.
// The caller must call .Close() on the returned Image.
func (ref ociArchiveReference) NewImage(ctx *types.SystemContext) (types.Image, error) {
src, err := newImageSource(ctx, ref, nil)
src, err := newImageSource(ctx, ref)
if err != nil {
return nil, err
}
return image.FromSource(src)
}

// NewImageSource returns a types.ImageSource for this reference,
// asking the backend to use a manifest from requestedManifestMIMETypes if possible.
// NewImageSource returns a types.ImageSource for this reference.
// The caller must call .Close() on the returned ImageSource.
func (ref ociArchiveReference) NewImageSource(ctx *types.SystemContext, requestedManifestMIMETypes []string) (types.ImageSource, error) {
return newImageSource(ctx, ref, requestedManifestMIMETypes)
func (ref ociArchiveReference) NewImageSource(ctx *types.SystemContext) (types.ImageSource, error) {
return newImageSource(ctx, ref)
}

// NewImageDestination returns a types.ImageDestination for this reference.
Expand Down
2 changes: 1 addition & 1 deletion oci/archive/oci_transport_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ func TestReferenceNewImage(t *testing.T) {
func TestReferenceNewImageSource(t *testing.T) {
ref, tmpTarFile := refToTempOCIArchive(t)
defer os.RemoveAll(tmpTarFile)
_, err := ref.NewImageSource(nil, nil)
_, err := ref.NewImageSource(nil)
assert.NoError(t, err)
}

Expand Down
6 changes: 2 additions & 4 deletions oci/layout/oci_transport.go
Original file line number Diff line number Diff line change
Expand Up @@ -241,11 +241,9 @@ func LoadManifestDescriptor(imgRef types.ImageReference) (imgspecv1.Descriptor,
return ociRef.getManifestDescriptor()
}

// NewImageSource returns a types.ImageSource for this reference,
// asking the backend to use a manifest from requestedManifestMIMETypes if possible.
// nil requestedManifestMIMETypes means manifest.DefaultRequestedManifestMIMETypes.
// NewImageSource returns a types.ImageSource for this reference.
// The caller must call .Close() on the returned ImageSource.
func (ref ociReference) NewImageSource(ctx *types.SystemContext, requestedManifestMIMETypes []string) (types.ImageSource, error) {
func (ref ociReference) NewImageSource(ctx *types.SystemContext) (types.ImageSource, error) {
return newImageSource(ref)
}

Expand Down
2 changes: 1 addition & 1 deletion oci/layout/oci_transport_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ func TestReferenceNewImage(t *testing.T) {
func TestReferenceNewImageSource(t *testing.T) {
ref, tmpDir := refToTempOCI(t)
defer os.RemoveAll(tmpDir)
_, err := ref.NewImageSource(nil, nil)
_, err := ref.NewImageSource(nil)
assert.NoError(t, err)
}

Expand Down
12 changes: 4 additions & 8 deletions openshift/openshift.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,18 +162,15 @@ func (c *openshiftClient) convertDockerImageReference(ref string) (string, error
type openshiftImageSource struct {
client *openshiftClient
// Values specific to this image
ctx *types.SystemContext
requestedManifestMIMETypes []string
ctx *types.SystemContext
// State
docker types.ImageSource // The Docker Registry endpoint, or nil if not resolved yet
imageStreamImageName string // Resolved image identifier, or "" if not known yet
}

// newImageSource creates a new ImageSource for the specified reference,
// asking the backend to use a manifest from requestedManifestMIMETypes if possible.
// nil requestedManifestMIMETypes means manifest.DefaultRequestedManifestMIMETypes.
// newImageSource creates a new ImageSource for the specified reference.
// The caller must call .Close() on the returned ImageSource.
func newImageSource(ctx *types.SystemContext, ref openshiftReference, requestedManifestMIMETypes []string) (types.ImageSource, error) {
func newImageSource(ctx *types.SystemContext, ref openshiftReference) (types.ImageSource, error) {
client, err := newOpenshiftClient(ref)
if err != nil {
return nil, err
Expand All @@ -182,7 +179,6 @@ func newImageSource(ctx *types.SystemContext, ref openshiftReference, requestedM
return &openshiftImageSource{
client: client,
ctx: ctx,
requestedManifestMIMETypes: requestedManifestMIMETypes,
}, nil
}

Expand Down Expand Up @@ -286,7 +282,7 @@ func (s *openshiftImageSource) ensureImageIsResolved(ctx context.Context) error
if err != nil {
return err
}
d, err := dockerRef.NewImageSource(s.ctx, s.requestedManifestMIMETypes)
d, err := dockerRef.NewImageSource(s.ctx)
if err != nil {
return err
}
Expand Down
10 changes: 4 additions & 6 deletions openshift/openshift_transport.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,19 +130,17 @@ func (ref openshiftReference) PolicyConfigurationNamespaces() []string {
// NOTE: If any kind of signature verification should happen, build an UnparsedImage from the value returned by NewImageSource,
// verify that UnparsedImage, and convert it into a real Image via image.FromUnparsedImage.
func (ref openshiftReference) NewImage(ctx *types.SystemContext) (types.Image, error) {
src, err := newImageSource(ctx, ref, nil)
src, err := newImageSource(ctx, ref)
if err != nil {
return nil, err
}
return genericImage.FromSource(src)
}

// NewImageSource returns a types.ImageSource for this reference,
// asking the backend to use a manifest from requestedManifestMIMETypes if possible.
// nil requestedManifestMIMETypes means manifest.DefaultRequestedManifestMIMETypes.
// NewImageSource returns a types.ImageSource for this reference.
// The caller must call .Close() on the returned ImageSource.
func (ref openshiftReference) NewImageSource(ctx *types.SystemContext, requestedManifestMIMETypes []string) (types.ImageSource, error) {
return newImageSource(ctx, ref, requestedManifestMIMETypes)
func (ref openshiftReference) NewImageSource(ctx *types.SystemContext) (types.ImageSource, error) {
return newImageSource(ctx, ref)
}

// NewImageDestination returns a types.ImageDestination for this reference.
Expand Down
Loading

0 comments on commit 742b329

Please sign in to comment.