Pick up changes to transports in containers/image

docker-archive and oci-archive now allow the image reference
for the destination to be empty.
Update tests for this new change.

Signed-off-by: umohnani8 <umohnani@redhat.com>
This commit is contained in:
umohnani8
2018-05-15 13:05:31 -04:00
parent 2d04db9ac8
commit 79449a358d
7 changed files with 39 additions and 31 deletions

View File

@@ -154,7 +154,10 @@ func (s *CopySuite) TestCopySimple(c *check.C) {
// docker v2s2 -> OCI image layout without image name // docker v2s2 -> OCI image layout without image name
ociDest = "busybox-latest-noimage" ociDest = "busybox-latest-noimage"
defer os.RemoveAll(ociDest) defer os.RemoveAll(ociDest)
assertSkopeoFails(c, ".*Error initializing destination oci:busybox-latest-noimage:: cannot save image with empty reference name.*", "copy", "docker://busybox:latest", "oci:"+ociDest) assertSkopeoSucceeds(c, "", "copy", "docker://busybox:latest", "oci:"+ociDest)
_, err = os.Stat(ociDest)
c.Assert(err, check.IsNil)
} }
// Check whether dir: images in dir1 and dir2 are equal, ignoring schema1 signatures. // Check whether dir: images in dir1 and dir2 are equal, ignoring schema1 signatures.

View File

