-
Notifications
You must be signed in to change notification settings - Fork 386
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add oci-archive transport that creates a tar archive of an image
Signed-off-by: umohnani8 <umohnani@redhat.com>
- Loading branch information
Showing
5 changed files
with
332 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
package archive | ||
|
||
import ( | ||
"io" | ||
"os" | ||
|
||
"github.com/containers/image/oci/layout" | ||
"github.com/containers/image/types" | ||
"github.com/containers/storage/pkg/archive" | ||
"github.com/pkg/errors" | ||
) | ||
|
||
type ociArchiveImageDestination struct { | ||
ref ociArchiveReference | ||
ociImgDest types.ImageDestination | ||
} | ||
|
||
// newImageDestination returns an ImageDestination for writing to an existing directory. | ||
func newImageDestination(ref ociArchiveReference, ctx *types.SystemContext) (types.ImageDestination, error) { | ||
ociImgDest, err := ref.ociRef.NewImageDestination(ctx) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return &ociArchiveImageDestination{ref: ref, | ||
ociImgDest: ociImgDest}, nil | ||
} | ||
|
||
// Reference returns the reference used to set up this destination. | ||
func (d *ociArchiveImageDestination) Reference() types.ImageReference { | ||
return d.ociImgDest.Reference() | ||
} | ||
|
||
// Close removes resources associated with an initialized ImageDestination, if any | ||
// Close deleted the temp directory of the oci-archive image | ||
func (d *ociArchiveImageDestination) Close() error { | ||
_, tmpDir, _ := layout.GetOciReference(d.ref.ociRef) | ||
defer os.RemoveAll(tmpDir) | ||
return d.ociImgDest.Close() | ||
} | ||
|
||
func (d *ociArchiveImageDestination) SupportedManifestMIMETypes() []string { | ||
return d.ociImgDest.SupportedManifestMIMETypes() | ||
} | ||
|
||
// SupportsSignatures returns an error (to be displayed to the user) if the destination certainly can't store signatures | ||
func (d *ociArchiveImageDestination) SupportsSignatures() error { | ||
return d.ociImgDest.SupportsSignatures() | ||
} | ||
|
||
// ShouldCompressLayers returns true iff it is desirable to compress layer blobs written to this destination | ||
func (d *ociArchiveImageDestination) ShouldCompressLayers() bool { | ||
return d.ociImgDest.ShouldCompressLayers() | ||
} | ||
|
||
// AcceptsForeignLayerURLs returns false iff foreign layers in manifest should be actually | ||
// uploaded to the image destination, true otherwise. | ||
func (d *ociArchiveImageDestination) AcceptsForeignLayerURLs() bool { | ||
return d.ociImgDest.AcceptsForeignLayerURLs() | ||
} | ||
|
||
// MustMatchRuntimeOS returns true iff the destination can store only images targeted for the current runtime OS. False otherwise | ||
func (d *ociArchiveImageDestination) MustMatchRuntimeOS() bool { | ||
return d.ociImgDest.MustMatchRuntimeOS() | ||
} | ||
|
||
// PutBlob writes contents of stream and returns data representing the result (with all data filled in). | ||
// inputInfo.Digest can be optionally provided if known; it is not mandatory for the implementation to verify it. | ||
// inputInfo.Size is the expected length of stream, if known. | ||
func (d *ociArchiveImageDestination) PutBlob(stream io.Reader, inputInfo types.BlobInfo) (types.BlobInfo, error) { | ||
return d.ociImgDest.PutBlob(stream, inputInfo) | ||
} | ||
|
||
// HasBlob returns true iff the image destination already contains a blob with the matching digest which can be reapplied using ReapplyBlob | ||
func (d *ociArchiveImageDestination) HasBlob(info types.BlobInfo) (bool, int64, error) { | ||
return d.ociImgDest.HasBlob(info) | ||
} | ||
|
||
func (d *ociArchiveImageDestination) ReapplyBlob(info types.BlobInfo) (types.BlobInfo, error) { | ||
return d.ociImgDest.ReapplyBlob(info) | ||
} | ||
|
||
// PutManifest writes manifest to the destination. | ||
func (d *ociArchiveImageDestination) PutManifest(m []byte) error { | ||
return d.ociImgDest.PutManifest(m) | ||
} | ||
|
||
func (d *ociArchiveImageDestination) PutSignatures(signatures [][]byte) error { | ||
return d.ociImgDest.PutSignatures(signatures) | ||
} | ||
|
||
// Commit marks the process of storing the image as successful and asks for the image to be persisted | ||
// after the directory is made, it is tarred up into a file and the directory is deleted | ||
func (d *ociArchiveImageDestination) Commit() error { | ||
if err := d.ociImgDest.Commit(); err != nil { | ||
return errors.Wrapf(err, "error storing image %q", d.ref.tag) | ||
} | ||
|
||
// path of directory to tar up | ||
_, src, _ := layout.GetOciReference(d.ref.ociRef) | ||
// path to save tarred up file | ||
dst := d.ref.resolvedDir | ||
if err := tar(src, dst); err != nil { | ||
return errors.Wrapf(err, "error tarring up directory %q", src) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
// tar converts the direstory at src and saves it to dst | ||
func tar(src, dst string) error { | ||
// input is a stream of bytes from the archive of the directory at path | ||
input, err := archive.Tar(src, 0) | ||
if err != nil { | ||
return errors.Wrapf(err, "error retrieving stream of bytes from %q", src) | ||
} | ||
|
||
// creates a temporary file | ||
outFile, err := os.Create(dst) | ||
if err != nil { | ||
return errors.Wrapf(err, "error creating tar file %q", dst) | ||
} | ||
defer outFile.Close() | ||
|
||
// copies the contents of the directory to the tar file | ||
_, err = io.Copy(outFile, input) | ||
|
||
return err | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
package archive | ||
|
||
import ( | ||
"io" | ||
|
||
"os" | ||
|
||
"github.com/Sirupsen/logrus" | ||
"github.com/containers/image/oci/layout" | ||
"github.com/containers/image/types" | ||
"github.com/containers/storage/pkg/archive" | ||
digest "github.com/opencontainers/go-digest" | ||
"github.com/pkg/errors" | ||
) | ||
|
||
type ociArchiveImageSource struct { | ||
ref ociArchiveReference | ||
ociImgSrc types.ImageSource | ||
} | ||
|
||
// newImageSource returns an ImageSource for reading from an existing directory. | ||
// newImageSource untars the file and saves it in a temp directory | ||
func newImageSource(ref ociArchiveReference, ctx *types.SystemContext, requestedManifestMIMETypes []string) (types.ImageSource, error) { | ||
// src is the path of the tarred file | ||
src := ref.resolvedDir | ||
// dst is the temp path of the directory after untarring the file | ||
_, dst, _ := layout.GetOciReference(ref.ociRef) | ||
if err := unTar(src, dst); err != nil { | ||
return nil, errors.Wrapf(err, "error untarring file %q", src) | ||
} | ||
|
||
ociImgSrc, err := ref.ociRef.NewImageSource(ctx, requestedManifestMIMETypes) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return &ociArchiveImageSource{ref: ref, | ||
ociImgSrc: ociImgSrc}, nil | ||
} | ||
|
||
// Reference returns the reference used to set up this source. | ||
func (s *ociArchiveImageSource) Reference() types.ImageReference { | ||
return s.ociImgSrc.Reference() | ||
} | ||
|
||
// Close removes resources associated with an initialized ImageSource, if any. | ||
// Close deletes the temporary directory at dst | ||
func (s *ociArchiveImageSource) Close() error { | ||
_, dst, _ := layout.GetOciReference(s.ref.ociRef) | ||
defer os.RemoveAll(dst) | ||
return s.ociImgSrc.Close() | ||
} | ||
|
||
// GetManifest returns the image's manifest along with its MIME type | ||
// (which may be empty when it can't be determined but the manifest is available). | ||
func (s *ociArchiveImageSource) GetManifest() ([]byte, string, error) { | ||
return s.ociImgSrc.GetManifest() | ||
} | ||
|
||
func (s *ociArchiveImageSource) GetTargetManifest(digest digest.Digest) ([]byte, string, error) { | ||
return s.ociImgSrc.GetTargetManifest(digest) | ||
} | ||
|
||
// GetBlob returns a stream for the specified blob, and the blob's size. | ||
func (s *ociArchiveImageSource) GetBlob(info types.BlobInfo) (io.ReadCloser, int64, error) { | ||
return s.ociImgSrc.GetBlob(info) | ||
} | ||
|
||
func (s *ociArchiveImageSource) GetSignatures() ([][]byte, error) { | ||
return s.ociImgSrc.GetSignatures() | ||
} | ||
|
||
// unTar unpacks the tar file at src and saves it at dst | ||
func unTar(src, dst string) error { | ||
if err := archive.UntarPath(src, dst); err != nil { | ||
logrus.Info("error untarring file") | ||
return errors.Wrapf(err, "error untarring file %q", src) | ||
} | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
package archive | ||
|
||
import ( | ||
"github.com/containers/image/docker/reference" | ||
"github.com/containers/image/image" | ||
"github.com/containers/image/oci/layout" | ||
"github.com/containers/image/transports" | ||
"github.com/containers/image/types" | ||
"github.com/pkg/errors" | ||
) | ||
|
||
func init() { | ||
transports.Register(Transport) | ||
} | ||
|
||
// Transport is an ImageTransport for OCI archive | ||
// it creates an oci-archive tar file by calling into the OCI transport | ||
// tarring the directory created by oci and deleting the directory | ||
var Transport = ociArchiveTransport{} | ||
|
||
type ociArchiveTransport struct{} | ||
|
||
// ociArchiveReference is an ImageReference for OCI Archive paths | ||
type ociArchiveReference struct { | ||
dir string | ||
resolvedDir string | ||
tag string | ||
ociRef types.ImageReference | ||
} | ||
|
||
func (t ociArchiveTransport) Name() string { | ||
return "oci-archive" | ||
} | ||
|
||
// ParseReference converts a string, which should not start with the ImageTransport.Name prefix | ||
// into an ImageReference. | ||
func (t ociArchiveTransport) ParseReference(reference string) (types.ImageReference, error) { | ||
// ociArchRef stores the dir, resolvedDir, and tag of the original path given by the user | ||
ociArchRef, err := layout.Transport.ParseReference(reference) | ||
if err != nil { | ||
return nil, errors.Wrapf(err, "error parsing reference %q", reference) | ||
} | ||
dir, resolvedDir, tag := layout.GetOciReference(ociArchRef) | ||
|
||
// tempRef is the path where the directory of the oci image created by oci is stored | ||
// this directory is deleted after a tar file is created from it | ||
tempRef := "/var/tmp/oci-image:" + tag | ||
// ociRef stores the dir, resolvedDir, and tag of the temporary path | ||
ociRef, err := layout.Transport.ParseReference(tempRef) | ||
if err != nil { | ||
return nil, errors.Wrapf(err, "error parsing temp reference %q", tempRef) | ||
} | ||
return ociArchiveReference{dir: dir, | ||
resolvedDir: resolvedDir, | ||
tag: tag, | ||
ociRef: ociRef, | ||
}, nil | ||
} | ||
|
||
// ValidatePolicyConfigurationScope checks that scope is a valid name for a signature.PolicyTransportScopes keys | ||
func (t ociArchiveTransport) ValidatePolicyConfigurationScope(scope string) error { | ||
return layout.Transport.ValidatePolicyConfigurationScope(scope) | ||
} | ||
|
||
func (ref ociArchiveReference) Transport() types.ImageTransport { | ||
return Transport | ||
} | ||
|
||
// StringWithinTransport returns a string representation of the reference, which MUST be such that | ||
// reference.Transport().ParseReference(reference.StringWithinTransport()) returns an equivalent reference. | ||
func (ref ociArchiveReference) StringWithinTransport() string { | ||
return ref.ociRef.StringWithinTransport() | ||
} | ||
|
||
// DockerReference returns a Docker reference associated with this reference | ||
func (ref ociArchiveReference) DockerReference() reference.Named { | ||
return nil | ||
} | ||
|
||
// PolicyConfigurationIdentity returns a string representation of the reference, suitable for policy lookup. | ||
func (ref ociArchiveReference) PolicyConfigurationIdentity() string { | ||
return ref.ociRef.PolicyConfigurationIdentity() | ||
} | ||
|
||
// PolicyConfigurationNamespaces returns a list of other policy configuration namespaces to search | ||
// for if explicit configuration for PolicyConfigurationIdentity() is not set | ||
func (ref ociArchiveReference) PolicyConfigurationNamespaces() []string { | ||
return ref.ociRef.PolicyConfigurationNamespaces() | ||
} | ||
|
||
// 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(ref, ctx, nil) | ||
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. | ||
// The caller must call .Close() on the returned ImageSource. | ||
func (ref ociArchiveReference) NewImageSource(ctx *types.SystemContext, requestedManifestMIMETypes []string) (types.ImageSource, error) { | ||
return newImageSource(ref, ctx, requestedManifestMIMETypes) | ||
} | ||
|
||
// NewImageDestination returns a types.ImageDestination for this reference. | ||
// The caller must call .Close() on the returned ImageDestination. | ||
func (ref ociArchiveReference) NewImageDestination(ctx *types.SystemContext) (types.ImageDestination, error) { | ||
return newImageDestination(ref, ctx) | ||
} | ||
|
||
// DeleteImage deletes the named image from the registry, if supported. | ||
func (ref ociArchiveReference) DeleteImage(ctx *types.SystemContext) error { | ||
return ref.ociRef.DeleteImage(ctx) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters