diff --git a/cmd/skopeo/inspect.go b/cmd/skopeo/inspect.go index 0faec9602e..6b7035fb9d 100644 --- a/cmd/skopeo/inspect.go +++ b/cmd/skopeo/inspect.go @@ -23,8 +23,7 @@ var inspectCmd = cli.Command{ logrus.Fatal(err) } if c.Bool("raw") { - // TODO(runcom): hardcoded schema 2 version 1 - b, err := img.RawManifest("2-1") + b, err := img.GetManifest() if err != nil { logrus.Fatal(err) } diff --git a/directory/directory.go b/directory/directory.go index e333c43398..49bb5765f0 100644 --- a/directory/directory.go +++ b/directory/directory.go @@ -77,6 +77,13 @@ func NewDirImageSource(dir string) types.ImageSource { return &dirImageSource{dir} } +// GetIntendedDockerReference returns the full, unambiguous, Docker reference for this image, _as specified by the user_ +// (not as the image itself, or its underlying storage, claims). This can be used e.g. to determine which public keys are trusted for this image. +// May be "" if unknown. +func (s *dirImageSource) GetIntendedDockerReference() string { + return "" +} + func (s *dirImageSource) GetManifest() ([]byte, string, error) { manifest, err := ioutil.ReadFile(manifestPath(s.dir)) if err != nil { diff --git a/docker/docker_image.go b/docker/docker_image.go index a2068dfb93..bd2bfe39b6 100644 --- a/docker/docker_image.go +++ b/docker/docker_image.go @@ -19,9 +19,10 @@ var ( ) type dockerImage struct { - src *dockerImageSource - digest string - rawManifest []byte + src *dockerImageSource + digest string + rawManifest []byte + cachedSignatures [][]byte // Private cache for GetSignatures; nil if not yet known. } // NewDockerImage returns a new Image interface type after setting up @@ -34,14 +35,33 @@ func NewDockerImage(img, certPath string, tlsVerify bool) (types.Image, error) { return &dockerImage{src: s}, nil } -func (i *dockerImage) RawManifest(version string) ([]byte, error) { - // TODO(runcom): unused version param for now, default to docker v2-1 +// GetIntendedDockerReference returns the full, unambiguous, Docker reference for this image, _as specified by the user_ +// (not as the image itself, or its underlying storage, claims). This can be used e.g. to determine which public keys are trusted for this image. +// May be "" if unknown. +func (i *dockerImage) GetIntendedDockerReference() string { + return i.src.GetIntendedDockerReference() +} + +// GetManifest is like ImageSource.GetManifest, but the result is cached; it is OK to call this however often you need. +func (i *dockerImage) GetManifest() ([]byte, error) { if err := i.retrieveRawManifest(); err != nil { return nil, err } return i.rawManifest, nil } +// GetSignatures is like ImageSource.GetSignatures, but the result is cached; it is OK to call this however often you need. +func (i *dockerImage) GetSignatures() ([][]byte, error) { + if i.cachedSignatures == nil { + sigs, err := i.src.GetSignatures() + if err != nil { + return nil, err + } + i.cachedSignatures = sigs + } + return i.cachedSignatures, nil +} + func (i *dockerImage) Manifest() (types.ImageManifest, error) { // TODO(runcom): unused version param for now, default to docker v2-1 m, err := i.getSchema1Manifest() diff --git a/docker/docker_image_src.go b/docker/docker_image_src.go index 4b68e4ffeb..53bbd4251b 100644 --- a/docker/docker_image_src.go +++ b/docker/docker_image_src.go @@ -48,6 +48,13 @@ func NewDockerImageSource(img, certPath string, tlsVerify bool) (types.ImageSour return newDockerImageSource(img, certPath, tlsVerify) } +// GetIntendedDockerReference returns the full, unambiguous, Docker reference for this image, _as specified by the user_ +// (not as the image itself, or its underlying storage, claims). This can be used e.g. to determine which public keys are trusted for this image. +// May be "" if unknown. +func (s *dockerImageSource) GetIntendedDockerReference() string { + return fmt.Sprintf("%s:%s", s.ref.Name(), s.tag) +} + func (s *dockerImageSource) GetManifest() (manifest []byte, unverifiedCanonicalDigest string, err error) { url := fmt.Sprintf(manifestURL, s.ref.RemoteName(), s.tag) // TODO(runcom) set manifest version header! schema1 for now - then schema2 etc etc and v1 diff --git a/openshift/openshift.go b/openshift/openshift.go index d433207b59..2e549c0dc9 100644 --- a/openshift/openshift.go +++ b/openshift/openshift.go @@ -133,6 +133,13 @@ func (c *openshiftClient) doRequest(method, path string, requestBody []byte) ([] return body, nil } +// canonicalDockerReference returns a canonical reference we use for signing OpenShift images. +// FIXME: This is, strictly speaking, a namespace conflict with images placed in a Docker registry running on the same host. +// Do we need to do something else, perhaps disambiguate (port number?) or namespace Docker and OpenShift separately? +func (c *openshiftClient) canonicalDockerReference() string { + return fmt.Sprintf("%s/%s/%s:%s", c.baseURL.Host, c.namespace, c.stream, c.tag) +} + // convertDockerImageReference takes an image API DockerImageReference value and returns a reference we can actually use; // currently OpenShift stores the cluster-internal service IPs here, which are unusable from the outside. func (c *openshiftClient) convertDockerImageReference(ref string) (string, error) { @@ -179,6 +186,13 @@ func NewOpenshiftImageSource(imageName, certPath string, tlsVerify bool) (types. }, nil } +// GetIntendedDockerReference returns the full, unambiguous, Docker reference for this image, _as specified by the user_ +// (not as the image itself, or its underlying storage, claims). This can be used e.g. to determine which public keys are trusted for this image. +// May be "" if unknown. +func (s *openshiftImageSource) GetIntendedDockerReference() string { + return s.client.canonicalDockerReference() +} + func (s *openshiftImageSource) GetManifest() (manifest []byte, unverifiedCanonicalDigest string, err error) { if err := s.ensureImageIsResolved(); err != nil { return nil, "", err @@ -270,7 +284,7 @@ func NewOpenshiftImageDestination(imageName, certPath string, tlsVerify bool) (t } func (d *openshiftImageDestination) CanonicalDockerReference() (string, error) { - return fmt.Sprintf("%s/%s/%s:%s", d.client.baseURL.Host, d.client.namespace, d.client.stream, d.client.tag), nil + return d.client.canonicalDockerReference(), nil } func (d *openshiftImageDestination) PutManifest(manifest []byte) error { diff --git a/types/types.go b/types/types.go index 2acec58758..3c579f9375 100644 --- a/types/types.go +++ b/types/types.go @@ -30,6 +30,10 @@ type Repository interface { // ImageSource is a service, possibly remote (= slow), to download components of a single image. type ImageSource interface { + // GetIntendedDockerReference returns the full, unambiguous, Docker reference for this image, _as specified by the user_ + // (not as the image itself, or its underlying storage, claims). This can be used e.g. to determine which public keys are trusted for this image. + // May be "" if unknown. + GetIntendedDockerReference() string GetManifest() (manifest []byte, unverifiedCanonicalDigest string, err error) GetLayer(digest string) (io.ReadCloser, error) GetSignatures() ([][]byte, error) @@ -47,9 +51,16 @@ type ImageDestination interface { // Image is a Docker image in a repository. type Image interface { // ref to repository? + // GetIntendedDockerReference returns the full, unambiguous, Docker reference for this image, _as specified by the user_ + // (not as the image itself, or its underlying storage, claims). This can be used e.g. to determine which public keys are trusted for this image. + // May be "" if unknown. + GetIntendedDockerReference() string + // GetManifest is like ImageSource.GetManifest, but the result is cached; it is OK to call this however often you need. + GetManifest() ([]byte, error) + // GetSignatures is like ImageSource.GetSignatures, but the result is cached; it is OK to call this however often you need. + GetSignatures() ([][]byte, error) Layers(layers ...string) error // configure download directory? Call it DownloadLayers? Manifest() (ImageManifest, error) - RawManifest(version string) ([]byte, error) DockerTar() ([]byte, error) // ??? also, configure output directory }