@@ -17,10 +17,6 @@ type archiveImageDestination struct {
} }
func newImageDestination(sys *types.SystemContext, ref archiveReference) (types.ImageDestination, error) { func newImageDestination(sys *types.SystemContext, ref archiveReference) (types.ImageDestination, error) {
if ref.destinationRef == nil {
return nil, errors.Errorf("docker-archive: destination reference not supplied (must be of form <path>:<reference:tag>)")
}
// ref.path can be either a pipe or a regular file // ref.path can be either a pipe or a regular file
// in the case of a pipe, we require that we can open it for write // in the case of a pipe, we require that we can open it for write
// in the case of a regular file, we don't want to overwrite any pre-existing file // in the case of a regular file, we don't want to overwrite any pre-existing file

View File

@@ -41,7 +41,9 @@ func (t archiveTransport) ValidatePolicyConfigurationScope(scope string) error {
// archiveReference is an ImageReference for Docker images. // archiveReference is an ImageReference for Docker images.
type archiveReference struct { type archiveReference struct {
destinationRef reference.NamedTagged // only used for destinations // only used for destinations
// archiveReference.destinationRef is optional and can be nil for destinations as well.
destinationRef reference.NamedTagged
path string path string
} }

View File

@@ -23,10 +23,9 @@ import (
// Destination is a partial implementation of types.ImageDestination for writing to an io.Writer. // Destination is a partial implementation of types.ImageDestination for writing to an io.Writer.
type Destination struct { type Destination struct {
writer io.Writer writer io.Writer
tar *tar.Writer tar *tar.Writer
reference reference.NamedTagged repoTags []reference.NamedTagged
repoTags []reference.NamedTagged
// Other state. // Other state.
blobs map[digest.Digest]types.BlobInfo // list of already-sent blobs blobs map[digest.Digest]types.BlobInfo // list of already-sent blobs
config []byte config []byte
@@ -34,12 +33,15 @@ type Destination struct {
// NewDestination returns a tarfile.Destination for the specified io.Writer. // NewDestination returns a tarfile.Destination for the specified io.Writer.
func NewDestination(dest io.Writer, ref reference.NamedTagged) *Destination { func NewDestination(dest io.Writer, ref reference.NamedTagged) *Destination {
repoTags := []reference.NamedTagged{}
if ref != nil {
repoTags = append(repoTags, ref)
}
return &Destination{ return &Destination{
writer: dest, writer: dest,
tar: tar.NewWriter(dest), tar: tar.NewWriter(dest),
reference: ref, repoTags: repoTags,
repoTags: []reference.NamedTagged{ref}, blobs: make(map[digest.Digest]types.BlobInfo),
blobs: make(map[digest.Digest]types.BlobInfo),
} }
} }
@@ -168,8 +170,15 @@ func (d *Destination) ReapplyBlob(ctx context.Context, info types.BlobInfo) (typ
} }
func (d *Destination) createRepositoriesFile(rootLayerID string) error { func (d *Destination) createRepositoriesFile(rootLayerID string) error {
repositories := map[string]map[string]string{ repositories := map[string]map[string]string{}
d.reference.Name(): {d.reference.Tag(): rootLayerID}} for _, repoTag := range d.repoTags {
if val, ok := repositories[repoTag.Name()]; ok {
val[repoTag.Tag()] = rootLayerID
} else {
repositories[repoTag.Name()] = map[string]string{repoTag.Tag(): rootLayerID}
}
}
b, err := json.Marshal(repositories) b, err := json.Marshal(repositories)
if err != nil { if err != nil {
return errors.Wrap(err, "Error marshaling repositories") return errors.Wrap(err, "Error marshaling repositories")

View File

@@ -25,10 +25,6 @@ type ociImageDestination struct {
// newImageDestination returns an ImageDestination for writing to an existing directory. // newImageDestination returns an ImageDestination for writing to an existing directory.
func newImageDestination(sys *types.SystemContext, ref ociReference) (types.ImageDestination, error) { func newImageDestination(sys *types.SystemContext, ref ociReference) (types.ImageDestination, error) {
if ref.image == "" {
return nil, errors.Errorf("cannot save image with empty reference name (syntax must be of form <transport>:<path>:<reference>)")
}
var index *imgspecv1.Index var index *imgspecv1.Index
if indexExists(ref) { if indexExists(ref) {
var err error var err error
@@ -217,13 +213,11 @@ func (d *ociImageDestination) PutManifest(ctx context.Context, m []byte) error {
return err return err
} }
if d.ref.image == "" { if d.ref.image != "" {
return errors.Errorf("cannot save image with empyt image.ref.name") annotations := make(map[string]string)
annotations["org.opencontainers.image.ref.name"] = d.ref.image
desc.Annotations = annotations
} }
annotations := make(map[string]string)
annotations["org.opencontainers.image.ref.name"] = d.ref.image
desc.Annotations = annotations
desc.Platform = &imgspecv1.Platform{ desc.Platform = &imgspecv1.Platform{
Architecture: runtime.GOARCH, Architecture: runtime.GOARCH,
OS: runtime.GOOS, OS: runtime.GOOS,

View File

@@ -55,7 +55,9 @@ type ociReference struct {
// (But in general, we make no attempt to be completely safe against concurrent hostile filesystem modifications.) // (But in general, we make no attempt to be completely safe against concurrent hostile filesystem modifications.)
dir string // As specified by the user. May be relative, contain symlinks, etc. dir string // As specified by the user. May be relative, contain symlinks, etc.
resolvedDir string // Absolute path with no symlinks, at least at the time of its creation. Primarily used for policy namespaces. resolvedDir string // Absolute path with no symlinks, at least at the time of its creation. Primarily used for policy namespaces.
image string // If image=="", it means the only image in the index.json is used // If image=="", it means the "only image" in the index.json is used in the case it is a source
// for destinations, the image name annotation "image.ref.name" is not added to the index.json
image string
} }
// ParseReference converts a string, which should not start with the ImageTransport.Name prefix, into an OCI ImageReference. // ParseReference converts a string, which should not start with the ImageTransport.Name prefix, into an OCI ImageReference.

View File

@@ -149,13 +149,15 @@ func getPathToAuth(sys *types.SystemContext) (string, error) {
runtimeDir := os.Getenv("XDG_RUNTIME_DIR") runtimeDir := os.Getenv("XDG_RUNTIME_DIR")
if runtimeDir != "" { if runtimeDir != "" {
// This function does not in general need to separately check that the returned path exists; thats racy, and callers will fail accessing the file anyway.
// We are checking for os.IsNotExist here only to give the user better guidance what to do in this special case.
_, err := os.Stat(runtimeDir) _, err := os.Stat(runtimeDir)
if os.IsNotExist(err) { if os.IsNotExist(err) {
// This means the user set the XDG_RUNTIME_DIR variable and either forgot to create the directory // This means the user set the XDG_RUNTIME_DIR variable and either forgot to create the directory
// or made a typo while setting the environment variable // or made a typo while setting the environment variable,
// so we log the error and return an empty string as the path // so return an error referring to $XDG_RUNTIME_DIR instead of …/authCfgFileName inside.
return "", errors.Wrapf(err, "%q directory set by $XDG_RUNTIME_DIR does not exist. Either create the directory or unset $XDG_RUNTIME_DIR.", runtimeDir) return "", errors.Wrapf(err, "%q directory set by $XDG_RUNTIME_DIR does not exist. Either create the directory or unset $XDG_RUNTIME_DIR.", runtimeDir)
} } // else ignore err and let the caller fail accessing …/authCfgFileName.
runtimeDir = filepath.Join(runtimeDir, authCfg) runtimeDir = filepath.Join(runtimeDir, authCfg)
} else { } else {
runtimeDir = filepath.Join(defaultPath, authCfg, strconv.Itoa(os.Getuid())) runtimeDir = filepath.Join(defaultPath, authCfg, strconv.Itoa(os.Getuid()))