mirror of
https://github.com/containers/skopeo.git
synced 2025-06-27 23:27:29 +00:00
Merge pull request #466 from nalind/update-storage
Bump containers/storage and containers/image
This commit is contained in:
commit
1c27d6918f
21
vendor/github.com/containers/image/docker/daemon/daemon_dest.go
generated
vendored
21
vendor/github.com/containers/image/docker/daemon/daemon_dest.go
generated
vendored
@ -14,6 +14,7 @@ import (
|
||||
|
||||
type daemonImageDestination struct {
|
||||
ref daemonReference
|
||||
mustMatchRuntimeOS bool
|
||||
*tarfile.Destination // Implements most of types.ImageDestination
|
||||
// For talking to imageLoadGoroutine
|
||||
goroutineCancel context.CancelFunc
|
||||
@ -33,6 +34,11 @@ func newImageDestination(ctx *types.SystemContext, ref daemonReference) (types.I
|
||||
return nil, errors.Errorf("Invalid destination docker-daemon:%s: a destination must be a name:tag", ref.StringWithinTransport())
|
||||
}
|
||||
|
||||
var mustMatchRuntimeOS = true
|
||||
if ctx != nil && ctx.DockerDaemonHost != client.DefaultDockerHost {
|
||||
mustMatchRuntimeOS = false
|
||||
}
|
||||
|
||||
c, err := newDockerClient(ctx)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Error initializing docker engine client")
|
||||
@ -46,12 +52,13 @@ func newImageDestination(ctx *types.SystemContext, ref daemonReference) (types.I
|
||||
go imageLoadGoroutine(goroutineContext, c, reader, statusChannel)
|
||||
|
||||
return &daemonImageDestination{
|
||||
ref: ref,
|
||||
Destination: tarfile.NewDestination(writer, namedTaggedRef),
|
||||
goroutineCancel: goroutineCancel,
|
||||
statusChannel: statusChannel,
|
||||
writer: writer,
|
||||
committed: false,
|
||||
ref: ref,
|
||||
mustMatchRuntimeOS: mustMatchRuntimeOS,
|
||||
Destination: tarfile.NewDestination(writer, namedTaggedRef),
|
||||
goroutineCancel: goroutineCancel,
|
||||
statusChannel: statusChannel,
|
||||
writer: writer,
|
||||
committed: false,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -80,7 +87,7 @@ func imageLoadGoroutine(ctx context.Context, c *client.Client, reader *io.PipeRe
|
||||
|
||||
// MustMatchRuntimeOS returns true iff the destination can store only images targeted for the current runtime OS. False otherwise.
|
||||
func (d *daemonImageDestination) MustMatchRuntimeOS() bool {
|
||||
return true
|
||||
return d.mustMatchRuntimeOS
|
||||
}
|
||||
|
||||
// Close removes resources associated with an initialized ImageDestination, if any.
|
||||
|
5
vendor/github.com/containers/image/docker/daemon/daemon_src.go
generated
vendored
5
vendor/github.com/containers/image/docker/daemon/daemon_src.go
generated
vendored
@ -6,13 +6,12 @@ import (
|
||||
"os"
|
||||
|
||||
"github.com/containers/image/docker/tarfile"
|
||||
"github.com/containers/image/internal/tmpdir"
|
||||
"github.com/containers/image/types"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
const temporaryDirectoryForBigFiles = "/var/tmp" // Do not use the system default of os.TempDir(), usually /tmp, because with systemd it could be a tmpfs.
|
||||
|
||||
type daemonImageSource struct {
|
||||
ref daemonReference
|
||||
*tarfile.Source // Implements most of types.ImageSource
|
||||
@ -47,7 +46,7 @@ func newImageSource(ctx *types.SystemContext, ref daemonReference) (types.ImageS
|
||||
defer inputStream.Close()
|
||||
|
||||
// FIXME: use SystemContext here.
|
||||
tarCopyFile, err := ioutil.TempFile(temporaryDirectoryForBigFiles, "docker-daemon-tar")
|
||||
tarCopyFile, err := ioutil.TempFile(tmpdir.TemporaryDirectoryForBigFiles(), "docker-daemon-tar")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
5
vendor/github.com/containers/image/docker/tarfile/dest.go
generated
vendored
5
vendor/github.com/containers/image/docker/tarfile/dest.go
generated
vendored
@ -11,6 +11,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/containers/image/docker/reference"
|
||||
"github.com/containers/image/internal/tmpdir"
|
||||
"github.com/containers/image/manifest"
|
||||
"github.com/containers/image/types"
|
||||
"github.com/opencontainers/go-digest"
|
||||
@ -18,8 +19,6 @@ import (
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
const temporaryDirectoryForBigFiles = "/var/tmp" // Do not use the system default of os.TempDir(), usually /tmp, because with systemd it could be a tmpfs.
|
||||
|
||||
// Destination is a partial implementation of types.ImageDestination for writing to an io.Writer.
|
||||
type Destination struct {
|
||||
writer io.Writer
|
||||
@ -107,7 +106,7 @@ func (d *Destination) PutBlob(stream io.Reader, inputInfo types.BlobInfo) (types
|
||||
|
||||
if inputInfo.Size == -1 { // Ouch, we need to stream the blob into a temporary file just to determine the size.
|
||||
logrus.Debugf("docker tarfile: input with unknown size, streaming to disk first ...")
|
||||
streamCopy, err := ioutil.TempFile(temporaryDirectoryForBigFiles, "docker-tarfile-blob")
|
||||
streamCopy, err := ioutil.TempFile(tmpdir.TemporaryDirectoryForBigFiles(), "docker-tarfile-blob")
|
||||
if err != nil {
|
||||
return types.BlobInfo{}, err
|
||||
}
|
||||
|
19
vendor/github.com/containers/image/internal/tmpdir/tmpdir.go
generated
vendored
Normal file
19
vendor/github.com/containers/image/internal/tmpdir/tmpdir.go
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
package tmpdir
|
||||
|
||||
import (
|
||||
"os"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// TemporaryDirectoryForBigFiles returns a directory for temporary (big) files.
|
||||
// On non Windows systems it avoids the use of os.TempDir(), because the default temporary directory usually falls under /tmp
|
||||
// which on systemd based systems could be the unsuitable tmpfs filesystem.
|
||||
func TemporaryDirectoryForBigFiles() string {
|
||||
var temporaryDirectoryForBigFiles string
|
||||
if runtime.GOOS == "windows" {
|
||||
temporaryDirectoryForBigFiles = os.TempDir()
|
||||
} else {
|
||||
temporaryDirectoryForBigFiles = "/var/tmp"
|
||||
}
|
||||
return temporaryDirectoryForBigFiles
|
||||
}
|
62
vendor/github.com/containers/image/oci/archive/oci_transport.go
generated
vendored
62
vendor/github.com/containers/image/oci/archive/oci_transport.go
generated
vendored
@ -4,13 +4,13 @@ import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/containers/image/directory/explicitfilepath"
|
||||
"github.com/containers/image/docker/reference"
|
||||
"github.com/containers/image/image"
|
||||
"github.com/containers/image/internal/tmpdir"
|
||||
"github.com/containers/image/oci/internal"
|
||||
ocilayout "github.com/containers/image/oci/layout"
|
||||
"github.com/containers/image/transports"
|
||||
"github.com/containers/image/types"
|
||||
@ -48,51 +48,12 @@ func (t ociArchiveTransport) ParseReference(reference string) (types.ImageRefere
|
||||
|
||||
// ValidatePolicyConfigurationScope checks that scope is a valid name for a signature.PolicyTransportScopes keys
|
||||
func (t ociArchiveTransport) ValidatePolicyConfigurationScope(scope string) error {
|
||||
var file string
|
||||
sep := strings.SplitN(scope, ":", 2)
|
||||
file = sep[0]
|
||||
|
||||
if len(sep) == 2 {
|
||||
image := sep[1]
|
||||
if !refRegexp.MatchString(image) {
|
||||
return errors.Errorf("Invalid image %s", image)
|
||||
}
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(file, "/") {
|
||||
return errors.Errorf("Invalid scope %s: must be an absolute path", scope)
|
||||
}
|
||||
// Refuse also "/", otherwise "/" and "" would have the same semantics,
|
||||
// and "" could be unexpectedly shadowed by the "/" entry.
|
||||
// (Note: we do allow "/:someimage", a bit ridiculous but why refuse it?)
|
||||
if scope == "/" {
|
||||
return errors.New(`Invalid scope "/": Use the generic default scope ""`)
|
||||
}
|
||||
cleaned := filepath.Clean(file)
|
||||
if cleaned != file {
|
||||
return errors.Errorf(`Invalid scope %s: Uses non-canonical path format, perhaps try with path %s`, scope, cleaned)
|
||||
}
|
||||
return nil
|
||||
return internal.ValidateScope(scope)
|
||||
}
|
||||
|
||||
// annotation spex from https://github.com/opencontainers/image-spec/blob/master/annotations.md#pre-defined-annotation-keys
|
||||
const (
|
||||
separator = `(?:[-._:@+]|--)`
|
||||
alphanum = `(?:[A-Za-z0-9]+)`
|
||||
component = `(?:` + alphanum + `(?:` + separator + alphanum + `)*)`
|
||||
)
|
||||
|
||||
var refRegexp = regexp.MustCompile(`^` + component + `(?:/` + component + `)*$`)
|
||||
|
||||
// ParseReference converts a string, which should not start with the ImageTransport.Name prefix, into an OCI ImageReference.
|
||||
func ParseReference(reference string) (types.ImageReference, error) {
|
||||
var file, image string
|
||||
sep := strings.SplitN(reference, ":", 2)
|
||||
file = sep[0]
|
||||
|
||||
if len(sep) == 2 {
|
||||
image = sep[1]
|
||||
}
|
||||
file, image := internal.SplitPathAndImage(reference)
|
||||
return NewReference(file, image)
|
||||
}
|
||||
|
||||
@ -102,14 +63,15 @@ func NewReference(file, image string) (types.ImageReference, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// This is necessary to prevent directory paths returned by PolicyConfigurationNamespaces
|
||||
// from being ambiguous with values of PolicyConfigurationIdentity.
|
||||
if strings.Contains(resolved, ":") {
|
||||
return nil, errors.Errorf("Invalid OCI reference %s:%s: path %s contains a colon", file, image, resolved)
|
||||
|
||||
if err := internal.ValidateOCIPath(file); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(image) > 0 && !refRegexp.MatchString(image) {
|
||||
return nil, errors.Errorf("Invalid image %s", image)
|
||||
|
||||
if err := internal.ValidateImageName(image); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ociArchiveReference{file: file, resolvedFile: resolved, image: image}, nil
|
||||
}
|
||||
|
||||
@ -197,7 +159,7 @@ func (t *tempDirOCIRef) deleteTempDir() error {
|
||||
|
||||
// createOCIRef creates the oci reference of the image
|
||||
func createOCIRef(image string) (tempDirOCIRef, error) {
|
||||
dir, err := ioutil.TempDir("/var/tmp", "oci")
|
||||
dir, err := ioutil.TempDir(tmpdir.TemporaryDirectoryForBigFiles(), "oci")
|
||||
if err != nil {
|
||||
return tempDirOCIRef{}, errors.Wrapf(err, "error creating temp directory")
|
||||
}
|
||||
|
126
vendor/github.com/containers/image/oci/internal/oci_util.go
generated
vendored
Normal file
126
vendor/github.com/containers/image/oci/internal/oci_util.go
generated
vendored
Normal file
@ -0,0 +1,126 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// annotation spex from https://github.com/opencontainers/image-spec/blob/master/annotations.md#pre-defined-annotation-keys
|
||||
const (
|
||||
separator = `(?:[-._:@+]|--)`
|
||||
alphanum = `(?:[A-Za-z0-9]+)`
|
||||
component = `(?:` + alphanum + `(?:` + separator + alphanum + `)*)`
|
||||
)
|
||||
|
||||
var refRegexp = regexp.MustCompile(`^` + component + `(?:/` + component + `)*$`)
|
||||
var windowsRefRegexp = regexp.MustCompile(`^([a-zA-Z]:\\.+?):(.*)$`)
|
||||
|
||||
// ValidateImageName returns nil if the image name is empty or matches the open-containers image name specs.
|
||||
// In any other case an error is returned.
|
||||
func ValidateImageName(image string) error {
|
||||
if len(image) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
var err error
|
||||
if !refRegexp.MatchString(image) {
|
||||
err = errors.Errorf("Invalid image %s", image)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// SplitPathAndImage tries to split the provided OCI reference into the OCI path and image.
|
||||
// Neither path nor image parts are validated at this stage.
|
||||
func SplitPathAndImage(reference string) (string, string) {
|
||||
if runtime.GOOS == "windows" {
|
||||
return splitPathAndImageWindows(reference)
|
||||
}
|
||||
return splitPathAndImageNonWindows(reference)
|
||||
}
|
||||
|
||||
func splitPathAndImageWindows(reference string) (string, string) {
|
||||
groups := windowsRefRegexp.FindStringSubmatch(reference)
|
||||
// nil group means no match
|
||||
if groups == nil {
|
||||
return reference, ""
|
||||
}
|
||||
|
||||
// we expect three elements. First one full match, second the capture group for the path and
|
||||
// the third the capture group for the image
|
||||
if len(groups) != 3 {
|
||||
return reference, ""
|
||||
}
|
||||
return groups[1], groups[2]
|
||||
}
|
||||
|
||||
func splitPathAndImageNonWindows(reference string) (string, string) {
|
||||
sep := strings.SplitN(reference, ":", 2)
|
||||
path := sep[0]
|
||||
|
||||
var image string
|
||||
if len(sep) == 2 {
|
||||
image = sep[1]
|
||||
}
|
||||
return path, image
|
||||
}
|
||||
|
||||
// ValidateOCIPath takes the OCI path and validates it.
|
||||
func ValidateOCIPath(path string) error {
|
||||
if runtime.GOOS == "windows" {
|
||||
// On Windows we must allow for a ':' as part of the path
|
||||
if strings.Count(path, ":") > 1 {
|
||||
return errors.Errorf("Invalid OCI reference: path %s contains more than one colon", path)
|
||||
}
|
||||
} else {
|
||||
if strings.Contains(path, ":") {
|
||||
return errors.Errorf("Invalid OCI reference: path %s contains a colon", path)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidateScope validates a policy configuration scope for an OCI transport.
|
||||
func ValidateScope(scope string) error {
|
||||
var err error
|
||||
if runtime.GOOS == "windows" {
|
||||
err = validateScopeWindows(scope)
|
||||
} else {
|
||||
err = validateScopeNonWindows(scope)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cleaned := filepath.Clean(scope)
|
||||
if cleaned != scope {
|
||||
return errors.Errorf(`Invalid scope %s: Uses non-canonical path format, perhaps try with path %s`, scope, cleaned)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateScopeWindows(scope string) error {
|
||||
matched, _ := regexp.Match(`^[a-zA-Z]:\\`, []byte(scope))
|
||||
if !matched {
|
||||
return errors.Errorf("Invalid scope '%s'. Must be an absolute path", scope)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateScopeNonWindows(scope string) error {
|
||||
if !strings.HasPrefix(scope, "/") {
|
||||
return errors.Errorf("Invalid scope %s: must be an absolute path", scope)
|
||||
}
|
||||
|
||||
// Refuse also "/", otherwise "/" and "" would have the same semantics,
|
||||
// and "" could be unexpectedly shadowed by the "/" entry.
|
||||
if scope == "/" {
|
||||
return errors.New(`Invalid scope "/": Use the generic default scope ""`)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
20
vendor/github.com/containers/image/oci/layout/oci_dest.go
generated
vendored
20
vendor/github.com/containers/image/oci/layout/oci_dest.go
generated
vendored
@ -112,8 +112,11 @@ func (d *ociImageDestination) PutBlob(stream io.Reader, inputInfo types.BlobInfo
|
||||
return types.BlobInfo{}, err
|
||||
}
|
||||
succeeded := false
|
||||
explicitClosed := false
|
||||
defer func() {
|
||||
blobFile.Close()
|
||||
if !explicitClosed {
|
||||
blobFile.Close()
|
||||
}
|
||||
if !succeeded {
|
||||
os.Remove(blobFile.Name())
|
||||
}
|
||||
@ -133,8 +136,15 @@ func (d *ociImageDestination) PutBlob(stream io.Reader, inputInfo types.BlobInfo
|
||||
if err := blobFile.Sync(); err != nil {
|
||||
return types.BlobInfo{}, err
|
||||
}
|
||||
if err := blobFile.Chmod(0644); err != nil {
|
||||
return types.BlobInfo{}, err
|
||||
|
||||
// On POSIX systems, blobFile was created with mode 0600, so we need to make it readable.
|
||||
// On Windows, the “permissions of newly created files” argument to syscall.Open is
|
||||
// ignored and the file is already readable; besides, blobFile.Chmod, i.e. syscall.Fchmod,
|
||||
// always fails on Windows.
|
||||
if runtime.GOOS != "windows" {
|
||||
if err := blobFile.Chmod(0644); err != nil {
|
||||
return types.BlobInfo{}, err
|
||||
}
|
||||
}
|
||||
|
||||
blobPath, err := d.ref.blobPath(computedDigest, d.sharedBlobDir)
|
||||
@ -144,6 +154,10 @@ func (d *ociImageDestination) PutBlob(stream io.Reader, inputInfo types.BlobInfo
|
||||
if err := ensureParentDirectoryExists(blobPath); err != nil {
|
||||
return types.BlobInfo{}, err
|
||||
}
|
||||
|
||||
// need to explicitly close the file, since a rename won't otherwise not work on Windows
|
||||
blobFile.Close()
|
||||
explicitClosed = true
|
||||
if err := os.Rename(blobFile.Name(), blobPath); err != nil {
|
||||
return types.BlobInfo{}, err
|
||||
}
|
||||
|
58
vendor/github.com/containers/image/oci/layout/oci_transport.go
generated
vendored
58
vendor/github.com/containers/image/oci/layout/oci_transport.go
generated
vendored
@ -5,12 +5,12 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/containers/image/directory/explicitfilepath"
|
||||
"github.com/containers/image/docker/reference"
|
||||
"github.com/containers/image/image"
|
||||
"github.com/containers/image/oci/internal"
|
||||
"github.com/containers/image/transports"
|
||||
"github.com/containers/image/types"
|
||||
"github.com/opencontainers/go-digest"
|
||||
@ -36,45 +36,12 @@ func (t ociTransport) ParseReference(reference string) (types.ImageReference, er
|
||||
return ParseReference(reference)
|
||||
}
|
||||
|
||||
// annotation spex from https://github.com/opencontainers/image-spec/blob/master/annotations.md#pre-defined-annotation-keys
|
||||
const (
|
||||
separator = `(?:[-._:@+]|--)`
|
||||
alphanum = `(?:[A-Za-z0-9]+)`
|
||||
component = `(?:` + alphanum + `(?:` + separator + alphanum + `)*)`
|
||||
)
|
||||
|
||||
var refRegexp = regexp.MustCompile(`^` + component + `(?:/` + component + `)*$`)
|
||||
|
||||
// ValidatePolicyConfigurationScope checks that scope is a valid name for a signature.PolicyTransportScopes keys
|
||||
// (i.e. a valid PolicyConfigurationIdentity() or PolicyConfigurationNamespaces() return value).
|
||||
// It is acceptable to allow an invalid value which will never be matched, it can "only" cause user confusion.
|
||||
// scope passed to this function will not be "", that value is always allowed.
|
||||
func (t ociTransport) ValidatePolicyConfigurationScope(scope string) error {
|
||||
var dir string
|
||||
sep := strings.SplitN(scope, ":", 2)
|
||||
dir = sep[0]
|
||||
|
||||
if len(sep) == 2 {
|
||||
image := sep[1]
|
||||
if !refRegexp.MatchString(image) {
|
||||
return errors.Errorf("Invalid image %s", image)
|
||||
}
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(dir, "/") {
|
||||
return errors.Errorf("Invalid scope %s: must be an absolute path", scope)
|
||||
}
|
||||
// Refuse also "/", otherwise "/" and "" would have the same semantics,
|
||||
// and "" could be unexpectedly shadowed by the "/" entry.
|
||||
// (Note: we do allow "/:someimage", a bit ridiculous but why refuse it?)
|
||||
if scope == "/" {
|
||||
return errors.New(`Invalid scope "/": Use the generic default scope ""`)
|
||||
}
|
||||
cleaned := filepath.Clean(dir)
|
||||
if cleaned != dir {
|
||||
return errors.Errorf(`Invalid scope %s: Uses non-canonical path format, perhaps try with path %s`, scope, cleaned)
|
||||
}
|
||||
return nil
|
||||
return internal.ValidateScope(scope)
|
||||
}
|
||||
|
||||
// ociReference is an ImageReference for OCI directory paths.
|
||||
@ -92,13 +59,7 @@ type ociReference struct {
|
||||
|
||||
// ParseReference converts a string, which should not start with the ImageTransport.Name prefix, into an OCI ImageReference.
|
||||
func ParseReference(reference string) (types.ImageReference, error) {
|
||||
var dir, image string
|
||||
sep := strings.SplitN(reference, ":", 2)
|
||||
dir = sep[0]
|
||||
|
||||
if len(sep) == 2 {
|
||||
image = sep[1]
|
||||
}
|
||||
dir, image := internal.SplitPathAndImage(reference)
|
||||
return NewReference(dir, image)
|
||||
}
|
||||
|
||||
@ -111,14 +72,15 @@ func NewReference(dir, image string) (types.ImageReference, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// This is necessary to prevent directory paths returned by PolicyConfigurationNamespaces
|
||||
// from being ambiguous with values of PolicyConfigurationIdentity.
|
||||
if strings.Contains(resolved, ":") {
|
||||
return nil, errors.Errorf("Invalid OCI reference %s:%s: path %s contains a colon", dir, image, resolved)
|
||||
|
||||
if err := internal.ValidateOCIPath(dir); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(image) > 0 && !refRegexp.MatchString(image) {
|
||||
return nil, errors.Errorf("Invalid image %s", image)
|
||||
|
||||
if err = internal.ValidateImageName(image); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ociReference{dir: dir, resolvedDir: resolved, image: image}, nil
|
||||
}
|
||||
|
||||
|
6
vendor/github.com/containers/image/storage/storage_transport.go
generated
vendored
6
vendor/github.com/containers/image/storage/storage_transport.go
generated
vendored
@ -159,11 +159,11 @@ func (s storageTransport) ParseStoreReference(store storage.Store, ref string) (
|
||||
refname = verboseName(name)
|
||||
}
|
||||
if refname == "" {
|
||||
logrus.Debugf("parsed reference into %q", storeSpec+"@"+id)
|
||||
logrus.Debugf("parsed reference to id into %q", storeSpec+"@"+id)
|
||||
} else if id == "" {
|
||||
logrus.Debugf("parsed reference into %q", storeSpec+refname)
|
||||
logrus.Debugf("parsed reference to refname into %q", storeSpec+refname)
|
||||
} else {
|
||||
logrus.Debugf("parsed reference into %q", storeSpec+refname+"@"+id)
|
||||
logrus.Debugf("parsed reference to refname@id into %q", storeSpec+refname+"@"+id)
|
||||
}
|
||||
return newReference(storageTransport{store: store, defaultUIDMap: s.defaultUIDMap, defaultGIDMap: s.defaultGIDMap}, refname, id, name), nil
|
||||
}
|
||||
|
110
vendor/github.com/containers/storage/drivers/overlay/overlay.go
generated
vendored
110
vendor/github.com/containers/storage/drivers/overlay/overlay.go
generated
vendored
@ -3,7 +3,6 @@
|
||||
package overlay
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
@ -26,7 +25,6 @@ import (
|
||||
"github.com/containers/storage/pkg/locker"
|
||||
"github.com/containers/storage/pkg/mount"
|
||||
"github.com/containers/storage/pkg/parsers"
|
||||
"github.com/containers/storage/pkg/parsers/kernel"
|
||||
"github.com/containers/storage/pkg/system"
|
||||
units "github.com/docker/go-units"
|
||||
"github.com/opencontainers/selinux/go-selinux/label"
|
||||
@ -124,22 +122,6 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := supportsOverlay(); err != nil {
|
||||
return nil, errors.Wrap(graphdriver.ErrNotSupported, "kernel does not support overlay fs")
|
||||
}
|
||||
|
||||
// require kernel 4.0.0 to ensure multiple lower dirs are supported
|
||||
v, err := kernel.GetKernelVersion()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if kernel.CompareKernelVersion(*v, kernel.VersionInfo{Kernel: 4, Major: 0, Minor: 0}) < 0 {
|
||||
if !opts.overrideKernelCheck {
|
||||
return nil, errors.Wrap(graphdriver.ErrNotSupported, "kernel too old to provide multiple lowers feature for overlay")
|
||||
}
|
||||
logrus.Warn("Using pre-4.0.0 kernel for overlay, mount failures may require kernel update")
|
||||
}
|
||||
|
||||
fsMagic, err := graphdriver.GetFSMagic(home)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -153,22 +135,18 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
|
||||
case graphdriver.FsMagicAufs, graphdriver.FsMagicZfs, graphdriver.FsMagicOverlay, graphdriver.FsMagicEcryptfs:
|
||||
logrus.Errorf("'overlay' is not supported over %s", backingFs)
|
||||
return nil, errors.Wrapf(graphdriver.ErrIncompatibleFS, "'overlay' is not supported over %s", backingFs)
|
||||
case graphdriver.FsMagicBtrfs:
|
||||
// Support for OverlayFS on BTRFS was added in kernel 4.7
|
||||
// See https://btrfs.wiki.kernel.org/index.php/Changelog
|
||||
if kernel.CompareKernelVersion(*v, kernel.VersionInfo{Kernel: 4, Major: 7, Minor: 0}) < 0 {
|
||||
if !opts.overrideKernelCheck {
|
||||
logrus.Errorf("'overlay' requires kernel 4.7 to use on %s", backingFs)
|
||||
return nil, errors.Wrapf(graphdriver.ErrIncompatibleFS, "'overlay' requires kernel 4.7 to use on %s", backingFs)
|
||||
}
|
||||
logrus.Warn("Using pre-4.7.0 kernel for overlay on btrfs, may require kernel update")
|
||||
}
|
||||
}
|
||||
|
||||
rootUID, rootGID, err := idtools.GetRootUIDGID(uidMaps, gidMaps)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
supportsDType, err := supportsOverlay(home, fsMagic, rootUID, rootGID)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(graphdriver.ErrNotSupported, "kernel does not support overlay fs")
|
||||
}
|
||||
|
||||
// Create the driver home dir
|
||||
if err := idtools.MkdirAllAs(path.Join(home, linkDir), 0700, rootUID, rootGID); err != nil && !os.IsExist(err) {
|
||||
return nil, err
|
||||
@ -178,16 +156,6 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
|
||||
return nil, err
|
||||
}
|
||||
|
||||
supportsDType, err := fsutils.SupportsDType(home)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !supportsDType {
|
||||
logrus.Warn(overlayutils.ErrDTypeNotSupported("overlay", backingFs))
|
||||
// TODO: Will make fatal when CRI-O Has AMI built on RHEL7.4
|
||||
// return nil, overlayutils.ErrDTypeNotSupported("overlay", backingFs)
|
||||
}
|
||||
|
||||
d := &Driver{
|
||||
name: "overlay",
|
||||
home: home,
|
||||
@ -210,10 +178,10 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
|
||||
}
|
||||
} else if opts.quota.Size > 0 {
|
||||
// if xfs is not the backing fs then error out if the storage-opt overlay.size is used.
|
||||
return nil, fmt.Errorf("Storage Option overlay.size only supported for backingFS XFS. Found %v", backingFs)
|
||||
return nil, fmt.Errorf("Storage option overlay.size only supported for backingFS XFS. Found %v", backingFs)
|
||||
}
|
||||
|
||||
logrus.Debugf("backingFs=%s, projectQuotaSupported=%v", backingFs, projectQuotaSupported)
|
||||
logrus.Debugf("backingFs=%s, projectQuotaSupported=%v", backingFs, projectQuotaSupported)
|
||||
|
||||
return d, nil
|
||||
}
|
||||
@ -264,25 +232,59 @@ func parseOptions(options []string) (*overlayOptions, error) {
|
||||
return o, nil
|
||||
}
|
||||
|
||||
func supportsOverlay() error {
|
||||
// We can try to modprobe overlay first before looking at
|
||||
// proc/filesystems for when overlay is supported
|
||||
func supportsOverlay(home string, homeMagic graphdriver.FsMagic, rootUID, rootGID int) (supportsDType bool, err error) {
|
||||
// We can try to modprobe overlay first
|
||||
exec.Command("modprobe", "overlay").Run()
|
||||
|
||||
f, err := os.Open("/proc/filesystems")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
s := bufio.NewScanner(f)
|
||||
for s.Scan() {
|
||||
if s.Text() == "nodev\toverlay" {
|
||||
return nil
|
||||
layerDir, err := ioutil.TempDir(home, "compat")
|
||||
if err == nil {
|
||||
// Check if reading the directory's contents populates the d_type field, which is required
|
||||
// for proper operation of the overlay filesystem.
|
||||
supportsDType, err = fsutils.SupportsDType(layerDir)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if !supportsDType {
|
||||
logrus.Warn(overlayutils.ErrDTypeNotSupported("overlay", backingFs))
|
||||
// TODO: Will make fatal when CRI-O Has AMI built on RHEL7.4
|
||||
// return nil, overlayutils.ErrDTypeNotSupported("overlay", backingFs)
|
||||
}
|
||||
|
||||
// Try a test mount in the specific location we're looking at using.
|
||||
mergedDir := filepath.Join(layerDir, "merged")
|
||||
lower1Dir := filepath.Join(layerDir, "lower1")
|
||||
lower2Dir := filepath.Join(layerDir, "lower2")
|
||||
defer func() {
|
||||
// Permitted to fail, since the various subdirectories
|
||||
// can be empty or not even there, and the home might
|
||||
// legitimately be not empty
|
||||
_ = unix.Unmount(mergedDir, unix.MNT_DETACH)
|
||||
_ = os.RemoveAll(layerDir)
|
||||
_ = os.Remove(home)
|
||||
}()
|
||||
_ = idtools.MkdirAs(mergedDir, 0700, rootUID, rootGID)
|
||||
_ = idtools.MkdirAs(lower1Dir, 0700, rootUID, rootGID)
|
||||
_ = idtools.MkdirAs(lower2Dir, 0700, rootUID, rootGID)
|
||||
flags := fmt.Sprintf("lowerdir=%s:%s", lower1Dir, lower2Dir)
|
||||
if len(flags) < unix.Getpagesize() {
|
||||
if mountFrom(filepath.Dir(home), "overlay", mergedDir, "overlay", 0, flags) == nil {
|
||||
logrus.Debugf("overlay test mount with multiple lowers succeeded")
|
||||
return supportsDType, nil
|
||||
}
|
||||
}
|
||||
flags = fmt.Sprintf("lowerdir=%s", lower1Dir)
|
||||
if len(flags) < unix.Getpagesize() {
|
||||
if mountFrom(filepath.Dir(home), "overlay", mergedDir, "overlay", 0, flags) == nil {
|
||||
logrus.Errorf("overlay test mount with multiple lowers failed, but succeeded with a single lower")
|
||||
return supportsDType, errors.Wrap(graphdriver.ErrNotSupported, "kernel too old to provide multiple lowers feature for overlay")
|
||||
}
|
||||
}
|
||||
logrus.Errorf("'overlay' is not supported over %s at %q", backingFs, home)
|
||||
return supportsDType, errors.Wrapf(graphdriver.ErrIncompatibleFS, "'overlay' is not supported over %s at %q", backingFs, home)
|
||||
}
|
||||
|
||||
logrus.Error("'overlay' not found as a supported filesystem on this host. Please ensure kernel is new enough and has overlay support loaded.")
|
||||
return errors.Wrap(graphdriver.ErrNotSupported, "'overlay' not found as a supported filesystem on this host. Please ensure kernel is new enough and has overlay support loaded.")
|
||||
return supportsDType, errors.Wrap(graphdriver.ErrNotSupported, "'overlay' not found as a supported filesystem on this host. Please ensure kernel is new enough and has overlay support loaded.")
|
||||
}
|
||||
|
||||
func useNaiveDiff(home string) bool {
|
||||
|
35
vendor/github.com/containers/storage/images.go
generated
vendored
35
vendor/github.com/containers/storage/images.go
generated
vendored
@ -27,6 +27,9 @@ type Image struct {
|
||||
// value which was generated by the library.
|
||||
ID string `json:"id"`
|
||||
|
||||
// Digest is a digest value that we can use to locate the image.
|
||||
Digest digest.Digest `json:"digest,omitempty"`
|
||||
|
||||
// Names is an optional set of user-defined convenience values. The
|
||||
// image can be referred to by its ID or any of its names. Names are
|
||||
// unique among images.
|
||||
@ -98,7 +101,7 @@ type ImageStore interface {
|
||||
// Create creates an image that has a specified ID (or a random one) and
|
||||
// optional names, using the specified layer as its topmost (hopefully
|
||||
// read-only) layer. That layer can be referenced by multiple images.
|
||||
Create(id string, names []string, layer, metadata string, created time.Time) (*Image, error)
|
||||
Create(id string, names []string, layer, metadata string, created time.Time, searchableDigest digest.Digest) (*Image, error)
|
||||
|
||||
// SetNames replaces the list of names associated with an image with the
|
||||
// supplied values.
|
||||
@ -165,9 +168,16 @@ func (r *imageStore) Load() error {
|
||||
}
|
||||
names[name] = images[n]
|
||||
}
|
||||
// Implicit digest
|
||||
if digest, ok := image.BigDataDigests[ImageDigestBigDataKey]; ok {
|
||||
digests[digest] = append(digests[digest], images[n])
|
||||
}
|
||||
// Explicit digest
|
||||
if image.Digest == "" {
|
||||
image.Digest = image.BigDataDigests[ImageDigestBigDataKey]
|
||||
} else if image.Digest != image.BigDataDigests[ImageDigestBigDataKey] {
|
||||
digests[image.Digest] = append(digests[image.Digest], images[n])
|
||||
}
|
||||
}
|
||||
}
|
||||
if shouldSave && !r.IsReadWrite() {
|
||||
@ -284,7 +294,7 @@ func (r *imageStore) SetFlag(id string, flag string, value interface{}) error {
|
||||
return r.Save()
|
||||
}
|
||||
|
||||
func (r *imageStore) Create(id string, names []string, layer, metadata string, created time.Time) (image *Image, err error) {
|
||||
func (r *imageStore) Create(id string, names []string, layer, metadata string, created time.Time, searchableDigest digest.Digest) (image *Image, err error) {
|
||||
if !r.IsReadWrite() {
|
||||
return nil, errors.Wrapf(ErrStoreIsReadOnly, "not allowed to create new images at %q", r.imagespath())
|
||||
}
|
||||
@ -311,6 +321,7 @@ func (r *imageStore) Create(id string, names []string, layer, metadata string, c
|
||||
if err == nil {
|
||||
image = &Image{
|
||||
ID: id,
|
||||
Digest: searchableDigest,
|
||||
Names: names,
|
||||
TopLayer: layer,
|
||||
Metadata: metadata,
|
||||
@ -323,6 +334,10 @@ func (r *imageStore) Create(id string, names []string, layer, metadata string, c
|
||||
r.images = append(r.images, image)
|
||||
r.idindex.Add(id)
|
||||
r.byid[id] = image
|
||||
if searchableDigest != "" {
|
||||
list := r.bydigest[searchableDigest]
|
||||
r.bydigest[searchableDigest] = append(list, image)
|
||||
}
|
||||
for _, name := range names {
|
||||
r.byname[name] = image
|
||||
}
|
||||
@ -413,6 +428,17 @@ func (r *imageStore) Delete(id string) error {
|
||||
}
|
||||
}
|
||||
}
|
||||
if image.Digest != "" {
|
||||
// remove the image's hard-coded digest from the digest-based index
|
||||
if list, ok := r.bydigest[image.Digest]; ok {
|
||||
prunedList := imageSliceWithoutValue(list, image)
|
||||
if len(prunedList) == 0 {
|
||||
delete(r.bydigest, image.Digest)
|
||||
} else {
|
||||
r.bydigest[image.Digest] = prunedList
|
||||
}
|
||||
}
|
||||
}
|
||||
if err := r.Save(); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -577,9 +603,10 @@ func (r *imageStore) SetBigData(id, key string, data []byte) error {
|
||||
save = true
|
||||
}
|
||||
if key == ImageDigestBigDataKey {
|
||||
if oldDigest != "" && oldDigest != newDigest {
|
||||
if oldDigest != "" && oldDigest != newDigest && oldDigest != image.Digest {
|
||||
// remove the image from the list of images in the digest-based
|
||||
// index which corresponds to the old digest for this item
|
||||
// index which corresponds to the old digest for this item, unless
|
||||
// it's also the hard-coded digest
|
||||
if list, ok := r.bydigest[oldDigest]; ok {
|
||||
prunedList := imageSliceWithoutValue(list, image)
|
||||
if len(prunedList) == 0 {
|
||||
|
52
vendor/github.com/containers/storage/images_ffjson.go
generated
vendored
52
vendor/github.com/containers/storage/images_ffjson.go
generated
vendored
@ -38,6 +38,11 @@ func (j *Image) MarshalJSONBuf(buf fflib.EncodingBuffer) error {
|
||||
buf.WriteString(`{ "id":`)
|
||||
fflib.WriteJsonString(buf, string(j.ID))
|
||||
buf.WriteByte(',')
|
||||
if len(j.Digest) != 0 {
|
||||
buf.WriteString(`"digest":`)
|
||||
fflib.WriteJsonString(buf, string(j.Digest))
|
||||
buf.WriteByte(',')
|
||||
}
|
||||
if len(j.Names) != 0 {
|
||||
buf.WriteString(`"names":`)
|
||||
if j.Names != nil {
|
||||
@ -146,6 +151,8 @@ const (
|
||||
|
||||
ffjtImageID
|
||||
|
||||
ffjtImageDigest
|
||||
|
||||
ffjtImageNames
|
||||
|
||||
ffjtImageTopLayer
|
||||
@ -165,6 +172,8 @@ const (
|
||||
|
||||
var ffjKeyImageID = []byte("id")
|
||||
|
||||
var ffjKeyImageDigest = []byte("digest")
|
||||
|
||||
var ffjKeyImageNames = []byte("names")
|
||||
|
||||
var ffjKeyImageTopLayer = []byte("layer")
|
||||
@ -268,6 +277,14 @@ mainparse:
|
||||
goto mainparse
|
||||
}
|
||||
|
||||
case 'd':
|
||||
|
||||
if bytes.Equal(ffjKeyImageDigest, kn) {
|
||||
currentKey = ffjtImageDigest
|
||||
state = fflib.FFParse_want_colon
|
||||
goto mainparse
|
||||
}
|
||||
|
||||
case 'f':
|
||||
|
||||
if bytes.Equal(ffjKeyImageFlags, kn) {
|
||||
@ -358,6 +375,12 @@ mainparse:
|
||||
goto mainparse
|
||||
}
|
||||
|
||||
if fflib.EqualFoldRight(ffjKeyImageDigest, kn) {
|
||||
currentKey = ffjtImageDigest
|
||||
state = fflib.FFParse_want_colon
|
||||
goto mainparse
|
||||
}
|
||||
|
||||
if fflib.SimpleLetterEqualFold(ffjKeyImageID, kn) {
|
||||
currentKey = ffjtImageID
|
||||
state = fflib.FFParse_want_colon
|
||||
@ -384,6 +407,9 @@ mainparse:
|
||||
case ffjtImageID:
|
||||
goto handle_ID
|
||||
|
||||
case ffjtImageDigest:
|
||||
goto handle_Digest
|
||||
|
||||
case ffjtImageNames:
|
||||
goto handle_Names
|
||||
|
||||
@ -448,6 +474,32 @@ handle_ID:
|
||||
state = fflib.FFParse_after_value
|
||||
goto mainparse
|
||||
|
||||
handle_Digest:
|
||||
|
||||
/* handler: j.Digest type=digest.Digest kind=string quoted=false*/
|
||||
|
||||
{
|
||||
|
||||
{
|
||||
if tok != fflib.FFTok_string && tok != fflib.FFTok_null {
|
||||
return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for Digest", tok))
|
||||
}
|
||||
}
|
||||
|
||||
if tok == fflib.FFTok_null {
|
||||
|
||||
} else {
|
||||
|
||||
outBuf := fs.Output.Bytes()
|
||||
|
||||
j.Digest = digest.Digest(string(outBuf))
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
state = fflib.FFParse_after_value
|
||||
goto mainparse
|
||||
|
||||
handle_Names:
|
||||
|
||||
/* handler: j.Names type=[]string kind=slice quoted=false*/
|
||||
|
11
vendor/github.com/containers/storage/store.go
generated
vendored
11
vendor/github.com/containers/storage/store.go
generated
vendored
@ -434,6 +434,8 @@ type ImageOptions struct {
|
||||
// CreationDate, if not zero, will override the default behavior of marking the image as having been
|
||||
// created when CreateImage() was called, recording CreationDate instead.
|
||||
CreationDate time.Time
|
||||
// Digest is a hard-coded digest value that we can use to look up the image. It is optional.
|
||||
Digest digest.Digest
|
||||
}
|
||||
|
||||
// ContainerOptions is used for passing options to a Store's CreateContainer() method.
|
||||
@ -491,11 +493,6 @@ func GetStore(options StoreOptions) (Store, error) {
|
||||
if err := os.MkdirAll(options.RunRoot, 0700); err != nil && !os.IsExist(err) {
|
||||
return nil, err
|
||||
}
|
||||
for _, subdir := range []string{} {
|
||||
if err := os.MkdirAll(filepath.Join(options.RunRoot, subdir), 0700); err != nil && !os.IsExist(err) {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if err := os.MkdirAll(options.GraphRoot, 0700); err != nil && !os.IsExist(err) {
|
||||
return nil, err
|
||||
}
|
||||
@ -838,11 +835,11 @@ func (s *store) CreateImage(id string, names []string, layer, metadata string, o
|
||||
}
|
||||
|
||||
creationDate := time.Now().UTC()
|
||||
if options != nil {
|
||||
if options != nil && !options.CreationDate.IsZero() {
|
||||
creationDate = options.CreationDate
|
||||
}
|
||||
|
||||
return ristore.Create(id, names, layer, metadata, creationDate)
|
||||
return ristore.Create(id, names, layer, metadata, creationDate, options.Digest)
|
||||
}
|
||||
|
||||
func (s *store) CreateContainer(id string, names []string, image, layer, metadata string, options *ContainerOptions) (*Container, error) {
|
||||
|
Loading…
Reference in New Issue
Block a user