mirror of https://github.com/containers/podman.git
Vendor in latest containers/image
Adds the tarball transport, which is used by the kpod import command Signed-off-by: Urvashi Mohnani <umohnani@redhat.com> Closes: #12 Approved by: rhatdan
This commit is contained in:
parent
df54adeaae
commit
d086beb7ab
|
|
@ -27,12 +27,23 @@ func newImageDestination(ref ociReference) (types.ImageDestination, error) {
|
||||||
if ref.image == "" {
|
if ref.image == "" {
|
||||||
return nil, errors.Errorf("cannot save image with empty image.ref.name")
|
return nil, errors.Errorf("cannot save image with empty image.ref.name")
|
||||||
}
|
}
|
||||||
index := imgspecv1.Index{
|
|
||||||
Versioned: imgspec.Versioned{
|
var index *imgspecv1.Index
|
||||||
SchemaVersion: 2,
|
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,
|
// 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,
|
Architecture: runtime.GOARCH,
|
||||||
OS: runtime.GOOS,
|
OS: runtime.GOOS,
|
||||||
}
|
}
|
||||||
d.index.Manifests = append(d.index.Manifests, desc)
|
d.addManifest(&desc)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func ensureDirectoryExists(path string) error {
|
func (d *ociImageDestination) addManifest(desc *imgspecv1.Descriptor) {
|
||||||
if _, err := os.Stat(path); err != nil && os.IsNotExist(err) {
|
for i, manifest := range d.index.Manifests {
|
||||||
if err := os.MkdirAll(path, 0755); err != nil {
|
if manifest.Annotations["org.opencontainers.image.ref.name"] == desc.Annotations["org.opencontainers.image.ref.name"] {
|
||||||
return err
|
// TODO Should there first be a cleanup based on the descriptor we are going to replace?
|
||||||
|
d.index.Manifests[i] = *desc
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
d.index.Manifests = append(d.index.Manifests, *desc)
|
||||||
}
|
|
||||||
|
|
||||||
// ensureParentDirectoryExists ensures the parent of the supplied path exists.
|
|
||||||
func ensureParentDirectoryExists(path string) error {
|
|
||||||
return ensureDirectoryExists(filepath.Dir(path))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *ociImageDestination) PutSignatures(signatures [][]byte) error {
|
func (d *ociImageDestination) PutSignatures(signatures [][]byte) error {
|
||||||
|
|
@ -231,3 +239,30 @@ func (d *ociImageDestination) Commit() error {
|
||||||
}
|
}
|
||||||
return ioutil.WriteFile(d.ref.indexPath(), indexJSON, 0644)
|
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
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -189,14 +189,25 @@ func (ref ociReference) NewImage(ctx *types.SystemContext) (types.Image, error)
|
||||||
return image.FromSource(src)
|
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())
|
indexJSON, err := os.Open(ref.indexPath())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return imgspecv1.Descriptor{}, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer indexJSON.Close()
|
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
|
return imgspecv1.Descriptor{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
// +build !containers_image_storage_stub
|
||||||
|
|
||||||
package storage
|
package storage
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
// +build !containers_image_storage_stub
|
||||||
|
|
||||||
package storage
|
package storage
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
// +build !containers_image_storage_stub
|
||||||
|
|
||||||
package storage
|
package storage
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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")
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
@ -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)
|
||||||
|
}
|
||||||
|
|
@ -13,8 +13,9 @@ import (
|
||||||
_ "github.com/containers/image/oci/archive"
|
_ "github.com/containers/image/oci/archive"
|
||||||
_ "github.com/containers/image/oci/layout"
|
_ "github.com/containers/image/oci/layout"
|
||||||
_ "github.com/containers/image/openshift"
|
_ "github.com/containers/image/openshift"
|
||||||
|
_ "github.com/containers/image/tarball"
|
||||||
// The ostree transport is registered by ostree*.go
|
// 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/transports"
|
||||||
"github.com/containers/image/types"
|
"github.com/containers/image/types"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
|
|
||||||
8
vendor/github.com/containers/image/transports/alltransports/storage.go
generated
vendored
Normal file
8
vendor/github.com/containers/image/transports/alltransports/storage.go
generated
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
// +build !containers_image_storage_stub
|
||||||
|
|
||||||
|
package alltransports
|
||||||
|
|
||||||
|
import (
|
||||||
|
// Register the storage transport
|
||||||
|
_ "github.com/containers/image/storage"
|
||||||
|
)
|
||||||
9
vendor/github.com/containers/image/transports/alltransports/storage_stub.go
generated
vendored
Normal file
9
vendor/github.com/containers/image/transports/alltransports/storage_stub.go
generated
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
// +build containers_image_storage_stub
|
||||||
|
|
||||||
|
package alltransports
|
||||||
|
|
||||||
|
import "github.com/containers/image/transports"
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
transports.Register(transports.NewStubTransport("storage"))
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue