summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--vendor/github.com/containers/image/oci/layout/oci_dest.go67
-rw-r--r--vendor/github.com/containers/image/oci/layout/oci_transport.go19
-rw-r--r--vendor/github.com/containers/image/storage/storage_image.go2
-rw-r--r--vendor/github.com/containers/image/storage/storage_reference.go2
-rw-r--r--vendor/github.com/containers/image/storage/storage_transport.go2
-rw-r--r--vendor/github.com/containers/image/tarball/doc.go48
-rw-r--r--vendor/github.com/containers/image/tarball/tarball_reference.go88
-rw-r--r--vendor/github.com/containers/image/tarball/tarball_src.go250
-rw-r--r--vendor/github.com/containers/image/tarball/tarball_transport.go66
-rw-r--r--vendor/github.com/containers/image/transports/alltransports/alltransports.go3
-rw-r--r--vendor/github.com/containers/image/transports/alltransports/storage.go8
-rw-r--r--vendor/github.com/containers/image/transports/alltransports/storage_stub.go9
12 files changed, 543 insertions, 21 deletions
diff --git a/vendor/github.com/containers/image/oci/layout/oci_dest.go b/vendor/github.com/containers/image/oci/layout/oci_dest.go
index ce1e0c3e2..4c6d349ed 100644
--- a/vendor/github.com/containers/image/oci/layout/oci_dest.go
+++ b/vendor/github.com/containers/image/oci/layout/oci_dest.go
@@ -27,12 +27,23 @@ func newImageDestination(ref ociReference) (types.ImageDestination, error) {
if ref.image == "" {
return nil, errors.Errorf("cannot save image with empty image.ref.name")
}
- index := imgspecv1.Index{
- Versioned: imgspec.Versioned{
- SchemaVersion: 2,
- },
+
+ var index *imgspecv1.Index
+ if indexExists(ref) {
+ var err error
+ index, err = ref.getIndex()
+ if err != nil {
+ return nil, err
+ }
+ } else {
+ index = &imgspecv1.Index{
+ Versioned: imgspec.Versioned{
+ SchemaVersion: 2,
+ },
+ }
}
- return &ociImageDestination{ref: ref, index: index}, nil
+
+ return &ociImageDestination{ref: ref, index: *index}, nil
}
// Reference returns the reference used to set up this destination. Note that this should directly correspond to user's intent,
@@ -191,23 +202,20 @@ func (d *ociImageDestination) PutManifest(m []byte) error {
Architecture: runtime.GOARCH,
OS: runtime.GOOS,
}
- d.index.Manifests = append(d.index.Manifests, desc)
+ d.addManifest(&desc)
return nil
}
-func ensureDirectoryExists(path string) error {
- if _, err := os.Stat(path); err != nil && os.IsNotExist(err) {
- if err := os.MkdirAll(path, 0755); err != nil {
- return err
+func (d *ociImageDestination) addManifest(desc *imgspecv1.Descriptor) {
+ for i, manifest := range d.index.Manifests {
+ if manifest.Annotations["org.opencontainers.image.ref.name"] == desc.Annotations["org.opencontainers.image.ref.name"] {
+ // TODO Should there first be a cleanup based on the descriptor we are going to replace?
+ d.index.Manifests[i] = *desc
+ return
}
}
- return nil
-}
-
-// ensureParentDirectoryExists ensures the parent of the supplied path exists.
-func ensureParentDirectoryExists(path string) error {
- return ensureDirectoryExists(filepath.Dir(path))
+ d.index.Manifests = append(d.index.Manifests, *desc)
}
func (d *ociImageDestination) PutSignatures(signatures [][]byte) error {
@@ -231,3 +239,30 @@ func (d *ociImageDestination) Commit() error {
}
return ioutil.WriteFile(d.ref.indexPath(), indexJSON, 0644)
}
+
+func ensureDirectoryExists(path string) error {
+ if _, err := os.Stat(path); err != nil && os.IsNotExist(err) {
+ if err := os.MkdirAll(path, 0755); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// ensureParentDirectoryExists ensures the parent of the supplied path exists.
+func ensureParentDirectoryExists(path string) error {
+ return ensureDirectoryExists(filepath.Dir(path))
+}
+
+// indexExists checks whether the index location specified in the OCI reference exists.
+// The implementation is opinionated, since in case of unexpected errors false is returned
+func indexExists(ref ociReference) bool {
+ _, err := os.Stat(ref.indexPath())
+ if err == nil {
+ return true
+ }
+ if os.IsNotExist(err) {
+ return false
+ }
+ return true
+}
diff --git a/vendor/github.com/containers/image/oci/layout/oci_transport.go b/vendor/github.com/containers/image/oci/layout/oci_transport.go
index 312bc0e4e..77730f390 100644
--- a/vendor/github.com/containers/image/oci/layout/oci_transport.go
+++ b/vendor/github.com/containers/image/oci/layout/oci_transport.go
@@ -189,14 +189,25 @@ func (ref ociReference) NewImage(ctx *types.SystemContext) (types.Image, error)
return image.FromSource(src)
}
-func (ref ociReference) getManifestDescriptor() (imgspecv1.Descriptor, error) {
+// getIndex returns a pointer to the index references by this ociReference. If an error occurs opening an index nil is returned together
+// with an error.
+func (ref ociReference) getIndex() (*imgspecv1.Index, error) {
indexJSON, err := os.Open(ref.indexPath())
if err != nil {
- return imgspecv1.Descriptor{}, err
+ return nil, err
}
defer indexJSON.Close()
- index := imgspecv1.Index{}
- if err := json.NewDecoder(indexJSON).Decode(&index); err != nil {
+
+ index := &imgspecv1.Index{}
+ if err := json.NewDecoder(indexJSON).Decode(index); err != nil {
+ return nil, err
+ }
+ return index, nil
+}
+
+func (ref ociReference) getManifestDescriptor() (imgspecv1.Descriptor, error) {
+ index, err := ref.getIndex()
+ if err != nil {
return imgspecv1.Descriptor{}, err
}
diff --git a/vendor/github.com/containers/image/storage/storage_image.go b/vendor/github.com/containers/image/storage/storage_image.go
index 185e5f492..46d1057de 100644
--- a/vendor/github.com/containers/image/storage/storage_image.go
+++ b/vendor/github.com/containers/image/storage/storage_image.go
@@ -1,3 +1,5 @@
+// +build !containers_image_storage_stub
+
package storage
import (
diff --git a/vendor/github.com/containers/image/storage/storage_reference.go b/vendor/github.com/containers/image/storage/storage_reference.go
index fb8b0ccc6..b7da47ac5 100644
--- a/vendor/github.com/containers/image/storage/storage_reference.go
+++ b/vendor/github.com/containers/image/storage/storage_reference.go
@@ -1,3 +1,5 @@
+// +build !containers_image_storage_stub
+
package storage
import (
diff --git a/vendor/github.com/containers/image/storage/storage_transport.go b/vendor/github.com/containers/image/storage/storage_transport.go
index 39c81a581..d21cf02c8 100644
--- a/vendor/github.com/containers/image/storage/storage_transport.go
+++ b/vendor/github.com/containers/image/storage/storage_transport.go
@@ -1,3 +1,5 @@
+// +build !containers_image_storage_stub
+
package storage
import (
diff --git a/vendor/github.com/containers/image/tarball/doc.go b/vendor/github.com/containers/image/tarball/doc.go
new file mode 100644
index 000000000..a6ced5a0e
--- /dev/null
+++ b/vendor/github.com/containers/image/tarball/doc.go
@@ -0,0 +1,48 @@
+// Package tarball provides a way to generate images using one or more layer
+// tarballs and an optional template configuration.
+//
+// An example:
+// package main
+//
+// import (
+// "fmt"
+//
+// cp "github.com/containers/image/copy"
+// "github.com/containers/image/tarball"
+// "github.com/containers/image/transports/alltransports"
+//
+// imgspecv1 "github.com/containers/image/transports/alltransports"
+// )
+//
+// func imageFromTarball() {
+// src, err := alltransports.ParseImageName("tarball:/var/cache/mock/fedora-26-x86_64/root_cache/cache.tar.gz")
+// // - or -
+// // src, err := tarball.Transport.ParseReference("/var/cache/mock/fedora-26-x86_64/root_cache/cache.tar.gz")
+// if err != nil {
+// panic(err)
+// }
+// updater, ok := src.(tarball.ConfigUpdater)
+// if !ok {
+// panic("unexpected: a tarball reference should implement tarball.ConfigUpdater")
+// }
+// config := imgspecv1.Image{
+// Config: imgspecv1.ImageConfig{
+// Cmd: []string{"/bin/bash"},
+// },
+// }
+// annotations := make(map[string]string)
+// annotations[imgspecv1.AnnotationDescription] = "test image built from a mock root cache"
+// err = updater.ConfigUpdate(config, annotations)
+// if err != nil {
+// panic(err)
+// }
+// dest, err := alltransports.ParseImageName("docker-daemon:mock:latest")
+// if err != nil {
+// panic(err)
+// }
+// err = cp.Image(nil, dest, src, nil)
+// if err != nil {
+// panic(err)
+// }
+// }
+package tarball
diff --git a/vendor/github.com/containers/image/tarball/tarball_reference.go b/vendor/github.com/containers/image/tarball/tarball_reference.go
new file mode 100644
index 000000000..18967041a
--- /dev/null
+++ b/vendor/github.com/containers/image/tarball/tarball_reference.go
@@ -0,0 +1,88 @@
+package tarball
+
+import (
+ "fmt"
+ "os"
+ "strings"
+
+ "github.com/containers/image/docker/reference"
+ "github.com/containers/image/image"
+ "github.com/containers/image/types"
+
+ imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
+)
+
+// ConfigUpdater is an interface that ImageReferences for "tarball" images also
+// implement. It can be used to set values for a configuration, and to set
+// image annotations which will be present in the images returned by the
+// reference's NewImage() or NewImageSource() methods.
+type ConfigUpdater interface {
+ ConfigUpdate(config imgspecv1.Image, annotations map[string]string) error
+}
+
+type tarballReference struct {
+ transport types.ImageTransport
+ config imgspecv1.Image
+ annotations map[string]string
+ filenames []string
+ stdin []byte
+}
+
+// ConfigUpdate updates the image's default configuration and adds annotations
+// which will be visible in source images created using this reference.
+func (r *tarballReference) ConfigUpdate(config imgspecv1.Image, annotations map[string]string) error {
+ r.config = config
+ if r.annotations == nil {
+ r.annotations = make(map[string]string)
+ }
+ for k, v := range annotations {
+ r.annotations[k] = v
+ }
+ return nil
+}
+
+func (r *tarballReference) Transport() types.ImageTransport {
+ return r.transport
+}
+
+func (r *tarballReference) StringWithinTransport() string {
+ return strings.Join(r.filenames, ":")
+}
+
+func (r *tarballReference) DockerReference() reference.Named {
+ return nil
+}
+
+func (r *tarballReference) PolicyConfigurationIdentity() string {
+ return ""
+}
+
+func (r *tarballReference) PolicyConfigurationNamespaces() []string {
+ return nil
+}
+
+func (r *tarballReference) NewImage(ctx *types.SystemContext) (types.Image, error) {
+ src, err := r.NewImageSource(ctx)
+ if err != nil {
+ return nil, err
+ }
+ img, err := image.FromSource(src)
+ if err != nil {
+ src.Close()
+ return nil, err
+ }
+ return img, nil
+}
+
+func (r *tarballReference) DeleteImage(ctx *types.SystemContext) error {
+ for _, filename := range r.filenames {
+ if err := os.Remove(filename); err != nil && !os.IsNotExist(err) {
+ return fmt.Errorf("error removing %q: %v", filename, err)
+ }
+ }
+ return nil
+}
+
+func (r *tarballReference) NewImageDestination(ctx *types.SystemContext) (types.ImageDestination, error) {
+ return nil, fmt.Errorf("destination not implemented yet")
+}
diff --git a/vendor/github.com/containers/image/tarball/tarball_src.go b/vendor/github.com/containers/image/tarball/tarball_src.go
new file mode 100644
index 000000000..22b98c16c
--- /dev/null
+++ b/vendor/github.com/containers/image/tarball/tarball_src.go
@@ -0,0 +1,250 @@
+package tarball
+
+import (
+ "bytes"
+ "compress/gzip"
+ "context"
+ "encoding/json"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "runtime"
+ "strings"
+ "time"
+
+ "github.com/containers/image/types"
+
+ digest "github.com/opencontainers/go-digest"
+ imgspecs "github.com/opencontainers/image-spec/specs-go"
+ imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
+)
+
+type tarballImageSource struct {
+ reference tarballReference
+ filenames []string
+ diffIDs []digest.Digest
+ diffSizes []int64
+ blobIDs []digest.Digest
+ blobSizes []int64
+ blobTypes []string
+ config []byte
+ configID digest.Digest
+ configSize int64
+ manifest []byte
+}
+
+func (r *tarballReference) NewImageSource(ctx *types.SystemContext) (types.ImageSource, error) {
+ // Gather up the digests, sizes, and date information for all of the files.
+ filenames := []string{}
+ diffIDs := []digest.Digest{}
+ diffSizes := []int64{}
+ blobIDs := []digest.Digest{}
+ blobSizes := []int64{}
+ blobTimes := []time.Time{}
+ blobTypes := []string{}
+ for _, filename := range r.filenames {
+ var file *os.File
+ var err error
+ var blobSize int64
+ var blobTime time.Time
+ var reader io.Reader
+ if filename == "-" {
+ blobSize = int64(len(r.stdin))
+ blobTime = time.Now()
+ reader = bytes.NewReader(r.stdin)
+ } else {
+ file, err = os.Open(filename)
+ if err != nil {
+ return nil, fmt.Errorf("error opening %q for reading: %v", filename, err)
+ }
+ defer file.Close()
+ reader = file
+ fileinfo, err := file.Stat()
+ if err != nil {
+ return nil, fmt.Errorf("error reading size of %q: %v", filename, err)
+ }
+ blobSize = fileinfo.Size()
+ blobTime = fileinfo.ModTime()
+ }
+
+ // Default to assuming the layer is compressed.
+ layerType := imgspecv1.MediaTypeImageLayerGzip
+
+ // Set up to digest the file as it is.
+ blobIDdigester := digest.Canonical.Digester()
+ reader = io.TeeReader(reader, blobIDdigester.Hash())
+
+ // Set up to digest the file after we maybe decompress it.
+ diffIDdigester := digest.Canonical.Digester()
+ uncompressed, err := gzip.NewReader(reader)
+ if err == nil {
+ // It is compressed, so the diffID is the digest of the uncompressed version
+ reader = io.TeeReader(uncompressed, diffIDdigester.Hash())
+ } else {
+ // It is not compressed, so the diffID and the blobID are going to be the same
+ diffIDdigester = blobIDdigester
+ layerType = imgspecv1.MediaTypeImageLayer
+ uncompressed = nil
+ }
+ n, err := io.Copy(ioutil.Discard, reader)
+ if err != nil {
+ return nil, fmt.Errorf("error reading %q: %v", filename, err)
+ }
+ if uncompressed != nil {
+ uncompressed.Close()
+ }
+
+ // Grab our uncompressed and possibly-compressed digests and sizes.
+ filenames = append(filenames, filename)
+ diffIDs = append(diffIDs, diffIDdigester.Digest())
+ diffSizes = append(diffSizes, n)
+ blobIDs = append(blobIDs, blobIDdigester.Digest())
+ blobSizes = append(blobSizes, blobSize)
+ blobTimes = append(blobTimes, blobTime)
+ blobTypes = append(blobTypes, layerType)
+ }
+
+ // Build the rootfs and history for the configuration blob.
+ rootfs := imgspecv1.RootFS{
+ Type: "layers",
+ DiffIDs: diffIDs,
+ }
+ created := time.Time{}
+ history := []imgspecv1.History{}
+ // Pick up the layer comment from the configuration's history list, if one is set.
+ comment := "imported from tarball"
+ if len(r.config.History) > 0 && r.config.History[0].Comment != "" {
+ comment = r.config.History[0].Comment
+ }
+ for i := range diffIDs {
+ createdBy := fmt.Sprintf("/bin/sh -c #(nop) ADD file:%s in %c", diffIDs[i].Hex(), os.PathSeparator)
+ history = append(history, imgspecv1.History{
+ Created: &blobTimes[i],
+ CreatedBy: createdBy,
+ Comment: comment,
+ })
+ // Use the mtime of the most recently modified file as the image's creation time.
+ if created.Before(blobTimes[i]) {
+ created = blobTimes[i]
+ }
+ }
+
+ // Pick up other defaults from the config in the reference.
+ config := r.config
+ if config.Created == nil {
+ config.Created = &created
+ }
+ if config.Architecture == "" {
+ config.Architecture = runtime.GOARCH
+ }
+ if config.OS == "" {
+ config.OS = runtime.GOOS
+ }
+ config.RootFS = rootfs
+ config.History = history
+
+ // Encode and digest the image configuration blob.
+ configBytes, err := json.Marshal(&config)
+ if err != nil {
+ return nil, fmt.Errorf("error generating configuration blob for %q: %v", strings.Join(r.filenames, separator), err)
+ }
+ configID := digest.Canonical.FromBytes(configBytes)
+ configSize := int64(len(configBytes))
+
+ // Populate a manifest with the configuration blob and the file as the single layer.
+ layerDescriptors := []imgspecv1.Descriptor{}
+ for i := range blobIDs {
+ layerDescriptors = append(layerDescriptors, imgspecv1.Descriptor{
+ Digest: blobIDs[i],
+ Size: blobSizes[i],
+ MediaType: blobTypes[i],
+ })
+ }
+ annotations := make(map[string]string)
+ for k, v := range r.annotations {
+ annotations[k] = v
+ }
+ manifest := imgspecv1.Manifest{
+ Versioned: imgspecs.Versioned{
+ SchemaVersion: 2,
+ },
+ Config: imgspecv1.Descriptor{
+ Digest: configID,
+ Size: configSize,
+ MediaType: imgspecv1.MediaTypeImageConfig,
+ },
+ Layers: layerDescriptors,
+ Annotations: annotations,
+ }
+
+ // Encode the manifest.
+ manifestBytes, err := json.Marshal(&manifest)
+ if err != nil {
+ return nil, fmt.Errorf("error generating manifest for %q: %v", strings.Join(r.filenames, separator), err)
+ }
+
+ // Return the image.
+ src := &tarballImageSource{
+ reference: *r,
+ filenames: filenames,
+ diffIDs: diffIDs,
+ diffSizes: diffSizes,
+ blobIDs: blobIDs,
+ blobSizes: blobSizes,
+ blobTypes: blobTypes,
+ config: configBytes,
+ configID: configID,
+ configSize: configSize,
+ manifest: manifestBytes,
+ }
+
+ return src, nil
+}
+
+func (is *tarballImageSource) Close() error {
+ return nil
+}
+
+func (is *tarballImageSource) GetBlob(blobinfo types.BlobInfo) (io.ReadCloser, int64, error) {
+ // We should only be asked about things in the manifest. Maybe the configuration blob.
+ if blobinfo.Digest == is.configID {
+ return ioutil.NopCloser(bytes.NewBuffer(is.config)), is.configSize, nil
+ }
+ // Maybe one of the layer blobs.
+ for i := range is.blobIDs {
+ if blobinfo.Digest == is.blobIDs[i] {
+ // We want to read that layer: open the file or memory block and hand it back.
+ if is.filenames[i] == "-" {
+ return ioutil.NopCloser(bytes.NewBuffer(is.reference.stdin)), int64(len(is.reference.stdin)), nil
+ }
+ reader, err := os.Open(is.filenames[i])
+ if err != nil {
+ return nil, -1, fmt.Errorf("error opening %q: %v", is.filenames[i], err)
+ }
+ return reader, is.blobSizes[i], nil
+ }
+ }
+ return nil, -1, fmt.Errorf("no blob with digest %q found", blobinfo.Digest.String())
+}
+
+func (is *tarballImageSource) GetManifest() ([]byte, string, error) {
+ return is.manifest, imgspecv1.MediaTypeImageManifest, nil
+}
+
+func (*tarballImageSource) GetSignatures(context.Context) ([][]byte, error) {
+ return nil, nil
+}
+
+func (*tarballImageSource) GetTargetManifest(digest.Digest) ([]byte, string, error) {
+ return nil, "", fmt.Errorf("manifest lists are not supported by the %q transport", transportName)
+}
+
+func (is *tarballImageSource) Reference() types.ImageReference {
+ return &is.reference
+}
+
+// UpdatedLayerInfos() returns updated layer info that should be used when reading, in preference to values in the manifest, if specified.
+func (*tarballImageSource) UpdatedLayerInfos() []types.BlobInfo {
+ return nil
+}
diff --git a/vendor/github.com/containers/image/tarball/tarball_transport.go b/vendor/github.com/containers/image/tarball/tarball_transport.go
new file mode 100644
index 000000000..72558b5e8
--- /dev/null
+++ b/vendor/github.com/containers/image/tarball/tarball_transport.go
@@ -0,0 +1,66 @@
+package tarball
+
+import (
+ "errors"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "strings"
+
+ "github.com/containers/image/transports"
+ "github.com/containers/image/types"
+)
+
+const (
+ transportName = "tarball"
+ separator = ":"
+)
+
+var (
+ // Transport implements the types.ImageTransport interface for "tarball:" images,
+ // which are makeshift images constructed using one or more possibly-compressed tar
+ // archives.
+ Transport = &tarballTransport{}
+)
+
+type tarballTransport struct {
+}
+
+func (t *tarballTransport) Name() string {
+ return transportName
+}
+
+func (t *tarballTransport) ParseReference(reference string) (types.ImageReference, error) {
+ var stdin []byte
+ var err error
+ filenames := strings.Split(reference, separator)
+ for _, filename := range filenames {
+ if filename == "-" {
+ stdin, err = ioutil.ReadAll(os.Stdin)
+ if err != nil {
+ return nil, fmt.Errorf("error buffering stdin: %v", err)
+ }
+ continue
+ }
+ f, err := os.Open(filename)
+ if err != nil {
+ return nil, fmt.Errorf("error opening %q: %v", filename, err)
+ }
+ f.Close()
+ }
+ ref := &tarballReference{
+ transport: t,
+ filenames: filenames,
+ stdin: stdin,
+ }
+ return ref, nil
+}
+
+func (t *tarballTransport) ValidatePolicyConfigurationScope(scope string) error {
+ // See the explanation in daemonReference.PolicyConfigurationIdentity.
+ return errors.New(`tarball: does not support any scopes except the default "" one`)
+}
+
+func init() {
+ transports.Register(Transport)
+}
diff --git a/vendor/github.com/containers/image/transports/alltransports/alltransports.go b/vendor/github.com/containers/image/transports/alltransports/alltransports.go
index 4279b9d23..b4552df66 100644
--- a/vendor/github.com/containers/image/transports/alltransports/alltransports.go
+++ b/vendor/github.com/containers/image/transports/alltransports/alltransports.go
@@ -13,8 +13,9 @@ import (
_ "github.com/containers/image/oci/archive"
_ "github.com/containers/image/oci/layout"
_ "github.com/containers/image/openshift"
+ _ "github.com/containers/image/tarball"
// The ostree transport is registered by ostree*.go
- _ "github.com/containers/image/storage"
+ // The storage transport is registered by storage*.go
"github.com/containers/image/transports"
"github.com/containers/image/types"
"github.com/pkg/errors"
diff --git a/vendor/github.com/containers/image/transports/alltransports/storage.go b/vendor/github.com/containers/image/transports/alltransports/storage.go
new file mode 100644
index 000000000..a867c6644
--- /dev/null
+++ b/vendor/github.com/containers/image/transports/alltransports/storage.go
@@ -0,0 +1,8 @@
+// +build !containers_image_storage_stub
+
+package alltransports
+
+import (
+ // Register the storage transport
+ _ "github.com/containers/image/storage"
+)
diff --git a/vendor/github.com/containers/image/transports/alltransports/storage_stub.go b/vendor/github.com/containers/image/transports/alltransports/storage_stub.go
new file mode 100644
index 000000000..1b7b005eb
--- /dev/null
+++ b/vendor/github.com/containers/image/transports/alltransports/storage_stub.go
@@ -0,0 +1,9 @@
+// +build containers_image_storage_stub
+
+package alltransports
+
+import "github.com/containers/image/transports"
+
+func init() {
+ transports.Register(transports.NewStubTransport("storage"))
+}