summaryrefslogtreecommitdiff
path: root/vendor/github.com
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com')
-rw-r--r--vendor/github.com/containers/buildah/.cirrus.yml85
-rw-r--r--vendor/github.com/containers/buildah/Makefile9
-rw-r--r--vendor/github.com/containers/buildah/add.go8
-rw-r--r--vendor/github.com/containers/buildah/buildah.go3
-rw-r--r--vendor/github.com/containers/buildah/changelog.txt31
-rw-r--r--vendor/github.com/containers/buildah/commit.go176
-rw-r--r--vendor/github.com/containers/buildah/copier/copier.go140
-rw-r--r--vendor/github.com/containers/buildah/copier/syscall_unix.go16
-rw-r--r--vendor/github.com/containers/buildah/copier/syscall_windows.go5
-rw-r--r--vendor/github.com/containers/buildah/define/build.go2
-rw-r--r--vendor/github.com/containers/buildah/define/types.go2
-rw-r--r--vendor/github.com/containers/buildah/go.mod19
-rw-r--r--vendor/github.com/containers/buildah/go.sum118
-rw-r--r--vendor/github.com/containers/buildah/image.go2
-rw-r--r--vendor/github.com/containers/buildah/imagebuildah/build.go13
-rw-r--r--vendor/github.com/containers/buildah/imagebuildah/chroot_symlink_linux.go151
-rw-r--r--vendor/github.com/containers/buildah/imagebuildah/chroot_symlink_unsupported.go13
-rw-r--r--vendor/github.com/containers/buildah/imagebuildah/executor.go68
-rw-r--r--vendor/github.com/containers/buildah/imagebuildah/stage_executor.go91
-rw-r--r--vendor/github.com/containers/buildah/install.md78
-rw-r--r--vendor/github.com/containers/buildah/new.go250
-rw-r--r--vendor/github.com/containers/buildah/pkg/blobcache/blobcache.go26
-rw-r--r--vendor/github.com/containers/buildah/pkg/cli/common.go12
-rw-r--r--vendor/github.com/containers/buildah/pkg/overlay/overlay.go10
-rw-r--r--vendor/github.com/containers/buildah/pkg/parse/parse.go57
-rw-r--r--vendor/github.com/containers/buildah/pull.go270
-rw-r--r--vendor/github.com/containers/buildah/push.go126
-rw-r--r--vendor/github.com/containers/buildah/run.go5
-rw-r--r--vendor/github.com/containers/buildah/run_linux.go237
-rw-r--r--vendor/github.com/containers/buildah/util/util.go85
-rw-r--r--vendor/github.com/containers/common/libimage/copier.go427
-rw-r--r--vendor/github.com/containers/common/libimage/disk_usage.go126
-rw-r--r--vendor/github.com/containers/common/libimage/download.go46
-rw-r--r--vendor/github.com/containers/common/libimage/events.go43
-rw-r--r--vendor/github.com/containers/common/libimage/filters.go228
-rw-r--r--vendor/github.com/containers/common/libimage/history.go80
-rw-r--r--vendor/github.com/containers/common/libimage/image.go802
-rw-r--r--vendor/github.com/containers/common/libimage/image_config.go242
-rw-r--r--vendor/github.com/containers/common/libimage/image_tree.go96
-rw-r--r--vendor/github.com/containers/common/libimage/import.go108
-rw-r--r--vendor/github.com/containers/common/libimage/inspect.go206
-rw-r--r--vendor/github.com/containers/common/libimage/layer_tree.go249
-rw-r--r--vendor/github.com/containers/common/libimage/load.go125
-rw-r--r--vendor/github.com/containers/common/libimage/manifest_list.go389
-rw-r--r--vendor/github.com/containers/common/libimage/manifests/copy.go (renamed from vendor/github.com/containers/buildah/manifests/copy.go)0
-rw-r--r--vendor/github.com/containers/common/libimage/manifests/manifests.go (renamed from vendor/github.com/containers/buildah/manifests/manifests.go)4
-rw-r--r--vendor/github.com/containers/common/libimage/normalize.go92
-rw-r--r--vendor/github.com/containers/common/libimage/oci.go97
-rw-r--r--vendor/github.com/containers/common/libimage/pull.go458
-rw-r--r--vendor/github.com/containers/common/libimage/push.go83
-rw-r--r--vendor/github.com/containers/common/libimage/runtime.go573
-rw-r--r--vendor/github.com/containers/common/libimage/save.go202
-rw-r--r--vendor/github.com/containers/common/libimage/search.go307
-rw-r--r--vendor/github.com/containers/common/pkg/config/config.go29
-rw-r--r--vendor/github.com/containers/common/pkg/config/pull_policy.go95
-rw-r--r--vendor/github.com/containers/common/pkg/filters/filters.go118
-rw-r--r--vendor/github.com/containers/common/pkg/manifests/errors.go (renamed from vendor/github.com/containers/buildah/pkg/manifests/errors.go)0
-rw-r--r--vendor/github.com/containers/common/pkg/manifests/manifests.go (renamed from vendor/github.com/containers/buildah/pkg/manifests/manifests.go)0
-rw-r--r--vendor/github.com/containers/common/pkg/signal/signal_common.go41
-rw-r--r--vendor/github.com/containers/common/pkg/signal/signal_linux.go108
-rw-r--r--vendor/github.com/containers/common/pkg/signal/signal_linux_mipsx.go108
-rw-r--r--vendor/github.com/containers/common/pkg/signal/signal_unsupported.go99
-rw-r--r--vendor/github.com/containers/common/pkg/supplemented/errors.go (renamed from vendor/github.com/containers/buildah/pkg/supplemented/errors.go)2
-rw-r--r--vendor/github.com/containers/common/pkg/supplemented/supplemented.go (renamed from vendor/github.com/containers/buildah/pkg/supplemented/supplemented.go)0
-rw-r--r--vendor/github.com/containers/common/pkg/timetype/timestamp.go131
-rw-r--r--vendor/github.com/containers/common/version/version.go2
-rw-r--r--vendor/github.com/containers/image/v5/copy/copy.go20
-rw-r--r--vendor/github.com/containers/image/v5/docker/tarfile/dest.go119
-rw-r--r--vendor/github.com/containers/image/v5/docker/tarfile/doc.go3
-rw-r--r--vendor/github.com/containers/image/v5/docker/tarfile/src.go104
-rw-r--r--vendor/github.com/containers/image/v5/docker/tarfile/types.go8
-rw-r--r--vendor/github.com/containers/image/v5/internal/types/types.go3
-rw-r--r--vendor/github.com/containers/image/v5/storage/storage_image.go87
-rw-r--r--vendor/github.com/containers/image/v5/version/version.go4
-rw-r--r--vendor/github.com/disiqueira/gotree/v3/.gitignore137
-rw-r--r--vendor/github.com/disiqueira/gotree/v3/.travis.yml11
-rw-r--r--vendor/github.com/disiqueira/gotree/v3/LICENSE21
-rw-r--r--vendor/github.com/disiqueira/gotree/v3/README.md104
-rw-r--r--vendor/github.com/disiqueira/gotree/v3/_config.yml1
-rw-r--r--vendor/github.com/disiqueira/gotree/v3/go.mod3
-rw-r--r--vendor/github.com/disiqueira/gotree/v3/gotree-logo.pngbin0 -> 24183 bytes
-rw-r--r--vendor/github.com/disiqueira/gotree/v3/gotree.go129
-rw-r--r--vendor/github.com/ishidawataru/sctp/.travis.yml11
-rw-r--r--vendor/github.com/ishidawataru/sctp/sctp_linux.go2
-rw-r--r--vendor/github.com/jinzhu/copier/License20
-rw-r--r--vendor/github.com/jinzhu/copier/README.md131
-rw-r--r--vendor/github.com/jinzhu/copier/copier.go491
-rw-r--r--vendor/github.com/jinzhu/copier/errors.go10
-rw-r--r--vendor/github.com/jinzhu/copier/go.mod3
-rw-r--r--vendor/github.com/onsi/ginkgo/CHANGELOG.md5
-rw-r--r--vendor/github.com/onsi/ginkgo/config/config.go2
-rw-r--r--vendor/github.com/onsi/ginkgo/ginkgo/run_command.go2
-rw-r--r--vendor/github.com/onsi/ginkgo/types/deprecation_support.go54
-rw-r--r--vendor/github.com/openshift/imagebuilder/README.md4
-rw-r--r--vendor/github.com/openshift/imagebuilder/builder.go4
-rw-r--r--vendor/github.com/openshift/imagebuilder/dispatchers.go21
-rw-r--r--vendor/github.com/openshift/imagebuilder/imagebuilder.spec2
97 files changed, 7889 insertions, 1451 deletions
diff --git a/vendor/github.com/containers/buildah/.cirrus.yml b/vendor/github.com/containers/buildah/.cirrus.yml
index 32c711be8..e62c14863 100644
--- a/vendor/github.com/containers/buildah/.cirrus.yml
+++ b/vendor/github.com/containers/buildah/.cirrus.yml
@@ -26,12 +26,12 @@ env:
# GCE project where images live
IMAGE_PROJECT: "libpod-218412"
# See https://github.com/containers/podman/blob/master/contrib/cirrus/README.md#test_build_cache_images_task-task
- FEDORA_NAME: "fedora-33"
- PRIOR_FEDORA_NAME: "fedora-32"
- UBUNTU_NAME: "ubuntu-2010"
- PRIOR_UBUNTU_NAME: "ubuntu-2004"
+ FEDORA_NAME: "fedora-34"
+ PRIOR_FEDORA_NAME: "fedora-33"
+ UBUNTU_NAME: "ubuntu-2104"
+ PRIOR_UBUNTU_NAME: "ubuntu-2010"
- IMAGE_SUFFIX: "c6102133168668672"
+ IMAGE_SUFFIX: "c6032583541653504"
FEDORA_CACHE_IMAGE_NAME: "fedora-${IMAGE_SUFFIX}"
PRIOR_FEDORA_CACHE_IMAGE_NAME: "prior-fedora-${IMAGE_SUFFIX}"
UBUNTU_CACHE_IMAGE_NAME: "ubuntu-${IMAGE_SUFFIX}"
@@ -133,14 +133,20 @@ vendor_task:
unit_task:
- name: "Unit tests"
+ name: 'Unit tests w/ $STORAGE_DRIVER'
alias: unit
depends_on:
- smoke
- vendor
- timeout_in: 45m
+ timeout_in: 50m
+
+ matrix:
+ - env:
+ STORAGE_DRIVER: 'vfs'
+ - env:
+ STORAGE_DRIVER: 'overlay'
setup_script: '${SCRIPT_BASE}/setup.sh |& ${_TIMESTAMP}'
build_script: '${SCRIPT_BASE}/build.sh |& ${_TIMESTAMP}'
@@ -149,13 +155,9 @@ unit_task:
binary_artifacts:
path: ./bin/*
- env:
- matrix:
- STORAGE_DRIVER: 'vfs'
- STORAGE_DRIVER: 'overlay'
conformance_task:
- name: "Docker Build Conformance"
+ name: 'Build Conformance w/ $STORAGE_DRIVER'
alias: conformance
depends_on:
@@ -166,13 +168,15 @@ conformance_task:
timeout_in: 25m
+ matrix:
+ - env:
+ STORAGE_DRIVER: 'vfs'
+ - env:
+ STORAGE_DRIVER: 'overlay'
+
setup_script: '${SCRIPT_BASE}/setup.sh |& ${_TIMESTAMP}'
conformance_test_script: '${SCRIPT_BASE}/test.sh conformance |& ${_TIMESTAMP}'
- env:
- matrix:
- STORAGE_DRIVER: 'vfs'
- STORAGE_DRIVER: 'overlay'
# Confirm cross-compile ALL archetectures on a Mac OS-X VM.
cross_build_task:
@@ -208,6 +212,9 @@ static_build_task:
memory: 12
disk: 200
+ env:
+ NIX_FQIN: "docker.io/nixos/nix:latest"
+
init_script: |
set -ex
setenforce 0
@@ -223,8 +230,16 @@ static_build_task:
set -ex
mkdir -p .cache
mv .cache /nix
- if [[ -z $(ls -A /nix) ]]; then podman run --rm --privileged -ti -v /:/mnt nixos/nix cp -rfT /nix /mnt/nix; fi
- podman run --rm --privileged -ti -v /nix:/nix -v ${PWD}:${PWD} -w ${PWD} nixos/nix nix --print-build-logs --option cores 8 --option max-jobs 8 build --file nix/
+ if [[ -z $(ls -A /nix) ]]; then
+ podman run --rm --privileged -i -v /:/mnt \
+ $NIX_FQIN \
+ cp -rfT /nix /mnt/nix
+ fi
+ podman run --rm --privileged -i -v /nix:/nix \
+ -v ${PWD}:${PWD} -w ${PWD} \
+ $NIX_FQIN \
+ nix --print-build-logs --option cores 8 \
+ --option max-jobs 8 build --file nix/
binaries_artifacts:
path: "result/bin/buildah"
@@ -235,25 +250,47 @@ static_build_task:
integration_task:
- name: "Integration $DISTRO_NV"
+ name: "Integration $DISTRO_NV w/ $STORAGE_DRIVER"
alias: integration
depends_on:
- unit
matrix:
+ # VFS
+ - env:
+ DISTRO_NV: "${FEDORA_NAME}"
+ IMAGE_NAME: "${FEDORA_CACHE_IMAGE_NAME}"
+ STORAGE_DRIVER: 'vfs'
+ - env:
+ DISTRO_NV: "${PRIOR_FEDORA_NAME}"
+ IMAGE_NAME: "${PRIOR_FEDORA_CACHE_IMAGE_NAME}"
+ STORAGE_DRIVER: 'vfs'
+ - env:
+ DISTRO_NV: "${UBUNTU_NAME}"
+ IMAGE_NAME: "${UBUNTU_CACHE_IMAGE_NAME}"
+ STORAGE_DRIVER: 'vfs'
+ - env:
+ DISTRO_NV: "${PRIOR_UBUNTU_NAME}"
+ IMAGE_NAME: "${PRIOR_UBUNTU_CACHE_IMAGE_NAME}"
+ STORAGE_DRIVER: 'vfs'
+ # OVERLAY
- env:
DISTRO_NV: "${FEDORA_NAME}"
IMAGE_NAME: "${FEDORA_CACHE_IMAGE_NAME}"
- # - env:
- # DISTRO_NV: "${PRIOR_FEDORA_NAME}"
- # IMAGE_NAME: "${PRIOR_FEDORA_CACHE_IMAGE_NAME}"
+ STORAGE_DRIVER: 'overlay'
+ - env:
+ DISTRO_NV: "${PRIOR_FEDORA_NAME}"
+ IMAGE_NAME: "${PRIOR_FEDORA_CACHE_IMAGE_NAME}"
+ STORAGE_DRIVER: 'overlay'
- env:
DISTRO_NV: "${UBUNTU_NAME}"
IMAGE_NAME: "${UBUNTU_CACHE_IMAGE_NAME}"
+ STORAGE_DRIVER: 'overlay'
- env:
DISTRO_NV: "${PRIOR_UBUNTU_NAME}"
IMAGE_NAME: "${PRIOR_UBUNTU_CACHE_IMAGE_NAME}"
+ STORAGE_DRIVER: 'overlay'
gce_instance:
image_name: "$IMAGE_NAME"
@@ -276,10 +313,6 @@ integration_task:
package_versions_script: '$GOSRC/$SCRIPT_BASE/logcollector.sh packages'
golang_version_script: '$GOSRC/$SCRIPT_BASE/logcollector.sh golang'
- env:
- matrix:
- STORAGE_DRIVER: 'vfs'
- STORAGE_DRIVER: 'overlay'
in_podman_task:
name: "Containerized Integration"
diff --git a/vendor/github.com/containers/buildah/Makefile b/vendor/github.com/containers/buildah/Makefile
index 9ff59df55..2a54d73c1 100644
--- a/vendor/github.com/containers/buildah/Makefile
+++ b/vendor/github.com/containers/buildah/Makefile
@@ -51,8 +51,11 @@ all: bin/buildah bin/imgtype docs
# Update nix/nixpkgs.json its latest stable commit
.PHONY: nixpkgs
nixpkgs:
- @nix run -f channel:nixos-20.09 nix-prefetch-git -c nix-prefetch-git \
- --no-deepClone https://github.com/nixos/nixpkgs > nix/nixpkgs.json
+ @nix run \
+ -f channel:nixos-20.09 nix-prefetch-git \
+ -c nix-prefetch-git \
+ --no-deepClone \
+ https://github.com/nixos/nixpkgs refs/heads/nixos-20.09 > nix/nixpkgs.json
# Build statically linked binary
.PHONY: static
@@ -161,7 +164,7 @@ tests/testreport/testreport: tests/testreport/testreport.go
.PHONY: test-unit
test-unit: tests/testreport/testreport
- $(GO_TEST) -v -tags "$(STORAGETAGS) $(SECURITYTAGS)" -cover -race $(shell $(GO) list ./... | grep -v vendor | grep -v tests | grep -v cmd) -timeout 40m
+ $(GO_TEST) -v -tags "$(STORAGETAGS) $(SECURITYTAGS)" -cover -race $(shell $(GO) list ./... | grep -v vendor | grep -v tests | grep -v cmd) -timeout 45m
tmp=$(shell mktemp -d) ; \
mkdir -p $$tmp/root $$tmp/runroot; \
$(GO_TEST) -v -tags "$(STORAGETAGS) $(SECURITYTAGS)" -cover -race ./cmd/buildah -args --root $$tmp/root --runroot $$tmp/runroot --storage-driver vfs --signature-policy $(shell pwd)/tests/policy.json --registries-conf $(shell pwd)/tests/registries.conf
diff --git a/vendor/github.com/containers/buildah/add.go b/vendor/github.com/containers/buildah/add.go
index e81e35c30..0a77e9f9d 100644
--- a/vendor/github.com/containers/buildah/add.go
+++ b/vendor/github.com/containers/buildah/add.go
@@ -224,7 +224,7 @@ func (b *Builder) Add(destination string, extract bool, options AddAndCopyOption
}
localSourceStats, err = copier.Stat(contextDir, contextDir, statOptions, localSources)
if err != nil {
- return errors.Wrapf(err, "error checking on sources %v under %q", localSources, contextDir)
+ return errors.Wrapf(err, "checking on sources under %q", contextDir)
}
}
numLocalSourceItems := 0
@@ -238,10 +238,10 @@ func (b *Builder) Add(destination string, extract bool, options AddAndCopyOption
if strings.HasPrefix(rel, ".."+string(os.PathSeparator)) {
errorText = fmt.Sprintf("possible escaping context directory error: %s", errorText)
}
- return errors.Errorf("error checking on source %v under %q: %v", localSourceStat.Glob, contextDir, errorText)
+ return errors.Errorf("checking on sources under %q: %v", contextDir, errorText)
}
if len(localSourceStat.Globbed) == 0 {
- return errors.Wrapf(syscall.ENOENT, "error checking on source %v under %q: no glob matches", localSourceStat.Glob, contextDir)
+ return errors.Wrapf(syscall.ENOENT, "checking source under %q: no glob matches", contextDir)
}
numLocalSourceItems += len(localSourceStat.Globbed)
}
@@ -433,7 +433,7 @@ func (b *Builder) Add(destination string, extract bool, options AddAndCopyOption
}
}
if localSourceStat == nil {
- return errors.Errorf("internal error: should have statted %s, but we didn't?", src)
+ continue
}
// Iterate through every item that matched the glob.
diff --git a/vendor/github.com/containers/buildah/buildah.go b/vendor/github.com/containers/buildah/buildah.go
index b0ddd0f72..771165d43 100644
--- a/vendor/github.com/containers/buildah/buildah.go
+++ b/vendor/github.com/containers/buildah/buildah.go
@@ -357,6 +357,9 @@ type ImportFromImageOptions struct {
// NewBuilder creates a new build container.
func NewBuilder(ctx context.Context, store storage.Store, options BuilderOptions) (*Builder, error) {
+ if options.CommonBuildOpts == nil {
+ options.CommonBuildOpts = &CommonBuildOptions{}
+ }
return newBuilder(ctx, store, options)
}
diff --git a/vendor/github.com/containers/buildah/changelog.txt b/vendor/github.com/containers/buildah/changelog.txt
index 74929da78..7d31c854d 100644
--- a/vendor/github.com/containers/buildah/changelog.txt
+++ b/vendor/github.com/containers/buildah/changelog.txt
@@ -1,3 +1,34 @@
+- Changelog for v1.20.1 (2021-04-13)
+ * Run container with isolation type set at 'from'
+ * bats helpers.bash - minor refactoring
+ * Bump containers/storage vendor to v1.29.0
+ * build(deps): bump github.com/onsi/ginkgo from 1.16.0 to 1.16.1
+ * Cirrus: Update VMs w/ F34beta
+ * CLI add/copy: add a --from option
+ * build(deps): bump github.com/onsi/ginkgo from 1.15.2 to 1.16.0
+ * Add authentication system tests for 'commit' and 'bud'
+ * fix local image lookup for custom platform
+ * Double-check existence of OCI runtimes
+ * Cirrus: Make use of shared get_ci_vm container
+ * Add system tests of "buildah run"
+ * Update nix pin with `make nixpkgs`
+ * Remove some stuttering on returns errors
+ * Setup alias for --tty to --terminal
+ * Add conformance tests for COPY /...
+ * Put a few more minutes on the clock for the CI conformance test
+ * Add a conformance test for COPY --from $symlink
+ * Add conformance tests for COPY ""
+ * Check for symlink in builtin volume
+ * Sort all mounts by destination directory
+ * System-test cleanup
+ * Export parse.Platform string to be used by podman-remote
+ * blobcache: fix sequencing error
+ * build(deps): bump github.com/containers/common from 0.35.3 to 0.35.4
+ * Fix URL in demos/buildah_multi_stage.sh
+ * Add a few system tests
+ * [NO TESTS NEEDED] Use --recurse-modules when building git context
+ * Bump to v1.20.1-dev
+
- Changelog for v1.20.0 (2021-03-25)
* vendor in containers/storage v1.28.1
* build(deps): bump github.com/containers/common from 0.35.2 to 0.35.3
diff --git a/vendor/github.com/containers/buildah/commit.go b/vendor/github.com/containers/buildah/commit.go
index f588c8043..139355517 100644
--- a/vendor/github.com/containers/buildah/commit.go
+++ b/vendor/github.com/containers/buildah/commit.go
@@ -3,16 +3,15 @@ package buildah
import (
"context"
"encoding/json"
- "fmt"
"io"
"io/ioutil"
"os"
"strings"
"time"
- "github.com/containers/buildah/manifests"
"github.com/containers/buildah/pkg/blobcache"
"github.com/containers/buildah/util"
+ "github.com/containers/common/libimage/manifests"
"github.com/containers/image/v5/docker"
"github.com/containers/image/v5/docker/reference"
"github.com/containers/image/v5/manifest"
@@ -104,59 +103,6 @@ type CommitOptions struct {
OciEncryptLayers *[]int
}
-// PushOptions can be used to alter how an image is copied somewhere.
-type PushOptions struct {
- // Compression specifies the type of compression which is applied to
- // layer blobs. The default is to not use compression, but
- // archive.Gzip is recommended.
- Compression archive.Compression
- // SignaturePolicyPath specifies an override location for the signature
- // policy which should be used for verifying the new image as it is
- // being written. Except in specific circumstances, no value should be
- // specified, indicating that the shared, system-wide default policy
- // should be used.
- SignaturePolicyPath string
- // ReportWriter is an io.Writer which will be used to log the writing
- // of the new image.
- ReportWriter io.Writer
- // Store is the local storage store which holds the source image.
- Store storage.Store
- // github.com/containers/image/types SystemContext to hold credentials
- // and other authentication/authorization information.
- SystemContext *types.SystemContext
- // ManifestType is the format to use when saving the image using the 'dir' transport
- // possible options are oci, v2s1, and v2s2
- ManifestType string
- // BlobDirectory is the name of a directory in which we'll look for
- // prebuilt copies of layer blobs that we might otherwise need to
- // regenerate from on-disk layers, substituting them in the list of
- // blobs to copy whenever possible.
- BlobDirectory string
- // Quiet is a boolean value that determines if minimal output to
- // the user will be displayed, this is best used for logging.
- // The default is false.
- Quiet bool
- // SignBy is the fingerprint of a GPG key to use for signing the image.
- SignBy string
- // RemoveSignatures causes any existing signatures for the image to be
- // discarded for the pushed copy.
- RemoveSignatures bool
- // MaxRetries is the maximum number of attempts we'll make to push any
- // one image to the external registry if the first attempt fails.
- MaxRetries int
- // RetryDelay is how long to wait before retrying a push attempt.
- RetryDelay time.Duration
- // OciEncryptConfig when non-nil indicates that an image should be encrypted.
- // The encryption options is derived from the construction of EncryptConfig object.
- OciEncryptConfig *encconfig.EncryptConfig
- // OciEncryptLayers represents the list of layers to encrypt.
- // If nil, don't encrypt any layers.
- // If non-nil and len==0, denotes encrypt all layers.
- // integers in the slice represent 0-indexed layer indices, with support for negative
- // indexing. i.e. 0 is the first layer, -1 is the last (top-most) layer.
- OciEncryptLayers *[]int
-}
-
var (
// storageAllowedPolicyScopes overrides the policy for local storage
// to ensure that we can read images from it.
@@ -239,7 +185,7 @@ func (b *Builder) addManifest(ctx context.Context, manifestName string, imageSpe
}
}
- names, err := util.ExpandNames([]string{manifestName}, "", systemContext, b.store)
+ names, err := util.ExpandNames([]string{manifestName}, systemContext, b.store)
if err != nil {
return "", errors.Wrapf(err, "error encountered while expanding image name %q", manifestName)
}
@@ -341,30 +287,6 @@ func (b *Builder) Commit(ctx context.Context, dest types.ImageReference, options
systemContext.OCIInsecureSkipTLSVerify = true
systemContext.DockerDaemonInsecureSkipTLSVerify = true
}
- if len(options.AdditionalTags) > 0 {
- names, err := util.ExpandNames(options.AdditionalTags, "", systemContext, b.store)
- if err != nil {
- return imgID, nil, "", err
- }
- for _, name := range names {
- additionalDest, err := docker.Transport.ParseReference(name)
- if err != nil {
- return imgID, nil, "", errors.Wrapf(err, "error parsing image name %q as an image reference", name)
- }
- insecure, err := checkRegistrySourcesAllows("commit to", additionalDest)
- if err != nil {
- return imgID, nil, "", err
- }
- if insecure {
- if systemContext.DockerInsecureSkipTLSVerify == types.OptionalBoolFalse {
- return imgID, nil, "", errors.Errorf("can't require tls verification on an insecured registry")
- }
- systemContext.DockerInsecureSkipTLSVerify = types.OptionalBoolTrue
- systemContext.OCIInsecureSkipTLSVerify = true
- systemContext.DockerDaemonInsecureSkipTLSVerify = true
- }
- }
- }
logrus.Debugf("committing image with reference %q is allowed by policy", transports.ImageName(dest))
// Check if the base image is already in the destination and it's some kind of local
@@ -495,97 +417,3 @@ func (b *Builder) Commit(ctx context.Context, dest types.ImageReference, options
}
return imgID, ref, manifestDigest, nil
}
-
-// Push copies the contents of the image to a new location.
-func Push(ctx context.Context, image string, dest types.ImageReference, options PushOptions) (reference.Canonical, digest.Digest, error) {
- systemContext := getSystemContext(options.Store, options.SystemContext, options.SignaturePolicyPath)
-
- if options.Quiet {
- options.ReportWriter = nil // Turns off logging output
- }
- blocked, err := isReferenceBlocked(dest, systemContext)
- if err != nil {
- return nil, "", errors.Wrapf(err, "error checking if pushing to registry for %q is blocked", transports.ImageName(dest))
- }
- if blocked {
- return nil, "", errors.Errorf("push access to registry for %q is blocked by configuration", transports.ImageName(dest))
- }
-
- // Load the system signing policy.
- pushPolicy, err := signature.DefaultPolicy(systemContext)
- if err != nil {
- return nil, "", errors.Wrapf(err, "error obtaining default signature policy")
- }
- // Override the settings for local storage to make sure that we can always read the source "image".
- pushPolicy.Transports[is.Transport.Name()] = storageAllowedPolicyScopes
-
- policyContext, err := signature.NewPolicyContext(pushPolicy)
- if err != nil {
- return nil, "", errors.Wrapf(err, "error creating new signature policy context")
- }
- defer func() {
- if err2 := policyContext.Destroy(); err2 != nil {
- logrus.Debugf("error destroying signature policy context: %v", err2)
- }
- }()
-
- // Look up the image.
- src, _, err := util.FindImage(options.Store, "", systemContext, image)
- if err != nil {
- return nil, "", err
- }
- maybeCachedSrc := src
- if options.BlobDirectory != "" {
- compress := types.PreserveOriginal
- if options.Compression != archive.Uncompressed {
- compress = types.Compress
- }
- cache, err := blobcache.NewBlobCache(src, options.BlobDirectory, compress)
- if err != nil {
- return nil, "", errors.Wrapf(err, "error wrapping image reference %q in blob cache at %q", transports.ImageName(src), options.BlobDirectory)
- }
- maybeCachedSrc = cache
- }
-
- // Check if the push is blocked by $BUILDER_REGISTRY_SOURCES.
- insecure, err := checkRegistrySourcesAllows("push to", dest)
- if err != nil {
- return nil, "", err
- }
- if insecure {
- if systemContext.DockerInsecureSkipTLSVerify == types.OptionalBoolFalse {
- return nil, "", errors.Errorf("can't require tls verification on an insecured registry")
- }
- systemContext.DockerInsecureSkipTLSVerify = types.OptionalBoolTrue
- systemContext.OCIInsecureSkipTLSVerify = true
- systemContext.DockerDaemonInsecureSkipTLSVerify = true
- }
- logrus.Debugf("pushing image to reference %q is allowed by policy", transports.ImageName(dest))
-
- // Copy everything.
- switch options.Compression {
- case archive.Uncompressed:
- systemContext.OCIAcceptUncompressedLayers = true
- case archive.Gzip:
- systemContext.DirForceCompress = true
- }
- var manifestBytes []byte
- if manifestBytes, err = retryCopyImage(ctx, policyContext, dest, maybeCachedSrc, dest, getCopyOptions(options.Store, options.ReportWriter, nil, systemContext, options.ManifestType, options.RemoveSignatures, options.SignBy, options.OciEncryptLayers, options.OciEncryptConfig, nil), options.MaxRetries, options.RetryDelay); err != nil {
- return nil, "", errors.Wrapf(err, "error copying layers and metadata from %q to %q", transports.ImageName(maybeCachedSrc), transports.ImageName(dest))
- }
- if options.ReportWriter != nil {
- fmt.Fprintf(options.ReportWriter, "")
- }
- manifestDigest, err := manifest.Digest(manifestBytes)
- if err != nil {
- return nil, "", errors.Wrapf(err, "error computing digest of manifest of new image %q", transports.ImageName(dest))
- }
- var ref reference.Canonical
- if name := dest.DockerReference(); name != nil {
- ref, err = reference.WithDigest(name, manifestDigest)
- if err != nil {
- logrus.Warnf("error generating canonical reference with name %q and digest %s: %v", name, manifestDigest.String(), err)
- }
- }
- return ref, manifestDigest, nil
-}
diff --git a/vendor/github.com/containers/buildah/copier/copier.go b/vendor/github.com/containers/buildah/copier/copier.go
index a37d4635e..8f6821c31 100644
--- a/vendor/github.com/containers/buildah/copier/copier.go
+++ b/vendor/github.com/containers/buildah/copier/copier.go
@@ -70,12 +70,13 @@ func isArchivePath(path string) bool {
type requestType string
const (
- requestEval requestType = "EVAL"
- requestStat requestType = "STAT"
- requestGet requestType = "GET"
- requestPut requestType = "PUT"
- requestMkdir requestType = "MKDIR"
- requestQuit requestType = "QUIT"
+ requestEval requestType = "EVAL"
+ requestStat requestType = "STAT"
+ requestGet requestType = "GET"
+ requestPut requestType = "PUT"
+ requestMkdir requestType = "MKDIR"
+ requestRemove requestType = "REMOVE"
+ requestQuit requestType = "QUIT"
)
// Request encodes a single request.
@@ -88,10 +89,11 @@ type request struct {
preservedDirectory string
Globs []string `json:",omitempty"` // used by stat, get
preservedGlobs []string
- StatOptions StatOptions `json:",omitempty"`
- GetOptions GetOptions `json:",omitempty"`
- PutOptions PutOptions `json:",omitempty"`
- MkdirOptions MkdirOptions `json:",omitempty"`
+ StatOptions StatOptions `json:",omitempty"`
+ GetOptions GetOptions `json:",omitempty"`
+ PutOptions PutOptions `json:",omitempty"`
+ MkdirOptions MkdirOptions `json:",omitempty"`
+ RemoveOptions RemoveOptions `json:",omitempty"`
}
func (req *request) Excludes() []string {
@@ -106,6 +108,8 @@ func (req *request) Excludes() []string {
return nil
case requestMkdir:
return nil
+ case requestRemove:
+ return nil
case requestQuit:
return nil
default:
@@ -125,6 +129,8 @@ func (req *request) UIDMap() []idtools.IDMap {
return req.PutOptions.UIDMap
case requestMkdir:
return req.MkdirOptions.UIDMap
+ case requestRemove:
+ return nil
case requestQuit:
return nil
default:
@@ -144,6 +150,8 @@ func (req *request) GIDMap() []idtools.IDMap {
return req.PutOptions.GIDMap
case requestMkdir:
return req.MkdirOptions.GIDMap
+ case requestRemove:
+ return nil
case requestQuit:
return nil
default:
@@ -153,12 +161,13 @@ func (req *request) GIDMap() []idtools.IDMap {
// Response encodes a single response.
type response struct {
- Error string `json:",omitempty"`
- Stat statResponse
- Eval evalResponse
- Get getResponse
- Put putResponse
- Mkdir mkdirResponse
+ Error string `json:",omitempty"`
+ Stat statResponse `json:",omitempty"`
+ Eval evalResponse `json:",omitempty"`
+ Get getResponse `json:",omitempty"`
+ Put putResponse `json:",omitempty"`
+ Mkdir mkdirResponse `json:",omitempty"`
+ Remove removeResponse `json:",omitempty"`
}
// statResponse encodes a response for a single Stat request.
@@ -205,6 +214,10 @@ type putResponse struct {
type mkdirResponse struct {
}
+// removeResponse encodes a response for a single Remove request.
+type removeResponse struct {
+}
+
// EvalOptions controls parts of Eval()'s behavior.
type EvalOptions struct {
}
@@ -285,6 +298,7 @@ type GetOptions struct {
Rename map[string]string // rename items with the specified names, or under the specified names
NoDerefSymlinks bool // don't follow symlinks when globs match them
IgnoreUnreadable bool // ignore errors reading items, instead of returning an error
+ NoCrossDevice bool // if a subdirectory is a mountpoint with a different device number, include it but skip its contents
}
// Get produces an archive containing items that match the specified glob
@@ -396,6 +410,36 @@ func Mkdir(root string, directory string, options MkdirOptions) error {
return nil
}
+// RemoveOptions controls parts of Remove()'s behavior.
+type RemoveOptions struct {
+ All bool // if Directory is a directory, remove its contents as well
+}
+
+// Remove removes the specified directory or item, traversing any intermediate
+// symbolic links.
+// If the root directory is not specified, the current root directory is used.
+// If root is specified and the current OS supports it, and the calling process
+// has the necessary privileges, the remove() is performed in a chrooted context.
+// If the item to remove is specified as an absolute path, it should either be
+// in the root directory or in a subdirectory of the root directory. Otherwise,
+// the directory is treated as a path relative to the root directory.
+func Remove(root string, item string, options RemoveOptions) error {
+ req := request{
+ Request: requestRemove,
+ Root: root,
+ Directory: item,
+ RemoveOptions: options,
+ }
+ resp, err := copier(nil, nil, req)
+ if err != nil {
+ return err
+ }
+ if resp.Error != "" {
+ return errors.New(resp.Error)
+ }
+ return nil
+}
+
// cleanerReldirectory resolves relative path candidate lexically, attempting
// to ensure that when joined as a subdirectory of another directory, it does
// not reference anything outside of that other directory.
@@ -819,6 +863,9 @@ func copierHandler(bulkReader io.Reader, bulkWriter io.Writer, req request) (*re
return copierHandlerPut(bulkReader, req, idMappings)
case requestMkdir:
return copierHandlerMkdir(req, idMappings)
+ case requestRemove:
+ resp := copierHandlerRemove(req)
+ return resp, nil, nil
case requestQuit:
return nil, nil, nil
}
@@ -859,7 +906,7 @@ func pathIsExcluded(root, path string, pm *fileutils.PatternMatcher) (string, bo
// it is not expected to be.
// This helps us approximate chrooted behavior on systems and in test cases
// where chroot isn't available.
-func resolvePath(root, path string, pm *fileutils.PatternMatcher) (string, error) {
+func resolvePath(root, path string, evaluateFinalComponent bool, pm *fileutils.PatternMatcher) (string, error) {
rel, err := convertToRelSubdirectory(root, path)
if err != nil {
return "", errors.Errorf("error making path %q relative to %q", path, root)
@@ -876,7 +923,7 @@ func resolvePath(root, path string, pm *fileutils.PatternMatcher) (string, error
}
excluded = excluded || thisExcluded
if !excluded {
- if target, err := os.Readlink(filepath.Join(workingPath, components[0])); err == nil {
+ if target, err := os.Readlink(filepath.Join(workingPath, components[0])); err == nil && !(len(components) == 1 && !evaluateFinalComponent) {
followed++
if followed > maxLoopsFollowed {
return "", &os.PathError{
@@ -922,7 +969,7 @@ func copierHandlerEval(req request) *response {
errorResponse := func(fmtspec string, args ...interface{}) *response {
return &response{Error: fmt.Sprintf(fmtspec, args...), Eval: evalResponse{}}
}
- resolvedTarget, err := resolvePath(req.Root, req.Directory, nil)
+ resolvedTarget, err := resolvePath(req.Root, req.Directory, true, nil)
if err != nil {
return errorResponse("copier: eval: error resolving %q: %v", req.Directory, err)
}
@@ -941,11 +988,13 @@ func copierHandlerStat(req request, pm *fileutils.PatternMatcher) *response {
s := StatsForGlob{
Glob: req.preservedGlobs[i],
}
- stats = append(stats, &s)
// glob this pattern
globMatched, err := filepath.Glob(glob)
if err != nil {
s.Error = fmt.Sprintf("copier: stat: %q while matching glob pattern %q", err.Error(), glob)
+ }
+
+ if len(globMatched) == 0 && strings.ContainsAny(glob, "*?[") {
continue
}
// collect the matches
@@ -1001,7 +1050,7 @@ func copierHandlerStat(req request, pm *fileutils.PatternMatcher) *response {
// could be a relative link) and in the context
// of the chroot
result.ImmediateTarget = immediateTarget
- resolvedTarget, err := resolvePath(req.Root, globbed, pm)
+ resolvedTarget, err := resolvePath(req.Root, globbed, true, pm)
if err != nil {
return errorResponse("copier: stat: error resolving %q: %v", globbed, err)
}
@@ -1032,6 +1081,14 @@ func copierHandlerStat(req request, pm *fileutils.PatternMatcher) *response {
s.Results = nil
s.Error = fmt.Sprintf("copier: stat: %q: %v", glob, syscall.ENOENT)
}
+ stats = append(stats, &s)
+ }
+ // no matches -> error
+ if len(stats) == 0 {
+ s := StatsForGlob{
+ Error: fmt.Sprintf("copier: stat: %q: %v", req.Globs, syscall.ENOENT),
+ }
+ stats = append(stats, &s)
}
return &response{Stat: statResponse{Globs: stats}}
}
@@ -1072,6 +1129,10 @@ func copierHandlerGet(bulkWriter io.Writer, req request, pm *fileutils.PatternMa
if len(queue) == 0 {
return errorResponse("copier: get: globs %v matched nothing (%d filtered out): %v", req.Globs, globMatchedCount, syscall.ENOENT)
}
+ topInfo, err := os.Stat(req.Directory)
+ if err != nil {
+ return errorResponse("copier: get: error reading info about directory %q: %v", req.Directory, err)
+ }
cb := func() error {
tw := tar.NewWriter(bulkWriter)
defer tw.Close()
@@ -1168,14 +1229,22 @@ func copierHandlerGet(bulkWriter io.Writer, req request, pm *fileutils.PatternMa
}
symlinkTarget = target
}
+ // if it's a directory and we're staying on one device, and it's on a
+ // different device than the one we started from, skip its contents
+ var ok error
+ if info.Mode().IsDir() && req.GetOptions.NoCrossDevice {
+ if !sameDevice(topInfo, info) {
+ ok = filepath.SkipDir
+ }
+ }
// add the item to the outgoing tar stream
if err := copierHandlerGetOne(info, symlinkTarget, rel, path, options, tw, hardlinkChecker, idMappings); err != nil {
if req.GetOptions.IgnoreUnreadable && errorIsPermission(err) {
- return nil
+ return ok
}
return err
}
- return nil
+ return ok
}
// walk the directory tree, checking/adding items individually
if err := filepath.Walk(item, walkfn); err != nil {
@@ -1463,7 +1532,7 @@ func copierHandlerPut(bulkReader io.Reader, req request, idMappings *idtools.IDM
}
return n, nil
}
- targetDirectory, err := resolvePath(req.Root, req.Directory, nil)
+ targetDirectory, err := resolvePath(req.Root, req.Directory, true, nil)
if err != nil {
return errorResponse("copier: put: error resolving %q: %v", req.Directory, err)
}
@@ -1568,7 +1637,7 @@ func copierHandlerPut(bulkReader io.Reader, req request, idMappings *idtools.IDM
if req.PutOptions.Rename != nil {
hdr.Linkname = handleRename(req.PutOptions.Rename, hdr.Linkname)
}
- if linkTarget, err = resolvePath(targetDirectory, filepath.Join(req.Root, filepath.FromSlash(hdr.Linkname)), nil); err != nil {
+ if linkTarget, err = resolvePath(targetDirectory, filepath.Join(req.Root, filepath.FromSlash(hdr.Linkname)), true, nil); err != nil {
return errors.Errorf("error resolving hardlink target path %q under root %q", hdr.Linkname, req.Root)
}
if err = os.Link(linkTarget, path); err != nil && os.IsExist(err) {
@@ -1742,7 +1811,7 @@ func copierHandlerMkdir(req request, idMappings *idtools.IDMappings) (*response,
dirUID, dirGID = hostDirPair.UID, hostDirPair.GID
}
- directory, err := resolvePath(req.Root, req.Directory, nil)
+ directory, err := resolvePath(req.Root, req.Directory, true, nil)
if err != nil {
return errorResponse("copier: mkdir: error resolving %q: %v", req.Directory, err)
}
@@ -1772,3 +1841,22 @@ func copierHandlerMkdir(req request, idMappings *idtools.IDMappings) (*response,
return &response{Error: "", Mkdir: mkdirResponse{}}, nil, nil
}
+
+func copierHandlerRemove(req request) *response {
+ errorResponse := func(fmtspec string, args ...interface{}) *response {
+ return &response{Error: fmt.Sprintf(fmtspec, args...), Remove: removeResponse{}}
+ }
+ resolvedTarget, err := resolvePath(req.Root, req.Directory, false, nil)
+ if err != nil {
+ return errorResponse("copier: remove: %v", err)
+ }
+ if req.RemoveOptions.All {
+ err = os.RemoveAll(resolvedTarget)
+ } else {
+ err = os.Remove(resolvedTarget)
+ }
+ if err != nil {
+ return errorResponse("copier: remove %q: %v", req.Directory, err)
+ }
+ return &response{Error: "", Remove: removeResponse{}}
+}
diff --git a/vendor/github.com/containers/buildah/copier/syscall_unix.go b/vendor/github.com/containers/buildah/copier/syscall_unix.go
index aa40f327c..9fc8fece3 100644
--- a/vendor/github.com/containers/buildah/copier/syscall_unix.go
+++ b/vendor/github.com/containers/buildah/copier/syscall_unix.go
@@ -4,6 +4,7 @@ package copier
import (
"os"
+ "syscall"
"time"
"github.com/pkg/errors"
@@ -73,6 +74,21 @@ func lutimes(isSymlink bool, path string, atime, mtime time.Time) error {
return unix.Lutimes(path, []unix.Timeval{unix.NsecToTimeval(atime.UnixNano()), unix.NsecToTimeval(mtime.UnixNano())})
}
+// sameDevice returns true unless we're sure that they're not on the same device
+func sameDevice(a, b os.FileInfo) bool {
+ aSys := a.Sys()
+ bSys := b.Sys()
+ if aSys == nil || bSys == nil {
+ return true
+ }
+ au, aok := aSys.(*syscall.Stat_t)
+ bu, bok := bSys.(*syscall.Stat_t)
+ if !aok || !bok {
+ return true
+ }
+ return au.Dev == bu.Dev
+}
+
const (
testModeMask = int64(os.ModePerm)
testIgnoreSymlinkDates = false
diff --git a/vendor/github.com/containers/buildah/copier/syscall_windows.go b/vendor/github.com/containers/buildah/copier/syscall_windows.go
index be50d473d..3a88d2d3e 100644
--- a/vendor/github.com/containers/buildah/copier/syscall_windows.go
+++ b/vendor/github.com/containers/buildah/copier/syscall_windows.go
@@ -77,6 +77,11 @@ func lutimes(isSymlink bool, path string, atime, mtime time.Time) error {
return windows.UtimesNano(path, []windows.Timespec{windows.NsecToTimespec(atime.UnixNano()), windows.NsecToTimespec(mtime.UnixNano())})
}
+// sameDevice returns true since we can't be sure that they're not on the same device
+func sameDevice(a, b os.FileInfo) bool {
+ return true
+}
+
const (
testModeMask = int64(0600)
testIgnoreSymlinkDates = true
diff --git a/vendor/github.com/containers/buildah/define/build.go b/vendor/github.com/containers/buildah/define/build.go
index 635626a64..dd49c47c1 100644
--- a/vendor/github.com/containers/buildah/define/build.go
+++ b/vendor/github.com/containers/buildah/define/build.go
@@ -69,6 +69,8 @@ type CommonBuildOptions struct {
Ulimit []string
// Volumes to bind mount into the container
Volumes []string
+ // Secrets are the available secrets to use in a build
+ Secrets []string
}
// BuildOptions can be used to alter how an image is built.
diff --git a/vendor/github.com/containers/buildah/define/types.go b/vendor/github.com/containers/buildah/define/types.go
index 6d4809cc0..45e85e138 100644
--- a/vendor/github.com/containers/buildah/define/types.go
+++ b/vendor/github.com/containers/buildah/define/types.go
@@ -28,7 +28,7 @@ const (
Package = "buildah"
// Version for the Package. Bump version in contrib/rpm/buildah.spec
// too.
- Version = "1.20.1-dev"
+ Version = "1.20.2-dev"
// DefaultRuntime if containers.conf fails.
DefaultRuntime = "runc"
diff --git a/vendor/github.com/containers/buildah/go.mod b/vendor/github.com/containers/buildah/go.mod
index 075bdfb01..047c0aeba 100644
--- a/vendor/github.com/containers/buildah/go.mod
+++ b/vendor/github.com/containers/buildah/go.mod
@@ -4,19 +4,19 @@ go 1.12
require (
github.com/containernetworking/cni v0.8.1
- github.com/containers/common v0.35.4
- github.com/containers/image/v5 v5.10.5
- github.com/containers/ocicrypt v1.1.0
- github.com/containers/storage v1.28.1
+ github.com/containers/common v0.37.2-0.20210503193405-42134aa138ce
+ github.com/containers/image/v5 v5.11.1
+ github.com/containers/ocicrypt v1.1.1
+ github.com/containers/storage v1.30.1
github.com/docker/distribution v2.7.1+incompatible
github.com/docker/go-units v0.4.0
github.com/docker/libnetwork v0.8.0-dev.2.0.20190625141545-5a177b73e316
github.com/fsouza/go-dockerclient v1.7.2
github.com/ghodss/yaml v1.0.0
github.com/hashicorp/go-multierror v1.1.1
- github.com/ishidawataru/sctp v0.0.0-20191218070446-00ab2ac2db07 // indirect
+ github.com/ishidawataru/sctp v0.0.0-20210226210310-f2269e66cdee // indirect
github.com/mattn/go-shellwords v1.0.11
- github.com/onsi/ginkgo v1.15.2
+ github.com/onsi/ginkgo v1.16.1
github.com/onsi/gomega v1.11.0
github.com/opencontainers/go-digest v1.0.0
github.com/opencontainers/image-spec v1.0.2-0.20190823105129-775207bd45b6
@@ -24,9 +24,8 @@ require (
github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d
github.com/opencontainers/runtime-tools v0.9.0
github.com/opencontainers/selinux v1.8.0
- github.com/openshift/imagebuilder v1.2.0
+ github.com/openshift/imagebuilder v1.2.2-0.20210415181909-87f3e48c2656
github.com/pkg/errors v0.9.1
- github.com/prometheus/procfs v0.6.0 // indirect
github.com/seccomp/libseccomp-golang v0.9.2-0.20200616122406-847368b35ebf
github.com/sirupsen/logrus v1.8.1
github.com/spf13/cobra v1.1.3
@@ -34,9 +33,9 @@ require (
github.com/stretchr/testify v1.7.0
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635
go.etcd.io/bbolt v1.3.5
- golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad
+ golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a
- golang.org/x/sys v0.0.0-20210216224549-f992740a1bac
+ golang.org/x/sys v0.0.0-20210324051608-47abb6519492
k8s.io/klog v1.0.0 // indirect
)
diff --git a/vendor/github.com/containers/buildah/go.sum b/vendor/github.com/containers/buildah/go.sum
index 6a48853ac..232a8aac1 100644
--- a/vendor/github.com/containers/buildah/go.sum
+++ b/vendor/github.com/containers/buildah/go.sum
@@ -53,9 +53,11 @@ github.com/Microsoft/hcsshim v0.8.7-0.20190325164909-8abdbb8205e4/go.mod h1:Op3h
github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ=
github.com/Microsoft/hcsshim v0.8.9/go.mod h1:5692vkUqntj1idxauYlpoINNKeqCiG6Sg38RRsjT5y8=
github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2ow3VK6a9Lg=
-github.com/Microsoft/hcsshim v0.8.15 h1:Aof83YILRs2Vx3GhHqlvvfyx1asRJKMFIMeVlHsZKtI=
github.com/Microsoft/hcsshim v0.8.15/go.mod h1:x38A4YbHbdxJtc0sF6oIz+RG0npwSCAvn69iY6URG00=
+github.com/Microsoft/hcsshim v0.8.16 h1:8/auA4LFIZFTGrqfKhGBSXwM6/4X1fHa/xniyEHu8ac=
+github.com/Microsoft/hcsshim v0.8.16/go.mod h1:o5/SZqmR7x9JNKsW3pu+nqHm0MF8vbA+VxGOoXdC600=
github.com/Microsoft/hcsshim/test v0.0.0-20201218223536-d3e5debf77da/go.mod h1:5hlzMzRKMLyo42nCZ9oml8AdTlq/0cvIaBv6tK1RehU=
+github.com/Microsoft/hcsshim/test v0.0.0-20210227013316-43a75bb4edd3/go.mod h1:mw7qgWloBUl75W/gVH3cQszUg1+gUITj7D6NY7ywVnY=
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
@@ -97,7 +99,6 @@ github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
-github.com/checkpoint-restore/go-criu/v4 v4.0.2/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw=
github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw=
github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
@@ -106,24 +107,26 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5P
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3/go.mod h1:MA5e5Lr8slmEg9bt0VpxxWqJlO4iwu3FBdHUzV7wQVg=
-github.com/cilium/ebpf v0.0.0-20200507155900-a9f01edf17e3/go.mod h1:XT+cAw5wfvsodedcijoh1l9cf7v1x9FlFB/3VmF/O8s=
github.com/cilium/ebpf v0.0.0-20200702112145-1c8d4c9ef775/go.mod h1:7cR51M8ViRLIdUjrmSXlK9pkrsDlLHbO8jiB8X8JnOc=
github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
github.com/containerd/aufs v0.0.0-20200908144142-dab0cbea06f4/go.mod h1:nukgQABAEopAHvB6j7cnP5zJ+/3aVcE7hCYqvIwAHyE=
+github.com/containerd/aufs v0.0.0-20201003224125-76a6863f2989/go.mod h1:AkGGQs9NM2vtYHaUen+NljV0/baGCAPELGm2q9ZXpWU=
+github.com/containerd/aufs v0.0.0-20210316121734-20793ff83c97/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU=
github.com/containerd/btrfs v0.0.0-20201111183144-404b9149801e/go.mod h1:jg2QkJcsabfHugurUvvPhS3E08Oxiuh5W/g1ybB4e0E=
+github.com/containerd/btrfs v0.0.0-20210316141732-918d888fb676/go.mod h1:zMcX3qkXTAi9GI50+0HOeuV8LU2ryCE/V2vG/ZBiTss=
github.com/containerd/cgroups v0.0.0-20190717030353-c4b9ac5c7601/go.mod h1:X9rLEHIqSf/wfK8NsPqxJmeZgW4pcfzdXITDrUSJ6uI=
github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko=
github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59/go.mod h1:pA0z1pT8KYB3TCXK/ocprsh7MAkoW8bZVzPdih9snmM=
github.com/containerd/cgroups v0.0.0-20200710171044-318312a37340/go.mod h1:s5q4SojHctfxANBDvMeIaIovkq29IP48TKAxnhYRxvo=
-github.com/containerd/cgroups v0.0.0-20200824123100-0b889c03f102 h1:Qf4HiqfvmB7zS6scsmNgTLmByHbq8n9RTF39v+TzP7A=
github.com/containerd/cgroups v0.0.0-20200824123100-0b889c03f102/go.mod h1:s5q4SojHctfxANBDvMeIaIovkq29IP48TKAxnhYRxvo=
+github.com/containerd/cgroups v0.0.0-20210114181951-8a68de567b68 h1:hkGVFjz+plgr5UfxZUTPFbUFIF/Km6/s+RVRIRHLrrY=
+github.com/containerd/cgroups v0.0.0-20210114181951-8a68de567b68/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE=
github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw=
github.com/containerd/console v0.0.0-20181022165439-0650fd9eeb50/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw=
github.com/containerd/console v0.0.0-20191206165004-02ecf6a7291e/go.mod h1:8Pf4gM6VEbTNRIT26AyyU7hxdQU3MvAvxVI0sc00XBE=
-github.com/containerd/console v1.0.0/go.mod h1:8Pf4gM6VEbTNRIT26AyyU7hxdQU3MvAvxVI0sc00XBE=
github.com/containerd/console v1.0.1/go.mod h1:XUsP6YE/mKtz6bxc+I8UiKKTP04qjQL4qcS3XoQ5xkw=
github.com/containerd/containerd v1.2.10/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
github.com/containerd/containerd v1.3.0-beta.2.0.20190828155532-0293cbd26c69/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
@@ -131,9 +134,12 @@ github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMX
github.com/containerd/containerd v1.3.1-0.20191213020239-082f7e3aed57/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
github.com/containerd/containerd v1.4.0-beta.2.0.20200729163537-40b22ef07410/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
+github.com/containerd/containerd v1.4.1/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
github.com/containerd/containerd v1.4.3/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
-github.com/containerd/containerd v1.5.0-beta.1 h1:IK6yirB4X7wpKyFSikWiT++nZsyIxGAAgNEv3fEGuls=
github.com/containerd/containerd v1.5.0-beta.1/go.mod h1:5HfvG1V2FsKesEGQ17k5/T7V960Tmcumvqn8Mc+pCYQ=
+github.com/containerd/containerd v1.5.0-beta.3/go.mod h1:/wr9AVtEM7x9c+n0+stptlo/uBBoBORwEx6ardVcmKU=
+github.com/containerd/containerd v1.5.0-beta.4 h1:zjz4MOAOFgdBlwid2nNUlJ3YLpVi/97L36lfMYJex60=
+github.com/containerd/containerd v1.5.0-beta.4/go.mod h1:GmdgZd2zA2GYIBZ0w09ZvgqEq8EfBp/m3lcVZIvPHhI=
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
github.com/containerd/continuity v0.0.0-20190815185530-f2a389ac0a02/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
github.com/containerd/continuity v0.0.0-20191127005431-f65d91d395eb/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
@@ -145,12 +151,17 @@ github.com/containerd/fifo v0.0.0-20180307165137-3d5202aec260/go.mod h1:ODA38xgv
github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI=
github.com/containerd/fifo v0.0.0-20200410184934-f15a3290365b/go.mod h1:jPQ2IAeZRCYxpS/Cm1495vGFww6ecHmMk1YJH2Q5ln0=
github.com/containerd/fifo v0.0.0-20201026212402-0724c46b320c/go.mod h1:jPQ2IAeZRCYxpS/Cm1495vGFww6ecHmMk1YJH2Q5ln0=
+github.com/containerd/fifo v0.0.0-20210316144830-115abcc95a1d/go.mod h1:ocF/ME1SX5b1AOlWi9r677YJmCPSwwWnQ9O123vzpE4=
github.com/containerd/go-cni v1.0.1/go.mod h1:+vUpYxKvAF72G9i1WoDOiPGRtQpqsNW/ZHtSlv++smU=
github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0=
github.com/containerd/go-runc v0.0.0-20190911050354-e029b79d8cda/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0=
github.com/containerd/go-runc v0.0.0-20200220073739-7016d3ce2328/go.mod h1:PpyHrqVs8FTi9vpyHwPwiNEGaACDxT/N/pLcvMSRA9g=
+github.com/containerd/go-runc v0.0.0-20201020171139-16b287bc67d0/go.mod h1:cNU0ZbCgCQVZK4lgG3P+9tn9/PaJNmoDXPpoJhDR+Ok=
github.com/containerd/imgcrypt v1.0.1/go.mod h1:mdd8cEPW7TPgNG4FpuP3sGBiQ7Yi/zak9TYCG3juvb0=
+github.com/containerd/imgcrypt v1.0.4-0.20210301171431-0ae5c75f59ba/go.mod h1:6TNsg0ctmizkrOgXRNQjAPFWpMYRWuiB6dSF4Pfa5SA=
+github.com/containerd/imgcrypt v1.1.1-0.20210312161619-7ed62a527887/go.mod h1:5AZJNI6sLHJljKuI9IHnw1pWqo/F0nGDOuR9zgTs7ow=
github.com/containerd/nri v0.0.0-20201007170849-eb1350a75164/go.mod h1:+2wGSDGFYfE5+So4M5syatU0N0f0LbWpuqyMi4/BE8c=
+github.com/containerd/nri v0.0.0-20210316161719-dbaa18c31c14/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY=
github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o=
github.com/containerd/ttrpc v0.0.0-20190828172938-92c8520ef9f8/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o=
github.com/containerd/ttrpc v0.0.0-20191028202541-4f1b8fe65a5c/go.mod h1:LPm1u0xBw8r8NOKoOdNMeVHSawSsltak+Ihv+etqsE8=
@@ -160,26 +171,26 @@ github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kw
github.com/containerd/typeurl v0.0.0-20190911142611-5eb25027c9fd/go.mod h1:GeKYzf2pQcqv7tJ0AoCuuhtnqhva5LNU3U+OyKxxJpk=
github.com/containerd/typeurl v1.0.1/go.mod h1:TB1hUtrpaiO88KEK56ijojHS1+NeF0izUACaJW2mdXg=
github.com/containerd/zfs v0.0.0-20200918131355-0a33824f23a2/go.mod h1:8IgZOBdv8fAgXddBT4dBXJPtxyRsejFIpXoklgxgEjw=
+github.com/containerd/zfs v0.0.0-20210301145711-11e8f1707f62/go.mod h1:A9zfAbMlQwE+/is6hi0Xw8ktpL+6glmqZYtevJgaB8Y=
+github.com/containerd/zfs v0.0.0-20210315114300-dde8f0fda960/go.mod h1:m+m51S1DvAP6r3FcmYCp54bQ34pyOwTieQDNRIRHsFY=
github.com/containernetworking/cni v0.7.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY=
github.com/containernetworking/cni v0.8.0/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY=
github.com/containernetworking/cni v0.8.1 h1:7zpDnQ3T3s4ucOuJ/ZCLrYBxzkg0AELFfII3Epo9TmI=
github.com/containernetworking/cni v0.8.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY=
github.com/containernetworking/plugins v0.8.6/go.mod h1:qnw5mN19D8fIwkqW7oHHYDHVlzhJpcY6TQxn/fUyDDM=
-github.com/containers/common v0.35.4 h1:szyWRncsHkBwCVpu1dkEOXUjkwCetlfcLmKJTwo1Sp8=
-github.com/containers/common v0.35.4/go.mod h1:rMzxgD7nMGw++cEbsp+NZv0UJO4rgXbm7F7IbJPTwIE=
-github.com/containers/image/v5 v5.10.5 h1:VK1UbsZMzjdw5Xqr3Im9h4iOqHWU0naFs+I78kavc7I=
-github.com/containers/image/v5 v5.10.5/go.mod h1:SgIbWEedCNBbn2FI5cH0/jed1Ecy2s8XK5zTxvJTzII=
+github.com/containers/common v0.37.2-0.20210503193405-42134aa138ce h1:e7VNmGqwfUQkw+D5bms262x1HYqxfN9/+t5SoaFnwTk=
+github.com/containers/common v0.37.2-0.20210503193405-42134aa138ce/go.mod h1:JjU+yvzIGyx8ZsY8nyf7snzs4VSNh1eIaYsqoSKBoRw=
+github.com/containers/image/v5 v5.11.1 h1:mNybUvU6zXUwcMsQaa3n+Idsru5pV+GE7k4oRuPzYi0=
+github.com/containers/image/v5 v5.11.1/go.mod h1:HC9lhJ/Nz5v3w/5Co7H431kLlgzlVlOC+auD/er3OqE=
github.com/containers/libtrust v0.0.0-20190913040956-14b96171aa3b h1:Q8ePgVfHDplZ7U33NwHZkrVELsZP5fYj9pM5WBZB2GE=
github.com/containers/libtrust v0.0.0-20190913040956-14b96171aa3b/go.mod h1:9rfv8iPl1ZP7aqh9YA68wnZv2NUDbXdcdPHVz0pFbPY=
github.com/containers/ocicrypt v1.0.1/go.mod h1:MeJDzk1RJHv89LjsH0Sp5KTY3ZYkjXO/C+bKAeWFIrc=
-github.com/containers/ocicrypt v1.0.3/go.mod h1:CUBa+8MRNL/VkpxYIpaMtgn1WgXGyvPQj8jcy0EVG6g=
-github.com/containers/ocicrypt v1.1.0 h1:A6UzSUFMla92uxO43O6lm86i7evMGjTY7wTKB2DyGPY=
github.com/containers/ocicrypt v1.1.0/go.mod h1:b8AOe0YR67uU8OqfVNcznfFpAzu3rdgUV4GP9qXPfu4=
-github.com/containers/storage v1.24.8/go.mod h1:YC+2pY8SkfEAcZkwycxYbpK8EiRbx5soPPwz9dxe4IQ=
-github.com/containers/storage v1.28.0 h1:lA/9i9BIjfmIRxCI8GuzasYHmU4IUXVcfZZiDceD0Eg=
-github.com/containers/storage v1.28.0/go.mod h1:ixAwO7Bj31cigqPEG7aCz+PYmxkDxbIFdUFioYdxbzI=
-github.com/containers/storage v1.28.1 h1:axYBD+c0N0YkHelDoqzdLQXfY3fgb8pqIMsRHqUNGts=
-github.com/containers/storage v1.28.1/go.mod h1:5bwiMh2LkrN3AWIfDFMH7A/xbVNLcve+oeXYvHvW8cc=
+github.com/containers/ocicrypt v1.1.1 h1:prL8l9w3ntVqXvNH1CiNn5ENjcCnr38JqpSyvKKB4GI=
+github.com/containers/ocicrypt v1.1.1/go.mod h1:Dm55fwWm1YZAjYRaJ94z2mfZikIyIN4B0oB3dj3jFxY=
+github.com/containers/storage v1.29.0/go.mod h1:u84RU4CCufGeJBNTRNwMB+FoE+AiFeFw4SsMoqAOeCM=
+github.com/containers/storage v1.30.1 h1:+87sZDoUp0uNsP45dWypHTWTEoy0eNDgFYjTU1XIRVQ=
+github.com/containers/storage v1.30.1/go.mod h1:NDJkiwxnSHD1Is+4DGcyR3SIEYSDOa0xnAW+uGQFx9E=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-iptables v0.4.5/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU=
@@ -212,13 +223,14 @@ github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8l
github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
+github.com/disiqueira/gotree/v3 v3.0.2 h1:ik5iuLQQoufZBNPY518dXhiO5056hyNBIK9lWhkNRq8=
+github.com/disiqueira/gotree/v3 v3.0.2/go.mod h1:ZuyjE4+mUQZlbpkI24AmruZKhg3VHEgPLDY8Qk+uUu8=
github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY=
github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug=
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v1.4.2-0.20191219165747-a9416c67da9f/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
-github.com/docker/docker v17.12.0-ce-rc1.0.20201020191947-73dc6a680cdd+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v20.10.3-0.20210216175712-646072ed6524+incompatible h1:Yu2uGErhwEoOT/OxAFe+/SiJCqRLs+pgcS5XKrDXnG4=
github.com/docker/docker v20.10.3-0.20210216175712-646072ed6524+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker-credential-helpers v0.6.3 h1:zI2p9+1NQYdnG6sMU26EX4aVGlqbInSQxQXLvzJ4RPQ=
@@ -279,6 +291,7 @@ github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8
github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/godbus/dbus v0.0.0-20151105175453-c7fdd8b5cd55/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e h1:BWhy2j3IXJhjCbC68FptL43tDKIq8FladmaTs3Xs7Z8=
@@ -321,6 +334,8 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA=
+github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
@@ -333,6 +348,8 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-intervals v0.0.2 h1:FGrVEiUnTRKR8yE04qzXYaJMtnIYqobR5QbblK3ixcM=
+github.com/google/go-intervals v0.0.2/go.mod h1:MkaR3LNRfeKLPmqgJYs4E66z5InYjmCjbbr4TQlcT6Y=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
@@ -373,7 +390,6 @@ github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjh
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
-github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
@@ -398,9 +414,11 @@ github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA=
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
-github.com/ishidawataru/sctp v0.0.0-20191218070446-00ab2ac2db07 h1:rw3IAne6CDuVFlZbPOkA7bhxlqawFh7RJJ+CejfMaxE=
-github.com/ishidawataru/sctp v0.0.0-20191218070446-00ab2ac2db07/go.mod h1:co9pwDoBCm1kGxawmb4sPq0cSIOOWNPT4KnHotMP1Zg=
+github.com/ishidawataru/sctp v0.0.0-20210226210310-f2269e66cdee h1:PAXLXk1heNZ5yokbMBpVLZQxo43wCZxRwl00mX+dd44=
+github.com/ishidawataru/sctp v0.0.0-20210226210310-f2269e66cdee/go.mod h1:co9pwDoBCm1kGxawmb4sPq0cSIOOWNPT4KnHotMP1Zg=
github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA=
+github.com/jinzhu/copier v0.3.0 h1:P5zN9OYSxmtzZmwgcVmt5Iu8egfP53BGMPAFgEksKPI=
+github.com/jinzhu/copier v0.3.0/go.mod h1:24xnZezI2Yqac9J61UC6/dG/k76ttpq0DdJI3QmUvro=
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
@@ -418,15 +436,15 @@ github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQL
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
-github.com/klauspost/compress v1.11.5/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
-github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
-github.com/klauspost/compress v1.11.12 h1:famVnQVu7QwryBN4jNseQdUKES71ZAOnB6UQQJPZvqk=
-github.com/klauspost/compress v1.11.12/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
+github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
+github.com/klauspost/compress v1.12.2 h1:2KCfW3I9M7nSc5wOqXAlW2v2U6v+w6cbjvbfp+OykW8=
+github.com/klauspost/compress v1.12.2/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE=
github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
-github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8=
+github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
@@ -437,6 +455,7 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/lunixbochs/vtclean v0.0.0-20180621232353-2d01aacdc34a h1:weJVJJRzAJBFRlAiJQROKQs8oC9vOxvm4rZmBBk0ONw=
github.com/lunixbochs/vtclean v0.0.0-20180621232353-2d01aacdc34a/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
+github.com/magefile/mage v1.10.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
@@ -450,10 +469,9 @@ github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNx
github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
-github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
-github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
+github.com/mattn/go-runewidth v0.0.10 h1:CoZ3S2P7pvtP45xOtBw+/mDL2z0RKI576gSkzRRpdGg=
+github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
-github.com/mattn/go-shellwords v1.0.10/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
github.com/mattn/go-shellwords v1.0.11 h1:vCoR9VPpsk/TZFW2JwK5I9S0xdrtUq2bph6/YjEPnaw=
github.com/mattn/go-shellwords v1.0.11/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
@@ -462,7 +480,6 @@ github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182aff
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/miekg/pkcs11 v1.0.3 h1:iMwmD7I5225wv84WxIG/bmxz9AXjWvTWIbM/TYHvWtw=
github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
-github.com/mistifyio/go-zfs v2.1.1+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4=
github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible h1:aKW/4cBs+yK6gpqU3K/oIwk9Q/XICqd3zOX/UFuvqmk=
github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
@@ -476,7 +493,6 @@ github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh
github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A=
github.com/moby/sys/mount v0.2.0 h1:WhCW5B355jtxndN5ovugJlMFJawbUODuW8fSnEH6SSM=
github.com/moby/sys/mount v0.2.0/go.mod h1:aAivFE2LB3W4bACsUXChRHQ0qKWsetY4Y9V7sxOougM=
-github.com/moby/sys/mountinfo v0.1.3/go.mod h1:w2t2Avltqx8vE7gX5l+QiBKxODu2TX0+Syr3h52Tw4o=
github.com/moby/sys/mountinfo v0.4.0/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A=
github.com/moby/sys/mountinfo v0.4.1 h1:1O+1cHA1aujwEwwVMa2Xm2l+gIpUHyd3+D+d7LZh1kM=
github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A=
@@ -490,7 +506,6 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
-github.com/mrunalp/fileutils v0.0.0-20171103030105-7d4729fb3618/go.mod h1:x8F1gnqOkIEiO4rqoeEEEqQbo7HjGMTvyoq3gej4iT0=
github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ=
github.com/mtrmac/gpgme v0.1.2 h1:dNOmvYmsrakgW7LcgiprD0yfRuQQe8/C8F6Z+zogO3s=
github.com/mtrmac/gpgme v0.1.2/go.mod h1:GYYHnGSuS7HK3zVS2n3y73y0okK/BeKzwnn5jgiVFNI=
@@ -511,8 +526,8 @@ github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+
github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
-github.com/onsi/ginkgo v1.15.2 h1:l77YT15o814C2qVL47NOyjV/6RbaP7kKdrvZnxQ3Org=
-github.com/onsi/ginkgo v1.15.2/go.mod h1:Dd6YFfwBW84ETqqtL0CPyPXillHgY6XhQH3uuCCTr/o=
+github.com/onsi/ginkgo v1.16.1 h1:foqVmeWDD6yYpK+Yz3fHyNIxFYNxswxqNFjSKe+vI54=
+github.com/onsi/ginkgo v1.16.1/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E=
github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
@@ -534,25 +549,22 @@ github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5X
github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
github.com/opencontainers/runc v1.0.0-rc8.0.20190926000215-3e425f80a8c9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
github.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
-github.com/opencontainers/runc v1.0.0-rc91/go.mod h1:3Sm6Dt7OT8z88EbdQqqcRN2oCT54jbi72tT/HqgflT8=
github.com/opencontainers/runc v1.0.0-rc93 h1:x2UMpOOVf3kQ8arv/EsDGwim8PTNqzL1/EYDr/+scOM=
github.com/opencontainers/runc v1.0.0-rc93/go.mod h1:3NOsor4w32B2tC0Zbl8Knk4Wg84SM2ImC1fxBuqJ/H0=
github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-spec v1.0.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-spec v1.0.2-0.20190207185410-29686dbc5559/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
-github.com/opencontainers/runtime-spec v1.0.3-0.20200520003142-237cc4f519e2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d h1:pNa8metDkwZjb9g4T8s+krQ+HRgZAkqnXml+wNir/+s=
github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs=
github.com/opencontainers/runtime-tools v0.9.0 h1:FYgwVsKRI/H9hU32MJ/4MLOzXWodKK5zsQavY8NPMkU=
github.com/opencontainers/runtime-tools v0.9.0/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs=
-github.com/opencontainers/selinux v1.5.1/go.mod h1:yTcKuYAh6R95iDpefGLQaPaRwJFwyzAJufJyiTt7s0g=
github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqiriPsEqVhc+svHE=
github.com/opencontainers/selinux v1.8.0 h1:+77ba4ar4jsCbL1GLbFL8fFM57w6suPfSS9PDLDY7KM=
github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo=
-github.com/openshift/imagebuilder v1.2.0 h1:uoZFjJICLlTMjlAL/UG2PA2kM8RjAsVflGfHJK7MMDk=
-github.com/openshift/imagebuilder v1.2.0/go.mod h1:9aJRczxCH0mvT6XQ+5STAQaPWz7OsWcU5/mRkt8IWeo=
+github.com/openshift/imagebuilder v1.2.2-0.20210415181909-87f3e48c2656 h1:WaxyNFpmIDu4i6so9r6LVFIbSaXqsj8oitMitt86ae4=
+github.com/openshift/imagebuilder v1.2.2-0.20210415181909-87f3e48c2656/go.mod h1:9aJRczxCH0mvT6XQ+5STAQaPWz7OsWcU5/mRkt8IWeo=
github.com/ostreedev/ostree-go v0.0.0-20190702140239-759a8c1ac913 h1:TnbXhKzrTOyuvWrjI8W6pcoI9XPbLHFXCdN2dtUw7Rw=
github.com/ostreedev/ostree-go v0.0.0-20190702140239-759a8c1ac913/go.mod h1:J6OG6YJVEWopen4avK3VNQSnALmmjvniMmni/YFYAwc=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
@@ -599,11 +611,13 @@ github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDa
github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
-github.com/prometheus/procfs v0.2.0 h1:wH4vA7pcjKuZzjF7lM8awk4fnuJO6idemZXoKnULUx4=
github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4=
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
+github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
+github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
+github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
@@ -647,6 +661,7 @@ github.com/stretchr/testify v0.0.0-20180303142811-b89eecf5ca5d/go.mod h1:a8OnRci
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
@@ -660,8 +675,6 @@ github.com/tchap/go-patricia v2.3.0+incompatible h1:GkY4dP3cEfEASBPPkWd+AmjYxhmD
github.com/tchap/go-patricia v2.3.0+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I=
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
-github.com/ulikunitz/xz v0.5.9 h1:RsKRIA2MO8x56wkkcd3LbtcE/uMszhb6DpRf+3uwa3I=
-github.com/ulikunitz/xz v0.5.9/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/ulikunitz/xz v0.5.10 h1:t92gobL9l3HE202wg3rlk19F6X+JOxl9BBrCCMYEYd8=
github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
@@ -670,8 +683,8 @@ github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtX
github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/vbatts/tar-split v0.11.1 h1:0Odu65rhcZ3JZaPHxl7tCI3V/C/Q9Zf82UFravl02dE=
github.com/vbatts/tar-split v0.11.1/go.mod h1:LEuURwDEiWjRjwu46yU3KVGuUdVv/dcnpcEPSzR8z6g=
-github.com/vbauerster/mpb/v5 v5.4.0 h1:n8JPunifvQvh6P1D1HAl2Ur9YcmKT1tpoUuiea5mlmg=
-github.com/vbauerster/mpb/v5 v5.4.0/go.mod h1:fi4wVo7BVQ22QcvFObm+VwliQXlV1eBT8JDaKXR4JGI=
+github.com/vbauerster/mpb/v6 v6.0.3 h1:j+twHHhSUe8aXWaT/27E98G5cSBeqEuJSVCMjmLg0PI=
+github.com/vbauerster/mpb/v6 v6.0.3/go.mod h1:5luBx4rDLWxpA4t6I5sdeeQuZhqDxc+wr5Nqf35+tnM=
github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk=
github.com/vishvananda/netlink v1.1.0 h1:1iyaYNBLmP6L0220aDnYQpo1QEV4t4hJ+xEEhhJH8j0=
github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
@@ -720,12 +733,11 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20200423211502-4bdfaf469ed5/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY=
-golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
+golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 h1:It14KIkyBFYkHkwZ7k45minvA9aorojkyjGk9KJ5B/w=
+golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -791,8 +803,9 @@ golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81R
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/net v0.0.0-20201224014010-6772e930b67b h1:iFwSg7t5GZmB/Q5TjiEAsdoLDrdJRC1RiF2WhuV29Qw=
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw=
+golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -804,9 +817,7 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a h1:DcqTD9SDLc+1P/r1EmRBwnVsrOwW+kk2vWf9n+1sGhs=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -855,8 +866,8 @@ golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200327173247-9dae0f8f5775/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200817155316-9781c653f443/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -868,13 +879,12 @@ golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201202213521-69691e467435/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20201218084310-7d0127a74742/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210216224549-f992740a1bac h1:9glrpwtNjBYgRpb67AZJKHfzj1stG/8BL5H7In2oTC4=
golang.org/x/sys v0.0.0-20210216224549-f992740a1bac/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210324051608-47abb6519492 h1:Paq34FxTluEPvVyayQqMPgHm+vTOrIifmcYxFBx9TLg=
+golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201113234701-d7a72108b828/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
-golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
diff --git a/vendor/github.com/containers/buildah/image.go b/vendor/github.com/containers/buildah/image.go
index 51d18232a..92e0c3e8e 100644
--- a/vendor/github.com/containers/buildah/image.go
+++ b/vendor/github.com/containers/buildah/image.go
@@ -295,7 +295,7 @@ func (i *containerImageRef) NewImageSource(ctx context.Context, sc *types.System
if src == nil {
err2 := os.RemoveAll(path)
if err2 != nil {
- logrus.Errorf("error removing layer blob directory %q: %v", path, err)
+ logrus.Errorf("error removing layer blob directory: %v", err)
}
}
}()
diff --git a/vendor/github.com/containers/buildah/imagebuildah/build.go b/vendor/github.com/containers/buildah/imagebuildah/build.go
index 062752274..62e656271 100644
--- a/vendor/github.com/containers/buildah/imagebuildah/build.go
+++ b/vendor/github.com/containers/buildah/imagebuildah/build.go
@@ -165,11 +165,22 @@ func BuildDockerfiles(ctx context.Context, store storage.Store, options define.B
}
func warnOnUnsetBuildArgs(node *parser.Node, args map[string]string) {
+ argFound := make(map[string]bool)
for _, child := range node.Children {
switch strings.ToUpper(child.Value) {
case "ARG":
argName := child.Next.Value
- if _, ok := args[argName]; !strings.Contains(argName, "=") && !ok {
+ if strings.Contains(argName, "=") {
+ res := strings.Split(argName, "=")
+ if res[1] != "" {
+ argFound[res[0]] = true
+ }
+ }
+ argHasValue := true
+ if !strings.Contains(argName, "=") {
+ argHasValue = argFound[argName]
+ }
+ if _, ok := args[argName]; !argHasValue && !ok {
logrus.Warnf("missing %q build argument. Try adding %q to the command line", argName, fmt.Sprintf("--build-arg %s=<VALUE>", argName))
}
default:
diff --git a/vendor/github.com/containers/buildah/imagebuildah/chroot_symlink_linux.go b/vendor/github.com/containers/buildah/imagebuildah/chroot_symlink_linux.go
deleted file mode 100644
index 4dd49130d..000000000
--- a/vendor/github.com/containers/buildah/imagebuildah/chroot_symlink_linux.go
+++ /dev/null
@@ -1,151 +0,0 @@
-package imagebuildah
-
-import (
- "flag"
- "fmt"
- "os"
- "path/filepath"
- "strings"
-
- "github.com/containers/storage/pkg/reexec"
- "github.com/pkg/errors"
- "golang.org/x/sys/unix"
-)
-
-const (
- symlinkChrootedCommand = "chrootsymlinks-resolve"
- maxSymlinksResolved = 40
-)
-
-func init() {
- reexec.Register(symlinkChrootedCommand, resolveChrootedSymlinks)
-}
-
-// resolveSymlink uses a child subprocess to resolve any symlinks in filename
-// in the context of rootdir.
-func resolveSymlink(rootdir, filename string) (string, error) {
- // The child process expects a chroot and one path that
- // will be consulted relative to the chroot directory and evaluated
- // for any symbolic links present.
- cmd := reexec.Command(symlinkChrootedCommand, rootdir, filename)
- output, err := cmd.CombinedOutput()
- if err != nil {
- return "", errors.Wrapf(err, string(output))
- }
-
- // Hand back the resolved symlink, will be filename if a symlink is not found
- return string(output), nil
-}
-
-// main() for resolveSymlink()'s subprocess.
-func resolveChrootedSymlinks() {
- status := 0
- flag.Parse()
- if len(flag.Args()) < 2 {
- fmt.Fprintf(os.Stderr, "%s needs two arguments\n", symlinkChrootedCommand)
- os.Exit(1)
- }
- // Our first parameter is the directory to chroot into.
- if err := unix.Chdir(flag.Arg(0)); err != nil {
- fmt.Fprintf(os.Stderr, "chdir(): %v\n", err)
- os.Exit(1)
- }
- if err := unix.Chroot(flag.Arg(0)); err != nil {
- fmt.Fprintf(os.Stderr, "chroot(): %v\n", err)
- os.Exit(1)
- }
-
- // Our second parameter is the path name to evaluate for symbolic links
- symLink, err := getSymbolicLink(flag.Arg(1))
- if err != nil {
- fmt.Fprintf(os.Stderr, "error getting symbolic links: %v\n", err)
- os.Exit(1)
- }
- if _, err := os.Stdout.WriteString(symLink); err != nil {
- fmt.Fprintf(os.Stderr, "error writing string to stdout: %v\n", err)
- os.Exit(1)
- }
- os.Exit(status)
-}
-
-// getSymbolic link goes through each part of the path and continues resolving symlinks as they appear.
-// Returns what the whole target path for what "path" resolves to.
-func getSymbolicLink(path string) (string, error) {
- var (
- symPath string
- symLinksResolved int
- )
- // Splitting path as we need to resolve each part of the path at a time
- splitPath := strings.Split(path, "/")
- if splitPath[0] == "" {
- splitPath = splitPath[1:]
- symPath = "/"
- }
- for _, p := range splitPath {
- // If we have resolved 40 symlinks, that means something is terribly wrong
- // will return an error and exit
- if symLinksResolved >= maxSymlinksResolved {
- return "", errors.Errorf("have resolved %q symlinks, something is terribly wrong!", maxSymlinksResolved)
- }
- symPath = filepath.Join(symPath, p)
- isSymlink, resolvedPath, err := hasSymlink(symPath)
- if err != nil {
- return "", err
- }
- // if isSymlink is true, check if resolvedPath is potentially another symlink
- // keep doing this till resolvedPath is not a symlink and isSymlink is false
- for isSymlink {
- // Need to keep track of number of symlinks resolved
- // Will also return an error if the symlink points to itself as that will exceed maxSymlinksResolved
- if symLinksResolved >= maxSymlinksResolved {
- return "", errors.Errorf("have resolved %q symlinks, something is terribly wrong!", maxSymlinksResolved)
- }
- isSymlink, resolvedPath, err = hasSymlink(resolvedPath)
- if err != nil {
- return "", err
- }
- symLinksResolved++
- }
- // Assign resolvedPath to symPath. The next part of the loop will append the next part of the original path
- // and continue resolving
- symPath = resolvedPath
- symLinksResolved++
- }
- return symPath, nil
-}
-
-// hasSymlink returns true and the target if path is symlink
-// otherwise it returns false and path
-func hasSymlink(path string) (bool, string, error) {
- info, err := os.Lstat(path)
- if err != nil {
- if os.IsNotExist(err) {
- if err = os.MkdirAll(path, 0755); err != nil {
- return false, "", err
- }
- info, err = os.Lstat(path)
- if err != nil {
- return false, "", err
- }
- } else {
- return false, path, err
- }
- }
-
- // Return false and path as path if not a symlink
- if info.Mode()&os.ModeSymlink != os.ModeSymlink {
- return false, path, nil
- }
-
- // Read the symlink to get what it points to
- targetDir, err := os.Readlink(path)
- if err != nil {
- return false, "", err
- }
- // if the symlink points to a relative path, prepend the path till now to the resolved path
- if !filepath.IsAbs(targetDir) {
- targetDir = filepath.Join(filepath.Dir(path), targetDir)
- }
- // run filepath.Clean to remove the ".." from relative paths
- return true, filepath.Clean(targetDir), nil
-}
diff --git a/vendor/github.com/containers/buildah/imagebuildah/chroot_symlink_unsupported.go b/vendor/github.com/containers/buildah/imagebuildah/chroot_symlink_unsupported.go
deleted file mode 100644
index 2cec4fe21..000000000
--- a/vendor/github.com/containers/buildah/imagebuildah/chroot_symlink_unsupported.go
+++ /dev/null
@@ -1,13 +0,0 @@
-// +build !linux
-
-package imagebuildah
-
-import "github.com/pkg/errors"
-
-func resolveSymlink(rootdir, filename string) (string, error) {
- return "", errors.New("function not supported on non-linux systems")
-}
-
-func resolveModifiedTime(rootdir, filename, historyTime string) (bool, error) {
- return false, errors.New("function not supported on non-linux systems")
-}
diff --git a/vendor/github.com/containers/buildah/imagebuildah/executor.go b/vendor/github.com/containers/buildah/imagebuildah/executor.go
index b7b339961..fc4753e35 100644
--- a/vendor/github.com/containers/buildah/imagebuildah/executor.go
+++ b/vendor/github.com/containers/buildah/imagebuildah/executor.go
@@ -16,10 +16,12 @@ import (
"github.com/containers/buildah/define"
"github.com/containers/buildah/pkg/parse"
"github.com/containers/buildah/util"
+ "github.com/containers/common/libimage"
"github.com/containers/common/pkg/config"
"github.com/containers/image/v5/docker/reference"
"github.com/containers/image/v5/manifest"
is "github.com/containers/image/v5/storage"
+ storageTransport "github.com/containers/image/v5/storage"
"github.com/containers/image/v5/transports"
"github.com/containers/image/v5/transports/alltransports"
"github.com/containers/image/v5/types"
@@ -117,6 +119,7 @@ type Executor struct {
imageInfoCache map[string]imageTypeAndHistoryAndDiffIDs
fromOverride string
manifest string
+ secrets map[string]string
}
type imageTypeAndHistoryAndDiffIDs struct {
@@ -164,6 +167,11 @@ func NewExecutor(store storage.Store, options define.BuildOptions, mainNode *par
transientMounts = append([]Mount{Mount(mount)}, transientMounts...)
}
+ secrets, err := parse.Secrets(options.CommonBuildOpts.Secrets)
+ if err != nil {
+ return nil, err
+ }
+
jobs := 1
if options.Jobs != nil {
jobs = *options.Jobs
@@ -234,6 +242,7 @@ func NewExecutor(store storage.Store, options define.BuildOptions, mainNode *par
imageInfoCache: make(map[string]imageTypeAndHistoryAndDiffIDs),
fromOverride: options.From,
manifest: options.Manifest,
+ secrets: secrets,
}
if exec.err == nil {
exec.err = os.Stderr
@@ -301,22 +310,23 @@ func (b *Executor) startStage(ctx context.Context, stage *imagebuilder.Stage, st
// resolveNameToImageRef creates a types.ImageReference for the output name in local storage
func (b *Executor) resolveNameToImageRef(output string) (types.ImageReference, error) {
- imageRef, err := alltransports.ParseImageName(output)
+ if imageRef, err := alltransports.ParseImageName(output); err == nil {
+ return imageRef, nil
+ }
+ runtime, err := libimage.RuntimeFromStore(b.store, &libimage.RuntimeOptions{SystemContext: b.systemContext})
if err != nil {
- candidates, _, _, err := util.ResolveName(output, "", b.systemContext, b.store)
- if err != nil {
- return nil, errors.Wrapf(err, "error parsing target image name %q", output)
- }
- if len(candidates) == 0 {
- return nil, errors.Errorf("error parsing target image name %q", output)
- }
- imageRef2, err2 := is.Transport.ParseStoreReference(b.store, candidates[0])
- if err2 != nil {
- return nil, errors.Wrapf(err, "error parsing target image name %q", output)
- }
- return imageRef2, nil
+ return nil, err
}
- return imageRef, nil
+ resolved, err := runtime.ResolveName(output)
+ if err != nil {
+ return nil, err
+ }
+ imageRef, err := storageTransport.Transport.ParseStoreReference(b.store, resolved)
+ if err == nil {
+ return imageRef, nil
+ }
+
+ return imageRef, err
}
// waitForStage waits for an entry to be added to terminatedStage indicating
@@ -661,19 +671,31 @@ func (b *Executor) Build(ctx context.Context, stages imagebuilder.Stages) (image
fmt.Fprintf(b.out, "[Warning] one or more build args were not consumed: %v\n", unusedList)
}
- if len(b.additionalTags) > 0 {
- if dest, err := b.resolveNameToImageRef(b.output); err == nil {
- switch dest.Transport().Name() {
- case is.Transport.Name():
- img, err := is.Transport.GetStoreImage(b.store, dest)
- if err != nil {
- return imageID, ref, errors.Wrapf(err, "error locating just-written image %q", transports.ImageName(dest))
- }
+ // Add additional tags and print image names recorded in storage
+ if dest, err := b.resolveNameToImageRef(b.output); err == nil {
+ switch dest.Transport().Name() {
+ case is.Transport.Name():
+ img, err := is.Transport.GetStoreImage(b.store, dest)
+ if err != nil {
+ return imageID, ref, errors.Wrapf(err, "error locating just-written image %q", transports.ImageName(dest))
+ }
+ if len(b.additionalTags) > 0 {
if err = util.AddImageNames(b.store, "", b.systemContext, img, b.additionalTags); err != nil {
return imageID, ref, errors.Wrapf(err, "error setting image names to %v", append(img.Names, b.additionalTags...))
}
logrus.Debugf("assigned names %v to image %q", img.Names, img.ID)
- default:
+ }
+ // Report back the caller the tags applied, if any.
+ img, err = is.Transport.GetStoreImage(b.store, dest)
+ if err != nil {
+ return imageID, ref, errors.Wrapf(err, "error locating just-written image %q", transports.ImageName(dest))
+ }
+ for _, name := range img.Names {
+ fmt.Fprintf(b.out, "Successfully tagged %s\n", name)
+ }
+
+ default:
+ if len(b.additionalTags) > 0 {
logrus.Warnf("don't know how to add tags to images stored in %q transport", dest.Transport().Name())
}
}
diff --git a/vendor/github.com/containers/buildah/imagebuildah/stage_executor.go b/vendor/github.com/containers/buildah/imagebuildah/stage_executor.go
index ff9abdda8..f1bee9366 100644
--- a/vendor/github.com/containers/buildah/imagebuildah/stage_executor.go
+++ b/vendor/github.com/containers/buildah/imagebuildah/stage_executor.go
@@ -24,7 +24,7 @@ import (
"github.com/containers/image/v5/transports"
"github.com/containers/image/v5/types"
"github.com/containers/storage"
- "github.com/containers/storage/pkg/archive"
+ "github.com/containers/storage/pkg/chrootarchive"
docker "github.com/fsouza/go-dockerclient"
digest "github.com/opencontainers/go-digest"
v1 "github.com/opencontainers/image-spec/specs-go/v1"
@@ -81,12 +81,12 @@ func (s *StageExecutor) Preserve(path string) error {
// This path is already a subdirectory of a volume path that
// we're already preserving, so there's nothing new to be done
// except ensure that it exists.
- archivedPath := filepath.Join(s.mountPoint, path)
- if err := os.MkdirAll(archivedPath, 0755); err != nil {
+ createdDirPerms := os.FileMode(0755)
+ if err := copier.Mkdir(s.mountPoint, filepath.Join(s.mountPoint, path), copier.MkdirOptions{ChmodNew: &createdDirPerms}); err != nil {
return errors.Wrapf(err, "error ensuring volume path exists")
}
if err := s.volumeCacheInvalidate(path); err != nil {
- return errors.Wrapf(err, "error ensuring volume path %q is preserved", archivedPath)
+ return errors.Wrapf(err, "error ensuring volume path %q is preserved", filepath.Join(s.mountPoint, path))
}
return nil
}
@@ -102,16 +102,24 @@ func (s *StageExecutor) Preserve(path string) error {
// Try and resolve the symlink (if one exists)
// Set archivedPath and path based on whether a symlink is found or not
- if symLink, err := resolveSymlink(s.mountPoint, path); err == nil {
- archivedPath = filepath.Join(s.mountPoint, symLink)
- path = symLink
+ if evaluated, err := copier.Eval(s.mountPoint, filepath.Join(s.mountPoint, path), copier.EvalOptions{}); err == nil {
+ symLink, err := filepath.Rel(s.mountPoint, evaluated)
+ if err != nil {
+ return errors.Wrapf(err, "making evaluated path %q relative to %q", evaluated, s.mountPoint)
+ }
+ if strings.HasPrefix(symLink, ".."+string(os.PathSeparator)) {
+ return errors.Errorf("evaluated path %q was not below %q", evaluated, s.mountPoint)
+ }
+ archivedPath = evaluated
+ path = string(os.PathSeparator) + symLink
} else {
- return errors.Wrapf(err, "error reading symbolic link to %q", path)
+ return errors.Wrapf(err, "error evaluating path %q", path)
}
st, err := os.Stat(archivedPath)
if os.IsNotExist(err) {
- if err = os.MkdirAll(archivedPath, 0755); err != nil {
+ createdDirPerms := os.FileMode(0755)
+ if err = copier.Mkdir(s.mountPoint, archivedPath, copier.MkdirOptions{ChmodNew: &createdDirPerms}); err != nil {
return errors.Wrapf(err, "error ensuring volume path exists")
}
st, err = os.Stat(archivedPath)
@@ -178,64 +186,85 @@ func (s *StageExecutor) volumeCacheInvalidate(path string) error {
return err
}
archivedPath := filepath.Join(s.mountPoint, cachedPath)
- logrus.Debugf("invalidated volume cache for %q from %q", archivedPath, s.volumeCache[cachedPath])
- delete(s.volumeCache, cachedPath)
+ logrus.Debugf("invalidated volume cache %q for %q from %q", archivedPath, path, s.volumeCache[cachedPath])
}
return nil
}
// Save the contents of each of the executor's list of volumes for which we
// don't already have a cache file.
-func (s *StageExecutor) volumeCacheSaveVFS() error {
+func (s *StageExecutor) volumeCacheSaveVFS() (mounts []specs.Mount, err error) {
for cachedPath, cacheFile := range s.volumeCache {
- archivedPath := filepath.Join(s.mountPoint, cachedPath)
- _, err := os.Stat(cacheFile)
+ archivedPath, err := copier.Eval(s.mountPoint, filepath.Join(s.mountPoint, cachedPath), copier.EvalOptions{})
+ if err != nil {
+ return nil, errors.Wrapf(err, "error evaluating volume path")
+ }
+ relativePath, err := filepath.Rel(s.mountPoint, archivedPath)
+ if err != nil {
+ return nil, errors.Wrapf(err, "error converting %q into a path relative to %q", archivedPath, s.mountPoint)
+ }
+ if strings.HasPrefix(relativePath, ".."+string(os.PathSeparator)) {
+ return nil, errors.Errorf("error converting %q into a path relative to %q", archivedPath, s.mountPoint)
+ }
+ _, err = os.Stat(cacheFile)
if err == nil {
logrus.Debugf("contents of volume %q are already cached in %q", archivedPath, cacheFile)
continue
}
if !os.IsNotExist(err) {
- return err
+ return nil, err
}
- if err := os.MkdirAll(archivedPath, 0755); err != nil {
- return errors.Wrapf(err, "error ensuring volume path exists")
+ createdDirPerms := os.FileMode(0755)
+ if err := copier.Mkdir(s.mountPoint, archivedPath, copier.MkdirOptions{ChmodNew: &createdDirPerms}); err != nil {
+ return nil, errors.Wrapf(err, "error ensuring volume path exists")
}
logrus.Debugf("caching contents of volume %q in %q", archivedPath, cacheFile)
cache, err := os.Create(cacheFile)
if err != nil {
- return err
+ return nil, err
}
defer cache.Close()
- rc, err := archive.Tar(archivedPath, archive.Uncompressed)
+ rc, err := chrootarchive.Tar(archivedPath, nil, s.mountPoint)
if err != nil {
- return errors.Wrapf(err, "error archiving %q", archivedPath)
+ return nil, errors.Wrapf(err, "error archiving %q", archivedPath)
}
defer rc.Close()
_, err = io.Copy(cache, rc)
if err != nil {
- return errors.Wrapf(err, "error archiving %q to %q", archivedPath, cacheFile)
+ return nil, errors.Wrapf(err, "error archiving %q to %q", archivedPath, cacheFile)
+ }
+ mount := specs.Mount{
+ Source: archivedPath,
+ Destination: string(os.PathSeparator) + relativePath,
+ Type: "bind",
+ Options: []string{"private"},
}
+ mounts = append(mounts, mount)
}
- return nil
+ return nil, nil
}
// Restore the contents of each of the executor's list of volumes.
func (s *StageExecutor) volumeCacheRestoreVFS() (err error) {
for cachedPath, cacheFile := range s.volumeCache {
- archivedPath := filepath.Join(s.mountPoint, cachedPath)
+ archivedPath, err := copier.Eval(s.mountPoint, filepath.Join(s.mountPoint, cachedPath), copier.EvalOptions{})
+ if err != nil {
+ return errors.Wrapf(err, "error evaluating volume path")
+ }
logrus.Debugf("restoring contents of volume %q from %q", archivedPath, cacheFile)
cache, err := os.Open(cacheFile)
if err != nil {
return err
}
defer cache.Close()
- if err := os.RemoveAll(archivedPath); err != nil {
+ if err := copier.Remove(s.mountPoint, archivedPath, copier.RemoveOptions{All: true}); err != nil {
return err
}
- if err := os.MkdirAll(archivedPath, 0755); err != nil {
+ createdDirPerms := os.FileMode(0755)
+ if err := copier.Mkdir(s.mountPoint, archivedPath, copier.MkdirOptions{ChmodNew: &createdDirPerms}); err != nil {
return err
}
- err = archive.Untar(cache, archivedPath, nil)
+ err = chrootarchive.Untar(cache, archivedPath, nil)
if err != nil {
return errors.Wrapf(err, "error extracting archive at %q", archivedPath)
}
@@ -264,6 +293,10 @@ func (s *StageExecutor) volumeCacheRestoreVFS() (err error) {
// don't already have a cache file.
func (s *StageExecutor) volumeCacheSaveOverlay() (mounts []specs.Mount, err error) {
for cachedPath := range s.volumeCache {
+ err = copier.Mkdir(s.mountPoint, filepath.Join(s.mountPoint, cachedPath), copier.MkdirOptions{})
+ if err != nil {
+ return nil, errors.Wrapf(err, "ensuring volume exists")
+ }
volumePath := filepath.Join(s.mountPoint, cachedPath)
mount := specs.Mount{
Source: volumePath,
@@ -287,7 +320,7 @@ func (s *StageExecutor) volumeCacheSave() (mounts []specs.Mount, err error) {
case "overlay":
return s.volumeCacheSaveOverlay()
}
- return nil, s.volumeCacheSaveVFS()
+ return s.volumeCacheSaveVFS()
}
// Reset the contents of each of the executor's list of volumes.
@@ -372,7 +405,7 @@ func (s *StageExecutor) Copy(excludes []string, copies ...imagebuilder.Copy) err
StripSetgidBit: stripSetgid,
}
if err := s.builder.Add(copy.Dest, copy.Download, options, sources...); err != nil {
- return errors.Wrapf(err, "error adding sources %v", sources)
+ return err
}
}
return nil
@@ -411,6 +444,8 @@ func (s *StageExecutor) Run(run imagebuilder.Run, config docker.Config) error {
Quiet: s.executor.quiet,
NamespaceOptions: s.executor.namespaceOptions,
Terminal: buildah.WithoutTerminal,
+ Secrets: s.executor.secrets,
+ RunMounts: run.Mounts,
}
if config.NetworkDisabled {
options.ConfigureNetwork = buildah.NetworkDisabled
diff --git a/vendor/github.com/containers/buildah/install.md b/vendor/github.com/containers/buildah/install.md
index 90e844c3e..4dc362911 100644
--- a/vendor/github.com/containers/buildah/install.md
+++ b/vendor/github.com/containers/buildah/install.md
@@ -4,19 +4,6 @@
## Installing packaged versions of buildah
-#### [Amazon Linux 2](https://aws.amazon.com/amazon-linux-2/)
-
-The [Kubic project](https://build.opensuse.org/project/show/devel:kubic:libcontainers:stable)
-provides updated packages for CentOS 7 which can be used unmodified on Amazon Linux 2.
-
-```bash
-cd /etc/yum.repos.d/
-sudo wget https://download.opensuse.org/repositories/devel:kubic:libcontainers:stable/CentOS_7/devel:kubic:libcontainers:stable.repo
-sudo yum -y install yum-plugin-copr
-sudo yum -y copr enable lsm5/container-selinux
-sudo yum -y install buildah
-```
-
### [Arch Linux](https://www.archlinux.org)
```bash
@@ -34,26 +21,28 @@ sudo yum -y install buildah
```
The [Kubic project](https://build.opensuse.org/project/show/devel:kubic:libcontainers:stable)
-provides updated packages for CentOS 7, 8 and Stream.
+provides updated packages for CentOS 8 and CentOS 8 Stream.
```bash
-# CentOS 7
-sudo curl -L -o /etc/yum.repos.d/devel:kubic:libcontainers:stable.repo https://download.opensuse.org/repositories/devel:kubic:libcontainers:stable/CentOS_7/devel:kubic:libcontainers:stable.repo
-sudo yum -y install buildah
-
# CentOS 8
sudo dnf -y module disable container-tools
sudo dnf -y install 'dnf-command(copr)'
sudo dnf -y copr enable rhcontainerbot/container-selinux
sudo curl -L -o /etc/yum.repos.d/devel:kubic:libcontainers:stable.repo https://download.opensuse.org/repositories/devel:kubic:libcontainers:stable/CentOS_8/devel:kubic:libcontainers:stable.repo
-sudo dnf -y install buildah
+# OPTIONAL FOR RUNC USERS: crun will be installed by default. Install runc first if you prefer runc
+sudo dnf -y --refresh install runc
+# Install Buildah
+sudo dnf -y --refresh install buildah
-# CentOS Stream
+# CentOS 8 Stream
sudo dnf -y module disable container-tools
sudo dnf -y install 'dnf-command(copr)'
sudo dnf -y copr enable rhcontainerbot/container-selinux
sudo curl -L -o /etc/yum.repos.d/devel:kubic:libcontainers:stable.repo https://download.opensuse.org/repositories/devel:kubic:libcontainers:stable/CentOS_8_Stream/devel:kubic:libcontainers:stable.repo
-sudo dnf -y install buildah
+# OPTIONAL FOR RUNC USERS: crun will be installed by default. Install runc first if you prefer runc
+sudo dnf -y --refresh install runc
+# Install Buildah
+sudo dnf -y --refresh install buildah
```
@@ -69,36 +58,6 @@ sudo apt-get update
sudo apt-get -y install buildah
```
-If you would prefer newer (though not as well-tested) packages,
-the [Kubic project](https://build.opensuse.org/package/show/devel:kubic:libcontainers:stable/buildah)
-provides packages for Debian 10 and newer. The packages in Kubic project repos are more frequently
-updated than the one in Debian's official repositories, due to how Debian works.
-The build sources for the Kubic packages can be found [here](https://gitlab.com/rhcontainerbot/buildah/-/tree/debian/debian).
-
-CAUTION: On Debian 11 and newer, including Testing and Sid/Unstable, we highly recommend you use Buildah, Podman and Skopeo ONLY from EITHER the Kubic repo
-OR the official Debian repos. Mixing and matching may lead to unpredictable situations including installation conflicts.
-
-```bash
-# Debian 10
-echo 'deb https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/Debian_10/ /' > /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list
-curl -L https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/Debian_10/Release.key | sudo apt-key add -
-sudo apt-get update
-sudo apt-get -y install buildah
-
-# Debian Testing
-echo 'deb https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/Debian_Testing/ /' > /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list
-curl -L https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/Debian_Testing/Release.key | sudo apt-key add -
-sudo apt-get update
-sudo apt-get -y install buildah
-
-# Debian Sid/Unstable
-echo 'deb https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/Debian_Unstable/ /' > /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list
-curl -L https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/Debian_Unstable/Release.key | sudo apt-key add -
-sudo apt-get update
-sudo apt-get -y install buildah
-```
-
-
### [Fedora](https://www.fedoraproject.org)
@@ -143,21 +102,6 @@ sudo subscription-manager repos --enable=rhel-7-server-extras-rpms
sudo yum -y install buildah
```
-#### [Raspberry Pi OS armhf (ex Raspbian)](https://www.raspberrypi.org/downloads/raspberry-pi-os/)
-
-The [Kubic project](https://build.opensuse.org/package/show/devel:kubic:libcontainers:stable/buildah) provides
-packages for Raspbian 10.
-
-```bash
-# Raspbian 10
-echo 'deb https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/Raspbian_10/ /' | sudo tee /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list
-curl -L https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/Raspbian_10/Release.key | sudo apt-key add -
-sudo apt-get update -qq
-sudo apt-get -qq -y install buildah
-```
-
-The build sources for the Kubic packages can be found [here](https://gitlab.com/rhcontainerbot/buildah/-/tree/debian/debian).
-
#### [Raspberry Pi OS arm64 (beta)](https://downloads.raspberrypi.org/raspios_arm64/images/)
Raspberry Pi OS use the standard Debian's repositories,
@@ -185,7 +129,7 @@ sudo apt-get -y install buildah
If you would prefer newer (though not as well-tested) packages,
the [Kubic project](https://build.opensuse.org/package/show/devel:kubic:libcontainers:stable/buildah)
-provides packages for active Ubuntu releases 18.04 and newer (it should also work with direct derivatives like Pop!\_OS).
+provides packages for active Ubuntu releases 20.04 and newer (it should also work with direct derivatives like Pop!\_OS).
The packages in Kubic project repos are more frequently updated than the one in Ubuntu's official repositories, due to how Debian/Ubuntu works.
Checkout the Kubic project page for a list of supported Ubuntu version and architecture combinations.
The build sources for the Kubic packages can be found [here](https://gitlab.com/rhcontainerbot/buildah/-/tree/debian/debian).
diff --git a/vendor/github.com/containers/buildah/new.go b/vendor/github.com/containers/buildah/new.go
index f29af1f5d..0293e4abd 100644
--- a/vendor/github.com/containers/buildah/new.go
+++ b/vendor/github.com/containers/buildah/new.go
@@ -4,18 +4,15 @@ import (
"context"
"fmt"
"math/rand"
- "runtime"
"strings"
"github.com/containers/buildah/define"
- "github.com/containers/buildah/util"
- "github.com/containers/image/v5/docker"
+ "github.com/containers/buildah/pkg/blobcache"
+ "github.com/containers/common/libimage"
+ "github.com/containers/common/pkg/config"
"github.com/containers/image/v5/image"
"github.com/containers/image/v5/manifest"
- "github.com/containers/image/v5/pkg/shortnames"
- is "github.com/containers/image/v5/storage"
"github.com/containers/image/v5/transports"
- "github.com/containers/image/v5/transports/alltransports"
"github.com/containers/image/v5/types"
"github.com/containers/storage"
digest "github.com/opencontainers/go-digest"
@@ -30,29 +27,6 @@ const (
BaseImageFakeName = imagebuilder.NoBaseImageSpecifier
)
-func pullAndFindImage(ctx context.Context, store storage.Store, srcRef types.ImageReference, options BuilderOptions, sc *types.SystemContext) (*storage.Image, types.ImageReference, error) {
- pullOptions := PullOptions{
- ReportWriter: options.ReportWriter,
- Store: store,
- SystemContext: options.SystemContext,
- BlobDirectory: options.BlobDirectory,
- MaxRetries: options.MaxPullRetries,
- RetryDelay: options.PullRetryDelay,
- OciDecryptConfig: options.OciDecryptConfig,
- }
- ref, err := pullImage(ctx, store, srcRef, pullOptions, sc)
- if err != nil {
- logrus.Debugf("error pulling image %q: %v", transports.ImageName(srcRef), err)
- return nil, nil, err
- }
- img, err := is.Transport.GetStoreImage(store, ref)
- if err != nil {
- logrus.Debugf("error reading pulled image %q: %v", transports.ImageName(srcRef), err)
- return nil, nil, errors.Wrapf(err, "error locating image %q in local storage", transports.ImageName(ref))
- }
- return img, ref, nil
-}
-
func getImageName(name string, img *storage.Image) string {
imageName := name
if len(img.Names) > 0 {
@@ -105,187 +79,6 @@ func newContainerIDMappingOptions(idmapOptions *define.IDMappingOptions) storage
return options
}
-func resolveLocalImage(systemContext *types.SystemContext, store storage.Store, options BuilderOptions) (types.ImageReference, string, string, *storage.Image, error) {
- candidates, _, _, err := util.ResolveName(options.FromImage, options.Registry, systemContext, store)
- if err != nil {
- return nil, "", "", nil, errors.Wrapf(err, "error resolving local image %q", options.FromImage)
- }
- for _, imageName := range candidates {
- img, err := store.Image(imageName)
- if err != nil {
- if errors.Cause(err) == storage.ErrImageUnknown {
- continue
- }
- return nil, "", "", nil, err
- }
- ref, err := is.Transport.ParseStoreReference(store, img.ID)
- if err != nil {
- return nil, "", "", nil, errors.Wrapf(err, "error parsing reference to image %q", img.ID)
- }
- return ref, ref.Transport().Name(), imageName, img, nil
- }
-
- return nil, "", "", nil, nil
-}
-
-func imageMatch(ctx context.Context, ref types.ImageReference, systemContext *types.SystemContext) bool {
- img, err := ref.NewImage(ctx, systemContext)
- if err != nil {
- logrus.Warnf("Failed to create newImage in imageMatch: %v", err)
- return false
- }
- defer img.Close()
- data, err := img.Inspect(ctx)
- if err != nil {
- logrus.Warnf("Failed to inspect img %s: %v", ref, err)
- return false
- }
- os := systemContext.OSChoice
- if os == "" {
- os = runtime.GOOS
- }
- arch := systemContext.ArchitectureChoice
- if arch == "" {
- arch = runtime.GOARCH
- }
- if os == data.Os && arch == data.Architecture {
- if systemContext.VariantChoice == "" || systemContext.VariantChoice == data.Variant {
- return true
- }
- }
- return false
-}
-
-func resolveImage(ctx context.Context, systemContext *types.SystemContext, store storage.Store, options BuilderOptions) (types.ImageReference, string, *storage.Image, error) {
- if systemContext == nil {
- systemContext = &types.SystemContext{}
- }
-
- fromImage := options.FromImage
- // If the image name includes a transport we can use it as it. Special
- // treatment for docker references which are subject to pull policies
- // that we're handling below.
- srcRef, err := alltransports.ParseImageName(options.FromImage)
- if err == nil {
- if srcRef.Transport().Name() == docker.Transport.Name() {
- fromImage = srcRef.DockerReference().String()
- } else {
- pulledImg, pulledReference, err := pullAndFindImage(ctx, store, srcRef, options, systemContext)
- return pulledReference, srcRef.Transport().Name(), pulledImg, err
- }
- }
-
- localImageRef, _, localImageName, localImage, err := resolveLocalImage(systemContext, store, options)
- if err != nil {
- return nil, "", nil, err
- }
-
- // If we could resolve the image locally, check if it was clearly
- // referring to a local image, either by ID or digest. In that case,
- // we don't need to perform a remote lookup.
- if localImage != nil && (strings.HasPrefix(localImage.ID, options.FromImage) || strings.HasPrefix(options.FromImage, "sha256:")) {
- return localImageRef, localImageRef.Transport().Name(), localImage, nil
- }
-
- if options.PullPolicy == define.PullNever || options.PullPolicy == define.PullIfMissing {
- if localImage != nil && imageMatch(ctx, localImageRef, systemContext) {
- return localImageRef, localImageRef.Transport().Name(), localImage, nil
- }
- if options.PullPolicy == define.PullNever {
- return nil, "", nil, errors.Errorf("pull policy is %q but %q could not be found locally", "never", options.FromImage)
- }
- }
-
- // If we found a local image, we must use it's name.
- // See #2904.
- if localImageRef != nil {
- fromImage = localImageName
- }
-
- resolved, err := shortnames.Resolve(systemContext, fromImage)
- if err != nil {
- return nil, "", nil, err
- }
-
- // Print the image-resolution description unless we're looking for a
- // new image and already found a local image. In many cases, the
- // description will be more confusing than helpful (e.g., `buildah from
- // localImage`).
- if desc := resolved.Description(); len(desc) > 0 {
- logrus.Debug(desc)
- if !(options.PullPolicy == define.PullIfNewer && localImage != nil) {
- if options.ReportWriter != nil {
- if _, err := options.ReportWriter.Write([]byte(desc + "\n")); err != nil {
- return nil, "", nil, err
- }
- }
- }
- }
-
- var pullErrors []error
- for _, pullCandidate := range resolved.PullCandidates {
- ref, err := docker.NewReference(pullCandidate.Value)
- if err != nil {
- return nil, "", nil, err
- }
-
- // We're tasked to pull a "newer" image. If there's no local
- // image, we have no base for comparison, so we'll pull the
- // first available image.
- //
- // If there's a local image, the `pullCandidate` is considered
- // to be newer if its time stamp differs from the local one.
- // Otherwise, we don't pull and skip it.
- if options.PullPolicy == define.PullIfNewer && localImage != nil {
- remoteImage, err := ref.NewImage(ctx, systemContext)
- if err != nil {
- logrus.Debugf("unable to remote-inspect image %q: %v", pullCandidate.Value.String(), err)
- pullErrors = append(pullErrors, err)
- continue
- }
- defer remoteImage.Close()
-
- remoteData, err := remoteImage.Inspect(ctx)
- if err != nil {
- logrus.Debugf("unable to remote-inspect image %q: %v", pullCandidate.Value.String(), err)
- pullErrors = append(pullErrors, err)
- continue
- }
-
- // FIXME: we should compare image digests not time stamps.
- // Comparing time stamps is flawed. Be aware that fixing
- // it may entail non-trivial changes to the tests. Please
- // refer to https://github.com/containers/buildah/issues/2779
- // for more.
- if localImage.Created.Equal(*remoteData.Created) {
- continue
- }
- }
-
- pulledImg, pulledReference, err := pullAndFindImage(ctx, store, ref, options, systemContext)
- if err != nil {
- logrus.Debugf("unable to pull and read image %q: %v", pullCandidate.Value.String(), err)
- pullErrors = append(pullErrors, err)
- continue
- }
-
- // Make sure to record the short-name alias if necessary.
- if err = pullCandidate.Record(); err != nil {
- return nil, "", nil, err
- }
-
- return pulledReference, "", pulledImg, nil
- }
-
- // If we were looking for a newer image but could not find one, return
- // the local image if present.
- if options.PullPolicy == define.PullIfNewer && localImage != nil {
- return localImageRef, localImageRef.Transport().Name(), localImage, nil
- }
-
- return nil, "", nil, resolved.FormatPullErrors(pullErrors)
-}
-
func containerNameExist(name string, containers []storage.Container) bool {
for _, container := range containers {
for _, cname := range container.Names {
@@ -313,6 +106,7 @@ func newBuilder(ctx context.Context, store storage.Store, options BuilderOptions
img *storage.Image
err error
)
+
if options.FromImage == BaseImageFakeName {
options.FromImage = ""
}
@@ -320,11 +114,45 @@ func newBuilder(ctx context.Context, store storage.Store, options BuilderOptions
systemContext := getSystemContext(store, options.SystemContext, options.SignaturePolicyPath)
if options.FromImage != "" && options.FromImage != "scratch" {
- ref, _, img, err = resolveImage(ctx, systemContext, store, options)
+ imageRuntime, err := libimage.RuntimeFromStore(store, &libimage.RuntimeOptions{SystemContext: systemContext})
+ if err != nil {
+ return nil, err
+ }
+
+ pullPolicy, err := config.ParsePullPolicy(options.PullPolicy.String())
if err != nil {
return nil, err
}
+
+ // Note: options.Format does *not* relate to the image we're
+ // about to pull (see tests/digests.bats). So we're not
+ // forcing a MIMEType in the pullOptions below.
+ pullOptions := libimage.PullOptions{}
+ pullOptions.RetryDelay = &options.PullRetryDelay
+ pullOptions.OciDecryptConfig = options.OciDecryptConfig
+ pullOptions.SignaturePolicyPath = options.SignaturePolicyPath
+ pullOptions.Writer = options.ReportWriter
+
+ maxRetries := uint(options.MaxPullRetries)
+ pullOptions.MaxRetries = &maxRetries
+
+ if options.BlobDirectory != "" {
+ pullOptions.DestinationLookupReferenceFunc = blobcache.CacheLookupReferenceFunc(options.BlobDirectory, types.PreserveOriginal)
+ }
+
+ pulledImages, err := imageRuntime.Pull(ctx, options.FromImage, pullPolicy, &pullOptions)
+ if err != nil {
+ return nil, err
+ }
+ if len(pulledImages) > 0 {
+ img = pulledImages[0].StorageImage()
+ ref, err = pulledImages[0].StorageReference()
+ if err != nil {
+ return nil, err
+ }
+ }
}
+
imageSpec := options.FromImage
imageID := ""
imageDigest := ""
diff --git a/vendor/github.com/containers/buildah/pkg/blobcache/blobcache.go b/vendor/github.com/containers/buildah/pkg/blobcache/blobcache.go
index f3876cd13..8dadec130 100644
--- a/vendor/github.com/containers/buildah/pkg/blobcache/blobcache.go
+++ b/vendor/github.com/containers/buildah/pkg/blobcache/blobcache.go
@@ -10,6 +10,7 @@ import (
"sync"
"github.com/containers/buildah/docker"
+ "github.com/containers/common/libimage"
"github.com/containers/image/v5/docker/reference"
"github.com/containers/image/v5/image"
"github.com/containers/image/v5/manifest"
@@ -82,6 +83,21 @@ func makeFilename(blobSum digest.Digest, isConfig bool) string {
return blobSum.String()
}
+// CacheLookupReferenceFunc wraps a BlobCache into a
+// libimage.LookupReferenceFunc to allow for using a BlobCache during
+// image-copy operations.
+func CacheLookupReferenceFunc(directory string, compress types.LayerCompression) libimage.LookupReferenceFunc {
+ // NOTE: this prevents us from moving BlobCache around and generalizes
+ // the libimage API.
+ return func(ref types.ImageReference) (types.ImageReference, error) {
+ ref, err := NewBlobCache(ref, directory, compress)
+ if err != nil {
+ return nil, errors.Wrapf(err, "error using blobcache %q", directory)
+ }
+ return ref, nil
+ }
+}
+
// NewBlobCache creates a new blob cache that wraps an image reference. Any blobs which are
// written to the destination image created from the resulting reference will also be stored
// as-is to the specified directory or a temporary directory. The cache directory's contents
@@ -141,7 +157,7 @@ func (r *blobCacheReference) HasBlob(blobinfo types.BlobInfo) (bool, int64, erro
return true, fileInfo.Size(), nil
}
if !os.IsNotExist(err) {
- return false, -1, errors.Wrapf(err, "error checking size of %q", filename)
+ return false, -1, errors.Wrap(err, "checking size")
}
}
@@ -155,7 +171,7 @@ func (r *blobCacheReference) Directory() string {
func (r *blobCacheReference) ClearCache() error {
f, err := os.Open(r.directory)
if err != nil {
- return errors.Wrapf(err, "error opening directory %q", r.directory)
+ return errors.WithStack(err)
}
defer f.Close()
names, err := f.Readdirnames(-1)
@@ -165,7 +181,7 @@ func (r *blobCacheReference) ClearCache() error {
for _, name := range names {
pathname := filepath.Join(r.directory, name)
if err = os.RemoveAll(pathname); err != nil {
- return errors.Wrapf(err, "error removing %q while clearing cache for %q", pathname, transports.ImageName(r))
+ return errors.Wrapf(err, "clearing cache for %q", transports.ImageName(r))
}
}
return nil
@@ -216,7 +232,7 @@ func (s *blobCacheSource) GetManifest(ctx context.Context, instanceDigest *diges
}
if !os.IsNotExist(err) {
s.cacheErrors++
- return nil, "", errors.Wrapf(err, "error checking for manifest file %q", filename)
+ return nil, "", errors.Wrap(err, "checking for manifest file")
}
}
s.cacheMisses++
@@ -246,7 +262,7 @@ func (s *blobCacheSource) GetBlob(ctx context.Context, blobinfo types.BlobInfo,
s.mu.Lock()
s.cacheErrors++
s.mu.Unlock()
- return nil, -1, errors.Wrapf(err, "error checking for cache file %q", filepath.Join(s.reference.directory, filename))
+ return nil, -1, errors.Wrap(err, "checking for cache")
}
}
}
diff --git a/vendor/github.com/containers/buildah/pkg/cli/common.go b/vendor/github.com/containers/buildah/pkg/cli/common.go
index 9c3c8cfe0..6e59dbe64 100644
--- a/vendor/github.com/containers/buildah/pkg/cli/common.go
+++ b/vendor/github.com/containers/buildah/pkg/cli/common.go
@@ -64,7 +64,6 @@ type BudResults struct {
Iidfile string
Label []string
Logfile string
- Loglevel int
Manifest string
NoCache bool
Timestamp int64
@@ -75,6 +74,7 @@ type BudResults struct {
Rm bool
Runtime string
RuntimeFlags []string
+ Secrets []string
SignaturePolicy string
SignBy string
Squash bool
@@ -191,7 +191,10 @@ func GetBudFlags(flags *BudResults) pflag.FlagSet {
fs.IntVar(&flags.Jobs, "jobs", 1, "how many stages to run in parallel")
fs.StringArrayVar(&flags.Label, "label", []string{}, "Set metadata for an image (default [])")
fs.StringVar(&flags.Logfile, "logfile", "", "log to `file` instead of stdout/stderr")
- fs.IntVar(&flags.Loglevel, "loglevel", 0, "adjust logging level (range from -2 to 3)")
+ fs.Int("loglevel", 0, "NO LONGER USED, flag ignored, and hidden")
+ if err := fs.MarkHidden("loglevel"); err != nil {
+ panic(fmt.Sprintf("error marking the loglevel flag as hidden: %v", err))
+ }
fs.BoolVar(&flags.LogRusage, "log-rusage", false, "log resource usage at each build step")
if err := fs.MarkHidden("log-rusage"); err != nil {
panic(fmt.Sprintf("error marking the log-rusage flag as hidden: %v", err))
@@ -207,6 +210,7 @@ func GetBudFlags(flags *BudResults) pflag.FlagSet {
fs.BoolVar(&flags.Rm, "rm", true, "Remove intermediate containers after a successful build")
// "runtime" definition moved to avoid name collision in podman build. Defined in cmd/buildah/bud.go.
fs.StringSliceVar(&flags.RuntimeFlags, "runtime-flag", []string{}, "add global flags for the container runtime")
+ fs.StringArrayVar(&flags.Secrets, "secret", []string{}, "secret file to expose to the build")
fs.StringVar(&flags.SignBy, "sign-by", "", "sign the image using a GPG key with the specified `FINGERPRINT`")
fs.StringVar(&flags.SignaturePolicy, "signature-policy", "", "`pathname` of signature policy file (not usually used)")
if err := fs.MarkHidden("signature-policy"); err != nil {
@@ -240,11 +244,11 @@ func GetBudFlagsCompletions() commonComp.FlagCompletions {
flagCompletion["jobs"] = commonComp.AutocompleteNone
flagCompletion["label"] = commonComp.AutocompleteNone
flagCompletion["logfile"] = commonComp.AutocompleteDefault
- flagCompletion["loglevel"] = commonComp.AutocompleteDefault
flagCompletion["manifest"] = commonComp.AutocompleteDefault
flagCompletion["os"] = commonComp.AutocompleteNone
flagCompletion["platform"] = commonComp.AutocompleteNone
flagCompletion["runtime-flag"] = commonComp.AutocompleteNone
+ flagCompletion["secret"] = commonComp.AutocompleteNone
flagCompletion["sign-by"] = commonComp.AutocompleteNone
flagCompletion["signature-policy"] = commonComp.AutocompleteNone
flagCompletion["tag"] = commonComp.AutocompleteNone
@@ -403,6 +407,8 @@ func AliasFlags(f *pflag.FlagSet, name string) pflag.NormalizedName {
name = "os"
case "purge":
name = "rm"
+ case "tty":
+ name = "terminal"
}
return pflag.NormalizedName(name)
}
diff --git a/vendor/github.com/containers/buildah/pkg/overlay/overlay.go b/vendor/github.com/containers/buildah/pkg/overlay/overlay.go
index 462561983..d1b8955bb 100644
--- a/vendor/github.com/containers/buildah/pkg/overlay/overlay.go
+++ b/vendor/github.com/containers/buildah/pkg/overlay/overlay.go
@@ -174,15 +174,15 @@ func recreate(contentDir string) error {
if os.IsNotExist(err) {
return nil
}
- return errors.Wrapf(err, "failed to stat overlay upper %s directory", contentDir)
+ return errors.Wrap(err, "failed to stat overlay upper directory")
}
if err := os.RemoveAll(contentDir); err != nil {
- return errors.Wrapf(err, "failed to cleanup overlay %s directory", contentDir)
+ return errors.WithStack(err)
}
if err := idtools.MkdirAllAs(contentDir, os.FileMode(st.Mode()), int(st.UID()), int(st.GID())); err != nil {
- return errors.Wrapf(err, "failed to create the overlay %s directory", contentDir)
+ return errors.Wrap(err, "failed to create overlay directory")
}
return nil
}
@@ -208,7 +208,7 @@ func CleanupContent(containerDir string) (Err error) {
if os.IsNotExist(err) {
return nil
}
- return errors.Wrapf(err, "read directory")
+ return errors.Wrap(err, "read directory")
}
for _, f := range files {
dir := filepath.Join(contentDir, f.Name())
@@ -218,7 +218,7 @@ func CleanupContent(containerDir string) (Err error) {
}
if err := os.RemoveAll(contentDir); err != nil && !os.IsNotExist(err) {
- return errors.Wrapf(err, "failed to cleanup overlay %s directory", contentDir)
+ return errors.Wrap(err, "failed to cleanup overlay directory")
}
return nil
}
diff --git a/vendor/github.com/containers/buildah/pkg/parse/parse.go b/vendor/github.com/containers/buildah/pkg/parse/parse.go
index 2ae07efe9..462ac212e 100644
--- a/vendor/github.com/containers/buildah/pkg/parse/parse.go
+++ b/vendor/github.com/containers/buildah/pkg/parse/parse.go
@@ -125,6 +125,8 @@ func CommonBuildOptions(c *cobra.Command) (*define.CommonBuildOptions, error) {
ulimit, _ = c.Flags().GetStringSlice("ulimit")
}
+ secrets, _ := c.Flags().GetStringArray("secret")
+
commonOpts := &define.CommonBuildOptions{
AddHost: addHost,
CPUPeriod: cpuPeriod,
@@ -142,6 +144,7 @@ func CommonBuildOptions(c *cobra.Command) (*define.CommonBuildOptions, error) {
ShmSize: c.Flag("shm-size").Value.String(),
Ulimit: ulimit,
Volumes: volumes,
+ Secrets: secrets,
}
securityOpts, _ := c.Flags().GetStringArray("security-opt")
if err := parseSecurityOpts(securityOpts, commonOpts); err != nil {
@@ -178,11 +181,11 @@ func parseSecurityOpts(securityOpts []string, commonOpts *define.CommonBuildOpti
commonOpts.SeccompProfilePath = SeccompOverridePath
} else {
if !os.IsNotExist(err) {
- return errors.Wrapf(err, "can't check if %q exists", SeccompOverridePath)
+ return errors.WithStack(err)
}
if _, err := os.Stat(SeccompDefaultPath); err != nil {
if !os.IsNotExist(err) {
- return errors.Wrapf(err, "can't check if %q exists", SeccompDefaultPath)
+ return errors.WithStack(err)
}
} else {
commonOpts.SeccompProfilePath = SeccompDefaultPath
@@ -454,7 +457,7 @@ func ValidateVolumeHostDir(hostDir string) error {
}
if filepath.IsAbs(hostDir) {
if _, err := os.Stat(hostDir); err != nil {
- return errors.Wrapf(err, "error checking path %q", hostDir)
+ return errors.WithStack(err)
}
}
// If hostDir is not an absolute path, that means the user wants to create a
@@ -468,7 +471,7 @@ func validateVolumeMountHostDir(hostDir string) error {
return errors.Errorf("invalid host path, must be an absolute path %q", hostDir)
}
if _, err := os.Stat(hostDir); err != nil {
- return errors.Wrapf(err, "error checking path %q", hostDir)
+ return errors.WithStack(err)
}
return nil
}
@@ -587,6 +590,14 @@ func SystemContextFromOptions(c *cobra.Command) (*types.SystemContext, error) {
ctx.OCIInsecureSkipTLSVerify = !tlsVerify
ctx.DockerDaemonInsecureSkipTLSVerify = !tlsVerify
}
+ disableCompression, err := c.Flags().GetBool("disable-compression")
+ if err == nil {
+ if disableCompression {
+ ctx.OCIAcceptUncompressedLayers = true
+ } else {
+ ctx.DirForceCompress = true
+ }
+ }
creds, err := c.Flags().GetString("creds")
if err == nil && c.Flag("creds").Changed {
var err error
@@ -832,7 +843,7 @@ func IDMappingOptions(c *cobra.Command, isolation define.Isolation) (usernsOptio
default:
how = strings.TrimPrefix(how, "ns:")
if _, err := os.Stat(how); err != nil {
- return nil, nil, errors.Wrapf(err, "error checking for %s namespace at %q", string(specs.UserNamespace), how)
+ return nil, nil, errors.Wrapf(err, "checking %s namespace", string(specs.UserNamespace))
}
logrus.Debugf("setting %q namespace to %q", string(specs.UserNamespace), how)
usernsOption.Path = how
@@ -922,7 +933,7 @@ func NamespaceOptions(c *cobra.Command) (namespaceOptions define.NamespaceOption
}
how = strings.TrimPrefix(how, "ns:")
if _, err := os.Stat(how); err != nil {
- return nil, define.NetworkDefault, errors.Wrapf(err, "error checking for %s namespace", what)
+ return nil, define.NetworkDefault, errors.Wrapf(err, "checking %s namespace", what)
}
policy = define.NetworkEnabled
logrus.Debugf("setting %q namespace to %q", what, how)
@@ -1043,3 +1054,37 @@ func GetTempDir() string {
}
return "/var/tmp"
}
+
+// Secrets parses the --secret flag
+func Secrets(secrets []string) (map[string]string, error) {
+ parsed := make(map[string]string)
+ invalidSyntax := errors.Errorf("incorrect secret flag format: should be --secret id=foo,src=bar")
+ for _, secret := range secrets {
+ split := strings.Split(secret, ",")
+ if len(split) > 2 {
+ return nil, invalidSyntax
+ }
+ if len(split) == 2 {
+ id := strings.Split(split[0], "=")
+ src := strings.Split(split[1], "=")
+ if len(split) == 2 && strings.ToLower(id[0]) == "id" && strings.ToLower(src[0]) == "src" {
+ fullPath, err := filepath.Abs(src[1])
+ if err != nil {
+ return nil, err
+ }
+ _, err = os.Stat(fullPath)
+ if err == nil {
+ parsed[id[1]] = fullPath
+ }
+ if err != nil {
+ return nil, errors.Wrap(err, "could not parse secrets")
+ }
+ } else {
+ return nil, invalidSyntax
+ }
+ } else {
+ return nil, invalidSyntax
+ }
+ }
+ return parsed, nil
+}
diff --git a/vendor/github.com/containers/buildah/pull.go b/vendor/github.com/containers/buildah/pull.go
index 04eac5821..7149ac986 100644
--- a/vendor/github.com/containers/buildah/pull.go
+++ b/vendor/github.com/containers/buildah/pull.go
@@ -3,28 +3,16 @@ package buildah
import (
"context"
"io"
- "strings"
"time"
"github.com/containers/buildah/define"
"github.com/containers/buildah/pkg/blobcache"
- "github.com/containers/image/v5/directory"
- "github.com/containers/image/v5/docker"
- dockerarchive "github.com/containers/image/v5/docker/archive"
- "github.com/containers/image/v5/docker/reference"
- tarfile "github.com/containers/image/v5/docker/tarfile"
- ociarchive "github.com/containers/image/v5/oci/archive"
- oci "github.com/containers/image/v5/oci/layout"
- "github.com/containers/image/v5/signature"
- is "github.com/containers/image/v5/storage"
- "github.com/containers/image/v5/transports"
- "github.com/containers/image/v5/transports/alltransports"
+ "github.com/containers/common/libimage"
+ "github.com/containers/common/pkg/config"
"github.com/containers/image/v5/types"
encconfig "github.com/containers/ocicrypt/config"
"github.com/containers/storage"
- multierror "github.com/hashicorp/go-multierror"
"github.com/pkg/errors"
- "github.com/sirupsen/logrus"
)
// PullOptions can be used to alter how an image is copied in from somewhere.
@@ -65,258 +53,44 @@ type PullOptions struct {
PullPolicy define.PullPolicy
}
-func localImageNameForReference(ctx context.Context, store storage.Store, srcRef types.ImageReference) (string, error) {
- if srcRef == nil {
- return "", errors.Errorf("reference to image is empty")
- }
- var name string
- switch srcRef.Transport().Name() {
- case dockerarchive.Transport.Name():
- file := srcRef.StringWithinTransport()
- tarSource, err := tarfile.NewSourceFromFile(file)
- if err != nil {
- return "", errors.Wrapf(err, "error opening tarfile %q as a source image", file)
- }
- defer tarSource.Close()
- manifest, err := tarSource.LoadTarManifest()
- if err != nil {
- return "", errors.Errorf("error retrieving manifest.json from tarfile %q: %v", file, err)
- }
- // to pull the first image stored in the tar file
- if len(manifest) == 0 {
- // use the hex of the digest if no manifest is found
- name, err = getImageDigest(ctx, srcRef, nil)
- if err != nil {
- return "", err
- }
- } else {
- if len(manifest[0].RepoTags) > 0 {
- name = manifest[0].RepoTags[0]
- } else {
- // If the input image has no repotags, we need to feed it a dest anyways
- name, err = getImageDigest(ctx, srcRef, nil)
- if err != nil {
- return "", err
- }
- }
- }
- case ociarchive.Transport.Name():
- // retrieve the manifest from index.json to access the image name
- manifest, err := ociarchive.LoadManifestDescriptor(srcRef)
- if err != nil {
- return "", errors.Wrapf(err, "error loading manifest for %q", transports.ImageName(srcRef))
- }
- // if index.json has no reference name, compute the image digest instead
- if manifest.Annotations == nil || manifest.Annotations["org.opencontainers.image.ref.name"] == "" {
- name, err = getImageDigest(ctx, srcRef, nil)
- if err != nil {
- return "", err
- }
- } else {
- name = manifest.Annotations["org.opencontainers.image.ref.name"]
- }
- case directory.Transport.Name():
- // supports pull from a directory
- name = toLocalImageName(srcRef.StringWithinTransport())
- case oci.Transport.Name():
- // supports pull from a directory
- split := strings.SplitN(srcRef.StringWithinTransport(), ":", 2)
- name = toLocalImageName(split[0])
- default:
- ref := srcRef.DockerReference()
- if ref == nil {
- name = srcRef.StringWithinTransport()
- _, err := is.Transport.ParseStoreReference(store, name)
- if err == nil {
- return name, nil
- }
- logrus.Debugf("error parsing local storage reference %q: %v", name, err)
- if strings.LastIndex(name, "/") != -1 {
- name = name[strings.LastIndex(name, "/")+1:]
- _, err = is.Transport.ParseStoreReference(store, name)
- if err == nil {
- return name, errors.Wrapf(err, "error parsing local storage reference %q", name)
- }
- }
- return "", errors.Errorf("reference to image %q is not a named reference", transports.ImageName(srcRef))
- }
-
- if named, ok := ref.(reference.Named); ok {
- name = named.Name()
- if namedTagged, ok := ref.(reference.NamedTagged); ok {
- name = name + ":" + namedTagged.Tag()
- }
- if canonical, ok := ref.(reference.Canonical); ok {
- name = name + "@" + canonical.Digest().String()
- }
- }
- }
-
- if _, err := is.Transport.ParseStoreReference(store, name); err != nil {
- return "", errors.Wrapf(err, "error parsing computed local image name %q", name)
- }
- return name, nil
-}
-
// Pull copies the contents of the image from somewhere else to local storage. Returns the
// ID of the local image or an error.
func Pull(ctx context.Context, imageName string, options PullOptions) (imageID string, err error) {
- systemContext := getSystemContext(options.Store, options.SystemContext, options.SignaturePolicyPath)
-
- boptions := BuilderOptions{
- FromImage: imageName,
- SignaturePolicyPath: options.SignaturePolicyPath,
- SystemContext: systemContext,
- BlobDirectory: options.BlobDirectory,
- ReportWriter: options.ReportWriter,
- MaxPullRetries: options.MaxRetries,
- PullRetryDelay: options.RetryDelay,
- OciDecryptConfig: options.OciDecryptConfig,
- PullPolicy: options.PullPolicy,
- }
-
- if !options.AllTags {
- _, _, img, err := resolveImage(ctx, systemContext, options.Store, boptions)
- if err != nil {
- return "", err
- }
- return img.ID, nil
- }
-
- srcRef, err := alltransports.ParseImageName(imageName)
- if err == nil && srcRef.Transport().Name() != docker.Transport.Name() {
- return "", errors.New("Non-docker transport is not supported, for --all-tags pulling")
- }
-
- storageRef, _, _, err := resolveImage(ctx, systemContext, options.Store, boptions)
- if err != nil {
- return "", err
- }
-
- var errs *multierror.Error
- repo := reference.TrimNamed(storageRef.DockerReference())
- dockerRef, err := docker.NewReference(reference.TagNameOnly(storageRef.DockerReference()))
- if err != nil {
- return "", errors.Wrapf(err, "internal error creating docker.Transport reference for %s", storageRef.DockerReference().String())
- }
- tags, err := docker.GetRepositoryTags(ctx, systemContext, dockerRef)
- if err != nil {
- return "", errors.Wrapf(err, "error getting repository tags")
- }
- for _, tag := range tags {
- tagged, err := reference.WithTag(repo, tag)
- if err != nil {
- errs = multierror.Append(errs, err)
- continue
- }
- taggedRef, err := docker.NewReference(tagged)
- if err != nil {
- return "", errors.Wrapf(err, "internal error creating docker.Transport reference for %s", tagged.String())
- }
- if options.ReportWriter != nil {
- if _, err := options.ReportWriter.Write([]byte("Pulling " + tagged.String() + "\n")); err != nil {
- return "", errors.Wrapf(err, "error writing pull report")
- }
- }
- ref, err := pullImage(ctx, options.Store, taggedRef, options, systemContext)
- if err != nil {
- errs = multierror.Append(errs, err)
- continue
- }
- taggedImg, err := is.Transport.GetStoreImage(options.Store, ref)
- if err != nil {
- errs = multierror.Append(errs, err)
- continue
- }
- imageID = taggedImg.ID
- }
-
- return imageID, errs.ErrorOrNil()
-}
+ libimageOptions := &libimage.PullOptions{}
+ libimageOptions.SignaturePolicyPath = options.SignaturePolicyPath
+ libimageOptions.Writer = options.ReportWriter
+ libimageOptions.RemoveSignatures = options.RemoveSignatures
+ libimageOptions.OciDecryptConfig = options.OciDecryptConfig
+ libimageOptions.AllTags = options.AllTags
+ libimageOptions.RetryDelay = &options.RetryDelay
-func pullImage(ctx context.Context, store storage.Store, srcRef types.ImageReference, options PullOptions, sc *types.SystemContext) (types.ImageReference, error) {
- blocked, err := isReferenceBlocked(srcRef, sc)
- if err != nil {
- return nil, errors.Wrapf(err, "error checking if pulling from registry for %q is blocked", transports.ImageName(srcRef))
- }
- if blocked {
- return nil, errors.Errorf("pull access to registry for %q is blocked by configuration", transports.ImageName(srcRef))
- }
- insecure, err := checkRegistrySourcesAllows("pull from", srcRef)
- if err != nil {
- return nil, err
- }
- if insecure {
- if sc.DockerInsecureSkipTLSVerify == types.OptionalBoolFalse {
- return nil, errors.Errorf("can't require tls verification on an insecured registry")
- }
- sc.DockerInsecureSkipTLSVerify = types.OptionalBoolTrue
- sc.OCIInsecureSkipTLSVerify = true
- sc.DockerDaemonInsecureSkipTLSVerify = true
- }
-
- destName, err := localImageNameForReference(ctx, store, srcRef)
- if err != nil {
- return nil, errors.Wrapf(err, "error computing local image name for %q", transports.ImageName(srcRef))
- }
- if destName == "" {
- return nil, errors.Errorf("error computing local image name for %q", transports.ImageName(srcRef))
+ if options.MaxRetries > 0 {
+ retries := uint(options.MaxRetries)
+ libimageOptions.MaxRetries = &retries
}
- destRef, err := is.Transport.ParseStoreReference(store, destName)
- if err != nil {
- return nil, errors.Wrapf(err, "error parsing image name %q", destName)
- }
- var maybeCachedDestRef = types.ImageReference(destRef)
if options.BlobDirectory != "" {
- cachedRef, err := blobcache.NewBlobCache(destRef, options.BlobDirectory, types.PreserveOriginal)
- if err != nil {
- return nil, errors.Wrapf(err, "error wrapping image reference %q in blob cache at %q", transports.ImageName(destRef), options.BlobDirectory)
- }
- maybeCachedDestRef = cachedRef
+ libimageOptions.DestinationLookupReferenceFunc = blobcache.CacheLookupReferenceFunc(options.BlobDirectory, types.PreserveOriginal)
}
- policy, err := signature.DefaultPolicy(sc)
+ pullPolicy, err := config.ParsePullPolicy(options.PullPolicy.String())
if err != nil {
- return nil, errors.Wrapf(err, "error obtaining default signature policy")
+ return "", err
}
- policyContext, err := signature.NewPolicyContext(policy)
+ runtime, err := libimage.RuntimeFromStore(options.Store, &libimage.RuntimeOptions{SystemContext: options.SystemContext})
if err != nil {
- return nil, errors.Wrapf(err, "error creating new signature policy context")
- }
-
- defer func() {
- if err2 := policyContext.Destroy(); err2 != nil {
- logrus.Debugf("error destroying signature policy context: %v", err2)
- }
- }()
-
- logrus.Debugf("copying %q to %q", transports.ImageName(srcRef), destName)
- if _, err := retryCopyImage(ctx, policyContext, maybeCachedDestRef, srcRef, srcRef, getCopyOptions(store, options.ReportWriter, sc, sc, "", options.RemoveSignatures, "", nil, nil, options.OciDecryptConfig), options.MaxRetries, options.RetryDelay); err != nil {
- logrus.Debugf("error copying src image [%q] to dest image [%q] err: %v", transports.ImageName(srcRef), destName, err)
- return nil, err
+ return "", err
}
- return destRef, nil
-}
-// getImageDigest creates an image object and uses the hex value of the digest as the image ID
-// for parsing the store reference
-func getImageDigest(ctx context.Context, src types.ImageReference, sc *types.SystemContext) (string, error) {
- newImg, err := src.NewImage(ctx, sc)
+ pulledImages, err := runtime.Pull(context.Background(), imageName, pullPolicy, libimageOptions)
if err != nil {
- return "", errors.Wrapf(err, "error opening image %q for reading", transports.ImageName(src))
+ return "", err
}
- defer newImg.Close()
- digest := newImg.ConfigInfo().Digest
- if err = digest.Validate(); err != nil {
- return "", errors.Wrapf(err, "error getting config info from image %q", transports.ImageName(src))
+ if len(pulledImages) == 0 {
+ return "", errors.Errorf("internal error pulling %s: no image pulled and no error", imageName)
}
- return "@" + digest.Hex(), nil
-}
-// toLocalImageName converts an image name into a 'localhost/' prefixed one
-func toLocalImageName(imageName string) string {
- return "localhost/" + strings.TrimLeft(imageName, "/")
+ return pulledImages[0].ID(), nil
}
diff --git a/vendor/github.com/containers/buildah/push.go b/vendor/github.com/containers/buildah/push.go
new file mode 100644
index 000000000..692dfccd4
--- /dev/null
+++ b/vendor/github.com/containers/buildah/push.go
@@ -0,0 +1,126 @@
+package buildah
+
+import (
+ "context"
+ "fmt"
+ "io"
+ "time"
+
+ "github.com/containers/buildah/pkg/blobcache"
+ "github.com/containers/common/libimage"
+ "github.com/containers/image/v5/docker/reference"
+ "github.com/containers/image/v5/manifest"
+ "github.com/containers/image/v5/transports"
+ "github.com/containers/image/v5/types"
+ encconfig "github.com/containers/ocicrypt/config"
+ "github.com/containers/storage"
+ "github.com/containers/storage/pkg/archive"
+ digest "github.com/opencontainers/go-digest"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+)
+
+// PushOptions can be used to alter how an image is copied somewhere.
+type PushOptions struct {
+ // Compression specifies the type of compression which is applied to
+ // layer blobs. The default is to not use compression, but
+ // archive.Gzip is recommended.
+ Compression archive.Compression
+ // SignaturePolicyPath specifies an override location for the signature
+ // policy which should be used for verifying the new image as it is
+ // being written. Except in specific circumstances, no value should be
+ // specified, indicating that the shared, system-wide default policy
+ // should be used.
+ SignaturePolicyPath string
+ // ReportWriter is an io.Writer which will be used to log the writing
+ // of the new image.
+ ReportWriter io.Writer
+ // Store is the local storage store which holds the source image.
+ Store storage.Store
+ // github.com/containers/image/types SystemContext to hold credentials
+ // and other authentication/authorization information.
+ SystemContext *types.SystemContext
+ // ManifestType is the format to use when saving the image using the 'dir' transport
+ // possible options are oci, v2s1, and v2s2
+ ManifestType string
+ // BlobDirectory is the name of a directory in which we'll look for
+ // prebuilt copies of layer blobs that we might otherwise need to
+ // regenerate from on-disk layers, substituting them in the list of
+ // blobs to copy whenever possible.
+ BlobDirectory string
+ // Quiet is a boolean value that determines if minimal output to
+ // the user will be displayed, this is best used for logging.
+ // The default is false.
+ Quiet bool
+ // SignBy is the fingerprint of a GPG key to use for signing the image.
+ SignBy string
+ // RemoveSignatures causes any existing signatures for the image to be
+ // discarded for the pushed copy.
+ RemoveSignatures bool
+ // MaxRetries is the maximum number of attempts we'll make to push any
+ // one image to the external registry if the first attempt fails.
+ MaxRetries int
+ // RetryDelay is how long to wait before retrying a push attempt.
+ RetryDelay time.Duration
+ // OciEncryptConfig when non-nil indicates that an image should be encrypted.
+ // The encryption options is derived from the construction of EncryptConfig object.
+ OciEncryptConfig *encconfig.EncryptConfig
+ // OciEncryptLayers represents the list of layers to encrypt.
+ // If nil, don't encrypt any layers.
+ // If non-nil and len==0, denotes encrypt all layers.
+ // integers in the slice represent 0-indexed layer indices, with support for negativ
+ // indexing. i.e. 0 is the first layer, -1 is the last (top-most) layer.
+ OciEncryptLayers *[]int
+}
+
+// Push copies the contents of the image to a new location.
+func Push(ctx context.Context, image string, dest types.ImageReference, options PushOptions) (reference.Canonical, digest.Digest, error) {
+ libimageOptions := &libimage.PushOptions{}
+ libimageOptions.SignaturePolicyPath = options.SignaturePolicyPath
+ libimageOptions.Writer = options.ReportWriter
+ libimageOptions.ManifestMIMEType = options.ManifestType
+ libimageOptions.SignBy = options.SignBy
+ libimageOptions.RemoveSignatures = options.RemoveSignatures
+ libimageOptions.RetryDelay = &options.RetryDelay
+ libimageOptions.OciEncryptConfig = options.OciEncryptConfig
+ libimageOptions.OciEncryptLayers = options.OciEncryptLayers
+ libimageOptions.PolicyAllowStorage = true
+
+ if options.Quiet {
+ libimageOptions.Writer = nil
+ }
+
+ if options.BlobDirectory != "" {
+ compress := types.PreserveOriginal
+ if options.Compression == archive.Gzip {
+ compress = types.Compress
+ }
+ libimageOptions.SourceLookupReferenceFunc = blobcache.CacheLookupReferenceFunc(options.BlobDirectory, compress)
+ }
+
+ runtime, err := libimage.RuntimeFromStore(options.Store, &libimage.RuntimeOptions{SystemContext: options.SystemContext})
+ if err != nil {
+ return nil, "", err
+ }
+
+ destString := fmt.Sprintf("%s:%s", dest.Transport().Name(), dest.StringWithinTransport())
+ manifestBytes, err := runtime.Push(ctx, image, destString, libimageOptions)
+ if err != nil {
+ return nil, "", err
+ }
+
+ manifestDigest, err := manifest.Digest(manifestBytes)
+ if err != nil {
+ return nil, "", errors.Wrapf(err, "error computing digest of manifest of new image %q", transports.ImageName(dest))
+ }
+
+ var ref reference.Canonical
+ if name := dest.DockerReference(); name != nil {
+ ref, err = reference.WithDigest(name, manifestDigest)
+ if err != nil {
+ logrus.Warnf("error generating canonical reference with name %q and digest %s: %v", name, manifestDigest.String(), err)
+ }
+ }
+
+ return ref, manifestDigest, nil
+}
diff --git a/vendor/github.com/containers/buildah/run.go b/vendor/github.com/containers/buildah/run.go
index 876850403..efffd1f5f 100644
--- a/vendor/github.com/containers/buildah/run.go
+++ b/vendor/github.com/containers/buildah/run.go
@@ -134,4 +134,9 @@ type RunOptions struct {
DropCapabilities []string
// Devices are the additional devices to add to the containers
Devices define.ContainerDevices
+ // Secrets are the available secrets to use in a RUN
+ Secrets map[string]string
+ // RunMounts are mounts for this run. RunMounts for this run
+ // will not show up in subsequent runs.
+ RunMounts []string
}
diff --git a/vendor/github.com/containers/buildah/run_linux.go b/vendor/github.com/containers/buildah/run_linux.go
index 6356d2602..005607792 100644
--- a/vendor/github.com/containers/buildah/run_linux.go
+++ b/vendor/github.com/containers/buildah/run_linux.go
@@ -246,10 +246,17 @@ rootless=%d
bindFiles["/run/.containerenv"] = containerenvPath
}
- err = b.setupMounts(mountPoint, spec, path, options.Mounts, bindFiles, volumes, b.CommonBuildOpts.Volumes, b.CommonBuildOpts.ShmSize, namespaceOptions)
+ runMountTargets, err := b.setupMounts(mountPoint, spec, path, options.Mounts, bindFiles, volumes, b.CommonBuildOpts.Volumes, b.CommonBuildOpts.ShmSize, namespaceOptions, options.Secrets, options.RunMounts)
if err != nil {
return errors.Wrapf(err, "error resolving mountpoints for container %q", b.ContainerID)
}
+
+ defer func() {
+ if err := cleanupRunMounts(runMountTargets, mountPoint); err != nil {
+ logrus.Errorf("unabe to cleanup run mounts %v", err)
+ }
+ }()
+
defer b.cleanupTempVolumes()
if options.CNIConfigDir == "" {
@@ -341,16 +348,16 @@ func runSetupBuiltinVolumes(mountLabel, mountPoint, containerDir string, builtin
// Add temporary copies of the contents of volume locations at the
// volume locations, unless we already have something there.
for _, volume := range builtinVolumes {
- subdir := digest.Canonical.FromString(volume).Hex()
- volumePath := filepath.Join(containerDir, "buildah-volumes", subdir)
- srcPath := filepath.Join(mountPoint, volume)
+ volumePath := filepath.Join(containerDir, "buildah-volumes", digest.Canonical.FromString(volume).Hex())
initializeVolume := false
- // If we need to, initialize the volume path's initial contents.
+ // If we need to, create the directory that we'll use to hold
+ // the volume contents. If we do need to create it, then we'll
+ // need to populate it, too, so make a note of that.
if _, err := os.Stat(volumePath); err != nil {
if !os.IsNotExist(err) {
return nil, err
}
- logrus.Debugf("setting up built-in volume at %q", volumePath)
+ logrus.Debugf("setting up built-in volume path at %q for %q", volumePath, volume)
if err = os.MkdirAll(volumePath, 0755); err != nil {
return nil, err
}
@@ -359,28 +366,25 @@ func runSetupBuiltinVolumes(mountLabel, mountPoint, containerDir string, builtin
}
initializeVolume = true
}
- // Check if srcPath is a symlink
- stat, err := os.Lstat(srcPath)
- // If srcPath is a symlink, follow the link and ensure the destination exists
- if err == nil && stat != nil && (stat.Mode()&os.ModeSymlink != 0) {
- srcPath, err = copier.Eval(mountPoint, volume, copier.EvalOptions{})
- if err != nil {
- return nil, errors.Wrapf(err, "evaluating symlink %q", srcPath)
- }
- // Stat the destination of the evaluated symlink
- stat, err = os.Stat(srcPath)
+ // Make sure the volume exists in the rootfs and read its attributes.
+ createDirPerms := os.FileMode(0755)
+ err := copier.Mkdir(mountPoint, filepath.Join(mountPoint, volume), copier.MkdirOptions{
+ ChownNew: &hostOwner,
+ ChmodNew: &createDirPerms,
+ })
+ if err != nil {
+ return nil, errors.Wrapf(err, "ensuring volume path %q", filepath.Join(mountPoint, volume))
}
+ srcPath, err := copier.Eval(mountPoint, filepath.Join(mountPoint, volume), copier.EvalOptions{})
if err != nil {
- if !os.IsNotExist(err) {
- return nil, err
- }
- if err = idtools.MkdirAllAndChownNew(srcPath, 0755, hostOwner); err != nil {
- return nil, err
- }
- if stat, err = os.Stat(srcPath); err != nil {
- return nil, err
- }
+ return nil, errors.Wrapf(err, "evaluating path %q", srcPath)
+ }
+ stat, err := os.Stat(srcPath)
+ if err != nil && !os.IsNotExist(err) {
+ return nil, err
}
+ // If we need to populate the mounted volume's contents with
+ // content from the rootfs, set it up now.
if initializeVolume {
if err = os.Chmod(volumePath, stat.Mode().Perm()); err != nil {
return nil, err
@@ -388,6 +392,7 @@ func runSetupBuiltinVolumes(mountLabel, mountPoint, containerDir string, builtin
if err = os.Chown(volumePath, int(stat.Sys().(*syscall.Stat_t).Uid), int(stat.Sys().(*syscall.Stat_t).Gid)); err != nil {
return nil, err
}
+ logrus.Debugf("populating directory %q for volume %q using contents of %q", volumePath, volume, srcPath)
if err = extractWithTar(mountPoint, srcPath, volumePath); err != nil && !os.IsNotExist(errors.Cause(err)) {
return nil, errors.Wrapf(err, "error populating directory %q for volume %q using contents of %q", volumePath, volume, srcPath)
}
@@ -403,7 +408,7 @@ func runSetupBuiltinVolumes(mountLabel, mountPoint, containerDir string, builtin
return mounts, nil
}
-func (b *Builder) setupMounts(mountPoint string, spec *specs.Spec, bundlePath string, optionMounts []specs.Mount, bindFiles map[string]string, builtinVolumes, volumeMounts []string, shmSize string, namespaceOptions define.NamespaceOptions) error {
+func (b *Builder) setupMounts(mountPoint string, spec *specs.Spec, bundlePath string, optionMounts []specs.Mount, bindFiles map[string]string, builtinVolumes, volumeMounts []string, shmSize string, namespaceOptions define.NamespaceOptions, secrets map[string]string, runFileMounts []string) (runMountTargets []string, err error) {
// Start building a new list of mounts.
var mounts []specs.Mount
haveMount := func(destination string) bool {
@@ -497,39 +502,45 @@ func (b *Builder) setupMounts(mountPoint string, spec *specs.Spec, bundlePath st
// After this point we need to know the per-container persistent storage directory.
cdir, err := b.store.ContainerDirectory(b.ContainerID)
if err != nil {
- return errors.Wrapf(err, "error determining work directory for container %q", b.ContainerID)
+ return nil, errors.Wrapf(err, "error determining work directory for container %q", b.ContainerID)
}
// Figure out which UID and GID to tell the subscriptions package to use
// for files that it creates.
rootUID, rootGID, err := util.GetHostRootIDs(spec)
if err != nil {
- return err
+ return nil, err
}
// Get the list of subscriptions mounts.
- secretMounts := subscriptions.MountsWithUIDGID(b.MountLabel, cdir, b.DefaultMountsFilePath, mountPoint, int(rootUID), int(rootGID), unshare.IsRootless(), false)
+ subscriptionMounts := subscriptions.MountsWithUIDGID(b.MountLabel, cdir, b.DefaultMountsFilePath, mountPoint, int(rootUID), int(rootGID), unshare.IsRootless(), false)
+
+ // Get the list of mounts that are just for this Run() call.
+ runMounts, runTargets, err := runSetupRunMounts(runFileMounts, secrets, b.MountLabel, cdir, spec.Linux.UIDMappings, spec.Linux.GIDMappings)
+ if err != nil {
+ return nil, err
+ }
// Add temporary copies of the contents of volume locations at the
// volume locations, unless we already have something there.
builtins, err := runSetupBuiltinVolumes(b.MountLabel, mountPoint, cdir, builtinVolumes, int(rootUID), int(rootGID))
if err != nil {
- return err
+ return nil, err
}
// Get host UID and GID of the container process.
processUID, processGID, err := util.GetHostIDs(spec.Linux.UIDMappings, spec.Linux.GIDMappings, spec.Process.User.UID, spec.Process.User.GID)
if err != nil {
- return err
+ return nil, err
}
// Get the list of explicitly-specified volume mounts.
volumes, err := b.runSetupVolumeMounts(spec.Linux.MountLabel, volumeMounts, optionMounts, int(rootUID), int(rootGID), int(processUID), int(processGID))
if err != nil {
- return err
+ return nil, err
}
- allMounts := util.SortMounts(append(append(append(append(append(volumes, builtins...), secretMounts...), bindFileMounts...), specMounts...), sysfsMount...))
+ allMounts := util.SortMounts(append(append(append(append(append(append(volumes, builtins...), runMounts...), subscriptionMounts...), bindFileMounts...), specMounts...), sysfsMount...))
// Add them all, in the preferred order, except where they conflict with something that was previously added.
for _, mount := range allMounts {
if haveMount(mount.Destination) {
@@ -542,7 +553,7 @@ func (b *Builder) setupMounts(mountPoint string, spec *specs.Spec, bundlePath st
// Set the list in the spec.
spec.Mounts = mounts
- return nil
+ return runTargets, nil
}
// addNetworkConfig copies files from host and sets them up to bind mount into container
@@ -818,7 +829,7 @@ func runUsingRuntime(isolation define.Isolation, options RunOptions, configureNe
logrus.Debugf("Running %q", create.Args)
err = create.Run()
if err != nil {
- return 1, errors.Wrapf(err, "error creating container for %v: %s", pargs, runCollectOutput(errorFds, closeBeforeReadingErrorFds))
+ return 1, errors.Wrapf(err, "error from %s creating container for %v: %s", runtime, pargs, runCollectOutput(errorFds, closeBeforeReadingErrorFds))
}
defer func() {
err2 := del.Run()
@@ -826,7 +837,7 @@ func runUsingRuntime(isolation define.Isolation, options RunOptions, configureNe
if err == nil {
err = errors.Wrapf(err2, "error deleting container")
} else {
- logrus.Infof("error deleting container: %v", err2)
+ logrus.Infof("error from %s deleting container: %v", runtime, err2)
}
}
}()
@@ -879,13 +890,13 @@ func runUsingRuntime(isolation define.Isolation, options RunOptions, configureNe
logrus.Debugf("Running %q", start.Args)
err = start.Run()
if err != nil {
- return 1, errors.Wrapf(err, "error starting container")
+ return 1, errors.Wrapf(err, "error from %s starting container", runtime)
}
stopped := false
defer func() {
if !stopped {
if err2 := kill.Run(); err2 != nil {
- logrus.Infof("error stopping container: %v", err2)
+ logrus.Infof("error from %s stopping container: %v", runtime, err2)
}
}
}()
@@ -900,10 +911,10 @@ func runUsingRuntime(isolation define.Isolation, options RunOptions, configureNe
stat.Stderr = os.Stderr
stateOutput, err := stat.Output()
if err != nil {
- return 1, errors.Wrapf(err, "error reading container state (got output: %q)", string(stateOutput))
+ return 1, errors.Wrapf(err, "error reading container state from %s (got output: %q)", runtime, string(stateOutput))
}
if err = json.Unmarshal(stateOutput, &state); err != nil {
- return 1, errors.Wrapf(err, "error parsing container state %q", string(stateOutput))
+ return 1, errors.Wrapf(err, "error parsing container state %q from %s", string(stateOutput), runtime)
}
switch state.Status {
case "running":
@@ -2248,3 +2259,149 @@ type runUsingRuntimeSubprocOptions struct {
func init() {
reexec.Register(runUsingRuntimeCommand, runUsingRuntimeMain)
}
+
+// runSetupRunMounts sets up mounts that exist only in this RUN, not in subsequent runs
+func runSetupRunMounts(mounts []string, secrets map[string]string, mountlabel string, containerWorkingDir string, uidmap []spec.LinuxIDMapping, gidmap []spec.LinuxIDMapping) ([]spec.Mount, []string, error) {
+ mountTargets := make([]string, 0, 10)
+ finalMounts := make([]specs.Mount, 0, len(mounts))
+ for _, mount := range mounts {
+ arr := strings.SplitN(mount, ",", 2)
+ if len(arr) < 2 {
+ return nil, nil, errors.New("invalid mount syntax")
+ }
+
+ kv := strings.Split(arr[0], "=")
+ if len(kv) != 2 || kv[0] != "type" {
+ return nil, nil, errors.New("invalid mount type")
+ }
+
+ tokens := strings.Split(arr[1], ",")
+ // For now, we only support type secret.
+ switch kv[1] {
+ case "secret":
+ mount, err := getSecretMount(tokens, secrets, mountlabel, containerWorkingDir, uidmap, gidmap)
+ if err != nil {
+ return nil, nil, err
+ }
+ if mount != nil {
+ finalMounts = append(finalMounts, *mount)
+ mountTargets = append(mountTargets, mount.Destination)
+
+ }
+ default:
+ return nil, nil, errors.Errorf("invalid filesystem type %q", kv[1])
+ }
+ }
+ return finalMounts, mountTargets, nil
+}
+
+func getSecretMount(tokens []string, secrets map[string]string, mountlabel string, containerWorkingDir string, uidmap []spec.LinuxIDMapping, gidmap []spec.LinuxIDMapping) (*spec.Mount, error) {
+ errInvalidSyntax := errors.New("secret should have syntax id=id[,target=path,required=bool,mode=uint,uid=uint,gid=uint")
+
+ var err error
+ var id, target string
+ var required bool
+ var uid, gid uint32
+ var mode uint32 = 400
+ for _, val := range tokens {
+ kv := strings.SplitN(val, "=", 2)
+ switch kv[0] {
+ case "id":
+ id = kv[1]
+ case "target":
+ target = kv[1]
+ case "required":
+ required, err = strconv.ParseBool(kv[1])
+ if err != nil {
+ return nil, errInvalidSyntax
+ }
+ case "mode":
+ mode64, err := strconv.ParseUint(kv[1], 8, 32)
+ if err != nil {
+ return nil, errInvalidSyntax
+ }
+ mode = uint32(mode64)
+ case "uid":
+ uid64, err := strconv.ParseUint(kv[1], 10, 32)
+ if err != nil {
+ return nil, errInvalidSyntax
+ }
+ uid = uint32(uid64)
+ case "gid":
+ gid64, err := strconv.ParseUint(kv[1], 10, 32)
+ if err != nil {
+ return nil, errInvalidSyntax
+ }
+ gid = uint32(gid64)
+ default:
+ return nil, errInvalidSyntax
+ }
+ }
+
+ if id == "" {
+ return nil, errInvalidSyntax
+ }
+ // Default location for secretis is /run/secrets/id
+ if target == "" {
+ target = "/run/secrets/" + id
+ }
+
+ src, ok := secrets[id]
+ if !ok {
+ if required {
+ return nil, errors.Errorf("secret required but no secret with id %s found", id)
+ }
+ return nil, nil
+ }
+
+ // Copy secrets to container working dir, since we need to chmod, chown and relabel it
+ // for the container user and we don't want to mess with the original file
+ ctrFileOnHost := filepath.Join(containerWorkingDir, "secrets", id)
+ _, err = os.Stat(ctrFileOnHost)
+ if os.IsNotExist(err) {
+ data, err := ioutil.ReadFile(src)
+ if err != nil {
+ return nil, err
+ }
+ if err := os.MkdirAll(filepath.Dir(ctrFileOnHost), 0644); err != nil {
+ return nil, err
+ }
+ if err := ioutil.WriteFile(ctrFileOnHost, data, 0644); err != nil {
+ return nil, err
+ }
+ }
+
+ if err := label.Relabel(ctrFileOnHost, mountlabel, false); err != nil {
+ return nil, err
+ }
+ hostUID, hostGID, err := util.GetHostIDs(uidmap, gidmap, uid, gid)
+ if err != nil {
+ return nil, err
+ }
+ if err := os.Lchown(ctrFileOnHost, int(hostUID), int(hostGID)); err != nil {
+ return nil, err
+ }
+ if err := os.Chmod(ctrFileOnHost, os.FileMode(mode)); err != nil {
+ return nil, err
+ }
+ newMount := specs.Mount{
+ Destination: target,
+ Type: "bind",
+ Source: ctrFileOnHost,
+ Options: []string{"bind", "rprivate", "ro"},
+ }
+ return &newMount, nil
+}
+
+func cleanupRunMounts(paths []string, mountpoint string) error {
+ opts := copier.RemoveOptions{
+ All: true,
+ }
+ for _, path := range paths {
+ err := copier.Remove(mountpoint, path, opts)
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
diff --git a/vendor/github.com/containers/buildah/util/util.go b/vendor/github.com/containers/buildah/util/util.go
index b3fae6003..3b22a3943 100644
--- a/vendor/github.com/containers/buildah/util/util.go
+++ b/vendor/github.com/containers/buildah/util/util.go
@@ -5,7 +5,6 @@ import (
"io"
"net/url"
"os"
- "path"
"path/filepath"
"sort"
"strings"
@@ -13,12 +12,12 @@ import (
"syscall"
"github.com/containers/buildah/define"
+ "github.com/containers/common/libimage"
"github.com/containers/common/pkg/config"
"github.com/containers/image/v5/docker/reference"
"github.com/containers/image/v5/pkg/shortnames"
"github.com/containers/image/v5/pkg/sysregistriesv2"
"github.com/containers/image/v5/signature"
- is "github.com/containers/image/v5/storage"
"github.com/containers/image/v5/transports/alltransports"
"github.com/containers/image/v5/types"
"github.com/containers/storage"
@@ -46,7 +45,7 @@ var (
}
)
-// ResolveName checks if name is a valid image name, and if that name doesn't
+// resolveName checks if name is a valid image name, and if that name doesn't
// include a domain portion, returns a list of the names which it might
// correspond to in the set of configured registries, the transport used to
// pull the image, and a boolean which is true iff
@@ -59,7 +58,7 @@ var (
//
// NOTE: The "list of search registries is empty" check does not count blocked registries,
// and neither the implied "localhost" nor a possible firstRegistry are counted
-func ResolveName(name string, firstRegistry string, sc *types.SystemContext, store storage.Store) ([]string, string, bool, error) {
+func resolveName(name string, sc *types.SystemContext, store storage.Store) ([]string, string, bool, error) {
if name == "" {
return nil, "", false, nil
}
@@ -112,16 +111,6 @@ func ResolveName(name string, firstRegistry string, sc *types.SystemContext, sto
searchRegistriesAreEmpty := len(registries) == 0
var candidates []string
- // Set the first registry if requested.
- if firstRegistry != "" && firstRegistry != "localhost" {
- middle := ""
- if prefix, ok := RegistryDefaultPathPrefix[firstRegistry]; ok && !strings.ContainsRune(name, '/') {
- middle = prefix
- }
- candidate := path.Join(firstRegistry, middle, name)
- candidates = append(candidates, candidate)
- }
-
// Local short-name resolution.
namedCandidates, err := shortnames.ResolveLocally(sc, name)
if err != nil {
@@ -144,11 +133,11 @@ func StartsWithValidTransport(name string) bool {
// the fully expanded result, including a tag. Names which don't include a registry
// name will be marked for the most-preferred registry (i.e., the first one in our
// configuration).
-func ExpandNames(names []string, firstRegistry string, systemContext *types.SystemContext, store storage.Store) ([]string, error) {
+func ExpandNames(names []string, systemContext *types.SystemContext, store storage.Store) ([]string, error) {
expanded := make([]string, 0, len(names))
for _, n := range names {
var name reference.Named
- nameList, _, _, err := ResolveName(n, firstRegistry, systemContext, store)
+ nameList, _, _, err := resolveName(n, systemContext, store)
if err != nil {
return nil, errors.Wrapf(err, "error parsing name %q", n)
}
@@ -172,45 +161,34 @@ func ExpandNames(names []string, firstRegistry string, systemContext *types.Syst
}
// FindImage locates the locally-stored image which corresponds to a given name.
+// Please note that the `firstRegistry` argument has been deprecated and has no
+// effect anymore.
func FindImage(store storage.Store, firstRegistry string, systemContext *types.SystemContext, image string) (types.ImageReference, *storage.Image, error) {
- var ref types.ImageReference
- var img *storage.Image
- var err error
- names, _, _, err := ResolveName(image, firstRegistry, systemContext, store)
+ runtime, err := libimage.RuntimeFromStore(store, &libimage.RuntimeOptions{SystemContext: systemContext})
if err != nil {
- return nil, nil, errors.Wrapf(err, "error parsing name %q", image)
+ return nil, nil, err
}
- for _, name := range names {
- ref, err = is.Transport.ParseStoreReference(store, name)
- if err != nil {
- logrus.Debugf("error parsing reference to image %q: %v", name, err)
- continue
- }
- img, err = is.Transport.GetStoreImage(store, ref)
- if err != nil {
- img2, err2 := store.Image(name)
- if err2 != nil {
- logrus.Debugf("error locating image %q: %v", name, err2)
- continue
- }
- img = img2
- }
- break
+
+ localImage, _, err := runtime.LookupImage(image, &libimage.LookupImageOptions{IgnorePlatform: true})
+ if err != nil {
+ return nil, nil, err
}
- if ref == nil || img == nil {
- return nil, nil, errors.Wrapf(err, "error locating image with name %q (%v)", image, names)
+ ref, err := localImage.StorageReference()
+ if err != nil {
+ return nil, nil, err
}
- return ref, img, nil
+
+ return ref, localImage.StorageImage(), nil
}
-// ResolveNameToReferences tries to create a list of possible references
+// resolveNameToReferences tries to create a list of possible references
// (including their transports) from the provided image name.
func ResolveNameToReferences(
store storage.Store,
systemContext *types.SystemContext,
image string,
) (refs []types.ImageReference, err error) {
- names, transport, _, err := ResolveName(image, "", systemContext, store)
+ names, transport, _, err := resolveName(image, systemContext, store)
if err != nil {
return nil, errors.Wrapf(err, "error parsing name %q", image)
}
@@ -233,16 +211,26 @@ func ResolveNameToReferences(
return refs, nil
}
-// AddImageNames adds the specified names to the specified image.
+// AddImageNames adds the specified names to the specified image. Please note
+// that the `firstRegistry` argument has been deprecated and has no effect
+// anymore.
func AddImageNames(store storage.Store, firstRegistry string, systemContext *types.SystemContext, image *storage.Image, addNames []string) error {
- names, err := ExpandNames(addNames, firstRegistry, systemContext, store)
+ runtime, err := libimage.RuntimeFromStore(store, &libimage.RuntimeOptions{SystemContext: systemContext})
if err != nil {
return err
}
- err = store.SetNames(image.ID, append(image.Names, names...))
+
+ localImage, _, err := runtime.LookupImage(image.ID, nil)
if err != nil {
- return errors.Wrapf(err, "error adding names (%v) to image %q", names, image.ID)
+ return err
}
+
+ for _, tag := range addNames {
+ if err := localImage.Tag(tag); err != nil {
+ return errors.Wrapf(err, "error tagging image %s", image.ID)
+ }
+ }
+
return nil
}
@@ -275,11 +263,6 @@ func Runtime() string {
return runtime
}
- // Need to switch default until runc supports cgroups v2
- if unified, _ := IsCgroup2UnifiedMode(); unified {
- return "crun"
- }
-
conf, err := config.Default()
if err != nil {
logrus.Warnf("Error loading container config when searching for local runtime: %v", err)
diff --git a/vendor/github.com/containers/common/libimage/copier.go b/vendor/github.com/containers/common/libimage/copier.go
new file mode 100644
index 000000000..34cc0d45d
--- /dev/null
+++ b/vendor/github.com/containers/common/libimage/copier.go
@@ -0,0 +1,427 @@
+package libimage
+
+import (
+ "context"
+ "encoding/json"
+ "io"
+ "os"
+ "strings"
+ "time"
+
+ "github.com/containers/common/pkg/config"
+ "github.com/containers/common/pkg/retry"
+ "github.com/containers/image/v5/copy"
+ "github.com/containers/image/v5/docker/reference"
+ "github.com/containers/image/v5/signature"
+ storageTransport "github.com/containers/image/v5/storage"
+ "github.com/containers/image/v5/types"
+ encconfig "github.com/containers/ocicrypt/config"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+)
+
+const (
+ defaultMaxRetries = 3
+ defaultRetryDelay = time.Second
+)
+
+// LookupReferenceFunc return an image reference based on the specified one.
+// This can be used to pass custom blob caches to the copy operation.
+type LookupReferenceFunc func(ref types.ImageReference) (types.ImageReference, error)
+
+// CopyOptions allow for customizing image-copy operations.
+type CopyOptions struct {
+ // If set, will be used for copying the image. Fields below may
+ // override certain settings.
+ SystemContext *types.SystemContext
+ // Allows for customizing the source reference lookup. This can be
+ // used to use custom blob caches.
+ SourceLookupReferenceFunc LookupReferenceFunc
+ // Allows for customizing the destination reference lookup. This can
+ // be used to use custom blob caches.
+ DestinationLookupReferenceFunc LookupReferenceFunc
+
+ // containers-auth.json(5) file to use when authenticating against
+ // container registries.
+ AuthFilePath string
+ // Custom path to a blob-info cache.
+ BlobInfoCacheDirPath string
+ // Path to the certificates directory.
+ CertDirPath string
+ // Force layer compression when copying to a `dir` transport destination.
+ DirForceCompress bool
+ // Allow contacting registries over HTTP, or HTTPS with failed TLS
+ // verification. Note that this does not affect other TLS connections.
+ InsecureSkipTLSVerify types.OptionalBool
+ // Maximum number of retries with exponential backoff when facing
+ // transient network errors. A reasonable default is used if not set.
+ // Default 3.
+ MaxRetries *uint
+ // RetryDelay used for the exponential back off of MaxRetries.
+ // Default 1 time.Scond.
+ RetryDelay *time.Duration
+ // ManifestMIMEType is the desired media type the image will be
+ // converted to if needed. Note that it must contain the exact MIME
+ // types. Short forms (e.g., oci, v2s2) used by some tools are not
+ // supported.
+ ManifestMIMEType string
+ // If OciEncryptConfig is non-nil, it indicates that an image should be
+ // encrypted. The encryption options is derived from the construction
+ // of EncryptConfig object. Note: During initial encryption process of
+ // a layer, the resultant digest is not known during creation, so
+ // newDigestingReader has to be set with validateDigest = false
+ OciEncryptConfig *encconfig.EncryptConfig
+ // OciEncryptLayers represents the list of layers to encrypt. If nil,
+ // don't encrypt any layers. If non-nil and len==0, denotes encrypt
+ // all layers. integers in the slice represent 0-indexed layer
+ // indices, with support for negative indexing. i.e. 0 is the first
+ // layer, -1 is the last (top-most) layer.
+ OciEncryptLayers *[]int
+ // OciDecryptConfig contains the config that can be used to decrypt an
+ // image if it is encrypted if non-nil. If nil, it does not attempt to
+ // decrypt an image.
+ OciDecryptConfig *encconfig.DecryptConfig
+ // Reported to when ProgressInterval has arrived for a single
+ // artifact+offset.
+ Progress chan types.ProgressProperties
+ // If set, allow using the storage transport even if it's disabled by
+ // the specified SignaturePolicyPath.
+ PolicyAllowStorage bool
+ // SignaturePolicyPath to overwrite the default one.
+ SignaturePolicyPath string
+ // If non-empty, asks for a signature to be added during the copy, and
+ // specifies a key ID.
+ SignBy string
+ // Remove any pre-existing signatures. SignBy will still add a new
+ // signature.
+ RemoveSignatures bool
+ // Writer is used to display copy information including progress bars.
+ Writer io.Writer
+
+ // ----- platform -----------------------------------------------------
+
+ // Architecture to use for choosing images.
+ Architecture string
+ // OS to use for choosing images.
+ OS string
+ // Variant to use when choosing images.
+ Variant string
+
+ // ----- credentials --------------------------------------------------
+
+ // Username to use when authenticating at a container registry.
+ Username string
+ // Password to use when authenticating at a container registry.
+ Password string
+ // Credentials is an alternative way to specify credentials in format
+ // "username[:password]". Cannot be used in combination with
+ // Username/Password.
+ Credentials string
+ // IdentityToken is used to authenticate the user and get
+ // an access token for the registry.
+ IdentityToken string `json:"identitytoken,omitempty"`
+
+ // ----- internal -----------------------------------------------------
+
+ // Additional tags when creating or copying a docker-archive.
+ dockerArchiveAdditionalTags []reference.NamedTagged
+}
+
+// copier is an internal helper to conveniently copy images.
+type copier struct {
+ imageCopyOptions copy.Options
+ retryOptions retry.RetryOptions
+ systemContext *types.SystemContext
+ policyContext *signature.PolicyContext
+
+ sourceLookup LookupReferenceFunc
+ destinationLookup LookupReferenceFunc
+}
+
+var (
+ // storageAllowedPolicyScopes overrides the policy for local storage
+ // to ensure that we can read images from it.
+ storageAllowedPolicyScopes = signature.PolicyTransportScopes{
+ "": []signature.PolicyRequirement{
+ signature.NewPRInsecureAcceptAnything(),
+ },
+ }
+)
+
+// getDockerAuthConfig extracts a docker auth config from the CopyOptions. Returns
+// nil if no credentials are set.
+func (options *CopyOptions) getDockerAuthConfig() (*types.DockerAuthConfig, error) {
+ authConf := &types.DockerAuthConfig{IdentityToken: options.IdentityToken}
+
+ if options.Username != "" {
+ if options.Credentials != "" {
+ return nil, errors.New("username/password cannot be used with credentials")
+ }
+ authConf.Username = options.Username
+ authConf.Password = options.Password
+ return authConf, nil
+ }
+
+ if options.Credentials != "" {
+ split := strings.SplitN(options.Credentials, ":", 2)
+ switch len(split) {
+ case 1:
+ authConf.Username = split[0]
+ default:
+ authConf.Username = split[0]
+ authConf.Password = split[1]
+ }
+ return authConf, nil
+ }
+
+ // We should return nil unless a token was set. That's especially
+ // useful for Podman's remote API.
+ if options.IdentityToken != "" {
+ return authConf, nil
+ }
+
+ return nil, nil
+}
+
+// newCopier creates a copier. Note that fields in options *may* overwrite the
+// counterparts of the specified system context. Please make sure to call
+// `(*copier).close()`.
+func (r *Runtime) newCopier(options *CopyOptions) (*copier, error) {
+ c := copier{}
+ c.systemContext = r.systemContextCopy()
+
+ if options.SourceLookupReferenceFunc != nil {
+ c.sourceLookup = options.SourceLookupReferenceFunc
+ }
+
+ if options.DestinationLookupReferenceFunc != nil {
+ c.destinationLookup = options.DestinationLookupReferenceFunc
+ }
+
+ if options.InsecureSkipTLSVerify != types.OptionalBoolUndefined {
+ c.systemContext.DockerInsecureSkipTLSVerify = options.InsecureSkipTLSVerify
+ c.systemContext.OCIInsecureSkipTLSVerify = options.InsecureSkipTLSVerify == types.OptionalBoolTrue
+ c.systemContext.DockerDaemonInsecureSkipTLSVerify = options.InsecureSkipTLSVerify == types.OptionalBoolTrue
+ }
+
+ c.systemContext.DirForceCompress = c.systemContext.DirForceCompress || options.DirForceCompress
+
+ if options.AuthFilePath != "" {
+ c.systemContext.AuthFilePath = options.AuthFilePath
+ }
+
+ c.systemContext.DockerArchiveAdditionalTags = options.dockerArchiveAdditionalTags
+
+ if options.Architecture != "" {
+ c.systemContext.ArchitectureChoice = options.Architecture
+ }
+ if options.OS != "" {
+ c.systemContext.OSChoice = options.OS
+ }
+ if options.Variant != "" {
+ c.systemContext.VariantChoice = options.Variant
+ }
+
+ if options.SignaturePolicyPath != "" {
+ c.systemContext.SignaturePolicyPath = options.SignaturePolicyPath
+ }
+
+ dockerAuthConfig, err := options.getDockerAuthConfig()
+ if err != nil {
+ return nil, err
+ }
+ if dockerAuthConfig != nil {
+ c.systemContext.DockerAuthConfig = dockerAuthConfig
+ }
+
+ if options.BlobInfoCacheDirPath != "" {
+ c.systemContext.BlobInfoCacheDir = options.BlobInfoCacheDirPath
+ }
+
+ if options.CertDirPath != "" {
+ c.systemContext.DockerCertPath = options.CertDirPath
+ }
+
+ policy, err := signature.DefaultPolicy(c.systemContext)
+ if err != nil {
+ return nil, err
+ }
+
+ // Buildah compatibility: even if the policy denies _all_ transports,
+ // Buildah still wants the storage to be accessible.
+ if options.PolicyAllowStorage {
+ policy.Transports[storageTransport.Transport.Name()] = storageAllowedPolicyScopes
+ }
+
+ policyContext, err := signature.NewPolicyContext(policy)
+ if err != nil {
+ return nil, err
+ }
+
+ c.policyContext = policyContext
+
+ c.retryOptions.MaxRetry = defaultMaxRetries
+ if options.MaxRetries != nil {
+ c.retryOptions.MaxRetry = int(*options.MaxRetries)
+ }
+ c.retryOptions.Delay = defaultRetryDelay
+ if options.RetryDelay != nil {
+ c.retryOptions.Delay = *options.RetryDelay
+ }
+
+ c.imageCopyOptions.Progress = options.Progress
+ if c.imageCopyOptions.Progress != nil {
+ c.imageCopyOptions.ProgressInterval = time.Second
+ }
+
+ c.imageCopyOptions.ForceManifestMIMEType = options.ManifestMIMEType
+ c.imageCopyOptions.SourceCtx = c.systemContext
+ c.imageCopyOptions.DestinationCtx = c.systemContext
+ c.imageCopyOptions.OciEncryptConfig = options.OciEncryptConfig
+ c.imageCopyOptions.OciEncryptLayers = options.OciEncryptLayers
+ c.imageCopyOptions.OciDecryptConfig = options.OciDecryptConfig
+ c.imageCopyOptions.RemoveSignatures = options.RemoveSignatures
+ c.imageCopyOptions.SignBy = options.SignBy
+ c.imageCopyOptions.ReportWriter = options.Writer
+
+ defaultContainerConfig, err := config.Default()
+ if err != nil {
+ logrus.Warnf("failed to get container config for copy options: %v", err)
+ } else {
+ c.imageCopyOptions.MaxParallelDownloads = defaultContainerConfig.Engine.ImageParallelCopies
+ }
+
+ return &c, nil
+}
+
+// close open resources.
+func (c *copier) close() error {
+ return c.policyContext.Destroy()
+}
+
+// copy the source to the destination. Returns the bytes of the copied
+// manifest which may be used for digest computation.
+func (c *copier) copy(ctx context.Context, source, destination types.ImageReference) ([]byte, error) {
+ logrus.Debugf("Copying source image %s to destination image %s", source.StringWithinTransport(), destination.StringWithinTransport())
+
+ var err error
+
+ if c.sourceLookup != nil {
+ source, err = c.sourceLookup(source)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ if c.destinationLookup != nil {
+ destination, err = c.destinationLookup(destination)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ // Buildah compat: used when running in OpenShift.
+ sourceInsecure, err := checkRegistrySourcesAllows(source)
+ if err != nil {
+ return nil, err
+ }
+ destinationInsecure, err := checkRegistrySourcesAllows(destination)
+ if err != nil {
+ return nil, err
+ }
+
+ // Sanity checks for Buildah.
+ if sourceInsecure != nil && *sourceInsecure {
+ if c.systemContext.DockerInsecureSkipTLSVerify == types.OptionalBoolFalse {
+ return nil, errors.Errorf("can't require tls verification on an insecured registry")
+ }
+ }
+ if destinationInsecure != nil && *destinationInsecure {
+ if c.systemContext.DockerInsecureSkipTLSVerify == types.OptionalBoolFalse {
+ return nil, errors.Errorf("can't require tls verification on an insecured registry")
+ }
+ }
+
+ var copiedManifest []byte
+ f := func() error {
+ opts := c.imageCopyOptions
+ if sourceInsecure != nil {
+ value := types.NewOptionalBool(*sourceInsecure)
+ opts.SourceCtx.DockerInsecureSkipTLSVerify = value
+ }
+ if destinationInsecure != nil {
+ value := types.NewOptionalBool(*destinationInsecure)
+ opts.DestinationCtx.DockerInsecureSkipTLSVerify = value
+ }
+
+ var err error
+ copiedManifest, err = copy.Image(ctx, c.policyContext, destination, source, &opts)
+ return err
+ }
+ return copiedManifest, retry.RetryIfNecessary(ctx, f, &c.retryOptions)
+}
+
+// checkRegistrySourcesAllows checks the $BUILD_REGISTRY_SOURCES environment
+// variable, if it's set. The contents are expected to be a JSON-encoded
+// github.com/openshift/api/config/v1.Image, set by an OpenShift build
+// controller that arranged for us to be run in a container.
+//
+// If set, the insecure return value indicates whether the registry is set to
+// be insecure.
+//
+// NOTE: this functionality is required by Buildah.
+func checkRegistrySourcesAllows(dest types.ImageReference) (insecure *bool, err error) {
+ registrySources, ok := os.LookupEnv("BUILD_REGISTRY_SOURCES")
+ if !ok || registrySources == "" {
+ return nil, nil
+ }
+
+ logrus.Debugf("BUILD_REGISTRY_SOURCES set %q", registrySources)
+
+ dref := dest.DockerReference()
+ if dref == nil || reference.Domain(dref) == "" {
+ return nil, nil
+ }
+
+ // Use local struct instead of github.com/openshift/api/config/v1 RegistrySources
+ var sources struct {
+ InsecureRegistries []string `json:"insecureRegistries,omitempty"`
+ BlockedRegistries []string `json:"blockedRegistries,omitempty"`
+ AllowedRegistries []string `json:"allowedRegistries,omitempty"`
+ }
+ if err := json.Unmarshal([]byte(registrySources), &sources); err != nil {
+ return nil, errors.Wrapf(err, "error parsing $BUILD_REGISTRY_SOURCES (%q) as JSON", registrySources)
+ }
+ blocked := false
+ if len(sources.BlockedRegistries) > 0 {
+ for _, blockedDomain := range sources.BlockedRegistries {
+ if blockedDomain == reference.Domain(dref) {
+ blocked = true
+ }
+ }
+ }
+ if blocked {
+ return nil, errors.Errorf("registry %q denied by policy: it is in the blocked registries list (%s)", reference.Domain(dref), registrySources)
+ }
+ allowed := true
+ if len(sources.AllowedRegistries) > 0 {
+ allowed = false
+ for _, allowedDomain := range sources.AllowedRegistries {
+ if allowedDomain == reference.Domain(dref) {
+ allowed = true
+ }
+ }
+ }
+ if !allowed {
+ return nil, errors.Errorf("registry %q denied by policy: not in allowed registries list (%s)", reference.Domain(dref), registrySources)
+ }
+
+ for _, inseureDomain := range sources.InsecureRegistries {
+ if inseureDomain == reference.Domain(dref) {
+ insecure := true
+ return &insecure, nil
+ }
+ }
+
+ return nil, nil
+}
diff --git a/vendor/github.com/containers/common/libimage/disk_usage.go b/vendor/github.com/containers/common/libimage/disk_usage.go
new file mode 100644
index 000000000..edfd095a0
--- /dev/null
+++ b/vendor/github.com/containers/common/libimage/disk_usage.go
@@ -0,0 +1,126 @@
+package libimage
+
+import (
+ "context"
+ "time"
+)
+
+// ImageDiskUsage reports the total size of an image. That is the size
+type ImageDiskUsage struct {
+ // Number of containers using the image.
+ Containers int
+ // ID of the image.
+ ID string
+ // Repository of the image.
+ Repository string
+ // Tag of the image.
+ Tag string
+ // Created time stamp.
+ Created time.Time
+ // The amount of space that an image shares with another one (i.e. their common data).
+ SharedSize int64
+ // The the amount of space that is only used by a given image.
+ UniqueSize int64
+ // Sum of shared an unique size.
+ Size int64
+}
+
+// DiskUsage calculates the disk usage for each image in the local containers
+// storage. Note that a single image may yield multiple usage reports, one for
+// each repository tag.
+func (r *Runtime) DiskUsage(ctx context.Context) ([]ImageDiskUsage, error) {
+ layerTree, err := r.layerTree()
+ if err != nil {
+ return nil, err
+ }
+
+ images, err := r.ListImages(ctx, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+
+ var allUsages []ImageDiskUsage
+ for _, image := range images {
+ usages, err := diskUsageForImage(ctx, image, layerTree)
+ if err != nil {
+ return nil, err
+ }
+ allUsages = append(allUsages, usages...)
+ }
+ return allUsages, err
+}
+
+// diskUsageForImage returns the disk-usage baseistics for the specified image.
+func diskUsageForImage(ctx context.Context, image *Image, tree *layerTree) ([]ImageDiskUsage, error) {
+ base := ImageDiskUsage{
+ ID: image.ID(),
+ Created: image.Created(),
+ Repository: "<none>",
+ Tag: "<none>",
+ }
+
+ // Shared, unique and total size.
+ parent, err := tree.parent(ctx, image)
+ if err != nil {
+ return nil, err
+ }
+ childIDs, err := tree.children(ctx, image, false)
+ if err != nil {
+ return nil, err
+ }
+
+ // Optimistically set unique size to the full size of the image.
+ size, err := image.Size()
+ if err != nil {
+ return nil, err
+ }
+ base.UniqueSize = size
+
+ if len(childIDs) > 0 {
+ // If we have children, we share everything.
+ base.SharedSize = base.UniqueSize
+ base.UniqueSize = 0
+ } else if parent != nil {
+ // If we have no children but a parent, remove the parent
+ // (shared) size from the unique one.
+ size, err := parent.Size()
+ if err != nil {
+ return nil, err
+ }
+ base.UniqueSize -= size
+ base.SharedSize = size
+ }
+
+ base.Size = base.SharedSize + base.UniqueSize
+
+ // Number of containers using the image.
+ containers, err := image.Containers()
+ if err != nil {
+ return nil, err
+ }
+ base.Containers = len(containers)
+
+ repoTags, err := image.NamedRepoTags()
+ if err != nil {
+ return nil, err
+ }
+
+ if len(repoTags) == 0 {
+ return []ImageDiskUsage{base}, nil
+ }
+
+ pairs, err := ToNameTagPairs(repoTags)
+ if err != nil {
+ return nil, err
+ }
+
+ results := make([]ImageDiskUsage, len(pairs))
+ for i, pair := range pairs {
+ res := base
+ res.Repository = pair.Name
+ res.Tag = pair.Tag
+ results[i] = res
+ }
+
+ return results, nil
+}
diff --git a/vendor/github.com/containers/common/libimage/download.go b/vendor/github.com/containers/common/libimage/download.go
new file mode 100644
index 000000000..5ea11f084
--- /dev/null
+++ b/vendor/github.com/containers/common/libimage/download.go
@@ -0,0 +1,46 @@
+package libimage
+
+import (
+ "fmt"
+ "io"
+ "io/ioutil"
+ "net/http"
+ "os"
+
+ "github.com/pkg/errors"
+)
+
+// tmpdir returns a path to a temporary directory.
+func (r *Runtime) tmpdir() string {
+ tmpdir := os.Getenv("TMPDIR")
+ if tmpdir == "" {
+ tmpdir = "/var/tmp"
+ }
+
+ return tmpdir
+}
+
+// downloadFromURL downloads an image in the format "https:/example.com/myimage.tar"
+// and temporarily saves in it $TMPDIR/importxyz, which is deleted after the image is imported
+func (r *Runtime) downloadFromURL(source string) (string, error) {
+ fmt.Printf("Downloading from %q\n", source)
+
+ outFile, err := ioutil.TempFile(r.tmpdir(), "import")
+ if err != nil {
+ return "", errors.Wrap(err, "error creating file")
+ }
+ defer outFile.Close()
+
+ response, err := http.Get(source) // nolint:noctx
+ if err != nil {
+ return "", errors.Wrapf(err, "error downloading %q", source)
+ }
+ defer response.Body.Close()
+
+ _, err = io.Copy(outFile, response.Body)
+ if err != nil {
+ return "", errors.Wrapf(err, "error saving %s to %s", source, outFile.Name())
+ }
+
+ return outFile.Name(), nil
+}
diff --git a/vendor/github.com/containers/common/libimage/events.go b/vendor/github.com/containers/common/libimage/events.go
new file mode 100644
index 000000000..bca736c7b
--- /dev/null
+++ b/vendor/github.com/containers/common/libimage/events.go
@@ -0,0 +1,43 @@
+package libimage
+
+import "time"
+
+// EventType indicates the type of an event. Currrently, there is only one
+// supported type for container image but we may add more (e.g., for manifest
+// lists) in the future.
+type EventType int
+
+const (
+ // EventTypeUnknow is an unitialized EventType.
+ EventTypeUnknown EventType = iota
+ // EventTypeImagePull represents an image pull.
+ EventTypeImagePull
+ // EventTypeImagePush represents an image push.
+ EventTypeImagePush
+ // EventTypeImageRemove represents an image removal.
+ EventTypeImageRemove
+ // EventTypeImageLoad represents an image being loaded.
+ EventTypeImageLoad
+ // EventTypeImageSave represents an image being saved.
+ EventTypeImageSave
+ // EventTypeImageTag represents an image being tagged.
+ EventTypeImageTag
+ // EventTypeImageUntag represents an image being untagged.
+ EventTypeImageUntag
+ // EventTypeImageMount represents an image being mounted.
+ EventTypeImageMount
+ // EventTypeImageUnmounted represents an image being unmounted.
+ EventTypeImageUnmount
+)
+
+// Event represents an event such an image pull or image tag.
+type Event struct {
+ // ID of the object (e.g., image ID).
+ ID string
+ // Name of the object (e.g., image name "quay.io/containers/podman:latest")
+ Name string
+ // Time of the event.
+ Time time.Time
+ // Type of the event.
+ Type EventType
+}
diff --git a/vendor/github.com/containers/common/libimage/filters.go b/vendor/github.com/containers/common/libimage/filters.go
new file mode 100644
index 000000000..eae18fd9c
--- /dev/null
+++ b/vendor/github.com/containers/common/libimage/filters.go
@@ -0,0 +1,228 @@
+package libimage
+
+import (
+ "context"
+ "fmt"
+ "path/filepath"
+ "strconv"
+ "strings"
+ "time"
+
+ filtersPkg "github.com/containers/common/pkg/filters"
+ "github.com/containers/common/pkg/timetype"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+)
+
+// filterFunc is a prototype for a positive image filter. Returning `true`
+// indicates that the image matches the criteria.
+type filterFunc func(*Image) (bool, error)
+
+// filterImages returns a slice of images which are passing all specified
+// filters.
+func filterImages(images []*Image, filters []filterFunc) ([]*Image, error) {
+ if len(filters) == 0 {
+ return images, nil
+ }
+ result := []*Image{}
+ for i := range images {
+ include := true
+ var err error
+ for _, filter := range filters {
+ include, err = filter(images[i])
+ if err != nil {
+ return nil, err
+ }
+ if !include {
+ break
+ }
+ }
+ if include {
+ result = append(result, images[i])
+ }
+ }
+ return result, nil
+}
+
+// compileImageFilters creates `filterFunc`s for the specified filters. The
+// required format is `key=value` with the following supported keys:
+// after, since, before, containers, dangling, id, label, readonly, reference, intermediate
+func (r *Runtime) compileImageFilters(ctx context.Context, filters []string) ([]filterFunc, error) {
+ logrus.Tracef("Parsing image filters %s", filters)
+
+ filterFuncs := []filterFunc{}
+ for _, filter := range filters {
+ var key, value string
+ split := strings.SplitN(filter, "=", 2)
+ if len(split) != 2 {
+ return nil, errors.Errorf("invalid image filter %q: must be in the format %q", filter, "filter=value")
+ }
+
+ key = split[0]
+ value = split[1]
+ switch key {
+
+ case "after", "since":
+ img, _, err := r.LookupImage(value, nil)
+ if err != nil {
+ return nil, errors.Wrapf(err, "could not find local image for filter %q", filter)
+ }
+ filterFuncs = append(filterFuncs, filterAfter(img.Created()))
+
+ case "before":
+ img, _, err := r.LookupImage(value, nil)
+ if err != nil {
+ return nil, errors.Wrapf(err, "could not find local image for filter %q", filter)
+ }
+ filterFuncs = append(filterFuncs, filterBefore(img.Created()))
+
+ case "containers":
+ containers, err := strconv.ParseBool(value)
+ if err != nil {
+ return nil, errors.Wrapf(err, "non-boolean value %q for dangling filter", value)
+ }
+ filterFuncs = append(filterFuncs, filterContainers(containers))
+
+ case "dangling":
+ dangling, err := strconv.ParseBool(value)
+ if err != nil {
+ return nil, errors.Wrapf(err, "non-boolean value %q for dangling filter", value)
+ }
+ filterFuncs = append(filterFuncs, filterDangling(dangling))
+
+ case "id":
+ filterFuncs = append(filterFuncs, filterID(value))
+
+ case "intermediate":
+ intermediate, err := strconv.ParseBool(value)
+ if err != nil {
+ return nil, errors.Wrapf(err, "non-boolean value %q for intermediate filter", value)
+ }
+ filterFuncs = append(filterFuncs, filterIntermediate(ctx, intermediate))
+
+ case "label":
+ filterFuncs = append(filterFuncs, filterLabel(ctx, value))
+
+ case "readonly":
+ readOnly, err := strconv.ParseBool(value)
+ if err != nil {
+ return nil, errors.Wrapf(err, "non-boolean value %q for readonly filter", value)
+ }
+ filterFuncs = append(filterFuncs, filterReadOnly(readOnly))
+
+ case "reference":
+ filterFuncs = append(filterFuncs, filterReference(value))
+
+ case "until":
+ ts, err := timetype.GetTimestamp(value, time.Now())
+ if err != nil {
+ return nil, err
+ }
+ seconds, nanoseconds, err := timetype.ParseTimestamps(ts, 0)
+ if err != nil {
+ return nil, err
+ }
+ until := time.Unix(seconds, nanoseconds)
+ filterFuncs = append(filterFuncs, filterBefore(until))
+
+ default:
+ return nil, errors.Errorf("unsupported image filter %q", key)
+ }
+ }
+
+ return filterFuncs, nil
+}
+
+// filterReference creates a reference filter for matching the specified value.
+func filterReference(value string) filterFunc {
+ // Replacing all '/' with '|' so that filepath.Match() can work '|'
+ // character is not valid in image name, so this is safe.
+ //
+ // TODO: this has been copied from Podman and requires some more review
+ // and especially tests.
+ filter := fmt.Sprintf("*%s*", value)
+ filter = strings.ReplaceAll(filter, "/", "|")
+ return func(img *Image) (bool, error) {
+ if len(value) < 1 {
+ return true, nil
+ }
+ for _, name := range img.Names() {
+ newName := strings.ReplaceAll(name, "/", "|")
+ match, _ := filepath.Match(filter, newName)
+ if match {
+ return true, nil
+ }
+ }
+ return false, nil
+ }
+}
+
+// filterLabel creates a label for matching the specified value.
+func filterLabel(ctx context.Context, value string) filterFunc {
+ return func(img *Image) (bool, error) {
+ labels, err := img.Labels(ctx)
+ if err != nil {
+ return false, err
+ }
+ return filtersPkg.MatchLabelFilters([]string{value}, labels), nil
+ }
+}
+
+// filterAfter creates an after filter for matching the specified value.
+func filterAfter(value time.Time) filterFunc {
+ return func(img *Image) (bool, error) {
+ return img.Created().After(value), nil
+ }
+}
+
+// filterBefore creates a before filter for matching the specified value.
+func filterBefore(value time.Time) filterFunc {
+ return func(img *Image) (bool, error) {
+ return img.Created().Before(value), nil
+ }
+}
+
+// filterReadOnly creates a readonly filter for matching the specified value.
+func filterReadOnly(value bool) filterFunc {
+ return func(img *Image) (bool, error) {
+ return img.IsReadOnly() == value, nil
+ }
+}
+
+// filterContainers creates a container filter for matching the specified value.
+func filterContainers(value bool) filterFunc {
+ return func(img *Image) (bool, error) {
+ ctrs, err := img.Containers()
+ if err != nil {
+ return false, err
+ }
+ return (len(ctrs) > 0) == value, nil
+ }
+}
+
+// filterDangling creates a dangling filter for matching the specified value.
+func filterDangling(value bool) filterFunc {
+ return func(img *Image) (bool, error) {
+ return img.IsDangling() == value, nil
+ }
+}
+
+// filterID creates an image-ID filter for matching the specified value.
+func filterID(value string) filterFunc {
+ return func(img *Image) (bool, error) {
+ return img.ID() == value, nil
+ }
+}
+
+// filterIntermediate creates an intermediate filter for images. An image is
+// considered to be an intermediate image if it is dangling (i.e., no tags) and
+// has no children (i.e., no other image depends on it).
+func filterIntermediate(ctx context.Context, value bool) filterFunc {
+ return func(img *Image) (bool, error) {
+ isIntermediate, err := img.IsIntermediate(ctx)
+ if err != nil {
+ return false, err
+ }
+ return isIntermediate == value, nil
+ }
+}
diff --git a/vendor/github.com/containers/common/libimage/history.go b/vendor/github.com/containers/common/libimage/history.go
new file mode 100644
index 000000000..b63fe696b
--- /dev/null
+++ b/vendor/github.com/containers/common/libimage/history.go
@@ -0,0 +1,80 @@
+package libimage
+
+import (
+ "context"
+ "time"
+
+ "github.com/containers/storage"
+)
+
+// ImageHistory contains the history information of an image.
+type ImageHistory struct {
+ ID string `json:"id"`
+ Created *time.Time `json:"created"`
+ CreatedBy string `json:"createdBy"`
+ Size int64 `json:"size"`
+ Comment string `json:"comment"`
+ Tags []string `json:"tags"`
+}
+
+// History computes the image history of the image including all of its parents.
+func (i *Image) History(ctx context.Context) ([]ImageHistory, error) {
+ ociImage, err := i.toOCI(ctx)
+ if err != nil {
+ return nil, err
+ }
+
+ layerTree, err := i.runtime.layerTree()
+ if err != nil {
+ return nil, err
+ }
+
+ var allHistory []ImageHistory
+ var layer *storage.Layer
+ if i.TopLayer() != "" {
+ layer, err = i.runtime.store.Layer(i.TopLayer())
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ // Iterate in reverse order over the history entries, and lookup the
+ // corresponding image ID, size and get the next later if needed.
+ numHistories := len(ociImage.History) - 1
+ usedIDs := make(map[string]bool) // prevents assigning images IDs more than once
+ for x := numHistories; x >= 0; x-- {
+ history := ImageHistory{
+ ID: "<missing>", // may be overridden below
+ Created: ociImage.History[x].Created,
+ CreatedBy: ociImage.History[x].CreatedBy,
+ Comment: ociImage.History[x].Comment,
+ }
+
+ if layer != nil {
+ history.Tags = layer.Names
+ if !ociImage.History[x].EmptyLayer {
+ history.Size = layer.UncompressedSize
+ }
+ // Query the layer tree if it's the top layer of an
+ // image.
+ node := layerTree.node(layer.ID)
+ if len(node.images) > 0 {
+ id := node.images[0].ID() // always use the first one
+ if _, used := usedIDs[id]; !used {
+ history.ID = id
+ usedIDs[id] = true
+ }
+ }
+ if layer.Parent != "" && !ociImage.History[x].EmptyLayer {
+ layer, err = i.runtime.store.Layer(layer.Parent)
+ if err != nil {
+ return nil, err
+ }
+ }
+ }
+
+ allHistory = append(allHistory, history)
+ }
+
+ return allHistory, nil
+}
diff --git a/vendor/github.com/containers/common/libimage/image.go b/vendor/github.com/containers/common/libimage/image.go
new file mode 100644
index 000000000..4728565bb
--- /dev/null
+++ b/vendor/github.com/containers/common/libimage/image.go
@@ -0,0 +1,802 @@
+package libimage
+
+import (
+ "context"
+ "path/filepath"
+ "sort"
+ "strings"
+ "time"
+
+ "github.com/containers/image/v5/docker/reference"
+ "github.com/containers/image/v5/manifest"
+ storageTransport "github.com/containers/image/v5/storage"
+ "github.com/containers/image/v5/types"
+ "github.com/containers/storage"
+ "github.com/hashicorp/go-multierror"
+ "github.com/opencontainers/go-digest"
+ ociv1 "github.com/opencontainers/image-spec/specs-go/v1"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+)
+
+// Image represents an image in the containers storage and allows for further
+// operations and data manipulation.
+type Image struct {
+ // Backwards pointer to the runtime.
+ runtime *Runtime
+
+ // Counterpart in the local containers storage.
+ storageImage *storage.Image
+
+ // Image reference to the containers storage.
+ storageReference types.ImageReference
+
+ // All fields in the below structure are cached. They may be cleared
+ // at any time. When adding a new field, please make sure to clear
+ // it in `(*Image).reload()`.
+ cached struct {
+ // Image source. Cached for performance reasons.
+ imageSource types.ImageSource
+ // Inspect data we get from containers/image.
+ partialInspectData *types.ImageInspectInfo
+ // Fully assembled image data.
+ completeInspectData *ImageData
+ // Corresponding OCI image.
+ ociv1Image *ociv1.Image
+ }
+}
+
+// reload the image and pessimitically clear all cached data.
+func (i *Image) reload() error {
+ logrus.Tracef("Reloading image %s", i.ID())
+ img, err := i.runtime.store.Image(i.ID())
+ if err != nil {
+ return errors.Wrap(err, "error reloading image")
+ }
+ i.storageImage = img
+ i.cached.imageSource = nil
+ i.cached.partialInspectData = nil
+ i.cached.completeInspectData = nil
+ i.cached.ociv1Image = nil
+ return nil
+}
+
+// Names returns associated names with the image which may be a mix of tags and
+// digests.
+func (i *Image) Names() []string {
+ return i.storageImage.Names
+}
+
+// StorageImage returns the underlying storage.Image.
+func (i *Image) StorageImage() *storage.Image {
+ return i.storageImage
+}
+
+// NamesHistory returns a string array of names previously associated with the
+// image, which may be a mixture of tags and digests.
+func (i *Image) NamesHistory() []string {
+ return i.storageImage.NamesHistory
+}
+
+// ID returns the ID of the image.
+func (i *Image) ID() string {
+ return i.storageImage.ID
+}
+
+// Digest is a digest value that we can use to locate the image, if one was
+// specified at creation-time.
+func (i *Image) Digest() digest.Digest {
+ return i.storageImage.Digest
+}
+
+// Digests is a list of digest values of the image's manifests, and possibly a
+// manually-specified value, that we can use to locate the image. If Digest is
+// set, its value is also in this list.
+func (i *Image) Digests() []digest.Digest {
+ return i.storageImage.Digests
+}
+
+// IsReadOnly returns whether the image is set read only.
+func (i *Image) IsReadOnly() bool {
+ return i.storageImage.ReadOnly
+}
+
+// IsDangling returns true if the image is dangling. An image is considered
+// dangling if no names are associated with it in the containers storage.
+func (i *Image) IsDangling() bool {
+ return len(i.Names()) == 0
+}
+
+// IsIntermediate returns true if the image is an intermediate image, that is
+// a dangling image without children.
+func (i *Image) IsIntermediate(ctx context.Context) (bool, error) {
+ // If the image has tags, it's not an intermediate one.
+ if !i.IsDangling() {
+ return false, nil
+ }
+ children, err := i.getChildren(ctx, false)
+ if err != nil {
+ return false, err
+ }
+ // No tags, no children -> intermediate!
+ return len(children) != 0, nil
+}
+
+// Created returns the time the image was created.
+func (i *Image) Created() time.Time {
+ return i.storageImage.Created
+}
+
+// Labels returns the label of the image.
+func (i *Image) Labels(ctx context.Context) (map[string]string, error) {
+ data, err := i.inspectInfo(ctx)
+ if err != nil {
+ isManifestList, listErr := i.IsManifestList(ctx)
+ if listErr != nil {
+ err = errors.Wrapf(err, "fallback error checking whether image is a manifest list: %v", err)
+ } else if isManifestList {
+ logrus.Debugf("Ignoring error: cannot return labels for manifest list or image index %s", i.ID())
+ return nil, nil
+ }
+ return nil, err
+ }
+
+ return data.Labels, nil
+}
+
+// TopLayer returns the top layer id as a string
+func (i *Image) TopLayer() string {
+ return i.storageImage.TopLayer
+}
+
+// Parent returns the parent image or nil if there is none
+func (i *Image) Parent(ctx context.Context) (*Image, error) {
+ tree, err := i.runtime.layerTree()
+ if err != nil {
+ return nil, err
+ }
+ return tree.parent(ctx, i)
+}
+
+// HasChildren returns indicates if the image has children.
+func (i *Image) HasChildren(ctx context.Context) (bool, error) {
+ children, err := i.getChildren(ctx, false)
+ if err != nil {
+ return false, err
+ }
+ return len(children) > 0, nil
+}
+
+// Children returns the image's children.
+func (i *Image) Children(ctx context.Context) ([]*Image, error) {
+ children, err := i.getChildren(ctx, true)
+ if err != nil {
+ return nil, err
+ }
+ return children, nil
+}
+
+// getChildren returns a list of imageIDs that depend on the image. If all is
+// false, only the first child image is returned.
+func (i *Image) getChildren(ctx context.Context, all bool) ([]*Image, error) {
+ tree, err := i.runtime.layerTree()
+ if err != nil {
+ return nil, err
+ }
+
+ return tree.children(ctx, i, all)
+}
+
+// Containers returns a list of containers using the image.
+func (i *Image) Containers() ([]string, error) {
+ var containerIDs []string
+ containers, err := i.runtime.store.Containers()
+ if err != nil {
+ return nil, err
+ }
+ imageID := i.ID()
+ for i := range containers {
+ if containers[i].ImageID == imageID {
+ containerIDs = append(containerIDs, containers[i].ID)
+ }
+ }
+ return containerIDs, nil
+}
+
+// removeContainers removes all containers using the image.
+func (i *Image) removeContainers(fn RemoveContainerFunc) error {
+ // Execute the custom removal func if specified.
+ if fn != nil {
+ logrus.Debugf("Removing containers of image %s with custom removal function", i.ID())
+ if err := fn(i.ID()); err != nil {
+ return err
+ }
+ }
+
+ containers, err := i.Containers()
+ if err != nil {
+ return err
+ }
+
+ logrus.Debugf("Removing containers of image %s from the local containers storage", i.ID())
+ var multiE error
+ for _, cID := range containers {
+ if err := i.runtime.store.DeleteContainer(cID); err != nil {
+ // If the container does not exist anymore, we're good.
+ if errors.Cause(err) != storage.ErrContainerUnknown {
+ multiE = multierror.Append(multiE, err)
+ }
+ }
+ }
+
+ return multiE
+}
+
+// RemoveContainerFunc allows for customizing the removal of containers using
+// an image specified by imageID.
+type RemoveContainerFunc func(imageID string) error
+
+// RemoveImagesReport is the assembled data from removing *one* image.
+type RemoveImageReport struct {
+ // ID of the image.
+ ID string
+ // Image was removed.
+ Removed bool
+ // Size of the removed image. Only set when explicitly requested in
+ // RemoveImagesOptions.
+ Size int64
+ // The untagged tags.
+ Untagged []string
+}
+
+// remove removes the image along with all dangling parent images that no other
+// image depends on. The image must not be set read-only and not be used by
+// containers.
+//
+// If the image is used by containers return storage.ErrImageUsedByContainer.
+// Use force to remove these containers.
+//
+// NOTE: the rmMap is used to assemble image-removal data across multiple
+// invocations of this function. The recursive nature requires some
+// bookkeeping to make sure that all data is aggregated correctly.
+//
+// This function is internal. Users of libimage should always use
+// `(*Runtime).RemoveImages()`.
+func (i *Image) remove(ctx context.Context, rmMap map[string]*RemoveImageReport, referencedBy string, options *RemoveImagesOptions) error {
+ // If referencedBy is empty, the image is considered to be removed via
+ // `image remove --all` which alters the logic below.
+
+ // The removal logic below is complex. There is a number of rules
+ // inherited from Podman and Buildah (and Docker). This function
+ // should be the *only* place to extend the removal logic so we keep it
+ // sealed in one place. Make sure to add verbose comments to leave
+ // some breadcrumbs for future readers.
+ logrus.Debugf("Removing image %s", i.ID())
+
+ if i.IsReadOnly() {
+ return errors.Errorf("cannot remove read-only image %q", i.ID())
+ }
+
+ // Check if already visisted this image.
+ report, exists := rmMap[i.ID()]
+ if exists {
+ // If the image has already been removed, we're done.
+ if report.Removed {
+ return nil
+ }
+ } else {
+ report = &RemoveImageReport{ID: i.ID()}
+ rmMap[i.ID()] = report
+ }
+
+ // The image may have already been (partially) removed, so we need to
+ // have a closer look at the errors. On top, image removal should be
+ // tolerant toward corrupted images.
+ handleError := func(err error) error {
+ switch errors.Cause(err) {
+ case storage.ErrImageUnknown, storage.ErrNotAnImage, storage.ErrLayerUnknown:
+ // The image or layers of the image may already
+ // have been removed in which case we consider
+ // the image to be removed.
+ return nil
+ default:
+ return err
+ }
+ }
+
+ // Calculate the size if requested. `podman-image-prune` likes to
+ // report the regained size.
+ if options.WithSize {
+ size, err := i.Size()
+ if handleError(err) != nil {
+ return err
+ }
+ report.Size = size
+ }
+
+ skipRemove := false
+ numNames := len(i.Names())
+
+ // NOTE: the `numNames == 1` check is not only a performance
+ // optimization but also preserves exiting Podman/Docker behaviour.
+ // If image "foo" is used by a container and has only this tag/name,
+ // an `rmi foo` will not untag "foo" but instead attempt to remove the
+ // entire image. If there's a container using "foo", we should get an
+ // error.
+ if options.Force || referencedBy == "" || numNames == 1 {
+ // DO NOTHING, the image will be removed
+ } else {
+ byID := strings.HasPrefix(i.ID(), referencedBy)
+ byDigest := strings.HasPrefix(referencedBy, "sha256:")
+ if byID && numNames > 1 {
+ return errors.Errorf("unable to delete image %q by ID with more than one tag (%s): please force removal", i.ID(), i.Names())
+ } else if byDigest && numNames > 1 {
+ // FIXME - Docker will remove the digest but containers storage
+ // does not support that yet, so our hands are tied.
+ return errors.Errorf("unable to delete image %q by digest with more than one tag (%s): please force removal", i.ID(), i.Names())
+ }
+
+ // Only try to untag if we know it's not an ID or digest.
+ if !byID && !byDigest {
+ if err := i.Untag(referencedBy); handleError(err) != nil {
+ return err
+ }
+ report.Untagged = append(report.Untagged, referencedBy)
+
+ // If there's still tags left, we cannot delete it.
+ skipRemove = len(i.Names()) > 0
+ }
+ }
+
+ if skipRemove {
+ return nil
+ }
+
+ // Perform the actual removal. First, remove containers if needed.
+ if options.Force {
+ if err := i.removeContainers(options.RemoveContainerFunc); err != nil {
+ return err
+ }
+ }
+
+ // Podman/Docker compat: we only report an image as removed if it has
+ // no children. Otherwise, the data is effectively still present in the
+ // storage despite the image being removed.
+ hasChildren, err := i.HasChildren(ctx)
+ if err != nil {
+ // We must be tolerant toward corrupted images.
+ // See containers/podman commit fd9dd7065d44.
+ logrus.Warnf("error determining if an image is a parent: %v, ignoring the error", err)
+ hasChildren = false
+ }
+
+ // If there's a dangling parent that no other image depends on, remove
+ // it recursively.
+ parent, err := i.Parent(ctx)
+ if err != nil {
+ // We must be tolerant toward corrupted images.
+ // See containers/podman commit fd9dd7065d44.
+ logrus.Warnf("error determining parent of image: %v, ignoring the error", err)
+ parent = nil
+ }
+
+ if _, err := i.runtime.store.DeleteImage(i.ID(), true); handleError(err) != nil {
+ return err
+ }
+ report.Untagged = append(report.Untagged, i.Names()...)
+
+ if !hasChildren {
+ report.Removed = true
+ }
+
+ // Check if can remove the parent image.
+ if parent == nil {
+ return nil
+ }
+
+ if !parent.IsDangling() {
+ return nil
+ }
+
+ // If the image has siblings, we don't remove the parent.
+ hasSiblings, err := parent.HasChildren(ctx)
+ if err != nil {
+ // See Podman commit fd9dd7065d44: we need to
+ // be tolerant toward corrupted images.
+ logrus.Warnf("error determining if an image is a parent: %v, ignoring the error", err)
+ hasSiblings = false
+ }
+ if hasSiblings {
+ return nil
+ }
+
+ // Recurse into removing the parent.
+ return parent.remove(ctx, rmMap, "", options)
+}
+
+// Tag the image with the specified name and store it in the local containers
+// storage. The name is normalized according to the rules of NormalizeName.
+func (i *Image) Tag(name string) error {
+ ref, err := NormalizeName(name)
+ if err != nil {
+ return errors.Wrapf(err, "error normalizing name %q", name)
+ }
+
+ logrus.Debugf("Tagging image %s with %q", i.ID(), ref.String())
+
+ newNames := append(i.Names(), ref.String())
+ if err := i.runtime.store.SetNames(i.ID(), newNames); err != nil {
+ return err
+ }
+
+ return i.reload()
+}
+
+// to have some symmetry with the errors from containers/storage.
+var errTagUnknown = errors.New("tag not known")
+
+// TODO (@vrothberg) - `docker rmi sha256:` will remove the digest from the
+// image. However, that's something containers storage does not support.
+var errUntagDigest = errors.New("untag by digest not supported")
+
+// Untag the image with the specified name and make the change persistent in
+// the local containers storage. The name is normalized according to the rules
+// of NormalizeName.
+func (i *Image) Untag(name string) error {
+ if strings.HasPrefix(name, "sha256:") {
+ return errors.Wrap(errUntagDigest, name)
+ }
+
+ ref, err := NormalizeName(name)
+ if err != nil {
+ return errors.Wrapf(err, "error normalizing name %q", name)
+ }
+ name = ref.String()
+
+ logrus.Debugf("Untagging %q from image %s", ref.String(), i.ID())
+
+ removedName := false
+ newNames := []string{}
+ for _, n := range i.Names() {
+ if n == name {
+ removedName = true
+ continue
+ }
+ newNames = append(newNames, n)
+ }
+
+ if !removedName {
+ return errors.Wrap(errTagUnknown, name)
+ }
+
+ if err := i.runtime.store.SetNames(i.ID(), newNames); err != nil {
+ return err
+ }
+
+ return i.reload()
+}
+
+// RepoTags returns a string slice of repotags associated with the image.
+func (i *Image) RepoTags() ([]string, error) {
+ namedTagged, err := i.NamedTaggedRepoTags()
+ if err != nil {
+ return nil, err
+ }
+ repoTags := make([]string, len(namedTagged))
+ for i := range namedTagged {
+ repoTags[i] = namedTagged[i].String()
+ }
+ return repoTags, nil
+}
+
+// NamedTaggedRepoTags returns the repotags associated with the image as a
+// slice of reference.NamedTagged.
+func (i *Image) NamedTaggedRepoTags() ([]reference.NamedTagged, error) {
+ var repoTags []reference.NamedTagged
+ for _, name := range i.Names() {
+ parsed, err := reference.Parse(name)
+ if err != nil {
+ return nil, err
+ }
+ named, isNamed := parsed.(reference.Named)
+ if !isNamed {
+ continue
+ }
+ tagged, isTagged := named.(reference.NamedTagged)
+ if !isTagged {
+ continue
+ }
+ repoTags = append(repoTags, tagged)
+ }
+ return repoTags, nil
+}
+
+// NamedRepoTags returns the repotags associated with the image as a
+// slice of reference.Named.
+func (i *Image) NamedRepoTags() ([]reference.Named, error) {
+ var repoTags []reference.Named
+ for _, name := range i.Names() {
+ parsed, err := reference.Parse(name)
+ if err != nil {
+ return nil, err
+ }
+ if named, isNamed := parsed.(reference.Named); isNamed {
+ repoTags = append(repoTags, named)
+ }
+ }
+ return repoTags, nil
+}
+
+// inRepoTags looks for the specified name/tag pair in the image's repo tags.
+// Note that tag may be empty.
+func (i *Image) inRepoTags(name, tag string) (reference.Named, error) {
+ repoTags, err := i.NamedRepoTags()
+ if err != nil {
+ return nil, err
+ }
+
+ pairs, err := ToNameTagPairs(repoTags)
+ if err != nil {
+ return nil, err
+ }
+
+ for _, pair := range pairs {
+ if tag != "" && tag != pair.Tag {
+ continue
+ }
+ if !strings.HasSuffix(pair.Name, name) {
+ continue
+ }
+ if len(pair.Name) == len(name) { // full match
+ return pair.named, nil
+ }
+ if pair.Name[len(pair.Name)-len(name)-1] == '/' { // matches at repo
+ return pair.named, nil
+ }
+ }
+
+ return nil, nil
+}
+
+// RepoDigests returns a string array of repodigests associated with the image.
+func (i *Image) RepoDigests() ([]string, error) {
+ repoDigests := []string{}
+ added := make(map[string]struct{})
+
+ for _, name := range i.Names() {
+ for _, imageDigest := range append(i.Digests(), i.Digest()) {
+ if imageDigest == "" {
+ continue
+ }
+
+ named, err := reference.ParseNormalizedNamed(name)
+ if err != nil {
+ return nil, err
+ }
+
+ canonical, err := reference.WithDigest(reference.TrimNamed(named), imageDigest)
+ if err != nil {
+ return nil, err
+ }
+
+ if _, alreadyInList := added[canonical.String()]; !alreadyInList {
+ repoDigests = append(repoDigests, canonical.String())
+ added[canonical.String()] = struct{}{}
+ }
+ }
+ }
+ sort.Strings(repoDigests)
+ return repoDigests, nil
+}
+
+// Mount the image with the specified mount options and label, both of which
+// are directly passed down to the containers storage. Returns the fully
+// evaluated path to the mount point.
+func (i *Image) Mount(ctx context.Context, mountOptions []string, mountLabel string) (string, error) {
+ mountPoint, err := i.runtime.store.MountImage(i.ID(), mountOptions, mountLabel)
+ if err != nil {
+ return "", err
+ }
+ mountPoint, err = filepath.EvalSymlinks(mountPoint)
+ if err != nil {
+ return "", err
+ }
+ logrus.Debugf("Mounted image %s at %q", i.ID(), mountPoint)
+ return mountPoint, nil
+}
+
+// Mountpoint returns the path to image's mount point. The path is empty if
+// the image is not mounted.
+func (i *Image) Mountpoint() (string, error) {
+ mountedTimes, err := i.runtime.store.Mounted(i.TopLayer())
+ if err != nil || mountedTimes == 0 {
+ if errors.Cause(err) == storage.ErrLayerUnknown {
+ // Can happen, Podman did it, but there's no
+ // explanation why.
+ err = nil
+ }
+ return "", err
+ }
+
+ layer, err := i.runtime.store.Layer(i.TopLayer())
+ if err != nil {
+ return "", err
+ }
+
+ mountPoint, err := filepath.EvalSymlinks(layer.MountPoint)
+ if err != nil {
+ return "", err
+ }
+
+ return mountPoint, nil
+}
+
+// Unmount the image. Use force to ignore the reference counter and forcefully
+// unmount.
+func (i *Image) Unmount(force bool) error {
+ logrus.Debugf("Unmounted image %s", i.ID())
+ _, err := i.runtime.store.UnmountImage(i.ID(), force)
+ return err
+}
+
+// MountPoint returns the fully-evaluated mount point of the image. If the
+// image isn't mounted, an empty string is returned.
+func (i *Image) MountPoint() (string, error) {
+ counter, err := i.runtime.store.Mounted(i.TopLayer())
+ if err != nil {
+ return "", err
+ }
+
+ if counter == 0 {
+ return "", nil
+ }
+
+ layer, err := i.runtime.store.Layer(i.TopLayer())
+ if err != nil {
+ return "", err
+ }
+ return filepath.EvalSymlinks(layer.MountPoint)
+}
+
+// Size computes the size of the image layers and associated data.
+func (i *Image) Size() (int64, error) {
+ return i.runtime.store.ImageSize(i.ID())
+}
+
+// HasDifferentDigest returns true if the image specified by `remoteRef` has a
+// different digest than the local one. This check can be useful to check for
+// updates on remote registries.
+func (i *Image) HasDifferentDigest(ctx context.Context, remoteRef types.ImageReference) (bool, error) {
+ // We need to account for the arch that the image uses. It seems
+ // common on ARM to tweak this option to pull the correct image. See
+ // github.com/containers/podman/issues/6613.
+ inspectInfo, err := i.inspectInfo(ctx)
+ if err != nil {
+ return false, err
+ }
+
+ sys := i.runtime.systemContextCopy()
+ sys.ArchitectureChoice = inspectInfo.Architecture
+ // OS and variant may not be set, so let's check to avoid accidental
+ // overrides of the runtime settings.
+ if inspectInfo.Os != "" {
+ sys.OSChoice = inspectInfo.Os
+ }
+ if inspectInfo.Variant != "" {
+ sys.VariantChoice = inspectInfo.Variant
+ }
+
+ remoteImg, err := remoteRef.NewImage(ctx, sys)
+ if err != nil {
+ return false, err
+ }
+
+ rawManifest, _, err := remoteImg.Manifest(ctx)
+ if err != nil {
+ return false, err
+ }
+
+ remoteDigest, err := manifest.Digest(rawManifest)
+ if err != nil {
+ return false, err
+ }
+
+ return i.Digest().String() != remoteDigest.String(), nil
+}
+
+// driverData gets the driver data from the store on a layer
+func (i *Image) driverData() (*DriverData, error) {
+ store := i.runtime.store
+ layerID := i.TopLayer()
+ driver, err := store.GraphDriver()
+ if err != nil {
+ return nil, err
+ }
+ metaData, err := driver.Metadata(layerID)
+ if err != nil {
+ return nil, err
+ }
+ if mountTimes, err := store.Mounted(layerID); mountTimes == 0 || err != nil {
+ delete(metaData, "MergedDir")
+ }
+ return &DriverData{
+ Name: driver.String(),
+ Data: metaData,
+ }, nil
+}
+
+// StorageReference returns the image's reference to the containers storage
+// using the image ID.
+func (i *Image) StorageReference() (types.ImageReference, error) {
+ if i.storageReference != nil {
+ return i.storageReference, nil
+ }
+ ref, err := storageTransport.Transport.ParseStoreReference(i.runtime.store, "@"+i.ID())
+ if err != nil {
+ return nil, err
+ }
+ i.storageReference = ref
+ return ref, nil
+}
+
+// source returns the possibly cached image reference.
+func (i *Image) source(ctx context.Context) (types.ImageSource, error) {
+ if i.cached.imageSource != nil {
+ return i.cached.imageSource, nil
+ }
+ ref, err := i.StorageReference()
+ if err != nil {
+ return nil, err
+ }
+ src, err := ref.NewImageSource(ctx, i.runtime.systemContextCopy())
+ if err != nil {
+ return nil, err
+ }
+ i.cached.imageSource = src
+ return src, nil
+}
+
+// rawConfigBlob returns the image's config as a raw byte slice. Users need to
+// unmarshal it to the corresponding type (OCI, Docker v2s{1,2})
+func (i *Image) rawConfigBlob(ctx context.Context) ([]byte, error) {
+ ref, err := i.StorageReference()
+ if err != nil {
+ return nil, err
+ }
+
+ imageCloser, err := ref.NewImage(ctx, i.runtime.systemContextCopy())
+ if err != nil {
+ return nil, err
+ }
+ defer imageCloser.Close()
+
+ return imageCloser.ConfigBlob(ctx)
+}
+
+// Manifest returns the raw data and the MIME type of the image's manifest.
+func (i *Image) Manifest(ctx context.Context) (rawManifest []byte, mimeType string, err error) {
+ src, err := i.source(ctx)
+ if err != nil {
+ return nil, "", err
+ }
+ return src.GetManifest(ctx, nil)
+}
+
+// getImageDigest creates an image object and uses the hex value of the digest as the image ID
+// for parsing the store reference
+func getImageDigest(ctx context.Context, src types.ImageReference, sys *types.SystemContext) (string, error) {
+ newImg, err := src.NewImage(ctx, sys)
+ if err != nil {
+ return "", err
+ }
+ defer func() {
+ if err := newImg.Close(); err != nil {
+ logrus.Errorf("failed to close image: %q", err)
+ }
+ }()
+ imageDigest := newImg.ConfigInfo().Digest
+ if err = imageDigest.Validate(); err != nil {
+ return "", errors.Wrapf(err, "error getting config info")
+ }
+ return "@" + imageDigest.Hex(), nil
+}
diff --git a/vendor/github.com/containers/common/libimage/image_config.go b/vendor/github.com/containers/common/libimage/image_config.go
new file mode 100644
index 000000000..b57121182
--- /dev/null
+++ b/vendor/github.com/containers/common/libimage/image_config.go
@@ -0,0 +1,242 @@
+package libimage
+
+import (
+ "encoding/json"
+ "fmt"
+ "path/filepath"
+ "strconv"
+ "strings"
+
+ "github.com/containers/common/pkg/signal"
+ ociv1 "github.com/opencontainers/image-spec/specs-go/v1"
+ "github.com/pkg/errors"
+)
+
+// ImageConfig is a wrapper around the OCIv1 Image Configuration struct exported
+// by containers/image, but containing additional fields that are not supported
+// by OCIv1 (but are by Docker v2) - notably OnBuild.
+type ImageConfig struct {
+ ociv1.ImageConfig
+ OnBuild []string
+}
+
+// ImageConfigFromChanges produces a v1.ImageConfig from the --change flag that
+// is accepted by several Podman commands. It accepts a (limited subset) of
+// Dockerfile instructions.
+// Valid changes are:
+// * USER
+// * EXPOSE
+// * ENV
+// * ENTRYPOINT
+// * CMD
+// * VOLUME
+// * WORKDIR
+// * LABEL
+// * STOPSIGNAL
+// * ONBUILD
+func ImageConfigFromChanges(changes []string) (*ImageConfig, error) { // nolint:gocyclo
+ config := &ImageConfig{}
+
+ for _, change := range changes {
+ // First, let's assume proper Dockerfile format - space
+ // separator between instruction and value
+ split := strings.SplitN(change, " ", 2)
+
+ if len(split) != 2 {
+ split = strings.SplitN(change, "=", 2)
+ if len(split) != 2 {
+ return nil, errors.Errorf("invalid change %q - must be formatted as KEY VALUE", change)
+ }
+ }
+
+ outerKey := strings.ToUpper(strings.TrimSpace(split[0]))
+ value := strings.TrimSpace(split[1])
+ switch outerKey {
+ case "USER":
+ // Assume literal contents are the user.
+ if value == "" {
+ return nil, errors.Errorf("invalid change %q - must provide a value to USER", change)
+ }
+ config.User = value
+ case "EXPOSE":
+ // EXPOSE is either [portnum] or
+ // [portnum]/[proto]
+ // Protocol must be "tcp" or "udp"
+ splitPort := strings.Split(value, "/")
+ if len(splitPort) > 2 {
+ return nil, errors.Errorf("invalid change %q - EXPOSE port must be formatted as PORT[/PROTO]", change)
+ }
+ portNum, err := strconv.Atoi(splitPort[0])
+ if err != nil {
+ return nil, errors.Wrapf(err, "invalid change %q - EXPOSE port must be an integer", change)
+ }
+ if portNum > 65535 || portNum <= 0 {
+ return nil, errors.Errorf("invalid change %q - EXPOSE port must be a valid port number", change)
+ }
+ proto := "tcp"
+ if len(splitPort) > 1 {
+ testProto := strings.ToLower(splitPort[1])
+ switch testProto {
+ case "tcp", "udp":
+ proto = testProto
+ default:
+ return nil, errors.Errorf("invalid change %q - EXPOSE protocol must be TCP or UDP", change)
+ }
+ }
+ if config.ExposedPorts == nil {
+ config.ExposedPorts = make(map[string]struct{})
+ }
+ config.ExposedPorts[fmt.Sprintf("%d/%s", portNum, proto)] = struct{}{}
+ case "ENV":
+ // Format is either:
+ // ENV key=value
+ // ENV key=value key=value ...
+ // ENV key value
+ // Both keys and values can be surrounded by quotes to group them.
+ // For now: we only support key=value
+ // We will attempt to strip quotation marks if present.
+
+ var (
+ key, val string
+ )
+
+ splitEnv := strings.SplitN(value, "=", 2)
+ key = splitEnv[0]
+ // We do need a key
+ if key == "" {
+ return nil, errors.Errorf("invalid change %q - ENV must have at least one argument", change)
+ }
+ // Perfectly valid to not have a value
+ if len(splitEnv) == 2 {
+ val = splitEnv[1]
+ }
+
+ if strings.HasPrefix(key, `"`) && strings.HasSuffix(key, `"`) {
+ key = strings.TrimPrefix(strings.TrimSuffix(key, `"`), `"`)
+ }
+ if strings.HasPrefix(val, `"`) && strings.HasSuffix(val, `"`) {
+ val = strings.TrimPrefix(strings.TrimSuffix(val, `"`), `"`)
+ }
+ config.Env = append(config.Env, fmt.Sprintf("%s=%s", key, val))
+ case "ENTRYPOINT":
+ // Two valid forms.
+ // First, JSON array.
+ // Second, not a JSON array - we interpret this as an
+ // argument to `sh -c`, unless empty, in which case we
+ // just use a blank entrypoint.
+ testUnmarshal := []string{}
+ if err := json.Unmarshal([]byte(value), &testUnmarshal); err != nil {
+ // It ain't valid JSON, so assume it's an
+ // argument to sh -c if not empty.
+ if value != "" {
+ config.Entrypoint = []string{"/bin/sh", "-c", value}
+ } else {
+ config.Entrypoint = []string{}
+ }
+ } else {
+ // Valid JSON
+ config.Entrypoint = testUnmarshal
+ }
+ case "CMD":
+ // Same valid forms as entrypoint.
+ // However, where ENTRYPOINT assumes that 'ENTRYPOINT '
+ // means no entrypoint, CMD assumes it is 'sh -c' with
+ // no third argument.
+ testUnmarshal := []string{}
+ if err := json.Unmarshal([]byte(value), &testUnmarshal); err != nil {
+ // It ain't valid JSON, so assume it's an
+ // argument to sh -c.
+ // Only include volume if it's not ""
+ config.Cmd = []string{"/bin/sh", "-c"}
+ if value != "" {
+ config.Cmd = append(config.Cmd, value)
+ }
+ } else {
+ // Valid JSON
+ config.Cmd = testUnmarshal
+ }
+ case "VOLUME":
+ // Either a JSON array or a set of space-separated
+ // paths.
+ // Acts rather similar to ENTRYPOINT and CMD, but always
+ // appends rather than replacing, and no sh -c prepend.
+ testUnmarshal := []string{}
+ if err := json.Unmarshal([]byte(value), &testUnmarshal); err != nil {
+ // Not valid JSON, so split on spaces
+ testUnmarshal = strings.Split(value, " ")
+ }
+ if len(testUnmarshal) == 0 {
+ return nil, errors.Errorf("invalid change %q - must provide at least one argument to VOLUME", change)
+ }
+ for _, vol := range testUnmarshal {
+ if vol == "" {
+ return nil, errors.Errorf("invalid change %q - VOLUME paths must not be empty", change)
+ }
+ if config.Volumes == nil {
+ config.Volumes = make(map[string]struct{})
+ }
+ config.Volumes[vol] = struct{}{}
+ }
+ case "WORKDIR":
+ // This can be passed multiple times.
+ // Each successive invocation is treated as relative to
+ // the previous one - so WORKDIR /A, WORKDIR b,
+ // WORKDIR c results in /A/b/c
+ // Just need to check it's not empty...
+ if value == "" {
+ return nil, errors.Errorf("invalid change %q - must provide a non-empty WORKDIR", change)
+ }
+ config.WorkingDir = filepath.Join(config.WorkingDir, value)
+ case "LABEL":
+ // Same general idea as ENV, but we no longer allow " "
+ // as a separator.
+ // We didn't do that for ENV either, so nice and easy.
+ // Potentially problematic: LABEL might theoretically
+ // allow an = in the key? If people really do this, we
+ // may need to investigate more advanced parsing.
+ var (
+ key, val string
+ )
+
+ splitLabel := strings.SplitN(value, "=", 2)
+ // Unlike ENV, LABEL must have a value
+ if len(splitLabel) != 2 {
+ return nil, errors.Errorf("invalid change %q - LABEL must be formatted key=value", change)
+ }
+ key = splitLabel[0]
+ val = splitLabel[1]
+
+ if strings.HasPrefix(key, `"`) && strings.HasSuffix(key, `"`) {
+ key = strings.TrimPrefix(strings.TrimSuffix(key, `"`), `"`)
+ }
+ if strings.HasPrefix(val, `"`) && strings.HasSuffix(val, `"`) {
+ val = strings.TrimPrefix(strings.TrimSuffix(val, `"`), `"`)
+ }
+ // Check key after we strip quotations
+ if key == "" {
+ return nil, errors.Errorf("invalid change %q - LABEL must have a non-empty key", change)
+ }
+ if config.Labels == nil {
+ config.Labels = make(map[string]string)
+ }
+ config.Labels[key] = val
+ case "STOPSIGNAL":
+ // Check the provided signal for validity.
+ killSignal, err := signal.ParseSignal(value)
+ if err != nil {
+ return nil, errors.Wrapf(err, "invalid change %q - KILLSIGNAL must be given a valid signal", change)
+ }
+ config.StopSignal = fmt.Sprintf("%d", killSignal)
+ case "ONBUILD":
+ // Onbuild always appends.
+ if value == "" {
+ return nil, errors.Errorf("invalid change %q - ONBUILD must be given an argument", change)
+ }
+ config.OnBuild = append(config.OnBuild, value)
+ default:
+ return nil, errors.Errorf("invalid change %q - invalid instruction %s", change, outerKey)
+ }
+ }
+
+ return config, nil
+}
diff --git a/vendor/github.com/containers/common/libimage/image_tree.go b/vendor/github.com/containers/common/libimage/image_tree.go
new file mode 100644
index 000000000..6583a7007
--- /dev/null
+++ b/vendor/github.com/containers/common/libimage/image_tree.go
@@ -0,0 +1,96 @@
+package libimage
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/disiqueira/gotree/v3"
+ "github.com/docker/go-units"
+)
+
+// Tree generates a tree for the specified image and its layers. Use
+// `traverseChildren` to traverse the layers of all children. By default, only
+// layers of the image are printed.
+func (i *Image) Tree(traverseChildren bool) (string, error) {
+ // NOTE: a string builder prevents us from copying to much data around
+ // and compile the string when and where needed.
+ sb := &strings.Builder{}
+
+ // First print the pretty header for the target image.
+ size, err := i.Size()
+ if err != nil {
+ return "", err
+ }
+ repoTags, err := i.RepoTags()
+ if err != nil {
+ return "", err
+ }
+
+ fmt.Fprintf(sb, "Image ID: %s\n", i.ID()[:12])
+ fmt.Fprintf(sb, "Tags: %s\n", repoTags)
+ fmt.Fprintf(sb, "Size: %v\n", units.HumanSizeWithPrecision(float64(size), 4))
+ if i.TopLayer() != "" {
+ fmt.Fprintf(sb, "Image Layers")
+ } else {
+ fmt.Fprintf(sb, "No Image Layers")
+ }
+
+ tree := gotree.New(sb.String())
+
+ layerTree, err := i.runtime.layerTree()
+ if err != nil {
+ return "", err
+ }
+
+ imageNode := layerTree.node(i.TopLayer())
+
+ // Traverse the entire tree down to all children.
+ if traverseChildren {
+ if err := imageTreeTraverseChildren(imageNode, tree); err != nil {
+ return "", err
+ }
+ } else {
+ // Walk all layers of the image and assemlbe their data.
+ for parentNode := imageNode; parentNode != nil; parentNode = parentNode.parent {
+ if parentNode.layer == nil {
+ break // we're done
+ }
+ var tags string
+ repoTags, err := parentNode.repoTags()
+ if err != nil {
+ return "", err
+ }
+ if len(repoTags) > 0 {
+ tags = fmt.Sprintf(" Top Layer of: %s", repoTags)
+ }
+ tree.Add(fmt.Sprintf("ID: %s Size: %7v%s", parentNode.layer.ID[:12], units.HumanSizeWithPrecision(float64(parentNode.layer.UncompressedSize), 4), tags))
+ }
+ }
+
+ return tree.Print(), nil
+}
+
+func imageTreeTraverseChildren(node *layerNode, parent gotree.Tree) error {
+ var tags string
+ repoTags, err := node.repoTags()
+ if err != nil {
+ return err
+ }
+ if len(repoTags) > 0 {
+ tags = fmt.Sprintf(" Top Layer of: %s", repoTags)
+ }
+
+ newNode := parent.Add(fmt.Sprintf("ID: %s Size: %7v%s", node.layer.ID[:12], units.HumanSizeWithPrecision(float64(node.layer.UncompressedSize), 4), tags))
+
+ if len(node.children) <= 1 {
+ newNode = parent
+ }
+ for i := range node.children {
+ child := node.children[i]
+ if err := imageTreeTraverseChildren(child, newNode); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/containers/common/libimage/import.go b/vendor/github.com/containers/common/libimage/import.go
new file mode 100644
index 000000000..4cce4c9ca
--- /dev/null
+++ b/vendor/github.com/containers/common/libimage/import.go
@@ -0,0 +1,108 @@
+package libimage
+
+import (
+ "context"
+ "net/url"
+ "os"
+
+ storageTransport "github.com/containers/image/v5/storage"
+ tarballTransport "github.com/containers/image/v5/tarball"
+ v1 "github.com/opencontainers/image-spec/specs-go/v1"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+)
+
+// ImportOptions allow for customizing image imports.
+type ImportOptions struct {
+ CopyOptions
+
+ // Apply the specified changes to the created image. Please refer to
+ // `ImageConfigFromChanges` for supported change instructions.
+ Changes []string
+ // Set the commit message as a comment to created image's history.
+ CommitMessage string
+ // Tag the imported image with this value.
+ Tag string
+}
+
+// Import imports a custom tarball at the specified path. Returns the name of
+// the imported image.
+func (r *Runtime) Import(ctx context.Context, path string, options *ImportOptions) (string, error) {
+ logrus.Debugf("Importing image from %q", path)
+
+ if options == nil {
+ options = &ImportOptions{}
+ }
+
+ ic := v1.ImageConfig{}
+ if len(options.Changes) > 0 {
+ config, err := ImageConfigFromChanges(options.Changes)
+ if err != nil {
+ return "", err
+ }
+ ic = config.ImageConfig
+ }
+
+ hist := []v1.History{
+ {Comment: options.CommitMessage},
+ }
+
+ config := v1.Image{
+ Config: ic,
+ History: hist,
+ }
+
+ u, err := url.ParseRequestURI(path)
+ if err == nil && u.Scheme != "" {
+ // If source is a URL, download the file.
+ file, err := r.downloadFromURL(path)
+ if err != nil {
+ return "", err
+ }
+ defer os.Remove(file)
+ path = file
+ } else if path == "-" {
+ // "-" special cases stdin
+ path = os.Stdin.Name()
+ }
+
+ srcRef, err := tarballTransport.Transport.ParseReference(path)
+ if err != nil {
+ return "", err
+ }
+
+ updater, ok := srcRef.(tarballTransport.ConfigUpdater)
+ if !ok {
+ return "", errors.New("unexpected type, a tarball reference should implement tarball.ConfigUpdater")
+ }
+ annotations := make(map[string]string)
+ if err := updater.ConfigUpdate(config, annotations); err != nil {
+ return "", err
+ }
+
+ name := options.Tag
+ if name == "" {
+ name, err = getImageDigest(ctx, srcRef, r.systemContextCopy())
+ if err != nil {
+ return "", err
+ }
+ name = "sha256:" + name[1:] // strip leading "@"
+ }
+
+ destRef, err := storageTransport.Transport.ParseStoreReference(r.store, name)
+ if err != nil {
+ return "", err
+ }
+
+ c, err := r.newCopier(&options.CopyOptions)
+ if err != nil {
+ return "", err
+ }
+ defer c.close()
+
+ if _, err := c.copy(ctx, srcRef, destRef); err != nil {
+ return "", err
+ }
+
+ return name, nil
+}
diff --git a/vendor/github.com/containers/common/libimage/inspect.go b/vendor/github.com/containers/common/libimage/inspect.go
new file mode 100644
index 000000000..349709155
--- /dev/null
+++ b/vendor/github.com/containers/common/libimage/inspect.go
@@ -0,0 +1,206 @@
+package libimage
+
+import (
+ "context"
+ "encoding/json"
+ "time"
+
+ "github.com/containers/image/v5/manifest"
+ "github.com/containers/image/v5/types"
+ "github.com/opencontainers/go-digest"
+ ociv1 "github.com/opencontainers/image-spec/specs-go/v1"
+ "github.com/sirupsen/logrus"
+)
+
+// ImageData contains the inspected data of an image.
+type ImageData struct {
+ ID string `json:"Id"`
+ Digest digest.Digest `json:"Digest"`
+ RepoTags []string `json:"RepoTags"`
+ RepoDigests []string `json:"RepoDigests"`
+ Parent string `json:"Parent"`
+ Comment string `json:"Comment"`
+ Created *time.Time `json:"Created"`
+ Config *ociv1.ImageConfig `json:"Config"`
+ Version string `json:"Version"`
+ Author string `json:"Author"`
+ Architecture string `json:"Architecture"`
+ Os string `json:"Os"`
+ Size int64 `json:"Size"`
+ VirtualSize int64 `json:"VirtualSize"`
+ GraphDriver *DriverData `json:"GraphDriver"`
+ RootFS *RootFS `json:"RootFS"`
+ Labels map[string]string `json:"Labels"`
+ Annotations map[string]string `json:"Annotations"`
+ ManifestType string `json:"ManifestType"`
+ User string `json:"User"`
+ History []ociv1.History `json:"History"`
+ NamesHistory []string `json:"NamesHistory"`
+ HealthCheck *manifest.Schema2HealthConfig `json:"Healthcheck,omitempty"`
+}
+
+// DriverData includes data on the storage driver of the image.
+type DriverData struct {
+ Name string `json:"Name"`
+ Data map[string]string `json:"Data"`
+}
+
+// RootFS includes data on the root filesystem of the image.
+type RootFS struct {
+ Type string `json:"Type"`
+ Layers []digest.Digest `json:"Layers"`
+}
+
+// Inspect inspects the image. Use `withSize` to also perform the
+// comparatively expensive size computation of the image.
+func (i *Image) Inspect(ctx context.Context, withSize bool) (*ImageData, error) {
+ logrus.Debugf("Inspecting image %s", i.ID())
+
+ if i.cached.completeInspectData != nil {
+ if withSize && i.cached.completeInspectData.Size == int64(-1) {
+ size, err := i.Size()
+ if err != nil {
+ return nil, err
+ }
+ i.cached.completeInspectData.Size = size
+ }
+ return i.cached.completeInspectData, nil
+ }
+
+ // First assemble data that does not depend on the format of the image.
+ info, err := i.inspectInfo(ctx)
+ if err != nil {
+ return nil, err
+ }
+ ociImage, err := i.toOCI(ctx)
+ if err != nil {
+ return nil, err
+ }
+ parentImage, err := i.Parent(ctx)
+ if err != nil {
+ return nil, err
+ }
+ repoTags, err := i.RepoTags()
+ if err != nil {
+ return nil, err
+ }
+ repoDigests, err := i.RepoDigests()
+ if err != nil {
+ return nil, err
+ }
+ driverData, err := i.driverData()
+ if err != nil {
+ return nil, err
+ }
+
+ size := int64(-1)
+ if withSize {
+ size, err = i.Size()
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ data := &ImageData{
+ ID: i.ID(),
+ RepoTags: repoTags,
+ RepoDigests: repoDigests,
+ Created: ociImage.Created,
+ Author: ociImage.Author,
+ Architecture: ociImage.Architecture,
+ Os: ociImage.OS,
+ Config: &ociImage.Config,
+ Version: info.DockerVersion,
+ Size: size,
+ VirtualSize: size, // TODO: they should be different (inherited from Podman)
+ Digest: i.Digest(),
+ Labels: info.Labels,
+ RootFS: &RootFS{
+ Type: ociImage.RootFS.Type,
+ Layers: ociImage.RootFS.DiffIDs,
+ },
+ GraphDriver: driverData,
+ User: ociImage.Config.User,
+ History: ociImage.History,
+ NamesHistory: i.NamesHistory(),
+ }
+
+ if parentImage != nil {
+ data.Parent = parentImage.ID()
+ }
+
+ // Determine the format of the image. How we determine certain data
+ // depends on the format (e.g., Docker v2s2, OCI v1).
+ src, err := i.source(ctx)
+ if err != nil {
+ return nil, err
+ }
+ manifestRaw, manifestType, err := src.GetManifest(ctx, nil)
+ if err != nil {
+ return nil, err
+ }
+
+ data.ManifestType = manifestType
+
+ switch manifestType {
+ // OCI image
+ case ociv1.MediaTypeImageManifest:
+ var ociManifest ociv1.Manifest
+ if err := json.Unmarshal(manifestRaw, &ociManifest); err != nil {
+ return nil, err
+ }
+ data.Annotations = ociManifest.Annotations
+ if len(ociImage.History) > 0 {
+ data.Comment = ociImage.History[0].Comment
+ }
+
+ // Docker image
+ case manifest.DockerV2Schema1MediaType, manifest.DockerV2Schema2MediaType:
+ rawConfig, err := i.rawConfigBlob(ctx)
+ if err != nil {
+ return nil, err
+ }
+ var dockerManifest manifest.Schema2V1Image
+ if err := json.Unmarshal(rawConfig, &dockerManifest); err != nil {
+ return nil, err
+ }
+ data.Comment = dockerManifest.Comment
+ data.HealthCheck = dockerManifest.ContainerConfig.Healthcheck
+ }
+
+ if data.Annotations == nil {
+ // Podman compat
+ data.Annotations = make(map[string]string)
+ }
+
+ i.cached.completeInspectData = data
+
+ return data, nil
+}
+
+// inspectInfo returns the image inspect info.
+func (i *Image) inspectInfo(ctx context.Context) (*types.ImageInspectInfo, error) {
+ if i.cached.partialInspectData != nil {
+ return i.cached.partialInspectData, nil
+ }
+
+ ref, err := i.StorageReference()
+ if err != nil {
+
+ return nil, err
+ }
+
+ img, err := ref.NewImage(ctx, i.runtime.systemContextCopy())
+ if err != nil {
+ return nil, err
+ }
+ defer img.Close()
+
+ data, err := img.Inspect(ctx)
+ if err != nil {
+ return nil, err
+ }
+
+ i.cached.partialInspectData = data
+ return data, nil
+}
diff --git a/vendor/github.com/containers/common/libimage/layer_tree.go b/vendor/github.com/containers/common/libimage/layer_tree.go
new file mode 100644
index 000000000..7e0940339
--- /dev/null
+++ b/vendor/github.com/containers/common/libimage/layer_tree.go
@@ -0,0 +1,249 @@
+package libimage
+
+import (
+ "context"
+
+ "github.com/containers/storage"
+ ociv1 "github.com/opencontainers/image-spec/specs-go/v1"
+ "github.com/sirupsen/logrus"
+)
+
+// layerTree is an internal representation of local layers.
+type layerTree struct {
+ // nodes is the actual layer tree with layer IDs being keys.
+ nodes map[string]*layerNode
+ // ociCache is a cache for Image.ID -> OCI Image. Translations are done
+ // on-demand.
+ ociCache map[string]*ociv1.Image
+}
+
+// node returns a layerNode for the specified layerID.
+func (t *layerTree) node(layerID string) *layerNode {
+ node, exists := t.nodes[layerID]
+ if !exists {
+ node = &layerNode{}
+ t.nodes[layerID] = node
+ }
+ return node
+}
+
+// toOCI returns an OCI image for the specified image.
+func (t *layerTree) toOCI(ctx context.Context, i *Image) (*ociv1.Image, error) {
+ var err error
+ oci, exists := t.ociCache[i.ID()]
+ if !exists {
+ oci, err = i.toOCI(ctx)
+ if err == nil {
+ t.ociCache[i.ID()] = oci
+ }
+ }
+ return oci, err
+}
+
+// layerNode is a node in a layerTree. It's ID is the key in a layerTree.
+type layerNode struct {
+ children []*layerNode
+ images []*Image
+ parent *layerNode
+ layer *storage.Layer
+}
+
+// repoTags assemble all repo tags all of images of the layer node.
+func (l *layerNode) repoTags() ([]string, error) {
+ orderedTags := []string{}
+ visitedTags := make(map[string]bool)
+
+ for _, image := range l.images {
+ repoTags, err := image.RepoTags()
+ if err != nil {
+ return nil, err
+ }
+ for _, tag := range repoTags {
+ if _, visted := visitedTags[tag]; visted {
+ continue
+ }
+ visitedTags[tag] = true
+ orderedTags = append(orderedTags, tag)
+ }
+ }
+
+ return orderedTags, nil
+}
+
+// layerTree extracts a layerTree from the layers in the local storage and
+// relates them to the specified images.
+func (r *Runtime) layerTree() (*layerTree, error) {
+ layers, err := r.store.Layers()
+ if err != nil {
+ return nil, err
+ }
+
+ images, err := r.ListImages(context.Background(), nil, nil)
+ if err != nil {
+ return nil, err
+ }
+
+ tree := layerTree{
+ nodes: make(map[string]*layerNode),
+ ociCache: make(map[string]*ociv1.Image),
+ }
+
+ // First build a tree purely based on layer information.
+ for i := range layers {
+ node := tree.node(layers[i].ID)
+ node.layer = &layers[i]
+ if layers[i].Parent == "" {
+ continue
+ }
+ parent := tree.node(layers[i].Parent)
+ node.parent = parent
+ parent.children = append(parent.children, node)
+ }
+
+ // Now assign the images to each (top) layer.
+ for i := range images {
+ img := images[i] // do not leak loop variable outside the scope
+ topLayer := img.TopLayer()
+ if topLayer == "" {
+ continue
+ }
+ node, exists := tree.nodes[topLayer]
+ if !exists {
+ // Note: erroring out in this case has turned out having been a
+ // mistake. Users may not be able to recover, so we're now
+ // throwing a warning to guide them to resolve the issue and
+ // turn the errors non-fatal.
+ logrus.Warnf("Top layer %s of image %s not found in layer tree. The storage may be corrupted, consider running `podman system reset`.", topLayer, img.ID())
+ continue
+ }
+ node.images = append(node.images, img)
+ }
+
+ return &tree, nil
+}
+
+// children returns the child images of parent. Child images are images with
+// either the same top layer as parent or parent being the true parent layer.
+// Furthermore, the history of the parent and child images must match with the
+// parent having one history item less. If all is true, all images are
+// returned. Otherwise, the first image is returned.
+func (t *layerTree) children(ctx context.Context, parent *Image, all bool) ([]*Image, error) {
+ if parent.TopLayer() == "" {
+ return nil, nil
+ }
+
+ var children []*Image
+
+ parentNode, exists := t.nodes[parent.TopLayer()]
+ if !exists {
+ // Note: erroring out in this case has turned out having been a
+ // mistake. Users may not be able to recover, so we're now
+ // throwing a warning to guide them to resolve the issue and
+ // turn the errors non-fatal.
+ logrus.Warnf("Layer %s not found in layer tree. The storage may be corrupted, consider running `podman system reset`.", parent.TopLayer())
+ return children, nil
+ }
+
+ parentID := parent.ID()
+ parentOCI, err := t.toOCI(ctx, parent)
+ if err != nil {
+ return nil, err
+ }
+
+ // checkParent returns true if child and parent are in such a relation.
+ checkParent := func(child *Image) (bool, error) {
+ if parentID == child.ID() {
+ return false, nil
+ }
+ childOCI, err := t.toOCI(ctx, child)
+ if err != nil {
+ return false, err
+ }
+ // History check.
+ return areParentAndChild(parentOCI, childOCI), nil
+ }
+
+ // addChildrenFrom adds child images of parent to children. Returns
+ // true if any image is a child of parent.
+ addChildrenFromNode := func(node *layerNode) (bool, error) {
+ foundChildren := false
+ for i, childImage := range node.images {
+ isChild, err := checkParent(childImage)
+ if err != nil {
+ return foundChildren, err
+ }
+ if isChild {
+ foundChildren = true
+ children = append(children, node.images[i])
+ if all {
+ return foundChildren, nil
+ }
+ }
+ }
+ return foundChildren, nil
+ }
+
+ // First check images where parent's top layer is also the parent
+ // layer.
+ for _, childNode := range parentNode.children {
+ found, err := addChildrenFromNode(childNode)
+ if err != nil {
+ return nil, err
+ }
+ if found && all {
+ return children, nil
+ }
+ }
+
+ // Now check images with the same top layer.
+ if _, err := addChildrenFromNode(parentNode); err != nil {
+ return nil, err
+ }
+
+ return children, nil
+}
+
+// parent returns the parent image or nil if no parent image could be found.
+func (t *layerTree) parent(ctx context.Context, child *Image) (*Image, error) {
+ if child.TopLayer() == "" {
+ return nil, nil
+ }
+
+ node, exists := t.nodes[child.TopLayer()]
+ if !exists {
+ // Note: erroring out in this case has turned out having been a
+ // mistake. Users may not be able to recover, so we're now
+ // throwing a warning to guide them to resolve the issue and
+ // turn the errors non-fatal.
+ logrus.Warnf("Layer %s not found in layer tree. The storage may be corrupted, consider running `podman system reset`.", child.TopLayer())
+ return nil, nil
+ }
+
+ childOCI, err := t.toOCI(ctx, child)
+ if err != nil {
+ return nil, err
+ }
+
+ // Check images from the parent node (i.e., parent layer) and images
+ // with the same layer (i.e., same top layer).
+ childID := child.ID()
+ images := node.images
+ if node.parent != nil {
+ images = append(images, node.parent.images...)
+ }
+ for _, parent := range images {
+ if parent.ID() == childID {
+ continue
+ }
+ parentOCI, err := t.toOCI(ctx, parent)
+ if err != nil {
+ return nil, err
+ }
+ // History check.
+ if areParentAndChild(parentOCI, childOCI) {
+ return parent, nil
+ }
+ }
+
+ return nil, nil
+}
diff --git a/vendor/github.com/containers/common/libimage/load.go b/vendor/github.com/containers/common/libimage/load.go
new file mode 100644
index 000000000..c606aca5b
--- /dev/null
+++ b/vendor/github.com/containers/common/libimage/load.go
@@ -0,0 +1,125 @@
+package libimage
+
+import (
+ "context"
+ "errors"
+ "os"
+
+ dirTransport "github.com/containers/image/v5/directory"
+ dockerArchiveTransport "github.com/containers/image/v5/docker/archive"
+ ociArchiveTransport "github.com/containers/image/v5/oci/archive"
+ ociTransport "github.com/containers/image/v5/oci/layout"
+ "github.com/containers/image/v5/types"
+ "github.com/sirupsen/logrus"
+)
+
+type LoadOptions struct {
+ CopyOptions
+}
+
+// Load loads one or more images (depending on the transport) from the
+// specified path. The path may point to an image the following transports:
+// oci, oci-archive, dir, docker-archive.
+func (r *Runtime) Load(ctx context.Context, path string, options *LoadOptions) ([]string, error) {
+ logrus.Debugf("Loading image from %q", path)
+
+ var (
+ loadedImages []string
+ loadError error
+ )
+
+ if options == nil {
+ options = &LoadOptions{}
+ }
+
+ for _, f := range []func() ([]string, error){
+ // OCI
+ func() ([]string, error) {
+ logrus.Debugf("-> Attempting to load %q as an OCI directory", path)
+ ref, err := ociTransport.NewReference(path, "")
+ if err != nil {
+ return nil, err
+ }
+ return r.copyFromDefault(ctx, ref, &options.CopyOptions)
+ },
+
+ // OCI-ARCHIVE
+ func() ([]string, error) {
+ logrus.Debugf("-> Attempting to load %q as an OCI archive", path)
+ ref, err := ociArchiveTransport.NewReference(path, "")
+ if err != nil {
+ return nil, err
+ }
+ return r.copyFromDefault(ctx, ref, &options.CopyOptions)
+ },
+
+ // DIR
+ func() ([]string, error) {
+ logrus.Debugf("-> Attempting to load %q as a Docker dir", path)
+ ref, err := dirTransport.NewReference(path)
+ if err != nil {
+ return nil, err
+ }
+ return r.copyFromDefault(ctx, ref, &options.CopyOptions)
+ },
+
+ // DOCKER-ARCHIVE
+ func() ([]string, error) {
+ logrus.Debugf("-> Attempting to load %q as a Docker archive", path)
+ ref, err := dockerArchiveTransport.ParseReference(path)
+ if err != nil {
+ return nil, err
+ }
+ return r.loadMultiImageDockerArchive(ctx, ref, &options.CopyOptions)
+ },
+
+ // Give a decent error message if nothing above worked.
+ func() ([]string, error) {
+ return nil, errors.New("payload does not match any of the supported image formats (oci, oci-archive, dir, docker-archive)")
+ },
+ } {
+ loadedImages, loadError = f()
+ if loadError == nil {
+ return loadedImages, loadError
+ }
+ logrus.Debugf("Error loading %s: %v", path, loadError)
+ }
+
+ return nil, loadError
+}
+
+// loadMultiImageDockerArchive loads the docker archive specified by ref. In
+// case the path@reference notation was used, only the specifiec image will be
+// loaded. Otherwise, all images will be loaded.
+func (r *Runtime) loadMultiImageDockerArchive(ctx context.Context, ref types.ImageReference, options *CopyOptions) ([]string, error) {
+ // If we cannot stat the path, it either does not exist OR the correct
+ // syntax to reference an image within the archive was used, so we
+ // should.
+ path := ref.StringWithinTransport()
+ if _, err := os.Stat(path); err != nil {
+ return r.copyFromDockerArchive(ctx, ref, options)
+ }
+
+ reader, err := dockerArchiveTransport.NewReader(r.systemContextCopy(), path)
+ if err != nil {
+ return nil, err
+ }
+
+ refLists, err := reader.List()
+ if err != nil {
+ return nil, err
+ }
+
+ var copiedImages []string
+ for _, list := range refLists {
+ for _, listRef := range list {
+ names, err := r.copyFromDockerArchiveReaderReference(ctx, reader, listRef, options)
+ if err != nil {
+ return nil, err
+ }
+ copiedImages = append(copiedImages, names...)
+ }
+ }
+
+ return copiedImages, nil
+}
diff --git a/vendor/github.com/containers/common/libimage/manifest_list.go b/vendor/github.com/containers/common/libimage/manifest_list.go
new file mode 100644
index 000000000..72a2cf55f
--- /dev/null
+++ b/vendor/github.com/containers/common/libimage/manifest_list.go
@@ -0,0 +1,389 @@
+package libimage
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/containers/common/libimage/manifests"
+ imageCopy "github.com/containers/image/v5/copy"
+ "github.com/containers/image/v5/docker"
+ "github.com/containers/image/v5/manifest"
+ "github.com/containers/image/v5/transports/alltransports"
+ "github.com/containers/image/v5/types"
+ "github.com/containers/storage"
+ "github.com/opencontainers/go-digest"
+ "github.com/pkg/errors"
+)
+
+// NOTE: the abstractions and APIs here are a first step to further merge
+// `libimage/manifests` into `libimage`.
+
+// ManifestList represents a manifest list (Docker) or an image index (OCI) in
+// the local containers storage.
+type ManifestList struct {
+ // NOTE: the *List* suffix is intentional as the term "manifest" is
+ // used ambiguously across the ecosystem. It may refer to the (JSON)
+ // manifest of an ordinary image OR to a manifest *list* (Docker) or to
+ // image index (OCI).
+ // It's a bit more work when typing but without ambiguity.
+
+ // The underlying image in the containers storage.
+ image *Image
+
+ // The underlying manifest list.
+ list manifests.List
+}
+
+// ID returns the ID of the manifest list.
+func (m *ManifestList) ID() string {
+ return m.image.ID()
+}
+
+// CreateManifestList creates a new empty manifest list with the specified
+// name.
+func (r *Runtime) CreateManifestList(name string) (*ManifestList, error) {
+ normalized, err := NormalizeName(name)
+ if err != nil {
+ return nil, err
+ }
+
+ list := manifests.Create()
+ listID, err := list.SaveToImage(r.store, "", []string{normalized.String()}, manifest.DockerV2ListMediaType)
+ if err != nil {
+ return nil, err
+ }
+
+ mList, err := r.LookupManifestList(listID)
+ if err != nil {
+ return nil, err
+ }
+
+ return mList, nil
+}
+
+// LookupManifestList looks up a manifest list with the specified name in the
+// containers storage.
+func (r *Runtime) LookupManifestList(name string) (*ManifestList, error) {
+ image, list, err := r.lookupManifestList(name)
+ if err != nil {
+ return nil, err
+ }
+ return &ManifestList{image: image, list: list}, nil
+}
+
+func (r *Runtime) lookupManifestList(name string) (*Image, manifests.List, error) {
+ image, _, err := r.LookupImage(name, &LookupImageOptions{IgnorePlatform: true})
+ if err != nil {
+ return nil, nil, err
+ }
+ if err := image.reload(); err != nil {
+ return nil, nil, err
+ }
+ list, err := image.getManifestList()
+ if err != nil {
+ return nil, nil, err
+ }
+ return image, list, nil
+}
+
+// ToManifestList converts the image into a manifest list. An error is thrown
+// if the image is no manifest list.
+func (i *Image) ToManifestList() (*ManifestList, error) {
+ list, err := i.getManifestList()
+ if err != nil {
+ return nil, err
+ }
+ return &ManifestList{image: i, list: list}, nil
+}
+
+// LookupInstance looks up an instance of the manifest list matching the
+// specified platform. The local machine's platform is used if left empty.
+func (m *ManifestList) LookupInstance(ctx context.Context, architecture, os, variant string) (*Image, error) {
+ sys := m.image.runtime.systemContextCopy()
+ if architecture != "" {
+ sys.ArchitectureChoice = architecture
+ }
+ if os != "" {
+ sys.OSChoice = os
+ }
+ if architecture != "" {
+ sys.VariantChoice = variant
+ }
+
+ // Now look at the *manifest* and select a matching instance.
+ rawManifest, manifestType, err := m.image.Manifest(ctx)
+ if err != nil {
+ return nil, err
+ }
+ list, err := manifest.ListFromBlob(rawManifest, manifestType)
+ if err != nil {
+ return nil, err
+ }
+ instanceDigest, err := list.ChooseInstance(sys)
+ if err != nil {
+ return nil, err
+ }
+
+ allImages, err := m.image.runtime.ListImages(ctx, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+
+ for _, image := range allImages {
+ for _, imageDigest := range append(image.Digests(), image.Digest()) {
+ if imageDigest == instanceDigest {
+ return image, nil
+ }
+ }
+ }
+
+ return nil, errors.Wrapf(storage.ErrImageUnknown, "could not find image instance %s of manifest list %s in local containers storage", instanceDigest, m.ID())
+}
+
+// Saves the specified manifest list and reloads it from storage with the new ID.
+func (m *ManifestList) saveAndReload() error {
+ newID, err := m.list.SaveToImage(m.image.runtime.store, m.image.ID(), nil, "")
+ if err != nil {
+ return err
+ }
+
+ // Make sure to reload the image from the containers storage to fetch
+ // the latest data (e.g., new or delete digests).
+ if err := m.image.reload(); err != nil {
+ return err
+ }
+ image, list, err := m.image.runtime.lookupManifestList(newID)
+ if err != nil {
+ return err
+ }
+ m.image = image
+ m.list = list
+ return nil
+}
+
+// getManifestList is a helper to obtain a manifest list
+func (i *Image) getManifestList() (manifests.List, error) {
+ _, list, err := manifests.LoadFromImage(i.runtime.store, i.ID())
+ return list, err
+}
+
+// IsManifestList returns true if the image is a manifest list (Docker) or an
+// image index (OCI). This information may be critical to make certain
+// execution paths more robust (e.g., suppress certain errors).
+func (i *Image) IsManifestList(ctx context.Context) (bool, error) {
+ ref, err := i.StorageReference()
+ if err != nil {
+ return false, err
+ }
+ imgRef, err := ref.NewImageSource(ctx, i.runtime.systemContextCopy())
+ if err != nil {
+ return false, err
+ }
+ _, manifestType, err := imgRef.GetManifest(ctx, nil)
+ if err != nil {
+ return false, err
+ }
+ return manifest.MIMETypeIsMultiImage(manifestType), nil
+}
+
+// Inspect returns a dockerized version of the manifest list.
+func (m *ManifestList) Inspect() (*manifest.Schema2List, error) {
+ return m.list.Docker(), nil
+}
+
+// Options for adding a manifest list.
+type ManifestListAddOptions struct {
+ // Add all images to the list if the to-be-added image itself is a
+ // manifest list.
+ All bool `json:"all"`
+ // containers-auth.json(5) file to use when authenticating against
+ // container registries.
+ AuthFilePath string
+ // Path to the certificates directory.
+ CertDirPath string
+ // Allow contacting registries over HTTP, or HTTPS with failed TLS
+ // verification. Note that this does not affect other TLS connections.
+ InsecureSkipTLSVerify types.OptionalBool
+ // Username to use when authenticating at a container registry.
+ Username string
+ // Password to use when authenticating at a container registry.
+ Password string
+}
+
+// Add adds one or more manifests to the manifest list and returns the digest
+// of the added instance.
+func (m *ManifestList) Add(ctx context.Context, name string, options *ManifestListAddOptions) (digest.Digest, error) {
+ if options == nil {
+ options = &ManifestListAddOptions{}
+ }
+
+ ref, err := alltransports.ParseImageName(name)
+ if err != nil {
+ withDocker := fmt.Sprintf("%s://%s", docker.Transport.Name(), name)
+ ref, err = alltransports.ParseImageName(withDocker)
+ if err != nil {
+ return "", err
+ }
+ }
+
+ // Now massage in the copy-related options into the system context.
+ systemContext := m.image.runtime.systemContextCopy()
+ if options.AuthFilePath != "" {
+ systemContext.AuthFilePath = options.AuthFilePath
+ }
+ if options.CertDirPath != "" {
+ systemContext.DockerCertPath = options.CertDirPath
+ }
+ if options.InsecureSkipTLSVerify != types.OptionalBoolUndefined {
+ systemContext.DockerInsecureSkipTLSVerify = options.InsecureSkipTLSVerify
+ systemContext.OCIInsecureSkipTLSVerify = options.InsecureSkipTLSVerify == types.OptionalBoolTrue
+ systemContext.DockerDaemonInsecureSkipTLSVerify = options.InsecureSkipTLSVerify == types.OptionalBoolTrue
+ }
+ if options.Username != "" {
+ systemContext.DockerAuthConfig = &types.DockerAuthConfig{
+ Username: options.Username,
+ Password: options.Password,
+ }
+ }
+
+ newDigest, err := m.list.Add(ctx, systemContext, ref, options.All)
+ if err != nil {
+ return "", err
+ }
+
+ // Write the changes to disk.
+ if err := m.saveAndReload(); err != nil {
+ return "", err
+ }
+ return newDigest, nil
+}
+
+// Options for annotationg a manifest list.
+type ManifestListAnnotateOptions struct {
+ // Add the specified annotations to the added image.
+ Annotations map[string]string
+ // Add the specified architecture to the added image.
+ Architecture string
+ // Add the specified features to the added image.
+ Features []string
+ // Add the specified OS to the added image.
+ OS string
+ // Add the specified OS features to the added image.
+ OSFeatures []string
+ // Add the specified OS version to the added image.
+ OSVersion string
+ // Add the specified variant to the added image.
+ Variant string
+}
+
+// Annotate an image instance specified by `d` in the manifest list.
+func (m *ManifestList) AnnotateInstance(d digest.Digest, options *ManifestListAnnotateOptions) error {
+ if options == nil {
+ return nil
+ }
+
+ if len(options.OS) > 0 {
+ if err := m.list.SetOS(d, options.OS); err != nil {
+ return err
+ }
+ }
+ if len(options.OSVersion) > 0 {
+ if err := m.list.SetOSVersion(d, options.OSVersion); err != nil {
+ return err
+ }
+ }
+ if len(options.Features) > 0 {
+ if err := m.list.SetFeatures(d, options.Features); err != nil {
+ return err
+ }
+ }
+ if len(options.OSFeatures) > 0 {
+ if err := m.list.SetOSFeatures(d, options.OSFeatures); err != nil {
+ return err
+ }
+ }
+ if len(options.Architecture) > 0 {
+ if err := m.list.SetArchitecture(d, options.Architecture); err != nil {
+ return err
+ }
+ }
+ if len(options.Variant) > 0 {
+ if err := m.list.SetVariant(d, options.Variant); err != nil {
+ return err
+ }
+ }
+ if len(options.Annotations) > 0 {
+ if err := m.list.SetAnnotations(&d, options.Annotations); err != nil {
+ return err
+ }
+ }
+
+ // Write the changes to disk.
+ if err := m.saveAndReload(); err != nil {
+ return err
+ }
+ return nil
+}
+
+// RemoveInstance removes the instance specified by `d` from the manifest list.
+// Returns the new ID of the image.
+func (m *ManifestList) RemoveInstance(d digest.Digest) error {
+ if err := m.list.Remove(d); err != nil {
+ return err
+ }
+
+ // Write the changes to disk.
+ if err := m.saveAndReload(); err != nil {
+ return err
+ }
+ return nil
+}
+
+// ManifestListPushOptions allow for customizing pushing a manifest list.
+type ManifestListPushOptions struct {
+ CopyOptions
+
+ // For tweaking the list selection.
+ ImageListSelection imageCopy.ImageListSelection
+ // Use when selecting only specific imags.
+ Instances []digest.Digest
+}
+
+// Push pushes a manifest to the specified destination.
+func (m *ManifestList) Push(ctx context.Context, destination string, options *ManifestListPushOptions) (digest.Digest, error) {
+ if options == nil {
+ options = &ManifestListPushOptions{}
+ }
+
+ dest, err := alltransports.ParseImageName(destination)
+ if err != nil {
+ oldErr := err
+ dest, err = alltransports.ParseImageName("docker://" + destination)
+ if err != nil {
+ return "", oldErr
+ }
+ }
+
+ // NOTE: we're using the logic in copier to create a proper
+ // types.SystemContext. This prevents us from having an error prone
+ // code duplicate here.
+ copier, err := m.image.runtime.newCopier(&options.CopyOptions)
+ if err != nil {
+ return "", err
+ }
+ defer copier.close()
+
+ pushOptions := manifests.PushOptions{
+ Store: m.image.runtime.store,
+ SystemContext: copier.systemContext,
+ ImageListSelection: options.ImageListSelection,
+ Instances: options.Instances,
+ ReportWriter: options.Writer,
+ SignBy: options.SignBy,
+ RemoveSignatures: options.RemoveSignatures,
+ ManifestType: options.ManifestMIMEType,
+ }
+
+ _, d, err := m.list.Push(ctx, dest, pushOptions)
+ return d, err
+}
diff --git a/vendor/github.com/containers/buildah/manifests/copy.go b/vendor/github.com/containers/common/libimage/manifests/copy.go
index 7e651a46c..7e651a46c 100644
--- a/vendor/github.com/containers/buildah/manifests/copy.go
+++ b/vendor/github.com/containers/common/libimage/manifests/copy.go
diff --git a/vendor/github.com/containers/buildah/manifests/manifests.go b/vendor/github.com/containers/common/libimage/manifests/manifests.go
index 0fe7e477b..875c2948d 100644
--- a/vendor/github.com/containers/buildah/manifests/manifests.go
+++ b/vendor/github.com/containers/common/libimage/manifests/manifests.go
@@ -6,8 +6,8 @@ import (
stderrors "errors"
"io"
- "github.com/containers/buildah/pkg/manifests"
- "github.com/containers/buildah/pkg/supplemented"
+ "github.com/containers/common/pkg/manifests"
+ "github.com/containers/common/pkg/supplemented"
cp "github.com/containers/image/v5/copy"
"github.com/containers/image/v5/docker/reference"
"github.com/containers/image/v5/image"
diff --git a/vendor/github.com/containers/common/libimage/normalize.go b/vendor/github.com/containers/common/libimage/normalize.go
new file mode 100644
index 000000000..03d2456de
--- /dev/null
+++ b/vendor/github.com/containers/common/libimage/normalize.go
@@ -0,0 +1,92 @@
+package libimage
+
+import (
+ "strings"
+
+ "github.com/containers/image/v5/docker/reference"
+ "github.com/pkg/errors"
+)
+
+// NormalizeName normalizes the provided name according to the conventions by
+// Podman and Buildah. If tag and digest are missing, the "latest" tag will be
+// used. If it's a short name, it will be prefixed with "localhost/".
+//
+// References to docker.io are normalized according to the Docker conventions.
+// For instance, "docker.io/foo" turns into "docker.io/library/foo".
+func NormalizeName(name string) (reference.Named, error) {
+ // NOTE: this code is in symmetrie with containers/image/pkg/shortnames.
+ ref, err := reference.Parse(name)
+ if err != nil {
+ return nil, errors.Wrapf(err, "error normalizing name %q", name)
+ }
+
+ named, ok := ref.(reference.Named)
+ if !ok {
+ return nil, errors.Errorf("%q is not a named reference", name)
+ }
+
+ // Enforce "localhost" if needed.
+ registry := reference.Domain(named)
+ if !(strings.ContainsAny(registry, ".:") || registry == "localhost") {
+ name = toLocalImageName(ref.String())
+ }
+
+ // Another parse which also makes sure that docker.io references are
+ // correctly normalized (e.g., docker.io/alpine to
+ // docker.io/library/alpine).
+ named, err = reference.ParseNormalizedNamed(name)
+ if err != nil {
+ return nil, err
+ }
+
+ if _, hasTag := named.(reference.NamedTagged); hasTag {
+ return named, nil
+ }
+ if _, hasDigest := named.(reference.Digested); hasDigest {
+ return named, nil
+ }
+
+ // Make sure to tag "latest".
+ return reference.TagNameOnly(named), nil
+}
+
+// prefix the specified name with "localhost/".
+func toLocalImageName(name string) string {
+ return "localhost/" + strings.TrimLeft(name, "/")
+}
+
+// NameTagPair represents a RepoTag of an image.
+type NameTagPair struct {
+ // Name of the RepoTag. Maybe "<none>".
+ Name string
+ // Tag of the RepoTag. Maybe "<none>".
+ Tag string
+
+ // for internal use
+ named reference.Named
+}
+
+// ToNameTagsPairs splits repoTags into name&tag pairs.
+// Guaranteed to return at least one pair.
+func ToNameTagPairs(repoTags []reference.Named) ([]NameTagPair, error) {
+ none := "<none>"
+
+ var pairs []NameTagPair
+ for i, named := range repoTags {
+ pair := NameTagPair{
+ Name: named.Name(),
+ Tag: none,
+ named: repoTags[i],
+ }
+
+ if tagged, isTagged := named.(reference.NamedTagged); isTagged {
+ pair.Tag = tagged.Tag()
+ }
+ pairs = append(pairs, pair)
+ }
+
+ if len(pairs) == 0 {
+ pairs = append(pairs, NameTagPair{Name: none, Tag: none})
+ }
+ return pairs, nil
+}
diff --git a/vendor/github.com/containers/common/libimage/oci.go b/vendor/github.com/containers/common/libimage/oci.go
new file mode 100644
index 000000000..b88d6613d
--- /dev/null
+++ b/vendor/github.com/containers/common/libimage/oci.go
@@ -0,0 +1,97 @@
+package libimage
+
+import (
+ "context"
+
+ ociv1 "github.com/opencontainers/image-spec/specs-go/v1"
+)
+
+// toOCI returns the image as OCI v1 image.
+func (i *Image) toOCI(ctx context.Context) (*ociv1.Image, error) {
+ if i.cached.ociv1Image != nil {
+ return i.cached.ociv1Image, nil
+ }
+ ref, err := i.StorageReference()
+ if err != nil {
+ return nil, err
+ }
+
+ img, err := ref.NewImage(ctx, i.runtime.systemContextCopy())
+ if err != nil {
+ return nil, err
+ }
+ defer img.Close()
+
+ return img.OCIConfig(ctx)
+}
+
+// historiesMatch returns the number of entries in the histories which have the
+// same contents
+func historiesMatch(a, b []ociv1.History) int {
+ i := 0
+ for i < len(a) && i < len(b) {
+ if a[i].Created != nil && b[i].Created == nil {
+ return i
+ }
+ if a[i].Created == nil && b[i].Created != nil {
+ return i
+ }
+ if a[i].Created != nil && b[i].Created != nil {
+ if !a[i].Created.Equal(*(b[i].Created)) {
+ return i
+ }
+ }
+ if a[i].CreatedBy != b[i].CreatedBy {
+ return i
+ }
+ if a[i].Author != b[i].Author {
+ return i
+ }
+ if a[i].Comment != b[i].Comment {
+ return i
+ }
+ if a[i].EmptyLayer != b[i].EmptyLayer {
+ return i
+ }
+ i++
+ }
+ return i
+}
+
+// areParentAndChild checks diff ID and history in the two images and return
+// true if the second should be considered to be directly based on the first
+func areParentAndChild(parent, child *ociv1.Image) bool {
+ // the child and candidate parent should share all of the
+ // candidate parent's diff IDs, which together would have
+ // controlled which layers were used
+
+ // Both, child and parent, may be nil when the storage is left in an
+ // incoherent state. Issue #7444 describes such a case when a build
+ // has been killed.
+ if child == nil || parent == nil {
+ return false
+ }
+
+ if len(parent.RootFS.DiffIDs) > len(child.RootFS.DiffIDs) {
+ return false
+ }
+ childUsesCandidateDiffs := true
+ for i := range parent.RootFS.DiffIDs {
+ if child.RootFS.DiffIDs[i] != parent.RootFS.DiffIDs[i] {
+ childUsesCandidateDiffs = false
+ break
+ }
+ }
+ if !childUsesCandidateDiffs {
+ return false
+ }
+ // the child should have the same history as the parent, plus
+ // one more entry
+ if len(parent.History)+1 != len(child.History) {
+ return false
+ }
+ if historiesMatch(parent.History, child.History) != len(parent.History) {
+ return false
+ }
+ return true
+}
diff --git a/vendor/github.com/containers/common/libimage/pull.go b/vendor/github.com/containers/common/libimage/pull.go
new file mode 100644
index 000000000..b92a5e15e
--- /dev/null
+++ b/vendor/github.com/containers/common/libimage/pull.go
@@ -0,0 +1,458 @@
+package libimage
+
+import (
+ "context"
+ "fmt"
+ "io"
+ "strings"
+
+ "github.com/containers/common/pkg/config"
+ dirTransport "github.com/containers/image/v5/directory"
+ dockerTransport "github.com/containers/image/v5/docker"
+ dockerArchiveTransport "github.com/containers/image/v5/docker/archive"
+ "github.com/containers/image/v5/docker/reference"
+ ociArchiveTransport "github.com/containers/image/v5/oci/archive"
+ ociTransport "github.com/containers/image/v5/oci/layout"
+ "github.com/containers/image/v5/pkg/shortnames"
+ storageTransport "github.com/containers/image/v5/storage"
+ "github.com/containers/image/v5/transports/alltransports"
+ "github.com/containers/image/v5/types"
+ "github.com/containers/storage"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+)
+
+// PullOptions allows for custommizing image pulls.
+type PullOptions struct {
+ CopyOptions
+
+ // If true, all tags of the image will be pulled from the container
+ // registry. Only supported for the docker transport.
+ AllTags bool
+}
+
+// Pull pulls the specified name. Name may refer to any of the supported
+// transports from github.com/containers/image. If no transport is encoded,
+// name will be treated as a reference to a registry (i.e., docker transport).
+//
+// Note that pullPolicy is only used when pulling from a container registry but
+// it *must* be different than the default value `config.PullPolicyUnsupported`. This
+// way, callers are forced to decide on the pull behaviour. The reasoning
+// behind is that some (commands of some) tools have different default pull
+// policies (e.g., buildah-bud versus podman-build). Making the pull-policy
+// choice explicit is an attempt to prevent silent regressions.
+//
+// The errror is storage.ErrImageUnknown iff the pull policy is set to "never"
+// and no local image has been found. This allows for an easier integration
+// into some users of this package (e.g., Buildah).
+func (r *Runtime) Pull(ctx context.Context, name string, pullPolicy config.PullPolicy, options *PullOptions) ([]*Image, error) {
+ logrus.Debugf("Pulling image %s (policy: %s)", name, pullPolicy)
+
+ if options == nil {
+ options = &PullOptions{}
+ }
+
+ ref, err := alltransports.ParseImageName(name)
+ if err != nil {
+ // If the image clearly refers to a local one, we can look it up directly.
+ // In fact, we need to since they are not parseable.
+ if strings.HasPrefix(name, "sha256:") || (len(name) == 64 && !strings.Contains(name, "/.:@")) {
+ if pullPolicy == config.PullPolicyAlways {
+ return nil, errors.Errorf("pull policy is always but image has been referred to by ID (%s)", name)
+ }
+ local, _, err := r.LookupImage(name, nil)
+ if err != nil {
+ return nil, err
+ }
+ return []*Image{local}, err
+ }
+
+ // If the input does not include a transport assume it refers
+ // to a registry.
+ dockerRef, dockerErr := alltransports.ParseImageName("docker://" + name)
+ if dockerErr != nil {
+ return nil, err
+ }
+ ref = dockerRef
+ }
+
+ if options.AllTags && ref.Transport().Name() != dockerTransport.Transport.Name() {
+ return nil, errors.Errorf("pulling all tags is not supported for %s transport", ref.Transport().Name())
+ }
+
+ var (
+ pulledImages []string
+ pullError error
+ )
+
+ // Dispatch the copy operation.
+ switch ref.Transport().Name() {
+
+ // DOCKER/REGISTRY
+ case dockerTransport.Transport.Name():
+ pulledImages, pullError = r.copyFromRegistry(ctx, ref, strings.TrimPrefix(name, "docker://"), pullPolicy, options)
+
+ // DOCKER ARCHIVE
+ case dockerArchiveTransport.Transport.Name():
+ pulledImages, pullError = r.copyFromDockerArchive(ctx, ref, &options.CopyOptions)
+
+ // OCI
+ case ociTransport.Transport.Name():
+ pulledImages, pullError = r.copyFromDefault(ctx, ref, &options.CopyOptions)
+
+ // OCI ARCHIVE
+ case ociArchiveTransport.Transport.Name():
+ pulledImages, pullError = r.copyFromDefault(ctx, ref, &options.CopyOptions)
+
+ // DIR
+ case dirTransport.Transport.Name():
+ pulledImages, pullError = r.copyFromDefault(ctx, ref, &options.CopyOptions)
+
+ // UNSUPPORTED
+ default:
+ return nil, errors.Errorf("unsupported transport %q for pulling", ref.Transport().Name())
+ }
+
+ if pullError != nil {
+ return nil, pullError
+ }
+
+ localImages := []*Image{}
+ lookupOptions := &LookupImageOptions{IgnorePlatform: true}
+ for _, name := range pulledImages {
+ local, _, err := r.LookupImage(name, lookupOptions)
+ if err != nil {
+ return nil, errors.Wrapf(err, "error locating pulled image %q name in containers storage", name)
+ }
+ localImages = append(localImages, local)
+ }
+
+ return localImages, pullError
+}
+
+// copyFromDefault is the default copier for a number of transports. Other
+// transports require some specific dancing, sometimes Yoga.
+func (r *Runtime) copyFromDefault(ctx context.Context, ref types.ImageReference, options *CopyOptions) ([]string, error) {
+ c, err := r.newCopier(options)
+ if err != nil {
+ return nil, err
+ }
+ defer c.close()
+
+ // Figure out a name for the storage destination.
+ var storageName, imageName string
+ switch ref.Transport().Name() {
+
+ case ociTransport.Transport.Name():
+ split := strings.SplitN(ref.StringWithinTransport(), ":", 2)
+ storageName = toLocalImageName(split[0])
+ imageName = storageName
+
+ case ociArchiveTransport.Transport.Name():
+ manifest, err := ociArchiveTransport.LoadManifestDescriptor(ref)
+ if err != nil {
+ return nil, err
+ }
+ // if index.json has no reference name, compute the image digest instead
+ if manifest.Annotations == nil || manifest.Annotations["org.opencontainers.image.ref.name"] == "" {
+ storageName, err = getImageDigest(ctx, ref, nil)
+ if err != nil {
+ return nil, err
+ }
+ imageName = "sha256:" + storageName[1:]
+ } else {
+ storageName = manifest.Annotations["org.opencontainers.image.ref.name"]
+ imageName = storageName
+ }
+
+ default:
+ storageName = toLocalImageName(ref.StringWithinTransport())
+ imageName = storageName
+ }
+
+ // Create a storage reference.
+ destRef, err := storageTransport.Transport.ParseStoreReference(r.store, storageName)
+ if err != nil {
+ return nil, err
+ }
+
+ _, err = c.copy(ctx, ref, destRef)
+ return []string{imageName}, err
+}
+
+// storageReferencesFromArchiveReader returns a slice of image references inside the
+// archive reader. A docker archive may include more than one image and this
+// method allows for extracting them into containers storage references which
+// can later be used from copying.
+func (r *Runtime) storageReferencesReferencesFromArchiveReader(ctx context.Context, readerRef types.ImageReference, reader *dockerArchiveTransport.Reader) ([]types.ImageReference, []string, error) {
+ destNames, err := reader.ManifestTagsForReference(readerRef)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ var imageNames []string
+ if len(destNames) == 0 {
+ destName, err := getImageDigest(ctx, readerRef, &r.systemContext)
+ if err != nil {
+ return nil, nil, err
+ }
+ destNames = append(destNames, destName)
+ // Make sure the image can be loaded after the pull by
+ // replacing the @ with sha256:.
+ imageNames = append(imageNames, "sha256:"+destName[1:])
+ } else {
+ for i := range destNames {
+ ref, err := NormalizeName(destNames[i])
+ if err != nil {
+ return nil, nil, err
+ }
+ destNames[i] = ref.String()
+ }
+ imageNames = destNames
+ }
+
+ references := []types.ImageReference{}
+ for _, destName := range destNames {
+ destRef, err := storageTransport.Transport.ParseStoreReference(r.store, destName)
+ if err != nil {
+ return nil, nil, errors.Wrapf(err, "error parsing dest reference name %#v", destName)
+ }
+ references = append(references, destRef)
+ }
+
+ return references, imageNames, nil
+}
+
+// copyFromDockerArchive copies one image from the specified reference.
+func (r *Runtime) copyFromDockerArchive(ctx context.Context, ref types.ImageReference, options *CopyOptions) ([]string, error) {
+ // There may be more than one image inside the docker archive, so we
+ // need a quick glimpse inside.
+ reader, readerRef, err := dockerArchiveTransport.NewReaderForReference(&r.systemContext, ref)
+ if err != nil {
+ return nil, err
+ }
+
+ return r.copyFromDockerArchiveReaderReference(ctx, reader, readerRef, options)
+}
+
+// copyFromDockerArchiveReaderReference copies the specified readerRef from reader.
+func (r *Runtime) copyFromDockerArchiveReaderReference(ctx context.Context, reader *dockerArchiveTransport.Reader, readerRef types.ImageReference, options *CopyOptions) ([]string, error) {
+ c, err := r.newCopier(options)
+ if err != nil {
+ return nil, err
+ }
+ defer c.close()
+
+ // Get a slice of storage references we can copy.
+ references, destNames, err := r.storageReferencesReferencesFromArchiveReader(ctx, readerRef, reader)
+ if err != nil {
+ return nil, err
+ }
+
+ // Now copy all of the images. Use readerRef for performance.
+ for _, destRef := range references {
+ if _, err := c.copy(ctx, readerRef, destRef); err != nil {
+ return nil, err
+ }
+ }
+
+ return destNames, nil
+}
+
+// copyFromRegistry pulls the specified, possibly unqualified, name from a
+// registry. On successful pull it returns the used fully-qualified name that
+// can later be used to look up the image in the local containers storage.
+//
+// If options.All is set, all tags from the specified registry will be pulled.
+func (r *Runtime) copyFromRegistry(ctx context.Context, ref types.ImageReference, inputName string, pullPolicy config.PullPolicy, options *PullOptions) ([]string, error) {
+ // Sanity check.
+ if err := pullPolicy.Validate(); err != nil {
+ return nil, err
+ }
+
+ if !options.AllTags {
+ return r.copySingleImageFromRegistry(ctx, inputName, pullPolicy, options)
+ }
+
+ named := reference.TrimNamed(ref.DockerReference())
+ tags, err := dockerTransport.GetRepositoryTags(ctx, &r.systemContext, ref)
+ if err != nil {
+ return nil, err
+ }
+
+ pulledTags := []string{}
+ for _, tag := range tags {
+ select { // Let's be gentle with Podman remote.
+ case <-ctx.Done():
+ return nil, errors.Errorf("pulling cancelled")
+ default:
+ // We can continue.
+ }
+ tagged, err := reference.WithTag(named, tag)
+ if err != nil {
+ return nil, errors.Wrapf(err, "error creating tagged reference (name %s, tag %s)", named.String(), tag)
+ }
+ pulled, err := r.copySingleImageFromRegistry(ctx, tagged.String(), pullPolicy, options)
+ if err != nil {
+ return nil, err
+ }
+ pulledTags = append(pulledTags, pulled...)
+ }
+
+ return pulledTags, nil
+}
+
+// copySingleImageFromRegistry pulls the specified, possibly unqualified, name
+// from a registry. On successful pull it returns the used fully-qualified
+// name that can later be used to look up the image in the local containers
+// storage.
+func (r *Runtime) copySingleImageFromRegistry(ctx context.Context, imageName string, pullPolicy config.PullPolicy, options *PullOptions) ([]string, error) {
+ // Sanity check.
+ if err := pullPolicy.Validate(); err != nil {
+ return nil, err
+ }
+
+ var (
+ localImage *Image
+ resolvedImageName string
+ err error
+ )
+
+ // Always check if there's a local image. If, we should use it's
+ // resolved name for pulling. Assume we're doing a `pull foo`.
+ // If there's already a local image "localhost/foo", then we should
+ // attempt pulling that instead of doing the full short-name dance.
+ localImage, resolvedImageName, err = r.LookupImage(imageName, nil)
+ if err != nil && errors.Cause(err) != storage.ErrImageUnknown {
+ return nil, errors.Wrap(err, "error looking up local image")
+ }
+
+ if pullPolicy == config.PullPolicyNever {
+ if localImage != nil {
+ logrus.Debugf("Pull policy %q but no local image has been found for %s", pullPolicy, imageName)
+ return []string{resolvedImageName}, nil
+ }
+ logrus.Debugf("Pull policy %q and %s resolved to local image %s", pullPolicy, imageName, resolvedImageName)
+ return nil, errors.Wrap(storage.ErrImageUnknown, imageName)
+ }
+
+ if pullPolicy == config.PullPolicyMissing && localImage != nil {
+ return []string{resolvedImageName}, nil
+ }
+
+ // If we looked up the image by ID, we cannot really pull from anywhere.
+ if localImage != nil && strings.HasPrefix(localImage.ID(), imageName) {
+ switch pullPolicy {
+ case config.PullPolicyAlways:
+ return nil, errors.Errorf("pull policy is always but image has been referred to by ID (%s)", imageName)
+ default:
+ return []string{resolvedImageName}, nil
+ }
+ }
+
+ // If we found a local image, we should use it's locally resolved name
+ // (see containers/buildah #2904).
+ if localImage != nil {
+ if imageName != resolvedImageName {
+ logrus.Debugf("Image %s resolved to local image %s which will be used for pulling", imageName, resolvedImageName)
+ }
+ imageName = resolvedImageName
+ }
+
+ sys := r.systemContextCopy()
+ resolved, err := shortnames.Resolve(sys, imageName)
+ if err != nil {
+ return nil, err
+ }
+
+ // NOTE: Below we print the description from the short-name resolution.
+ // In theory we could print it here. In practice, however, this is
+ // causing a hard time for Buildah uses who are doing a `buildah from
+ // image` and expect just the container name to be printed if the image
+ // is present locally.
+ // The pragmatic solution is to only print the description when we found
+ // a _newer_ image that we're about to pull.
+ wroteDesc := false
+ writeDesc := func() error {
+ if wroteDesc {
+ return nil
+ }
+ wroteDesc = true
+ if desc := resolved.Description(); len(desc) > 0 {
+ logrus.Debug(desc)
+ if options.Writer != nil {
+ if _, err := options.Writer.Write([]byte(desc + "\n")); err != nil {
+ return err
+ }
+ }
+ }
+ return nil
+ }
+
+ c, err := r.newCopier(&options.CopyOptions)
+ if err != nil {
+ return nil, err
+ }
+ defer c.close()
+
+ var pullErrors []error
+ for _, candidate := range resolved.PullCandidates {
+ candidateString := candidate.Value.String()
+ logrus.Debugf("Attempting to pull candidate %s for %s", candidateString, imageName)
+ srcRef, err := dockerTransport.NewReference(candidate.Value)
+ if err != nil {
+ return nil, err
+ }
+
+ if pullPolicy == config.PullPolicyNewer && localImage != nil {
+ isNewer, err := localImage.HasDifferentDigest(ctx, srcRef)
+ if err != nil {
+ pullErrors = append(pullErrors, err)
+ continue
+ }
+
+ if !isNewer {
+ logrus.Debugf("Skipping pull candidate %s as the image is not newer (pull policy %s)", candidateString, pullPolicy)
+ continue
+ }
+ }
+
+ destRef, err := storageTransport.Transport.ParseStoreReference(r.store, candidate.Value.String())
+ if err != nil {
+ return nil, err
+ }
+
+ if err := writeDesc(); err != nil {
+ return nil, err
+ }
+ if options.Writer != nil {
+ if _, err := io.WriteString(options.Writer, fmt.Sprintf("Trying to pull %s...\n", candidateString)); err != nil {
+ return nil, err
+ }
+ }
+ if _, err := c.copy(ctx, srcRef, destRef); err != nil {
+ logrus.Debugf("Error pulling candidate %s: %v", candidateString, err)
+ pullErrors = append(pullErrors, err)
+ continue
+ }
+ if err := candidate.Record(); err != nil {
+ // Only log the recording errors. Podman has seen
+ // reports where users set most of the system to
+ // read-only which can cause issues.
+ logrus.Errorf("Error recording short-name alias %q: %v", candidateString, err)
+ }
+
+ logrus.Debugf("Pulled candidate %s successfully", candidateString)
+ return []string{candidate.Value.String()}, nil
+ }
+
+ if localImage != nil && pullPolicy == config.PullPolicyNewer {
+ return []string{resolvedImageName}, nil
+ }
+
+ if len(pullErrors) == 0 {
+ return nil, errors.Errorf("internal error: no image pulled (pull policy %s)", pullPolicy)
+ }
+
+ return nil, resolved.FormatPullErrors(pullErrors)
+}
diff --git a/vendor/github.com/containers/common/libimage/push.go b/vendor/github.com/containers/common/libimage/push.go
new file mode 100644
index 000000000..8ff5d5ffd
--- /dev/null
+++ b/vendor/github.com/containers/common/libimage/push.go
@@ -0,0 +1,83 @@
+package libimage
+
+import (
+ "context"
+
+ dockerArchiveTransport "github.com/containers/image/v5/docker/archive"
+ "github.com/containers/image/v5/docker/reference"
+ "github.com/containers/image/v5/transports/alltransports"
+ "github.com/sirupsen/logrus"
+)
+
+// PushOptions allows for custommizing image pushes.
+type PushOptions struct {
+ CopyOptions
+}
+
+// Push pushes the specified source which must refer to an image in the local
+// containers storage. It may or may not have the `containers-storage:`
+// prefix. Use destination to push to a custom destination. The destination
+// can refer to any supported transport. If not transport is specified, the
+// docker transport (i.e., a registry) is implied. If destination is left
+// empty, the docker destination will be extrapolated from the source.
+//
+// Return storage.ErrImageUnknown if source could not be found in the local
+// containers storage.
+func (r *Runtime) Push(ctx context.Context, source, destination string, options *PushOptions) ([]byte, error) {
+ if options == nil {
+ options = &PushOptions{}
+ }
+
+ // Look up the local image.
+ image, resolvedSource, err := r.LookupImage(source, nil)
+ if err != nil {
+ return nil, err
+ }
+
+ srcRef, err := image.StorageReference()
+ if err != nil {
+ return nil, err
+ }
+
+ // Make sure we have a proper destination, and parse it into an image
+ // reference for copying.
+ if destination == "" {
+ // Doing an ID check here is tempting but false positives (due
+ // to a short partial IDs) are more painful than false
+ // negatives.
+ destination = resolvedSource
+ }
+
+ logrus.Debugf("Pushing image %s to %s", source, destination)
+
+ destRef, err := alltransports.ParseImageName(destination)
+ if err != nil {
+ // If the input does not include a transport assume it refers
+ // to a registry.
+ dockerRef, dockerErr := alltransports.ParseImageName("docker://" + destination)
+ if dockerErr != nil {
+ return nil, err
+ }
+ destRef = dockerRef
+ }
+
+ // Buildah compat: Make sure to tag the destination image if it's a
+ // Docker archive. This way, we preseve the image name.
+ if destRef.Transport().Name() == dockerArchiveTransport.Transport.Name() {
+ if named, err := reference.ParseNamed(resolvedSource); err == nil {
+ tagged, isTagged := named.(reference.NamedTagged)
+ if isTagged {
+ options.dockerArchiveAdditionalTags = []reference.NamedTagged{tagged}
+ }
+ }
+ }
+
+ c, err := r.newCopier(&options.CopyOptions)
+ if err != nil {
+ return nil, err
+ }
+
+ defer c.close()
+
+ return c.copy(ctx, srcRef, destRef)
+}
diff --git a/vendor/github.com/containers/common/libimage/runtime.go b/vendor/github.com/containers/common/libimage/runtime.go
new file mode 100644
index 000000000..4e6bd2cf2
--- /dev/null
+++ b/vendor/github.com/containers/common/libimage/runtime.go
@@ -0,0 +1,573 @@
+package libimage
+
+import (
+ "context"
+ "os"
+ "path/filepath"
+ "runtime"
+ "strings"
+
+ "github.com/containers/image/v5/docker/reference"
+ "github.com/containers/image/v5/pkg/shortnames"
+ storageTransport "github.com/containers/image/v5/storage"
+ "github.com/containers/image/v5/transports/alltransports"
+ "github.com/containers/image/v5/types"
+ "github.com/containers/storage"
+ deepcopy "github.com/jinzhu/copier"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+)
+
+// RuntimeOptions allow for creating a customized Runtime.
+type RuntimeOptions struct {
+ SystemContext *types.SystemContext
+}
+
+// setRegistriesConfPath sets the registries.conf path for the specified context.
+func setRegistriesConfPath(systemContext *types.SystemContext) {
+ if systemContext.SystemRegistriesConfPath != "" {
+ return
+ }
+ if envOverride, ok := os.LookupEnv("CONTAINERS_REGISTRIES_CONF"); ok {
+ systemContext.SystemRegistriesConfPath = envOverride
+ return
+ }
+ if envOverride, ok := os.LookupEnv("REGISTRIES_CONFIG_PATH"); ok {
+ systemContext.SystemRegistriesConfPath = envOverride
+ return
+ }
+}
+
+// Runtime is responsible for image management and storing them in a containers
+// storage.
+type Runtime struct {
+ // Underlying storage store.
+ store storage.Store
+ // Global system context. No pointer to simplify copying and modifying
+ // it.
+ systemContext types.SystemContext
+}
+
+// Returns a copy of the runtime's system context.
+func (r *Runtime) systemContextCopy() *types.SystemContext {
+ var sys types.SystemContext
+ deepcopy.Copy(&sys, &r.systemContext)
+ return &sys
+}
+
+// RuntimeFromStore returns a Runtime for the specified store.
+func RuntimeFromStore(store storage.Store, options *RuntimeOptions) (*Runtime, error) {
+ if options == nil {
+ options = &RuntimeOptions{}
+ }
+
+ var systemContext types.SystemContext
+ if options.SystemContext != nil {
+ systemContext = *options.SystemContext
+ } else {
+ systemContext = types.SystemContext{}
+ }
+
+ setRegistriesConfPath(&systemContext)
+
+ if systemContext.BlobInfoCacheDir == "" {
+ systemContext.BlobInfoCacheDir = filepath.Join(store.GraphRoot(), "cache")
+ }
+
+ return &Runtime{
+ store: store,
+ systemContext: systemContext,
+ }, nil
+}
+
+// RuntimeFromStoreOptions returns a return for the specified store options.
+func RuntimeFromStoreOptions(runtimeOptions *RuntimeOptions, storeOptions *storage.StoreOptions) (*Runtime, error) {
+ if storeOptions == nil {
+ storeOptions = &storage.StoreOptions{}
+ }
+ store, err := storage.GetStore(*storeOptions)
+ if err != nil {
+ return nil, err
+ }
+ storageTransport.Transport.SetStore(store)
+ return RuntimeFromStore(store, runtimeOptions)
+}
+
+// Shutdown attempts to free any kernel resources which are being used by the
+// underlying driver. If "force" is true, any mounted (i.e., in use) layers
+// are unmounted beforehand. If "force" is not true, then layers being in use
+// is considered to be an error condition.
+func (r *Runtime) Shutdown(force bool) error {
+ _, err := r.store.Shutdown(force)
+ return err
+}
+
+// storageToImage transforms a storage.Image to an Image.
+func (r *Runtime) storageToImage(storageImage *storage.Image, ref types.ImageReference) *Image {
+ return &Image{
+ runtime: r,
+ storageImage: storageImage,
+ storageReference: ref,
+ }
+}
+
+// Exists returns true if the specicifed image exists in the local containers
+// storage.
+func (r *Runtime) Exists(name string) (bool, error) {
+ image, _, err := r.LookupImage(name, &LookupImageOptions{IgnorePlatform: true})
+ if err != nil && errors.Cause(err) != storage.ErrImageUnknown {
+ return false, err
+ }
+ return image != nil, nil
+}
+
+// LookupImageOptions allow for customizing local image lookups.
+type LookupImageOptions struct {
+ // If set, the image will be purely looked up by name. No matching to
+ // the current platform will be performed. This can be helpful when
+ // the platform does not matter, for instance, for image removal.
+ IgnorePlatform bool
+}
+
+// Lookup Image looks up `name` in the local container storage matching the
+// specified SystemContext. Returns the image and the name it has been found
+// with. Note that name may also use the `containers-storage:` prefix used to
+// refer to the containers-storage transport. Returns storage.ErrImageUnknown
+// if the image could not be found.
+//
+// If the specified name uses the `containers-storage` transport, the resolved
+// name is empty.
+func (r *Runtime) LookupImage(name string, options *LookupImageOptions) (*Image, string, error) {
+ logrus.Debugf("Looking up image %q in local containers storage", name)
+
+ if options == nil {
+ options = &LookupImageOptions{}
+ }
+
+ // If needed extract the name sans transport.
+ storageRef, err := alltransports.ParseImageName(name)
+ if err == nil {
+ if storageRef.Transport().Name() != storageTransport.Transport.Name() {
+ return nil, "", errors.Errorf("unsupported transport %q for looking up local images", storageRef.Transport().Name())
+ }
+ img, err := storageTransport.Transport.GetStoreImage(r.store, storageRef)
+ if err != nil {
+ return nil, "", err
+ }
+ logrus.Debugf("Found image %q in local containers storage (%s)", name, storageRef.StringWithinTransport())
+ return r.storageToImage(img, storageRef), "", nil
+ }
+
+ originalName := name
+ idByDigest := false
+ if strings.HasPrefix(name, "sha256:") {
+ // Strip off the sha256 prefix so it can be parsed later on.
+ idByDigest = true
+ name = strings.TrimPrefix(name, "sha256:")
+ }
+
+ // First, check if we have an exact match in the storage. Maybe an ID
+ // or a fully-qualified image name.
+ img, err := r.lookupImageInLocalStorage(name, name, options)
+ if err != nil {
+ return nil, "", err
+ }
+ if img != nil {
+ return img, originalName, nil
+ }
+
+ // If the name clearly referred to a local image, there's nothing we can
+ // do anymore.
+ if storageRef != nil || idByDigest {
+ return nil, "", errors.Wrap(storage.ErrImageUnknown, originalName)
+ }
+
+ // Second, try out the candidates as resolved by shortnames. This takes
+ // "localhost/" prefixed images into account as well.
+ candidates, err := shortnames.ResolveLocally(&r.systemContext, name)
+ if err != nil {
+ return nil, "", errors.Wrap(storage.ErrImageUnknown, originalName)
+ }
+ // Backwards compat: normalize to docker.io as some users may very well
+ // rely on that.
+ if dockerNamed, err := reference.ParseDockerRef(name); err == nil {
+ candidates = append(candidates, dockerNamed)
+ }
+
+ for _, candidate := range candidates {
+ img, err := r.lookupImageInLocalStorage(name, candidate.String(), options)
+ if err != nil {
+ return nil, "", err
+ }
+ if img != nil {
+ return img, candidate.String(), err
+ }
+ }
+
+ return r.lookupImageInDigestsAndRepoTags(originalName, options)
+}
+
+// lookupImageInLocalStorage looks up the specified candidate for name in the
+// storage and checks whether it's matching the system context.
+func (r *Runtime) lookupImageInLocalStorage(name, candidate string, options *LookupImageOptions) (*Image, error) {
+ logrus.Debugf("Trying %q ...", candidate)
+ img, err := r.store.Image(candidate)
+ if err != nil && errors.Cause(err) != storage.ErrImageUnknown {
+ return nil, err
+ }
+ if img == nil {
+ return nil, nil
+ }
+ ref, err := storageTransport.Transport.ParseStoreReference(r.store, img.ID)
+ if err != nil {
+ return nil, err
+ }
+
+ image := r.storageToImage(img, ref)
+ if options.IgnorePlatform {
+ logrus.Debugf("Found image %q as %q in local containers storage", name, candidate)
+ return image, nil
+ }
+
+ // If we referenced a manifest list, we need to check whether we can
+ // find a matching instance in the local containers storage.
+ isManifestList, err := image.IsManifestList(context.Background())
+ if err != nil {
+ return nil, err
+ }
+ if isManifestList {
+ manifestList, err := image.ToManifestList()
+ if err != nil {
+ return nil, err
+ }
+ image, err = manifestList.LookupInstance(context.Background(), "", "", "")
+ if err != nil {
+ return nil, err
+ }
+ ref, err = storageTransport.Transport.ParseStoreReference(r.store, "@"+image.ID())
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ matches, err := imageReferenceMatchesContext(context.Background(), ref, &r.systemContext)
+ if err != nil {
+ return nil, err
+ }
+
+ // NOTE: if the user referenced by ID we must optimistically assume
+ // that they know what they're doing. Given, we already did the
+ // manifest limbo above, we may already have resolved it.
+ if !matches && !strings.HasPrefix(image.ID(), candidate) {
+ return nil, nil
+ }
+ // Also print the string within the storage transport. That may aid in
+ // debugging when using additional stores since we see explicitly where
+ // the store is and which driver (options) are used.
+ logrus.Debugf("Found image %q as %q in local containers storage (%s)", name, candidate, ref.StringWithinTransport())
+ return image, nil
+}
+
+// lookupImageInDigestsAndRepoTags attempts to match name against any image in
+// the local containers storage. If name is digested, it will be compared
+// against image digests. Otherwise, it will be looked up in the repo tags.
+func (r *Runtime) lookupImageInDigestsAndRepoTags(name string, options *LookupImageOptions) (*Image, string, error) {
+ // Until now, we've tried very hard to find an image but now it is time
+ // for limbo. If the image includes a digest that we couldn't detect
+ // verbatim in the storage, we must have a look at all digests of all
+ // images. Those may change over time (e.g., via manifest lists).
+ // Both Podman and Buildah want us to do that dance.
+ allImages, err := r.ListImages(context.Background(), nil, nil)
+ if err != nil {
+ return nil, "", err
+ }
+
+ if !shortnames.IsShortName(name) {
+ named, err := reference.ParseNormalizedNamed(name)
+ if err != nil {
+ return nil, "", err
+ }
+ digested, hasDigest := named.(reference.Digested)
+ if !hasDigest {
+ return nil, "", errors.Wrap(storage.ErrImageUnknown, name)
+ }
+
+ logrus.Debug("Looking for image with matching recorded digests")
+ digest := digested.Digest()
+ for _, image := range allImages {
+ for _, d := range image.Digests() {
+ if d == digest {
+ return image, name, nil
+ }
+ }
+ }
+
+ return nil, "", errors.Wrap(storage.ErrImageUnknown, name)
+ }
+
+ // Podman compat: if we're looking for a short name but couldn't
+ // resolve it via the registries.conf dance, we need to look at *all*
+ // images and check if the name we're looking for matches a repo tag.
+ // Split the name into a repo/tag pair
+ split := strings.SplitN(name, ":", 2)
+ repo := split[0]
+ tag := ""
+ if len(split) == 2 {
+ tag = split[1]
+ }
+ for _, image := range allImages {
+ named, err := image.inRepoTags(repo, tag)
+ if err != nil {
+ return nil, "", err
+ }
+ if named == nil {
+ continue
+ }
+ img, err := r.lookupImageInLocalStorage(name, named.String(), options)
+ if err != nil {
+ return nil, "", err
+ }
+ if img != nil {
+ return img, named.String(), err
+ }
+ }
+
+ return nil, "", errors.Wrap(storage.ErrImageUnknown, name)
+}
+
+// ResolveName resolves the specified name. If the name resolves to a local
+// image, the fully resolved name will be returned. Otherwise, the name will
+// be properly normalized.
+//
+// Note that an empty string is returned as is.
+func (r *Runtime) ResolveName(name string) (string, error) {
+ if name == "" {
+ return "", nil
+ }
+ image, resolvedName, err := r.LookupImage(name, &LookupImageOptions{IgnorePlatform: true})
+ if err != nil && errors.Cause(err) != storage.ErrImageUnknown {
+ return "", err
+ }
+
+ if image != nil && !strings.HasPrefix(image.ID(), resolvedName) {
+ return resolvedName, err
+ }
+
+ normalized, err := NormalizeName(name)
+ if err != nil {
+ return "", err
+ }
+
+ return normalized.String(), nil
+}
+
+// imageReferenceMatchesContext return true if the specified reference matches
+// the platform (os, arch, variant) as specified by the system context.
+func imageReferenceMatchesContext(ctx context.Context, ref types.ImageReference, sys *types.SystemContext) (bool, error) {
+ if sys == nil {
+ return true, nil
+ }
+ img, err := ref.NewImage(ctx, sys)
+ if err != nil {
+ return false, err
+ }
+ defer img.Close()
+ data, err := img.Inspect(ctx)
+ if err != nil {
+ return false, err
+ }
+ osChoice := sys.OSChoice
+ if osChoice == "" {
+ osChoice = runtime.GOOS
+ }
+ arch := sys.ArchitectureChoice
+ if arch == "" {
+ arch = runtime.GOARCH
+ }
+ if osChoice == data.Os && arch == data.Architecture {
+ if sys.VariantChoice == "" || sys.VariantChoice == data.Variant {
+ return true, nil
+ }
+ }
+ return false, nil
+}
+
+// ListImagesOptions allow for customizing listing images.
+type ListImagesOptions struct {
+ // Filters to filter the listed images. Supported filters are
+ // * after,before,since=image
+ // * dangling=true,false
+ // * intermediate=true,false (useful for pruning images)
+ // * id=id
+ // * label=key[=value]
+ // * readonly=true,false
+ // * reference=name[:tag] (wildcards allowed)
+ Filters []string
+}
+
+// ListImages lists images in the local container storage. If names are
+// specified, only images with the specified names are looked up and filtered.
+func (r *Runtime) ListImages(ctx context.Context, names []string, options *ListImagesOptions) ([]*Image, error) {
+ if options == nil {
+ options = &ListImagesOptions{}
+ }
+
+ var images []*Image
+ if len(names) > 0 {
+ lookupOpts := LookupImageOptions{IgnorePlatform: true}
+ for _, name := range names {
+ image, _, err := r.LookupImage(name, &lookupOpts)
+ if err != nil {
+ return nil, err
+ }
+ images = append(images, image)
+ }
+ } else {
+ storageImages, err := r.store.Images()
+ if err != nil {
+ return nil, err
+ }
+ for i := range storageImages {
+ images = append(images, r.storageToImage(&storageImages[i], nil))
+ }
+ }
+
+ var filters []filterFunc
+ if len(options.Filters) > 0 {
+ compiledFilters, err := r.compileImageFilters(ctx, options.Filters)
+ if err != nil {
+ return nil, err
+ }
+ filters = append(filters, compiledFilters...)
+ }
+
+ return filterImages(images, filters)
+}
+
+// RemoveImagesOptions allow for customizing image removal.
+type RemoveImagesOptions struct {
+ // Force will remove all containers from the local storage that are
+ // using a removed image. Use RemoveContainerFunc for a custom logic.
+ // If set, all child images will be removed as well.
+ Force bool
+ // RemoveContainerFunc allows for a custom logic for removing
+ // containers using a specific image. By default, all containers in
+ // the local containers storage will be removed (if Force is set).
+ RemoveContainerFunc RemoveContainerFunc
+ // Filters to filter the removed images. Supported filters are
+ // * after,before,since=image
+ // * dangling=true,false
+ // * intermediate=true,false (useful for pruning images)
+ // * id=id
+ // * label=key[=value]
+ // * readonly=true,false
+ // * reference=name[:tag] (wildcards allowed)
+ Filters []string
+ // The RemoveImagesReport will include the size of the removed image.
+ // This information may be useful when pruning images to figure out how
+ // much space was freed. However, computing the size of an image is
+ // comparatively expensive, so it is made optional.
+ WithSize bool
+}
+
+// RemoveImages removes images specified by names. All images are expected to
+// exist in the local containers storage.
+//
+// If an image has more names than one name, the image will be untagged with
+// the specified name. RemoveImages returns a slice of untagged and removed
+// images.
+//
+// Note that most errors are non-fatal and collected into `rmErrors` return
+// value.
+func (r *Runtime) RemoveImages(ctx context.Context, names []string, options *RemoveImagesOptions) (reports []*RemoveImageReport, rmErrors []error) {
+ if options == nil {
+ options = &RemoveImagesOptions{}
+ }
+
+ // The logic here may require some explanation. Image removal is
+ // surprisingly complex since it is recursive (intermediate parents are
+ // removed) and since multiple items in `names` may resolve to the
+ // *same* image. On top, the data in the containers storage is shared,
+ // so we need to be careful and the code must be robust. That is why
+ // users can only remove images via this function; the logic may be
+ // complex but the execution path is clear.
+
+ // Bundle an image with a possible empty slice of names to untag. That
+ // allows for a decent untagging logic and to bundle multiple
+ // references to the same *Image (and circumvent consistency issues).
+ type deleteMe struct {
+ image *Image
+ referencedBy []string
+ }
+
+ appendError := func(err error) {
+ rmErrors = append(rmErrors, err)
+ }
+
+ orderedIDs := []string{} // determinism and relative order
+ deleteMap := make(map[string]*deleteMe) // ID -> deleteMe
+
+ // Look up images in the local containers storage and fill out
+ // orderedIDs and the deleteMap.
+ switch {
+ case len(names) > 0:
+ lookupOptions := LookupImageOptions{IgnorePlatform: true}
+ for _, name := range names {
+ img, resolvedName, err := r.LookupImage(name, &lookupOptions)
+ if err != nil {
+ appendError(err)
+ continue
+ }
+ dm, exists := deleteMap[img.ID()]
+ if !exists {
+ orderedIDs = append(orderedIDs, img.ID())
+ dm = &deleteMe{image: img}
+ deleteMap[img.ID()] = dm
+ }
+ dm.referencedBy = append(dm.referencedBy, resolvedName)
+ }
+ if len(orderedIDs) == 0 {
+ return nil, rmErrors
+ }
+
+ case len(options.Filters) > 0:
+ filteredImages, err := r.ListImages(ctx, nil, &ListImagesOptions{Filters: options.Filters})
+ if err != nil {
+ appendError(err)
+ return nil, rmErrors
+ }
+ for _, img := range filteredImages {
+ orderedIDs = append(orderedIDs, img.ID())
+ deleteMap[img.ID()] = &deleteMe{image: img}
+ }
+ }
+
+ // Now remove the images in the given order.
+ rmMap := make(map[string]*RemoveImageReport)
+ for _, id := range orderedIDs {
+ del, exists := deleteMap[id]
+ if !exists {
+ appendError(errors.Errorf("internal error: ID %s not in found in image-deletion map", id))
+ continue
+ }
+ if len(del.referencedBy) == 0 {
+ del.referencedBy = []string{""}
+ }
+ for _, ref := range del.referencedBy {
+ if err := del.image.remove(ctx, rmMap, ref, options); err != nil {
+ appendError(err)
+ continue
+ }
+ }
+ }
+
+ // Finally, we can assemble the reports slice.
+ for _, id := range orderedIDs {
+ report, exists := rmMap[id]
+ if exists {
+ reports = append(reports, report)
+ }
+ }
+
+ return reports, rmErrors
+}
diff --git a/vendor/github.com/containers/common/libimage/save.go b/vendor/github.com/containers/common/libimage/save.go
new file mode 100644
index 000000000..c03437682
--- /dev/null
+++ b/vendor/github.com/containers/common/libimage/save.go
@@ -0,0 +1,202 @@
+package libimage
+
+import (
+ "context"
+ "strings"
+
+ dirTransport "github.com/containers/image/v5/directory"
+ dockerArchiveTransport "github.com/containers/image/v5/docker/archive"
+ "github.com/containers/image/v5/docker/reference"
+ "github.com/containers/image/v5/manifest"
+ ociArchiveTransport "github.com/containers/image/v5/oci/archive"
+ ociTransport "github.com/containers/image/v5/oci/layout"
+ "github.com/containers/image/v5/types"
+ ociv1 "github.com/opencontainers/image-spec/specs-go/v1"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+)
+
+// SaveOptions allow for customizing saving images.
+type SaveOptions struct {
+ CopyOptions
+
+ // AdditionalTags for the saved image. Incompatible when saving
+ // multiple images.
+ AdditionalTags []string
+}
+
+// Save saves one or more images indicated by `names` in the specified `format`
+// to `path`. Supported formats are oci-archive, docker-archive, oci-dir and
+// docker-dir. The latter two adhere to the dir transport in the corresponding
+// oci or docker v2s2 format. Please note that only docker-archive supports
+// saving more than one images. Other formats will yield an error attempting
+// to save more than one.
+func (r *Runtime) Save(ctx context.Context, names []string, format, path string, options *SaveOptions) error {
+ logrus.Debugf("Saving one more images (%s) to %q", names, path)
+
+ if options == nil {
+ options = &SaveOptions{}
+ }
+
+ // First some sanity checks to simplify subsequent code.
+ switch len(names) {
+ case 0:
+ return errors.New("no image specified for saving images")
+ case 1:
+ // All formats support saving 1.
+ default:
+ if format != "docker-archive" {
+ return errors.Errorf("unspported format %q for saving multiple images (only docker-archive)", format)
+ }
+ if len(options.AdditionalTags) > 0 {
+ return errors.Errorf("cannot save multiple images with multiple tags")
+ }
+ }
+
+ // Dispatch the save operations.
+ switch format {
+ case "oci-archive", "oci-dir", "docker-dir":
+ return r.saveSingleImage(ctx, names[0], format, path, options)
+
+ case "docker-archive":
+ return r.saveDockerArchive(ctx, names, path, options)
+ }
+
+ return errors.Errorf("unspported format %q for saving images", format)
+
+}
+
+// saveSingleImage saves the specified image name to the specified path.
+// Supported formats are "oci-archive", "oci-dir" and "docker-dir".
+func (r *Runtime) saveSingleImage(ctx context.Context, name, format, path string, options *SaveOptions) error {
+ image, imageName, err := r.LookupImage(name, nil)
+ if err != nil {
+ return err
+ }
+
+ // Unless the image was referenced by ID, use the resolved name as a
+ // tag.
+ var tag string
+ if !strings.HasPrefix(image.ID(), imageName) {
+ tag = imageName
+ }
+
+ srcRef, err := image.StorageReference()
+ if err != nil {
+ return err
+ }
+
+ // Prepare the destination reference.
+ var destRef types.ImageReference
+ switch format {
+ case "oci-archive":
+ destRef, err = ociArchiveTransport.NewReference(path, tag)
+
+ case "oci-dir":
+ destRef, err = ociTransport.NewReference(path, tag)
+ options.ManifestMIMEType = ociv1.MediaTypeImageManifest
+
+ case "docker-dir":
+ destRef, err = dirTransport.NewReference(path)
+ options.ManifestMIMEType = manifest.DockerV2Schema2MediaType
+
+ default:
+ return errors.Errorf("unspported format %q for saving images", format)
+ }
+
+ if err != nil {
+ return err
+ }
+
+ c, err := r.newCopier(&options.CopyOptions)
+ if err != nil {
+ return err
+ }
+ defer c.close()
+
+ _, err = c.copy(ctx, srcRef, destRef)
+ return err
+}
+
+// saveDockerArchive saves the specified images indicated by names to the path.
+// It loads all images from the local containers storage and assembles the meta
+// data needed to properly save images. Since multiple names could refer to
+// the *same* image, we need to dance a bit and store additional "names".
+// Those can then be used as additional tags when copying.
+func (r *Runtime) saveDockerArchive(ctx context.Context, names []string, path string, options *SaveOptions) error {
+ type localImage struct {
+ image *Image
+ tags []reference.NamedTagged
+ }
+
+ orderedIDs := []string{} // to preserve the relative order
+ localImages := make(map[string]*localImage) // to assemble tags
+ visitedNames := make(map[string]bool) // filters duplicate names
+ for _, name := range names {
+ // Look up local images.
+ image, imageName, err := r.LookupImage(name, nil)
+ if err != nil {
+ return err
+ }
+ // Make sure to filter duplicates purely based on the resolved
+ // name.
+ if _, exists := visitedNames[imageName]; exists {
+ continue
+ }
+ visitedNames[imageName] = true
+ // Extract and assemble the data.
+ local, exists := localImages[image.ID()]
+ if !exists {
+ local = &localImage{image: image}
+ orderedIDs = append(orderedIDs, image.ID())
+ }
+ // Add the tag if the locally resolved name is properly tagged
+ // (which it should unless we looked it up by ID).
+ named, err := reference.ParseNamed(imageName)
+ if err == nil {
+ tagged, withTag := named.(reference.NamedTagged)
+ if withTag {
+ local.tags = append(local.tags, tagged)
+ }
+ }
+ localImages[image.ID()] = local
+ }
+
+ writer, err := dockerArchiveTransport.NewWriter(r.systemContextCopy(), path)
+ if err != nil {
+ return err
+ }
+ defer writer.Close()
+
+ for _, id := range orderedIDs {
+ local, exists := localImages[id]
+ if !exists {
+ return errors.Errorf("internal error: saveDockerArchive: ID %s not found in local map", id)
+ }
+
+ copyOpts := options.CopyOptions
+ copyOpts.dockerArchiveAdditionalTags = local.tags
+
+ c, err := r.newCopier(&copyOpts)
+ if err != nil {
+ return err
+ }
+ defer c.close()
+
+ destRef, err := writer.NewReference(nil)
+ if err != nil {
+ return err
+ }
+
+ srcRef, err := local.image.StorageReference()
+ if err != nil {
+ return err
+ }
+
+ if _, err := c.copy(ctx, srcRef, destRef); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/containers/common/libimage/search.go b/vendor/github.com/containers/common/libimage/search.go
new file mode 100644
index 000000000..b36b6d2a3
--- /dev/null
+++ b/vendor/github.com/containers/common/libimage/search.go
@@ -0,0 +1,307 @@
+package libimage
+
+import (
+ "context"
+ "fmt"
+ "strconv"
+ "strings"
+ "sync"
+
+ dockerTransport "github.com/containers/image/v5/docker"
+ "github.com/containers/image/v5/pkg/sysregistriesv2"
+ "github.com/containers/image/v5/transports/alltransports"
+ "github.com/containers/image/v5/types"
+ "github.com/hashicorp/go-multierror"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+ "golang.org/x/sync/semaphore"
+)
+
+const (
+ searchTruncLength = 44
+ searchMaxQueries = 25
+ // Let's follow Firefox by limiting parallel downloads to 6. We do the
+ // same when pulling images in c/image.
+ searchMaxParallel = int64(6)
+)
+
+// SearchResult is holding image-search related data.
+type SearchResult struct {
+ // Index is the image index (e.g., "docker.io" or "quay.io")
+ Index string
+ // Name is the canonical name of the image (e.g., "docker.io/library/alpine").
+ Name string
+ // Description of the image.
+ Description string
+ // Stars is the number of stars of the image.
+ Stars int
+ // Official indicates if it's an official image.
+ Official string
+ // Automated indicates if the image was created by an automated build.
+ Automated string
+ // Tag is the image tag
+ Tag string
+}
+
+// SearchOptions customize searching images.
+type SearchOptions struct {
+ // Filter allows to filter the results.
+ Filter SearchFilter
+ // Limit limits the number of queries per index (default: 25). Must be
+ // greater than 0 to overwrite the default value.
+ Limit int
+ // NoTrunc avoids the output to be truncated.
+ NoTrunc bool
+ // Authfile is the path to the authentication file.
+ Authfile string
+ // InsecureSkipTLSVerify allows to skip TLS verification.
+ InsecureSkipTLSVerify types.OptionalBool
+ // ListTags returns the search result with available tags
+ ListTags bool
+}
+
+// SearchFilter allows filtering images while searching.
+type SearchFilter struct {
+ // Stars describes the minimal amount of starts of an image.
+ Stars int
+ // IsAutomated decides if only images from automated builds are displayed.
+ IsAutomated types.OptionalBool
+ // IsOfficial decides if only official images are displayed.
+ IsOfficial types.OptionalBool
+}
+
+// ParseSearchFilter turns the filter into a SearchFilter that can be used for
+// searching images.
+func ParseSearchFilter(filter []string) (*SearchFilter, error) {
+ sFilter := new(SearchFilter)
+ for _, f := range filter {
+ arr := strings.SplitN(f, "=", 2)
+ switch arr[0] {
+ case "stars":
+ if len(arr) < 2 {
+ return nil, errors.Errorf("invalid `stars` filter %q, should be stars=<value>", filter)
+ }
+ stars, err := strconv.Atoi(arr[1])
+ if err != nil {
+ return nil, errors.Wrapf(err, "incorrect value type for stars filter")
+ }
+ sFilter.Stars = stars
+ case "is-automated":
+ if len(arr) == 2 && arr[1] == "false" {
+ sFilter.IsAutomated = types.OptionalBoolFalse
+ } else {
+ sFilter.IsAutomated = types.OptionalBoolTrue
+ }
+ case "is-official":
+ if len(arr) == 2 && arr[1] == "false" {
+ sFilter.IsOfficial = types.OptionalBoolFalse
+ } else {
+ sFilter.IsOfficial = types.OptionalBoolTrue
+ }
+ default:
+ return nil, errors.Errorf("invalid filter type %q", f)
+ }
+ }
+ return sFilter, nil
+}
+
+func (r *Runtime) Search(ctx context.Context, term string, options *SearchOptions) ([]SearchResult, error) {
+ if options == nil {
+ options = &SearchOptions{}
+ }
+
+ var searchRegistries []string
+
+ // Try to extract a registry from the specified search term. We
+ // consider everything before the first slash to be the registry. Note
+ // that we cannot use the reference parser from the containers/image
+ // library as the search term may container arbitrary input such as
+ // wildcards. See bugzilla.redhat.com/show_bug.cgi?id=1846629.
+ if spl := strings.SplitN(term, "/", 2); len(spl) > 1 {
+ searchRegistries = append(searchRegistries, spl[0])
+ term = spl[1]
+ } else {
+ regs, err := sysregistriesv2.UnqualifiedSearchRegistries(r.systemContextCopy())
+ if err != nil {
+ return nil, err
+ }
+ searchRegistries = regs
+ }
+
+ logrus.Debugf("Searching images matching term %s at the following registries %s", term, searchRegistries)
+
+ // searchOutputData is used as a return value for searching in parallel.
+ type searchOutputData struct {
+ data []SearchResult
+ err error
+ }
+
+ sem := semaphore.NewWeighted(searchMaxParallel)
+ wg := sync.WaitGroup{}
+ wg.Add(len(searchRegistries))
+ data := make([]searchOutputData, len(searchRegistries))
+
+ for i := range searchRegistries {
+ if err := sem.Acquire(ctx, 1); err != nil {
+ return nil, err
+ }
+ index := i
+ go func() {
+ defer sem.Release(1)
+ defer wg.Done()
+ searchOutput, err := r.searchImageInRegistry(ctx, term, searchRegistries[index], options)
+ data[index] = searchOutputData{data: searchOutput, err: err}
+ }()
+ }
+
+ wg.Wait()
+ results := []SearchResult{}
+ var multiErr error
+ for _, d := range data {
+ if d.err != nil {
+ multiErr = multierror.Append(multiErr, d.err)
+ continue
+ }
+ results = append(results, d.data...)
+ }
+
+ // Optimistically assume that one successfully searched registry
+ // includes what the user is looking for.
+ if len(results) > 0 {
+ return results, nil
+ }
+ return results, multiErr
+}
+
+func (r *Runtime) searchImageInRegistry(ctx context.Context, term, registry string, options *SearchOptions) ([]SearchResult, error) {
+ // Max number of queries by default is 25
+ limit := searchMaxQueries
+ if options.Limit > 0 {
+ limit = options.Limit
+ }
+
+ sys := r.systemContextCopy()
+ if options.InsecureSkipTLSVerify != types.OptionalBoolUndefined {
+ sys.DockerInsecureSkipTLSVerify = options.InsecureSkipTLSVerify
+ }
+
+ if options.ListTags {
+ results, err := searchRepositoryTags(ctx, sys, registry, term, options)
+ if err != nil {
+ return []SearchResult{}, err
+ }
+ return results, nil
+ }
+
+ results, err := dockerTransport.SearchRegistry(ctx, sys, registry, term, limit)
+ if err != nil {
+ return []SearchResult{}, err
+ }
+ index := registry
+ arr := strings.Split(registry, ".")
+ if len(arr) > 2 {
+ index = strings.Join(arr[len(arr)-2:], ".")
+ }
+
+ // limit is the number of results to output
+ // if the total number of results is less than the limit, output all
+ // if the limit has been set by the user, output those number of queries
+ limit = searchMaxQueries
+ if len(results) < limit {
+ limit = len(results)
+ }
+ if options.Limit != 0 {
+ limit = len(results)
+ if options.Limit < len(results) {
+ limit = options.Limit
+ }
+ }
+
+ paramsArr := []SearchResult{}
+ for i := 0; i < limit; i++ {
+ // Check whether query matches filters
+ if !(options.Filter.matchesAutomatedFilter(results[i]) && options.Filter.matchesOfficialFilter(results[i]) && options.Filter.matchesStarFilter(results[i])) {
+ continue
+ }
+ official := ""
+ if results[i].IsOfficial {
+ official = "[OK]"
+ }
+ automated := ""
+ if results[i].IsAutomated {
+ automated = "[OK]"
+ }
+ description := strings.ReplaceAll(results[i].Description, "\n", " ")
+ if len(description) > 44 && !options.NoTrunc {
+ description = description[:searchTruncLength] + "..."
+ }
+ name := registry + "/" + results[i].Name
+ if index == "docker.io" && !strings.Contains(results[i].Name, "/") {
+ name = index + "/library/" + results[i].Name
+ }
+ params := SearchResult{
+ Index: index,
+ Name: name,
+ Description: description,
+ Official: official,
+ Automated: automated,
+ Stars: results[i].StarCount,
+ }
+ paramsArr = append(paramsArr, params)
+ }
+ return paramsArr, nil
+}
+
+func searchRepositoryTags(ctx context.Context, sys *types.SystemContext, registry, term string, options *SearchOptions) ([]SearchResult, error) {
+ dockerPrefix := "docker://"
+ imageRef, err := alltransports.ParseImageName(fmt.Sprintf("%s/%s", registry, term))
+ if err == nil && imageRef.Transport().Name() != dockerTransport.Transport.Name() {
+ return nil, errors.Errorf("reference %q must be a docker reference", term)
+ } else if err != nil {
+ imageRef, err = alltransports.ParseImageName(fmt.Sprintf("%s%s", dockerPrefix, fmt.Sprintf("%s/%s", registry, term)))
+ if err != nil {
+ return nil, errors.Errorf("reference %q must be a docker reference", term)
+ }
+ }
+ tags, err := dockerTransport.GetRepositoryTags(ctx, sys, imageRef)
+ if err != nil {
+ return nil, errors.Errorf("error getting repository tags: %v", err)
+ }
+ limit := searchMaxQueries
+ if len(tags) < limit {
+ limit = len(tags)
+ }
+ if options.Limit != 0 {
+ limit = len(tags)
+ if options.Limit < limit {
+ limit = options.Limit
+ }
+ }
+ paramsArr := []SearchResult{}
+ for i := 0; i < limit; i++ {
+ params := SearchResult{
+ Name: imageRef.DockerReference().Name(),
+ Tag: tags[i],
+ }
+ paramsArr = append(paramsArr, params)
+ }
+ return paramsArr, nil
+}
+
+func (f *SearchFilter) matchesStarFilter(result dockerTransport.SearchResult) bool {
+ return result.StarCount >= f.Stars
+}
+
+func (f *SearchFilter) matchesAutomatedFilter(result dockerTransport.SearchResult) bool {
+ if f.IsAutomated != types.OptionalBoolUndefined {
+ return result.IsAutomated == (f.IsAutomated == types.OptionalBoolTrue)
+ }
+ return true
+}
+
+func (f *SearchFilter) matchesOfficialFilter(result dockerTransport.SearchResult) bool {
+ if f.IsOfficial != types.OptionalBoolUndefined {
+ return result.IsOfficial == (f.IsOfficial == types.OptionalBoolTrue)
+ }
+ return true
+}
diff --git a/vendor/github.com/containers/common/pkg/config/config.go b/vendor/github.com/containers/common/pkg/config/config.go
index 1531422cd..371dd3667 100644
--- a/vendor/github.com/containers/common/pkg/config/config.go
+++ b/vendor/github.com/containers/common/pkg/config/config.go
@@ -47,18 +47,6 @@ const (
BoltDBStateStore RuntimeStateStore = iota
)
-// PullPolicy whether to pull new image
-type PullPolicy int
-
-const (
- // PullImageAlways always try to pull new image when create or run
- PullImageAlways PullPolicy = iota
- // PullImageMissing pulls image if it is not locally
- PullImageMissing
- // PullImageNever will never pull new image
- PullImageNever
-)
-
// Config contains configuration options for container tools
type Config struct {
// Containers specify settings that configure how containers will run ont the system
@@ -700,23 +688,6 @@ func (c *NetworkConfig) Validate() error {
return errors.Errorf("invalid cni_plugin_dirs: %s", strings.Join(c.CNIPluginDirs, ","))
}
-// ValidatePullPolicy check if the pullPolicy from CLI is valid and returns the valid enum type
-// if the value from CLI or containers.conf is invalid returns the error
-func ValidatePullPolicy(pullPolicy string) (PullPolicy, error) {
- switch strings.ToLower(pullPolicy) {
- case "always":
- return PullImageAlways, nil
- case "missing", "ifnotpresent":
- return PullImageMissing, nil
- case "never":
- return PullImageNever, nil
- case "":
- return PullImageMissing, nil
- default:
- return PullImageMissing, errors.Errorf("invalid pull policy %q", pullPolicy)
- }
-}
-
// FindConmon iterates over (*Config).ConmonPath and returns the path
// to first (version) matching conmon binary. If non is found, we try
// to do a path lookup of "conmon".
diff --git a/vendor/github.com/containers/common/pkg/config/pull_policy.go b/vendor/github.com/containers/common/pkg/config/pull_policy.go
new file mode 100644
index 000000000..7c32dd660
--- /dev/null
+++ b/vendor/github.com/containers/common/pkg/config/pull_policy.go
@@ -0,0 +1,95 @@
+package config
+
+import (
+ "fmt"
+
+ "github.com/pkg/errors"
+)
+
+// PullPolicy determines how and which images are being pulled from a container
+// registry (i.e., docker transport only).
+//
+// Supported string values are:
+// * "always" <-> PullPolicyAlways
+// * "missing" <-> PullPolicyMissing
+// * "newer" <-> PullPolicyNewer
+// * "never" <-> PullPolicyNever
+type PullPolicy int
+
+const (
+ // Always pull the image.
+ PullPolicyAlways PullPolicy = iota
+ // Pull the image only if it could not be found in the local containers
+ // storage.
+ PullPolicyMissing
+ // Never pull the image but use the one from the local containers
+ // storage.
+ PullPolicyNever
+ // Pull if the image on the registry is new than the one in the local
+ // containers storage. An image is considered to be newer when the
+ // digests are different. Comparing the time stamps is prone to
+ // errors.
+ PullPolicyNewer
+
+ // Ideally this should be the first `ioata` but backwards compatibility
+ // prevents us from changing the values.
+ PullPolicyUnsupported = -1
+)
+
+// String converts a PullPolicy into a string.
+//
+// Supported string values are:
+// * "always" <-> PullPolicyAlways
+// * "missing" <-> PullPolicyMissing
+// * "newer" <-> PullPolicyNewer
+// * "never" <-> PullPolicyNever
+func (p PullPolicy) String() string {
+ switch p {
+ case PullPolicyAlways:
+ return "always"
+ case PullPolicyMissing:
+ return "missing"
+ case PullPolicyNewer:
+ return "newer"
+ case PullPolicyNever:
+ return "never"
+ }
+ return fmt.Sprintf("unrecognized policy %d", p)
+}
+
+// Validate returns if the pull policy is not supported.
+func (p PullPolicy) Validate() error {
+ switch p {
+ case PullPolicyAlways, PullPolicyMissing, PullPolicyNewer, PullPolicyNever:
+ return nil
+ default:
+ return errors.Errorf("unsupported pull policy %d", p)
+ }
+}
+
+// ParsePullPolicy parses the string into a pull policy.
+//
+// Supported string values are:
+// * "always" <-> PullPolicyAlways
+// * "missing" <-> PullPolicyMissing (also "ifnotpresent" and "")
+// * "newer" <-> PullPolicyNewer (also "ifnewer")
+// * "never" <-> PullPolicyNever
+func ParsePullPolicy(s string) (PullPolicy, error) {
+ switch s {
+ case "always":
+ return PullPolicyAlways, nil
+ case "missing", "ifnotpresent", "":
+ return PullPolicyMissing, nil
+ case "newer", "ifnewer":
+ return PullPolicyNewer, nil
+ case "never":
+ return PullPolicyNever, nil
+ default:
+ return PullPolicyUnsupported, errors.Errorf("unsupported pull policy %q", s)
+ }
+}
+
+// Deprecated: please use `ParsePullPolicy` instead.
+func ValidatePullPolicy(s string) (PullPolicy, error) {
+ return ParsePullPolicy(s)
+}
diff --git a/vendor/github.com/containers/common/pkg/filters/filters.go b/vendor/github.com/containers/common/pkg/filters/filters.go
new file mode 100644
index 000000000..53f420db2
--- /dev/null
+++ b/vendor/github.com/containers/common/pkg/filters/filters.go
@@ -0,0 +1,118 @@
+package filters
+
+import (
+ "encoding/json"
+ "fmt"
+ "net/http"
+ "strings"
+ "time"
+
+ "github.com/containers/common/pkg/timetype"
+ "github.com/pkg/errors"
+)
+
+// ComputeUntilTimestamp extracts until timestamp from filters
+func ComputeUntilTimestamp(filterValues []string) (time.Time, error) {
+ invalid := time.Time{}
+ if len(filterValues) != 1 {
+ return invalid, errors.Errorf("specify exactly one timestamp for until")
+ }
+ ts, err := timetype.GetTimestamp(filterValues[0], time.Now())
+ if err != nil {
+ return invalid, err
+ }
+ seconds, nanoseconds, err := timetype.ParseTimestamps(ts, 0)
+ if err != nil {
+ return invalid, err
+ }
+ return time.Unix(seconds, nanoseconds), nil
+}
+
+// filtersFromRequests extracts the "filters" parameter from the specified
+// http.Request. The parameter can either be a `map[string][]string` as done
+// in new versions of Docker and libpod, or a `map[string]map[string]bool` as
+// done in older versions of Docker. We have to do a bit of Yoga to support
+// both - just as Docker does as well.
+//
+// Please refer to https://github.com/containers/podman/issues/6899 for some
+// background.
+func FiltersFromRequest(r *http.Request) ([]string, error) {
+ var (
+ compatFilters map[string]map[string]bool
+ filters map[string][]string
+ libpodFilters []string
+ raw []byte
+ )
+
+ if _, found := r.URL.Query()["filters"]; found {
+ raw = []byte(r.Form.Get("filters"))
+ } else if _, found := r.URL.Query()["Filters"]; found {
+ raw = []byte(r.Form.Get("Filters"))
+ } else {
+ return []string{}, nil
+ }
+
+ // Backwards compat with older versions of Docker.
+ if err := json.Unmarshal(raw, &compatFilters); err == nil {
+ for filterKey, filterMap := range compatFilters {
+ for filterValue, toAdd := range filterMap {
+ if toAdd {
+ libpodFilters = append(libpodFilters, fmt.Sprintf("%s=%s", filterKey, filterValue))
+ }
+ }
+ }
+ return libpodFilters, nil
+ }
+
+ if err := json.Unmarshal(raw, &filters); err != nil {
+ return nil, err
+ }
+
+ for filterKey, filterSlice := range filters {
+ f := filterKey
+ for _, filterValue := range filterSlice {
+ f += "=" + filterValue
+ }
+ libpodFilters = append(libpodFilters, f)
+ }
+
+ return libpodFilters, nil
+}
+
+// PrepareFilters prepares a *map[string][]string of filters to be later searched
+// in lipod and compat API to get desired filters
+func PrepareFilters(r *http.Request) (map[string][]string, error) {
+ filtersList, err := FiltersFromRequest(r)
+ if err != nil {
+ return nil, err
+ }
+ filterMap := map[string][]string{}
+ for _, filter := range filtersList {
+ split := strings.SplitN(filter, "=", 2)
+ if len(split) > 1 {
+ filterMap[split[0]] = append(filterMap[split[0]], split[1])
+ }
+ }
+ return filterMap, nil
+}
+
+// MatchLabelFilters matches labels and returs true if they are valid
+func MatchLabelFilters(filterValues []string, labels map[string]string) bool {
+outer:
+ for _, filterValue := range filterValues {
+ filterArray := strings.SplitN(filterValue, "=", 2)
+ filterKey := filterArray[0]
+ if len(filterArray) > 1 {
+ filterValue = filterArray[1]
+ } else {
+ filterValue = ""
+ }
+ for labelKey, labelValue := range labels {
+ if labelKey == filterKey && (filterValue == "" || labelValue == filterValue) {
+ continue outer
+ }
+ }
+ return false
+ }
+ return true
+}
diff --git a/vendor/github.com/containers/buildah/pkg/manifests/errors.go b/vendor/github.com/containers/common/pkg/manifests/errors.go
index 8398d7efc..8398d7efc 100644
--- a/vendor/github.com/containers/buildah/pkg/manifests/errors.go
+++ b/vendor/github.com/containers/common/pkg/manifests/errors.go
diff --git a/vendor/github.com/containers/buildah/pkg/manifests/manifests.go b/vendor/github.com/containers/common/pkg/manifests/manifests.go
index ea9495ee7..ea9495ee7 100644
--- a/vendor/github.com/containers/buildah/pkg/manifests/manifests.go
+++ b/vendor/github.com/containers/common/pkg/manifests/manifests.go
diff --git a/vendor/github.com/containers/common/pkg/signal/signal_common.go b/vendor/github.com/containers/common/pkg/signal/signal_common.go
new file mode 100644
index 000000000..7c2662909
--- /dev/null
+++ b/vendor/github.com/containers/common/pkg/signal/signal_common.go
@@ -0,0 +1,41 @@
+package signal
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+ "syscall"
+)
+
+// ParseSignal translates a string to a valid syscall signal.
+// It returns an error if the signal map doesn't include the given signal.
+func ParseSignal(rawSignal string) (syscall.Signal, error) {
+ s, err := strconv.Atoi(rawSignal)
+ if err == nil {
+ if s == 0 {
+ return -1, fmt.Errorf("invalid signal: %s", rawSignal)
+ }
+ return syscall.Signal(s), nil
+ }
+ sig, ok := signalMap[strings.TrimPrefix(strings.ToUpper(rawSignal), "SIG")]
+ if !ok {
+ return -1, fmt.Errorf("invalid signal: %s", rawSignal)
+ }
+ return sig, nil
+}
+
+// ParseSignalNameOrNumber translates a string to a valid syscall signal. Input
+// can be a name or number representation i.e. "KILL" "9"
+func ParseSignalNameOrNumber(rawSignal string) (syscall.Signal, error) {
+ basename := strings.TrimPrefix(rawSignal, "-")
+ s, err := ParseSignal(basename)
+ if err == nil {
+ return s, nil
+ }
+ for k, v := range signalMap {
+ if strings.EqualFold(k, basename) {
+ return v, nil
+ }
+ }
+ return -1, fmt.Errorf("invalid signal: %s", basename)
+}
diff --git a/vendor/github.com/containers/common/pkg/signal/signal_linux.go b/vendor/github.com/containers/common/pkg/signal/signal_linux.go
new file mode 100644
index 000000000..305b9d21f
--- /dev/null
+++ b/vendor/github.com/containers/common/pkg/signal/signal_linux.go
@@ -0,0 +1,108 @@
+// +build linux
+// +build !mips,!mipsle,!mips64,!mips64le
+
+// Signal handling for Linux only.
+package signal
+
+// Copyright 2013-2018 Docker, Inc.
+
+// NOTE: this package has originally been copied from github.com/docker/docker.
+
+import (
+ "os"
+ "os/signal"
+ "syscall"
+
+ "golang.org/x/sys/unix"
+)
+
+const (
+ sigrtmin = 34
+ sigrtmax = 64
+
+ SIGWINCH = syscall.SIGWINCH // For cross-compilation with Windows
+)
+
+// signalMap is a map of Linux signals.
+var signalMap = map[string]syscall.Signal{
+ "ABRT": unix.SIGABRT,
+ "ALRM": unix.SIGALRM,
+ "BUS": unix.SIGBUS,
+ "CHLD": unix.SIGCHLD,
+ "CLD": unix.SIGCLD,
+ "CONT": unix.SIGCONT,
+ "FPE": unix.SIGFPE,
+ "HUP": unix.SIGHUP,
+ "ILL": unix.SIGILL,
+ "INT": unix.SIGINT,
+ "IO": unix.SIGIO,
+ "IOT": unix.SIGIOT,
+ "KILL": unix.SIGKILL,
+ "PIPE": unix.SIGPIPE,
+ "POLL": unix.SIGPOLL,
+ "PROF": unix.SIGPROF,
+ "PWR": unix.SIGPWR,
+ "QUIT": unix.SIGQUIT,
+ "SEGV": unix.SIGSEGV,
+ "STKFLT": unix.SIGSTKFLT,
+ "STOP": unix.SIGSTOP,
+ "SYS": unix.SIGSYS,
+ "TERM": unix.SIGTERM,
+ "TRAP": unix.SIGTRAP,
+ "TSTP": unix.SIGTSTP,
+ "TTIN": unix.SIGTTIN,
+ "TTOU": unix.SIGTTOU,
+ "URG": unix.SIGURG,
+ "USR1": unix.SIGUSR1,
+ "USR2": unix.SIGUSR2,
+ "VTALRM": unix.SIGVTALRM,
+ "WINCH": unix.SIGWINCH,
+ "XCPU": unix.SIGXCPU,
+ "XFSZ": unix.SIGXFSZ,
+ "RTMIN": sigrtmin,
+ "RTMIN+1": sigrtmin + 1,
+ "RTMIN+2": sigrtmin + 2,
+ "RTMIN+3": sigrtmin + 3,
+ "RTMIN+4": sigrtmin + 4,
+ "RTMIN+5": sigrtmin + 5,
+ "RTMIN+6": sigrtmin + 6,
+ "RTMIN+7": sigrtmin + 7,
+ "RTMIN+8": sigrtmin + 8,
+ "RTMIN+9": sigrtmin + 9,
+ "RTMIN+10": sigrtmin + 10,
+ "RTMIN+11": sigrtmin + 11,
+ "RTMIN+12": sigrtmin + 12,
+ "RTMIN+13": sigrtmin + 13,
+ "RTMIN+14": sigrtmin + 14,
+ "RTMIN+15": sigrtmin + 15,
+ "RTMAX-14": sigrtmax - 14,
+ "RTMAX-13": sigrtmax - 13,
+ "RTMAX-12": sigrtmax - 12,
+ "RTMAX-11": sigrtmax - 11,
+ "RTMAX-10": sigrtmax - 10,
+ "RTMAX-9": sigrtmax - 9,
+ "RTMAX-8": sigrtmax - 8,
+ "RTMAX-7": sigrtmax - 7,
+ "RTMAX-6": sigrtmax - 6,
+ "RTMAX-5": sigrtmax - 5,
+ "RTMAX-4": sigrtmax - 4,
+ "RTMAX-3": sigrtmax - 3,
+ "RTMAX-2": sigrtmax - 2,
+ "RTMAX-1": sigrtmax - 1,
+ "RTMAX": sigrtmax,
+}
+
+// CatchAll catches all signals and relays them to the specified channel.
+func CatchAll(sigc chan os.Signal) {
+ handledSigs := make([]os.Signal, 0, len(signalMap))
+ for _, s := range signalMap {
+ handledSigs = append(handledSigs, s)
+ }
+ signal.Notify(sigc, handledSigs...)
+}
+
+// StopCatch stops catching the signals and closes the specified channel.
+func StopCatch(sigc chan os.Signal) {
+ signal.Stop(sigc)
+ close(sigc)
+}
diff --git a/vendor/github.com/containers/common/pkg/signal/signal_linux_mipsx.go b/vendor/github.com/containers/common/pkg/signal/signal_linux_mipsx.go
new file mode 100644
index 000000000..45c9d5af1
--- /dev/null
+++ b/vendor/github.com/containers/common/pkg/signal/signal_linux_mipsx.go
@@ -0,0 +1,108 @@
+// +build linux
+// +build mips mipsle mips64 mips64le
+
+// Special signal handling for mips architecture
+package signal
+
+// Copyright 2013-2018 Docker, Inc.
+
+// NOTE: this package has originally been copied from github.com/docker/docker.
+
+import (
+ "os"
+ "os/signal"
+ "syscall"
+
+ "golang.org/x/sys/unix"
+)
+
+const (
+ sigrtmin = 34
+ sigrtmax = 127
+
+ SIGWINCH = syscall.SIGWINCH
+)
+
+// signalMap is a map of Linux signals.
+var signalMap = map[string]syscall.Signal{
+ "ABRT": unix.SIGABRT,
+ "ALRM": unix.SIGALRM,
+ "BUS": unix.SIGBUS,
+ "CHLD": unix.SIGCHLD,
+ "CLD": unix.SIGCLD,
+ "CONT": unix.SIGCONT,
+ "FPE": unix.SIGFPE,
+ "HUP": unix.SIGHUP,
+ "ILL": unix.SIGILL,
+ "INT": unix.SIGINT,
+ "IO": unix.SIGIO,
+ "IOT": unix.SIGIOT,
+ "KILL": unix.SIGKILL,
+ "PIPE": unix.SIGPIPE,
+ "POLL": unix.SIGPOLL,
+ "PROF": unix.SIGPROF,
+ "PWR": unix.SIGPWR,
+ "QUIT": unix.SIGQUIT,
+ "SEGV": unix.SIGSEGV,
+ "EMT": unix.SIGEMT,
+ "STOP": unix.SIGSTOP,
+ "SYS": unix.SIGSYS,
+ "TERM": unix.SIGTERM,
+ "TRAP": unix.SIGTRAP,
+ "TSTP": unix.SIGTSTP,
+ "TTIN": unix.SIGTTIN,
+ "TTOU": unix.SIGTTOU,
+ "URG": unix.SIGURG,
+ "USR1": unix.SIGUSR1,
+ "USR2": unix.SIGUSR2,
+ "VTALRM": unix.SIGVTALRM,
+ "WINCH": unix.SIGWINCH,
+ "XCPU": unix.SIGXCPU,
+ "XFSZ": unix.SIGXFSZ,
+ "RTMIN": sigrtmin,
+ "RTMIN+1": sigrtmin + 1,
+ "RTMIN+2": sigrtmin + 2,
+ "RTMIN+3": sigrtmin + 3,
+ "RTMIN+4": sigrtmin + 4,
+ "RTMIN+5": sigrtmin + 5,
+ "RTMIN+6": sigrtmin + 6,
+ "RTMIN+7": sigrtmin + 7,
+ "RTMIN+8": sigrtmin + 8,
+ "RTMIN+9": sigrtmin + 9,
+ "RTMIN+10": sigrtmin + 10,
+ "RTMIN+11": sigrtmin + 11,
+ "RTMIN+12": sigrtmin + 12,
+ "RTMIN+13": sigrtmin + 13,
+ "RTMIN+14": sigrtmin + 14,
+ "RTMIN+15": sigrtmin + 15,
+ "RTMAX-14": sigrtmax - 14,
+ "RTMAX-13": sigrtmax - 13,
+ "RTMAX-12": sigrtmax - 12,
+ "RTMAX-11": sigrtmax - 11,
+ "RTMAX-10": sigrtmax - 10,
+ "RTMAX-9": sigrtmax - 9,
+ "RTMAX-8": sigrtmax - 8,
+ "RTMAX-7": sigrtmax - 7,
+ "RTMAX-6": sigrtmax - 6,
+ "RTMAX-5": sigrtmax - 5,
+ "RTMAX-4": sigrtmax - 4,
+ "RTMAX-3": sigrtmax - 3,
+ "RTMAX-2": sigrtmax - 2,
+ "RTMAX-1": sigrtmax - 1,
+ "RTMAX": sigrtmax,
+}
+
+// CatchAll catches all signals and relays them to the specified channel.
+func CatchAll(sigc chan os.Signal) {
+ handledSigs := make([]os.Signal, 0, len(signalMap))
+ for _, s := range signalMap {
+ handledSigs = append(handledSigs, s)
+ }
+ signal.Notify(sigc, handledSigs...)
+}
+
+// StopCatch stops catching the signals and closes the specified channel.
+func StopCatch(sigc chan os.Signal) {
+ signal.Stop(sigc)
+ close(sigc)
+}
diff --git a/vendor/github.com/containers/common/pkg/signal/signal_unsupported.go b/vendor/github.com/containers/common/pkg/signal/signal_unsupported.go
new file mode 100644
index 000000000..9d1733c02
--- /dev/null
+++ b/vendor/github.com/containers/common/pkg/signal/signal_unsupported.go
@@ -0,0 +1,99 @@
+// +build !linux
+
+// Signal handling for Linux only.
+package signal
+
+import (
+ "os"
+ "syscall"
+)
+
+const (
+ sigrtmin = 34
+ sigrtmax = 64
+
+ SIGWINCH = syscall.Signal(0xff)
+)
+
+// signalMap is a map of Linux signals.
+// These constants are sourced from the Linux version of golang.org/x/sys/unix
+// (I don't see much risk of this changing).
+// This should work as long as Podman only runs containers on Linux, which seems
+// a safe assumption for now.
+var signalMap = map[string]syscall.Signal{
+ "ABRT": syscall.Signal(0x6),
+ "ALRM": syscall.Signal(0xe),
+ "BUS": syscall.Signal(0x7),
+ "CHLD": syscall.Signal(0x11),
+ "CLD": syscall.Signal(0x11),
+ "CONT": syscall.Signal(0x12),
+ "FPE": syscall.Signal(0x8),
+ "HUP": syscall.Signal(0x1),
+ "ILL": syscall.Signal(0x4),
+ "INT": syscall.Signal(0x2),
+ "IO": syscall.Signal(0x1d),
+ "IOT": syscall.Signal(0x6),
+ "KILL": syscall.Signal(0x9),
+ "PIPE": syscall.Signal(0xd),
+ "POLL": syscall.Signal(0x1d),
+ "PROF": syscall.Signal(0x1b),
+ "PWR": syscall.Signal(0x1e),
+ "QUIT": syscall.Signal(0x3),
+ "SEGV": syscall.Signal(0xb),
+ "STKFLT": syscall.Signal(0x10),
+ "STOP": syscall.Signal(0x13),
+ "SYS": syscall.Signal(0x1f),
+ "TERM": syscall.Signal(0xf),
+ "TRAP": syscall.Signal(0x5),
+ "TSTP": syscall.Signal(0x14),
+ "TTIN": syscall.Signal(0x15),
+ "TTOU": syscall.Signal(0x16),
+ "URG": syscall.Signal(0x17),
+ "USR1": syscall.Signal(0xa),
+ "USR2": syscall.Signal(0xc),
+ "VTALRM": syscall.Signal(0x1a),
+ "WINCH": syscall.Signal(0x1c),
+ "XCPU": syscall.Signal(0x18),
+ "XFSZ": syscall.Signal(0x19),
+ "RTMIN": sigrtmin,
+ "RTMIN+1": sigrtmin + 1,
+ "RTMIN+2": sigrtmin + 2,
+ "RTMIN+3": sigrtmin + 3,
+ "RTMIN+4": sigrtmin + 4,
+ "RTMIN+5": sigrtmin + 5,
+ "RTMIN+6": sigrtmin + 6,
+ "RTMIN+7": sigrtmin + 7,
+ "RTMIN+8": sigrtmin + 8,
+ "RTMIN+9": sigrtmin + 9,
+ "RTMIN+10": sigrtmin + 10,
+ "RTMIN+11": sigrtmin + 11,
+ "RTMIN+12": sigrtmin + 12,
+ "RTMIN+13": sigrtmin + 13,
+ "RTMIN+14": sigrtmin + 14,
+ "RTMIN+15": sigrtmin + 15,
+ "RTMAX-14": sigrtmax - 14,
+ "RTMAX-13": sigrtmax - 13,
+ "RTMAX-12": sigrtmax - 12,
+ "RTMAX-11": sigrtmax - 11,
+ "RTMAX-10": sigrtmax - 10,
+ "RTMAX-9": sigrtmax - 9,
+ "RTMAX-8": sigrtmax - 8,
+ "RTMAX-7": sigrtmax - 7,
+ "RTMAX-6": sigrtmax - 6,
+ "RTMAX-5": sigrtmax - 5,
+ "RTMAX-4": sigrtmax - 4,
+ "RTMAX-3": sigrtmax - 3,
+ "RTMAX-2": sigrtmax - 2,
+ "RTMAX-1": sigrtmax - 1,
+ "RTMAX": sigrtmax,
+}
+
+// CatchAll catches all signals and relays them to the specified channel.
+func CatchAll(sigc chan os.Signal) {
+ panic("Unsupported on non-linux platforms")
+}
+
+// StopCatch stops catching the signals and closes the specified channel.
+func StopCatch(sigc chan os.Signal) {
+ panic("Unsupported on non-linux platforms")
+}
diff --git a/vendor/github.com/containers/buildah/pkg/supplemented/errors.go b/vendor/github.com/containers/common/pkg/supplemented/errors.go
index 6de679b50..a031951f1 100644
--- a/vendor/github.com/containers/buildah/pkg/supplemented/errors.go
+++ b/vendor/github.com/containers/common/pkg/supplemented/errors.go
@@ -3,7 +3,7 @@ package supplemented
import (
"errors"
- "github.com/containers/buildah/pkg/manifests"
+ "github.com/containers/common/pkg/manifests"
)
var (
diff --git a/vendor/github.com/containers/buildah/pkg/supplemented/supplemented.go b/vendor/github.com/containers/common/pkg/supplemented/supplemented.go
index a36c3eda4..a36c3eda4 100644
--- a/vendor/github.com/containers/buildah/pkg/supplemented/supplemented.go
+++ b/vendor/github.com/containers/common/pkg/supplemented/supplemented.go
diff --git a/vendor/github.com/containers/common/pkg/timetype/timestamp.go b/vendor/github.com/containers/common/pkg/timetype/timestamp.go
new file mode 100644
index 000000000..ce2cb64f2
--- /dev/null
+++ b/vendor/github.com/containers/common/pkg/timetype/timestamp.go
@@ -0,0 +1,131 @@
+package timetype
+
+// code adapted from https://github.com/moby/moby/blob/master/api/types/time/timestamp.go
+
+import (
+ "fmt"
+ "math"
+ "strconv"
+ "strings"
+ "time"
+)
+
+// These are additional predefined layouts for use in Time.Format and Time.Parse
+// with --since and --until parameters for `docker logs` and `docker events`
+const (
+ rFC3339Local = "2006-01-02T15:04:05" // RFC3339 with local timezone
+ rFC3339NanoLocal = "2006-01-02T15:04:05.999999999" // RFC3339Nano with local timezone
+ dateWithZone = "2006-01-02Z07:00" // RFC3339 with time at 00:00:00
+ dateLocal = "2006-01-02" // RFC3339 with local timezone and time at 00:00:00
+)
+
+// GetTimestamp tries to parse given string as golang duration,
+// then RFC3339 time and finally as a Unix timestamp. If
+// any of these were successful, it returns a Unix timestamp
+// as string otherwise returns the given value back.
+// In case of duration input, the returned timestamp is computed
+// as the given reference time minus the amount of the duration.
+func GetTimestamp(value string, reference time.Time) (string, error) {
+ if d, err := time.ParseDuration(value); value != "0" && err == nil {
+ return strconv.FormatInt(reference.Add(-d).Unix(), 10), nil
+ }
+
+ var format string
+ // if the string has a Z or a + or three dashes use parse otherwise use parseinlocation
+ parseInLocation := !(strings.ContainsAny(value, "zZ+") || strings.Count(value, "-") == 3)
+
+ if strings.Contains(value, ".") { // nolint:gocritic
+ if parseInLocation {
+ format = rFC3339NanoLocal
+ } else {
+ format = time.RFC3339Nano
+ }
+ } else if strings.Contains(value, "T") {
+ // we want the number of colons in the T portion of the timestamp
+ tcolons := strings.Count(value, ":")
+ // if parseInLocation is off and we have a +/- zone offset (not Z) then
+ // there will be an extra colon in the input for the tz offset subtract that
+ // colon from the tcolons count
+ if !parseInLocation && !strings.ContainsAny(value, "zZ") && tcolons > 0 {
+ tcolons--
+ }
+ if parseInLocation {
+ switch tcolons {
+ case 0:
+ format = "2006-01-02T15"
+ case 1:
+ format = "2006-01-02T15:04"
+ default:
+ format = rFC3339Local
+ }
+ } else {
+ switch tcolons {
+ case 0:
+ format = "2006-01-02T15Z07:00"
+ case 1:
+ format = "2006-01-02T15:04Z07:00"
+ default:
+ format = time.RFC3339
+ }
+ }
+ } else if parseInLocation {
+ format = dateLocal
+ } else {
+ format = dateWithZone
+ }
+
+ var t time.Time
+ var err error
+
+ if parseInLocation {
+ t, err = time.ParseInLocation(format, value, time.FixedZone(reference.Zone()))
+ } else {
+ t, err = time.Parse(format, value)
+ }
+
+ if err != nil {
+ // if there is a `-` then it's an RFC3339 like timestamp
+ if strings.Contains(value, "-") {
+ return "", err // was probably an RFC3339 like timestamp but the parser failed with an error
+ }
+ if _, _, err := parseTimestamp(value); err != nil {
+ return "", fmt.Errorf("failed to parse value as time or duration: %q", value)
+ }
+ return value, nil // unix timestamp in and out case (meaning: the value passed at the command line is already in the right format for passing to the server)
+ }
+
+ return fmt.Sprintf("%d.%09d", t.Unix(), int64(t.Nanosecond())), nil
+}
+
+// ParseTimestamps returns seconds and nanoseconds from a timestamp that has the
+// format "%d.%09d", time.Unix(), int64(time.Nanosecond()))
+// if the incoming nanosecond portion is longer or shorter than 9 digits it is
+// converted to nanoseconds. The expectation is that the seconds and
+// seconds will be used to create a time variable. For example:
+// seconds, nanoseconds, err := ParseTimestamp("1136073600.000000001",0)
+// if err == nil since := time.Unix(seconds, nanoseconds)
+// returns seconds as def(aultSeconds) if value == ""
+func ParseTimestamps(value string, def int64) (secs, nanoSecs int64, err error) {
+ if value == "" {
+ return def, 0, nil
+ }
+ return parseTimestamp(value)
+}
+
+func parseTimestamp(value string) (int64, int64, error) { // nolint:gocritic
+ sa := strings.SplitN(value, ".", 2)
+ s, err := strconv.ParseInt(sa[0], 10, 64)
+ if err != nil {
+ return s, 0, err
+ }
+ if len(sa) != 2 {
+ return s, 0, nil
+ }
+ n, err := strconv.ParseInt(sa[1], 10, 64)
+ if err != nil {
+ return s, n, err
+ }
+ // should already be in nanoseconds but just in case convert n to nanoseconds
+ n = int64(float64(n) * math.Pow(float64(10), float64(9-len(sa[1]))))
+ return s, n, nil
+}
diff --git a/vendor/github.com/containers/common/version/version.go b/vendor/github.com/containers/common/version/version.go
index cb1eb342d..af0a1269e 100644
--- a/vendor/github.com/containers/common/version/version.go
+++ b/vendor/github.com/containers/common/version/version.go
@@ -1,4 +1,4 @@
package version
// Version is the version of the build.
-const Version = "0.37.1"
+const Version = "0.37.2-dev"
diff --git a/vendor/github.com/containers/image/v5/copy/copy.go b/vendor/github.com/containers/image/v5/copy/copy.go
index fb704283b..ed76283f9 100644
--- a/vendor/github.com/containers/image/v5/copy/copy.go
+++ b/vendor/github.com/containers/image/v5/copy/copy.go
@@ -910,7 +910,7 @@ func (ic *imageCopier) copyLayers(ctx context.Context) error {
}
data := make([]copyLayerData, numLayers)
- copyLayerHelper := func(index int, srcLayer types.BlobInfo, toEncrypt bool, pool *mpb.Progress) {
+ copyLayerHelper := func(index int, srcLayer types.BlobInfo, toEncrypt bool, pool *mpb.Progress, srcRef reference.Named) {
defer copySemaphore.Release(1)
defer copyGroup.Done()
cld := copyLayerData{}
@@ -925,7 +925,7 @@ func (ic *imageCopier) copyLayers(ctx context.Context) error {
logrus.Debugf("Skipping foreign layer %q copy to %s", cld.destInfo.Digest, ic.c.dest.Reference().Transport().Name())
}
} else {
- cld.destInfo, cld.diffID, cld.err = ic.copyLayer(ctx, srcLayer, toEncrypt, pool, index)
+ cld.destInfo, cld.diffID, cld.err = ic.copyLayer(ctx, srcLayer, toEncrypt, pool, index, srcRef)
}
data[index] = cld
}
@@ -962,7 +962,7 @@ func (ic *imageCopier) copyLayers(ctx context.Context) error {
return errors.Wrapf(err, "Can't acquire semaphore")
}
copyGroup.Add(1)
- go copyLayerHelper(i, srcLayer, encLayerBitmap[i], progressPool)
+ go copyLayerHelper(i, srcLayer, encLayerBitmap[i], progressPool, ic.c.rawSource.Reference().DockerReference())
}
// A call to copyGroup.Wait() is done at this point by the defer above.
@@ -1147,7 +1147,8 @@ type diffIDResult struct {
// copyLayer copies a layer with srcInfo (with known Digest and Annotations and possibly known Size) in src to dest, perhaps (de/re/)compressing it,
// and returns a complete blobInfo of the copied layer, and a value for LayerDiffIDs if diffIDIsNeeded
-func (ic *imageCopier) copyLayer(ctx context.Context, srcInfo types.BlobInfo, toEncrypt bool, pool *mpb.Progress, layerIndex int) (types.BlobInfo, digest.Digest, error) {
+// srcRef can be used as an additional hint to the destination during checking whehter a layer can be reused but srcRef can be nil.
+func (ic *imageCopier) copyLayer(ctx context.Context, srcInfo types.BlobInfo, toEncrypt bool, pool *mpb.Progress, layerIndex int, srcRef reference.Named) (types.BlobInfo, digest.Digest, error) {
// If the srcInfo doesn't contain compression information, try to compute it from the
// MediaType, which was either read from a manifest by way of LayerInfos() or constructed
// by LayerInfosForCopy(), if it was supplied at all. If we succeed in copying the blob,
@@ -1189,11 +1190,14 @@ func (ic *imageCopier) copyLayer(ctx context.Context, srcInfo types.BlobInfo, to
// layers which requires passing the index of the layer.
// Hence, we need to special case and cast.
dest, ok := ic.c.dest.(internalTypes.ImageDestinationWithOptions)
- if ok && enableEarlyCommit {
+ if ok {
options := internalTypes.TryReusingBlobOptions{
Cache: ic.c.blobInfoCache,
CanSubstitute: ic.canSubstituteBlobs,
- LayerIndex: &layerIndex,
+ SrcRef: srcRef,
+ }
+ if enableEarlyCommit {
+ options.LayerIndex = &layerIndex
}
reused, blobInfo, err = dest.TryReusingBlobWithOptions(ctx, srcInfo, options)
} else {
@@ -1550,12 +1554,12 @@ func (c *copier) copyBlobFromStream(ctx context.Context, srcStream io.Reader, sr
// which requires passing the index of the layer. Hence, we need to
// special case and cast.
dest, ok := c.dest.(internalTypes.ImageDestinationWithOptions)
- if ok && enableEarlyCommit {
+ if ok {
options := internalTypes.PutBlobOptions{
Cache: c.blobInfoCache,
IsConfig: isConfig,
}
- if !isConfig {
+ if !isConfig && enableEarlyCommit {
options.LayerIndex = &layerIndex
}
uploadedInfo, err = dest.PutBlobWithOptions(ctx, &errorAnnotationReader{destStream}, inputInfo, options)
diff --git a/vendor/github.com/containers/image/v5/docker/tarfile/dest.go b/vendor/github.com/containers/image/v5/docker/tarfile/dest.go
deleted file mode 100644
index 4f2465cac..000000000
--- a/vendor/github.com/containers/image/v5/docker/tarfile/dest.go
+++ /dev/null
@@ -1,119 +0,0 @@
-package tarfile
-
-import (
- "context"
- "io"
-
- internal "github.com/containers/image/v5/docker/internal/tarfile"
- "github.com/containers/image/v5/docker/reference"
- "github.com/containers/image/v5/types"
- "github.com/opencontainers/go-digest"
-)
-
-// Destination is a partial implementation of types.ImageDestination for writing to an io.Writer.
-type Destination struct {
- internal *internal.Destination
- archive *internal.Writer
-}
-
-// NewDestination returns a tarfile.Destination for the specified io.Writer.
-// Deprecated: please use NewDestinationWithContext instead
-func NewDestination(dest io.Writer, ref reference.NamedTagged) *Destination {
- return NewDestinationWithContext(nil, dest, ref)
-}
-
-// NewDestinationWithContext returns a tarfile.Destination for the specified io.Writer.
-func NewDestinationWithContext(sys *types.SystemContext, dest io.Writer, ref reference.NamedTagged) *Destination {
- archive := internal.NewWriter(dest)
- return &Destination{
- internal: internal.NewDestination(sys, archive, ref),
- archive: archive,
- }
-}
-
-// AddRepoTags adds the specified tags to the destination's repoTags.
-func (d *Destination) AddRepoTags(tags []reference.NamedTagged) {
- d.internal.AddRepoTags(tags)
-}
-
-// SupportedManifestMIMETypes tells which manifest mime types the destination supports
-// If an empty slice or nil it's returned, then any mime type can be tried to upload
-func (d *Destination) SupportedManifestMIMETypes() []string {
- return d.internal.SupportedManifestMIMETypes()
-}
-
-// SupportsSignatures returns an error (to be displayed to the user) if the destination certainly can't store signatures.
-// Note: It is still possible for PutSignatures to fail if SupportsSignatures returns nil.
-func (d *Destination) SupportsSignatures(ctx context.Context) error {
- return d.internal.SupportsSignatures(ctx)
-}
-
-// AcceptsForeignLayerURLs returns false iff foreign layers in manifest should be actually
-// uploaded to the image destination, true otherwise.
-func (d *Destination) AcceptsForeignLayerURLs() bool {
- return d.internal.AcceptsForeignLayerURLs()
-}
-
-// MustMatchRuntimeOS returns true iff the destination can store only images targeted for the current runtime architecture and OS. False otherwise.
-func (d *Destination) MustMatchRuntimeOS() bool {
- return d.internal.MustMatchRuntimeOS()
-}
-
-// IgnoresEmbeddedDockerReference returns true iff the destination does not care about Image.EmbeddedDockerReferenceConflicts(),
-// and would prefer to receive an unmodified manifest instead of one modified for the destination.
-// Does not make a difference if Reference().DockerReference() is nil.
-func (d *Destination) IgnoresEmbeddedDockerReference() bool {
- return d.internal.IgnoresEmbeddedDockerReference()
-}
-
-// HasThreadSafePutBlob indicates whether PutBlob can be executed concurrently.
-func (d *Destination) HasThreadSafePutBlob() bool {
- return d.internal.HasThreadSafePutBlob()
-}
-
-// 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.
-// May update cache.
-// WARNING: The contents of stream are being verified on the fly. Until stream.Read() returns io.EOF, the contents of the data SHOULD NOT be available
-// to any other readers for download using the supplied digest.
-// If stream.Read() at any time, ESPECIALLY at end of input, returns an error, PutBlob MUST 1) fail, and 2) delete any data stored so far.
-func (d *Destination) PutBlob(ctx context.Context, stream io.Reader, inputInfo types.BlobInfo, cache types.BlobInfoCache, isConfig bool) (types.BlobInfo, error) {
- return d.internal.PutBlob(ctx, stream, inputInfo, cache, isConfig)
-}
-
-// TryReusingBlob checks whether the transport already contains, or can efficiently reuse, a blob, and if so, applies it to the current destination
-// (e.g. if the blob is a filesystem layer, this signifies that the changes it describes need to be applied again when composing a filesystem tree).
-// info.Digest must not be empty.
-// If canSubstitute, TryReusingBlob can use an equivalent equivalent of the desired blob; in that case the returned info may not match the input.
-// If the blob has been successfully reused, returns (true, info, nil); info must contain at least a digest and size, and may
-// include CompressionOperation and CompressionAlgorithm fields to indicate that a change to the compression type should be
-// reflected in the manifest that will be written.
-// If the transport can not reuse the requested blob, TryReusingBlob returns (false, {}, nil); it returns a non-nil error only on an unexpected failure.
-// May use and/or update cache.
-func (d *Destination) TryReusingBlob(ctx context.Context, info types.BlobInfo, cache types.BlobInfoCache, canSubstitute bool) (bool, types.BlobInfo, error) {
- return d.internal.TryReusingBlob(ctx, info, cache, canSubstitute)
-}
-
-// PutManifest writes manifest to the destination.
-// The instanceDigest value is expected to always be nil, because this transport does not support manifest lists, so
-// there can be no secondary manifests.
-// FIXME? This should also receive a MIME type if known, to differentiate between schema versions.
-// If the destination is in principle available, refuses this manifest type (e.g. it does not recognize the schema),
-// but may accept a different manifest type, the returned error must be an ManifestTypeRejectedError.
-func (d *Destination) PutManifest(ctx context.Context, m []byte, instanceDigest *digest.Digest) error {
- return d.internal.PutManifest(ctx, m, instanceDigest)
-}
-
-// PutSignatures would add the given signatures to the docker tarfile (currently not supported).
-// The instanceDigest value is expected to always be nil, because this transport does not support manifest lists, so
-// there can be no secondary manifests. MUST be called after PutManifest (signatures reference manifest contents).
-func (d *Destination) PutSignatures(ctx context.Context, signatures [][]byte, instanceDigest *digest.Digest) error {
- return d.internal.PutSignatures(ctx, signatures, instanceDigest)
-}
-
-// Commit finishes writing data to the underlying io.Writer.
-// It is the caller's responsibility to close it, if necessary.
-func (d *Destination) Commit(ctx context.Context) error {
- return d.archive.Close()
-}
diff --git a/vendor/github.com/containers/image/v5/docker/tarfile/doc.go b/vendor/github.com/containers/image/v5/docker/tarfile/doc.go
deleted file mode 100644
index 4ea5369c0..000000000
--- a/vendor/github.com/containers/image/v5/docker/tarfile/doc.go
+++ /dev/null
@@ -1,3 +0,0 @@
-// Package tarfile is an internal implementation detail of some transports.
-// Do not use outside of the github.com/containers/image repo!
-package tarfile
diff --git a/vendor/github.com/containers/image/v5/docker/tarfile/src.go b/vendor/github.com/containers/image/v5/docker/tarfile/src.go
deleted file mode 100644
index ee341eb39..000000000
--- a/vendor/github.com/containers/image/v5/docker/tarfile/src.go
+++ /dev/null
@@ -1,104 +0,0 @@
-package tarfile
-
-import (
- "context"
- "io"
-
- internal "github.com/containers/image/v5/docker/internal/tarfile"
- "github.com/containers/image/v5/types"
- digest "github.com/opencontainers/go-digest"
-)
-
-// Source is a partial implementation of types.ImageSource for reading from tarPath.
-// Most users should use this via implementations of ImageReference from docker/archive or docker/daemon.
-type Source struct {
- internal *internal.Source
-}
-
-// NewSourceFromFile returns a tarfile.Source for the specified path.
-// Deprecated: Please use NewSourceFromFileWithContext which will allows you to configure temp directory
-// for big files through SystemContext.BigFilesTemporaryDir
-func NewSourceFromFile(path string) (*Source, error) {
- return NewSourceFromFileWithContext(nil, path)
-}
-
-// NewSourceFromFileWithContext returns a tarfile.Source for the specified path.
-func NewSourceFromFileWithContext(sys *types.SystemContext, path string) (*Source, error) {
- archive, err := internal.NewReaderFromFile(sys, path)
- if err != nil {
- return nil, err
- }
- src := internal.NewSource(archive, true, nil, -1)
- return &Source{internal: src}, nil
-}
-
-// NewSourceFromStream returns a tarfile.Source for the specified inputStream,
-// which can be either compressed or uncompressed. The caller can close the
-// inputStream immediately after NewSourceFromFile returns.
-// Deprecated: Please use NewSourceFromStreamWithSystemContext which will allows you to configure
-// temp directory for big files through SystemContext.BigFilesTemporaryDir
-func NewSourceFromStream(inputStream io.Reader) (*Source, error) {
- return NewSourceFromStreamWithSystemContext(nil, inputStream)
-}
-
-// NewSourceFromStreamWithSystemContext returns a tarfile.Source for the specified inputStream,
-// which can be either compressed or uncompressed. The caller can close the
-// inputStream immediately after NewSourceFromFile returns.
-func NewSourceFromStreamWithSystemContext(sys *types.SystemContext, inputStream io.Reader) (*Source, error) {
- archive, err := internal.NewReaderFromStream(sys, inputStream)
- if err != nil {
- return nil, err
- }
- src := internal.NewSource(archive, true, nil, -1)
- return &Source{internal: src}, nil
-}
-
-// Close removes resources associated with an initialized Source, if any.
-func (s *Source) Close() error {
- return s.internal.Close()
-}
-
-// LoadTarManifest loads and decodes the manifest.json
-func (s *Source) LoadTarManifest() ([]ManifestItem, error) {
- return s.internal.TarManifest(), nil
-}
-
-// 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).
-// It may use a remote (= slow) service.
-// If instanceDigest is not nil, it contains a digest of the specific manifest instance to retrieve (when the primary manifest is a manifest list);
-// this never happens if the primary manifest is not a manifest list (e.g. if the source never returns manifest lists).
-// This source implementation does not support manifest lists, so the passed-in instanceDigest should always be nil,
-// as the primary manifest can not be a list, so there can be no secondary instances.
-func (s *Source) GetManifest(ctx context.Context, instanceDigest *digest.Digest) ([]byte, string, error) {
- return s.internal.GetManifest(ctx, instanceDigest)
-}
-
-// HasThreadSafeGetBlob indicates whether GetBlob can be executed concurrently.
-func (s *Source) HasThreadSafeGetBlob() bool {
- return s.internal.HasThreadSafeGetBlob()
-}
-
-// GetBlob returns a stream for the specified blob, and the blob’s size (or -1 if unknown).
-// The Digest field in BlobInfo is guaranteed to be provided, Size may be -1 and MediaType may be optionally provided.
-// May update BlobInfoCache, preferably after it knows for certain that a blob truly exists at a specific location.
-func (s *Source) GetBlob(ctx context.Context, info types.BlobInfo, cache types.BlobInfoCache) (io.ReadCloser, int64, error) {
- return s.internal.GetBlob(ctx, info, cache)
-}
-
-// GetSignatures returns the image's signatures. It may use a remote (= slow) service.
-// This source implementation does not support manifest lists, so the passed-in instanceDigest should always be nil,
-// as there can be no secondary manifests.
-func (s *Source) GetSignatures(ctx context.Context, instanceDigest *digest.Digest) ([][]byte, error) {
- return s.internal.GetSignatures(ctx, instanceDigest)
-}
-
-// LayerInfosForCopy returns either nil (meaning the values in the manifest are fine), or updated values for the layer
-// blobsums that are listed in the image's manifest. If values are returned, they should be used when using GetBlob()
-// to read the image's layers.
-// This source implementation does not support manifest lists, so the passed-in instanceDigest should always be nil,
-// as the primary manifest can not be a list, so there can be no secondary manifests.
-// The Digest field is guaranteed to be provided; Size may be -1.
-// WARNING: The list may contain duplicates, and they are semantically relevant.
-func (s *Source) LayerInfosForCopy(ctx context.Context, instanceDigest *digest.Digest) ([]types.BlobInfo, error) {
- return s.internal.LayerInfosForCopy(ctx, instanceDigest)
-}
diff --git a/vendor/github.com/containers/image/v5/docker/tarfile/types.go b/vendor/github.com/containers/image/v5/docker/tarfile/types.go
deleted file mode 100644
index 0f14389e6..000000000
--- a/vendor/github.com/containers/image/v5/docker/tarfile/types.go
+++ /dev/null
@@ -1,8 +0,0 @@
-package tarfile
-
-import (
- internal "github.com/containers/image/v5/docker/internal/tarfile"
-)
-
-// ManifestItem is an element of the array stored in the top-level manifest.json file.
-type ManifestItem = internal.ManifestItem // All public members from the internal package remain accessible.
diff --git a/vendor/github.com/containers/image/v5/internal/types/types.go b/vendor/github.com/containers/image/v5/internal/types/types.go
index 9adf0d536..bf89a69b8 100644
--- a/vendor/github.com/containers/image/v5/internal/types/types.go
+++ b/vendor/github.com/containers/image/v5/internal/types/types.go
@@ -4,6 +4,7 @@ import (
"context"
"io"
+ "github.com/containers/image/v5/docker/reference"
publicTypes "github.com/containers/image/v5/types"
)
@@ -50,4 +51,6 @@ type TryReusingBlobOptions struct {
CanSubstitute bool
// The corresponding index in the layer slice.
LayerIndex *int
+ // The reference of the image that contains the target blob.
+ SrcRef reference.Named
}
diff --git a/vendor/github.com/containers/image/v5/storage/storage_image.go b/vendor/github.com/containers/image/v5/storage/storage_image.go
index 3a2c18c89..f4747357c 100644
--- a/vendor/github.com/containers/image/v5/storage/storage_image.go
+++ b/vendor/github.com/containers/image/v5/storage/storage_image.go
@@ -76,11 +76,12 @@ type storageImageDestination struct {
indexToStorageID map[int]*string
// All accesses to below data are protected by `lock` which is made
// *explicit* in the code.
- blobDiffIDs map[digest.Digest]digest.Digest // Mapping from layer blobsums to their corresponding DiffIDs
- fileSizes map[digest.Digest]int64 // Mapping from layer blobsums to their sizes
- filenames map[digest.Digest]string // Mapping from layer blobsums to names of files we used to hold them
- currentIndex int // The index of the layer to be committed (i.e., lower indices have already been committed)
- indexToPulledBlob map[int]*types.BlobInfo // Mapping from layer (by index) to pulled down blob
+ blobDiffIDs map[digest.Digest]digest.Digest // Mapping from layer blobsums to their corresponding DiffIDs
+ fileSizes map[digest.Digest]int64 // Mapping from layer blobsums to their sizes
+ filenames map[digest.Digest]string // Mapping from layer blobsums to names of files we used to hold them
+ currentIndex int // The index of the layer to be committed (i.e., lower indices have already been committed)
+ indexToPulledBlob map[int]*types.BlobInfo // Mapping from layer (by index) to pulled down blob
+ blobAdditionalLayer map[digest.Digest]storage.AdditionalLayer // Mapping from layer blobsums to their corresponding additional layer
}
type storageImageCloser struct {
@@ -391,16 +392,17 @@ func newImageDestination(sys *types.SystemContext, imageRef storageReference) (*
return nil, errors.Wrapf(err, "error creating a temporary directory")
}
image := &storageImageDestination{
- imageRef: imageRef,
- directory: directory,
- signatureses: make(map[digest.Digest][]byte),
- blobDiffIDs: make(map[digest.Digest]digest.Digest),
- fileSizes: make(map[digest.Digest]int64),
- filenames: make(map[digest.Digest]string),
- SignatureSizes: []int{},
- SignaturesSizes: make(map[digest.Digest][]int),
- indexToStorageID: make(map[int]*string),
- indexToPulledBlob: make(map[int]*types.BlobInfo),
+ imageRef: imageRef,
+ directory: directory,
+ signatureses: make(map[digest.Digest][]byte),
+ blobDiffIDs: make(map[digest.Digest]digest.Digest),
+ blobAdditionalLayer: make(map[digest.Digest]storage.AdditionalLayer),
+ fileSizes: make(map[digest.Digest]int64),
+ filenames: make(map[digest.Digest]string),
+ SignatureSizes: []int{},
+ SignaturesSizes: make(map[digest.Digest][]int),
+ indexToStorageID: make(map[int]*string),
+ indexToPulledBlob: make(map[int]*types.BlobInfo),
}
return image, nil
}
@@ -411,8 +413,11 @@ func (s *storageImageDestination) Reference() types.ImageReference {
return s.imageRef
}
-// Close cleans up the temporary directory.
+// Close cleans up the temporary directory and additional layer store handlers.
func (s *storageImageDestination) Close() error {
+ for _, al := range s.blobAdditionalLayer {
+ al.Release()
+ }
return os.RemoveAll(s.directory)
}
@@ -532,7 +537,7 @@ func (s *storageImageDestination) PutBlob(ctx context.Context, stream io.Reader,
// used the together. Mixing the two with the non "WithOptions" functions
// is not supported.
func (s *storageImageDestination) TryReusingBlobWithOptions(ctx context.Context, blobinfo types.BlobInfo, options internalTypes.TryReusingBlobOptions) (bool, types.BlobInfo, error) {
- reused, info, err := s.TryReusingBlob(ctx, blobinfo, options.Cache, options.CanSubstitute)
+ reused, info, err := s.tryReusingBlobWithSrcRef(ctx, blobinfo, options.Cache, options.CanSubstitute, options.SrcRef)
if err != nil || !reused || options.LayerIndex == nil {
return reused, info, err
}
@@ -540,6 +545,33 @@ func (s *storageImageDestination) TryReusingBlobWithOptions(ctx context.Context,
return reused, info, s.queueOrCommit(ctx, info, *options.LayerIndex)
}
+// tryReusingBlobWithSrcRef is a wrapper around TryReusingBlob.
+// If ref is provided, this function first tries to get layer from Additional Layer Store.
+func (s *storageImageDestination) tryReusingBlobWithSrcRef(ctx context.Context, blobinfo types.BlobInfo, cache types.BlobInfoCache, canSubstitute bool, ref reference.Named) (bool, types.BlobInfo, error) {
+ // lock the entire method as it executes fairly quickly
+ s.lock.Lock()
+ defer s.lock.Unlock()
+
+ if ref != nil {
+ // Check if we have the layer in the underlying additional layer store.
+ aLayer, err := s.imageRef.transport.store.LookupAdditionalLayer(blobinfo.Digest, ref.String())
+ if err != nil && errors.Cause(err) != storage.ErrLayerUnknown {
+ return false, types.BlobInfo{}, errors.Wrapf(err, `Error looking for compressed layers with digest %q and labels`, blobinfo.Digest)
+ } else if err == nil {
+ // Record the uncompressed value so that we can use it to calculate layer IDs.
+ s.blobDiffIDs[blobinfo.Digest] = aLayer.UncompressedDigest()
+ s.blobAdditionalLayer[blobinfo.Digest] = aLayer
+ return true, types.BlobInfo{
+ Digest: blobinfo.Digest,
+ Size: aLayer.CompressedSize(),
+ MediaType: blobinfo.MediaType,
+ }, nil
+ }
+ }
+
+ return s.tryReusingBlobLocked(ctx, blobinfo, cache, canSubstitute)
+}
+
// TryReusingBlob checks whether the transport already contains, or can efficiently reuse, a blob, and if so, applies it to the current destination
// (e.g. if the blob is a filesystem layer, this signifies that the changes it describes need to be applied again when composing a filesystem tree).
// info.Digest must not be empty.
@@ -553,6 +585,13 @@ func (s *storageImageDestination) TryReusingBlob(ctx context.Context, blobinfo t
// lock the entire method as it executes fairly quickly
s.lock.Lock()
defer s.lock.Unlock()
+
+ return s.tryReusingBlobLocked(ctx, blobinfo, cache, canSubstitute)
+}
+
+// tryReusingBlobLocked implements a core functionality of TryReusingBlob.
+// This must be called with a lock being held on storageImageDestination.
+func (s *storageImageDestination) tryReusingBlobLocked(ctx context.Context, blobinfo types.BlobInfo, cache types.BlobInfoCache, canSubstitute bool) (bool, types.BlobInfo, error) {
if blobinfo.Digest == "" {
return false, types.BlobInfo{}, errors.Errorf(`Can not check for a blob with unknown digest`)
}
@@ -804,6 +843,20 @@ func (s *storageImageDestination) commitLayer(ctx context.Context, blob manifest
s.indexToStorageID[index] = &lastLayer
return nil
}
+
+ s.lock.Lock()
+ al, ok := s.blobAdditionalLayer[blob.Digest]
+ s.lock.Unlock()
+ if ok {
+ layer, err := al.PutAs(id, lastLayer, nil)
+ if err != nil {
+ return errors.Wrapf(err, "failed to put layer from digest and labels")
+ }
+ lastLayer = layer.ID
+ s.indexToStorageID[index] = &lastLayer
+ return nil
+ }
+
// Check if we previously cached a file with that blob's contents. If we didn't,
// then we need to read the desired contents from a layer.
s.lock.Lock()
diff --git a/vendor/github.com/containers/image/v5/version/version.go b/vendor/github.com/containers/image/v5/version/version.go
index 23b2e3571..4afb3b90b 100644
--- a/vendor/github.com/containers/image/v5/version/version.go
+++ b/vendor/github.com/containers/image/v5/version/version.go
@@ -6,9 +6,9 @@ const (
// VersionMajor is for an API incompatible changes
VersionMajor = 5
// VersionMinor is for functionality in a backwards-compatible manner
- VersionMinor = 11
+ VersionMinor = 12
// VersionPatch is for backwards-compatible bug fixes
- VersionPatch = 1
+ VersionPatch = 0
// VersionDev indicates development branch. Releases will be empty string.
VersionDev = ""
diff --git a/vendor/github.com/disiqueira/gotree/v3/.gitignore b/vendor/github.com/disiqueira/gotree/v3/.gitignore
new file mode 100644
index 000000000..3236c30ab
--- /dev/null
+++ b/vendor/github.com/disiqueira/gotree/v3/.gitignore
@@ -0,0 +1,137 @@
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+# Folders
+_obj
+_test
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe
+*.test
+*.prof
+
+.idea/
+GoTree.iml
+### Linux template
+*~
+
+# temporary files which can be created if a process still has a handle open of a deleted file
+.fuse_hidden*
+
+# KDE directory preferences
+.directory
+
+# Linux trash folder which might appear on any partition or disk
+.Trash-*
+### Windows template
+# Windows image file caches
+Thumbs.db
+ehthumbs.db
+
+# Folder config file
+Desktop.ini
+
+# Recycle Bin used on file shares
+$RECYCLE.BIN/
+
+# Windows Installer files
+*.cab
+*.msi
+*.msm
+*.msp
+
+# Windows shortcuts
+*.lnk
+### JetBrains template
+# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
+# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
+
+# User-specific stuff:
+.idea/workspace.xml
+.idea/tasks.xml
+.idea/dictionaries
+.idea/vcs.xml
+.idea/jsLibraryMappings.xml
+
+# Sensitive or high-churn files:
+.idea/dataSources.ids
+.idea/dataSources.xml
+.idea/dataSources.local.xml
+.idea/sqlDataSources.xml
+.idea/dynamic.xml
+.idea/uiDesigner.xml
+
+# Gradle:
+.idea/gradle.xml
+.idea/libraries
+
+# Mongo Explorer plugin:
+.idea/mongoSettings.xml
+
+## File-based project format:
+*.iws
+
+## Plugin-specific files:
+
+# IntelliJ
+/out/
+
+# mpeltonen/sbt-idea plugin
+.idea_modules/
+
+# JIRA plugin
+atlassian-ide-plugin.xml
+
+# Crashlytics plugin (for Android Studio and IntelliJ)
+com_crashlytics_export_strings.xml
+crashlytics.properties
+crashlytics-build.properties
+fabric.properties
+### Go template
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+
+# Folders
+
+# Architecture specific extensions/prefixes
+
+
+
+### OSX template
+*.DS_Store
+.AppleDouble
+.LSOverride
+
+# Icon must end with two \r
+Icon
+
+# Thumbnails
+._*
+
+# Files that might appear in the root of a volume
+.DocumentRevisions-V100
+.fseventsd
+.Spotlight-V100
+.TemporaryItems
+.Trashes
+.VolumeIcon.icns
+.com.apple.timemachine.donotpresent
+
+# Directories potentially created on remote AFP share
+.AppleDB
+.AppleDesktop
+Network Trash Folder
+Temporary Items
+.apdisk
diff --git a/vendor/github.com/disiqueira/gotree/v3/.travis.yml b/vendor/github.com/disiqueira/gotree/v3/.travis.yml
new file mode 100644
index 000000000..29261dfff
--- /dev/null
+++ b/vendor/github.com/disiqueira/gotree/v3/.travis.yml
@@ -0,0 +1,11 @@
+language: go
+go_import_path: github.com/disiqueira/gotree
+git:
+ depth: 1
+env:
+ - GO111MODULE=on
+ - GO111MODULE=off
+go: [ 1.11.x, 1.12.x, 1.13.x ]
+os: [ linux, osx ]
+script:
+ - go test -race -v ./...
diff --git a/vendor/github.com/disiqueira/gotree/v3/LICENSE b/vendor/github.com/disiqueira/gotree/v3/LICENSE
new file mode 100644
index 000000000..e790b5a52
--- /dev/null
+++ b/vendor/github.com/disiqueira/gotree/v3/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2017 Diego Siqueira
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/vendor/github.com/disiqueira/gotree/v3/README.md b/vendor/github.com/disiqueira/gotree/v3/README.md
new file mode 100644
index 000000000..d09d4a98c
--- /dev/null
+++ b/vendor/github.com/disiqueira/gotree/v3/README.md
@@ -0,0 +1,104 @@
+# ![GoTree](https://rawgit.com/DiSiqueira/GoTree/master/gotree-logo.png)
+
+# GoTree ![Language Badge](https://img.shields.io/badge/Language-Go-blue.svg) ![Go Report](https://goreportcard.com/badge/github.com/DiSiqueira/GoTree) ![License Badge](https://img.shields.io/badge/License-MIT-blue.svg) ![Status Badge](https://img.shields.io/badge/Status-Beta-brightgreen.svg) [![GoDoc](https://godoc.org/github.com/DiSiqueira/GoTree?status.svg)](https://godoc.org/github.com/DiSiqueira/GoTree) [![Build Status](https://travis-ci.org/DiSiqueira/GoTree.svg?branch=master)](https://travis-ci.org/DiSiqueira/GoTree)
+
+Simple Go module to print tree structures in terminal. Heavily inpired by [The Tree Command for Linux][treecommand]
+
+The GoTree's goal is to be a simple tool providing a stupidly easy-to-use and fast way to print recursive structures.
+
+[treecommand]: http://mama.indstate.edu/users/ice/tree/
+
+## Project Status
+
+GoTree is on beta. Pull Requests [are welcome](https://github.com/DiSiqueira/GoTree#social-coding)
+
+![](http://image.prntscr.com/image/2a0dbf0777454446b8083fb6a0dc51fe.png)
+
+## Features
+
+- Very simple and fast code
+- Intuitive names
+- Easy to extend
+- Uses only native libs
+- STUPIDLY [EASY TO USE](https://github.com/DiSiqueira/GoTree#usage)
+
+## Installation
+
+### Go Get
+
+```bash
+$ go get github.com/disiqueira/gotree
+```
+
+## Usage
+
+### Simple create, populate and print example
+
+![](http://image.prntscr.com/image/dd2fe3737e6543f7b21941a6953598c2.png)
+
+```golang
+package main
+
+import (
+ "fmt"
+
+ "github.com/disiqueira/gotree"
+)
+
+func main() {
+ artist := gotree.New("Pantera")
+ album := artist.Add("Far Beyond Driven")
+ album.Add("5 minutes Alone")
+
+ fmt.Println(artist.Print())
+}
+```
+
+## Contributing
+
+### Bug Reports & Feature Requests
+
+Please use the [issue tracker](https://github.com/DiSiqueira/GoTree/issues) to report any bugs or file feature requests.
+
+### Developing
+
+PRs are welcome. To begin developing, do this:
+
+```bash
+$ git clone --recursive git@github.com:DiSiqueira/GoTree.git
+$ cd GoTree/
+```
+
+## Social Coding
+
+1. Create an issue to discuss about your idea
+2. [Fork it] (https://github.com/DiSiqueira/GoTree/fork)
+3. Create your feature branch (`git checkout -b my-new-feature`)
+4. Commit your changes (`git commit -am 'Add some feature'`)
+5. Push to the branch (`git push origin my-new-feature`)
+6. Create a new Pull Request
+7. Profit! :white_check_mark:
+
+## License
+
+The MIT License (MIT)
+
+Copyright (c) 2013-2018 Diego Siqueira
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/vendor/github.com/disiqueira/gotree/v3/_config.yml b/vendor/github.com/disiqueira/gotree/v3/_config.yml
new file mode 100644
index 000000000..c74188174
--- /dev/null
+++ b/vendor/github.com/disiqueira/gotree/v3/_config.yml
@@ -0,0 +1 @@
+theme: jekyll-theme-slate \ No newline at end of file
diff --git a/vendor/github.com/disiqueira/gotree/v3/go.mod b/vendor/github.com/disiqueira/gotree/v3/go.mod
new file mode 100644
index 000000000..7e17c637e
--- /dev/null
+++ b/vendor/github.com/disiqueira/gotree/v3/go.mod
@@ -0,0 +1,3 @@
+module github.com/disiqueira/gotree/v3
+
+go 1.13
diff --git a/vendor/github.com/disiqueira/gotree/v3/gotree-logo.png b/vendor/github.com/disiqueira/gotree/v3/gotree-logo.png
new file mode 100644
index 000000000..1735c6008
--- /dev/null
+++ b/vendor/github.com/disiqueira/gotree/v3/gotree-logo.png
Binary files differ
diff --git a/vendor/github.com/disiqueira/gotree/v3/gotree.go b/vendor/github.com/disiqueira/gotree/v3/gotree.go
new file mode 100644
index 000000000..c529f62be
--- /dev/null
+++ b/vendor/github.com/disiqueira/gotree/v3/gotree.go
@@ -0,0 +1,129 @@
+// Package gotree create and print tree.
+package gotree
+
+import (
+ "strings"
+)
+
+const (
+ newLine = "\n"
+ emptySpace = " "
+ middleItem = "├── "
+ continueItem = "│ "
+ lastItem = "└── "
+)
+
+type (
+ tree struct {
+ text string
+ items []Tree
+ }
+
+ // Tree is tree interface
+ Tree interface {
+ Add(text string) Tree
+ AddTree(tree Tree)
+ Items() []Tree
+ Text() string
+ Print() string
+ }
+
+ printer struct {
+ }
+
+ // Printer is printer interface
+ Printer interface {
+ Print(Tree) string
+ }
+)
+
+//New returns a new GoTree.Tree
+func New(text string) Tree {
+ return &tree{
+ text: text,
+ items: []Tree{},
+ }
+}
+
+//Add adds a node to the tree
+func (t *tree) Add(text string) Tree {
+ n := New(text)
+ t.items = append(t.items, n)
+ return n
+}
+
+//AddTree adds a tree as an item
+func (t *tree) AddTree(tree Tree) {
+ t.items = append(t.items, tree)
+}
+
+//Text returns the node's value
+func (t *tree) Text() string {
+ return t.text
+}
+
+//Items returns all items in the tree
+func (t *tree) Items() []Tree {
+ return t.items
+}
+
+//Print returns an visual representation of the tree
+func (t *tree) Print() string {
+ return newPrinter().Print(t)
+}
+
+func newPrinter() Printer {
+ return &printer{}
+}
+
+//Print prints a tree to a string
+func (p *printer) Print(t Tree) string {
+ return t.Text() + newLine + p.printItems(t.Items(), []bool{})
+}
+
+func (p *printer) printText(text string, spaces []bool, last bool) string {
+ var result string
+ for _, space := range spaces {
+ if space {
+ result += emptySpace
+ } else {
+ result += continueItem
+ }
+ }
+
+ indicator := middleItem
+ if last {
+ indicator = lastItem
+ }
+
+ var out string
+ lines := strings.Split(text, "\n")
+ for i := range lines {
+ text := lines[i]
+ if i == 0 {
+ out += result + indicator + text + newLine
+ continue
+ }
+ if last {
+ indicator = emptySpace
+ } else {
+ indicator = continueItem
+ }
+ out += result + indicator + text + newLine
+ }
+
+ return out
+}
+
+func (p *printer) printItems(t []Tree, spaces []bool) string {
+ var result string
+ for i, f := range t {
+ last := i == len(t)-1
+ result += p.printText(f.Text(), spaces, last)
+ if len(f.Items()) > 0 {
+ spacesChild := append(spaces, last)
+ result += p.printItems(f.Items(), spacesChild)
+ }
+ }
+ return result
+}
diff --git a/vendor/github.com/ishidawataru/sctp/.travis.yml b/vendor/github.com/ishidawataru/sctp/.travis.yml
index 01a76be9a..a1c693c01 100644
--- a/vendor/github.com/ishidawataru/sctp/.travis.yml
+++ b/vendor/github.com/ishidawataru/sctp/.travis.yml
@@ -1,10 +1,20 @@
language: go
+arch:
+ - amd64
+ - ppc64le
go:
- 1.9.x
- 1.10.x
- 1.11.x
- 1.12.x
- 1.13.x
+# allowing test cases to fail for the versions were not suppotred by ppc64le
+matrix:
+ allow_failures:
+ - go: 1.9.x
+ - go: 1.10.x
+ - go: 1.13.x
+
script:
- go test -v -race ./...
@@ -12,6 +22,7 @@ script:
- GOOS=linux GOARCH=arm go build .
- GOOS=linux GOARCH=arm64 go build .
- GOOS=linux GOARCH=ppc64le go build .
+ - GOOS=linux GOARCH=mips64le go build .
- (go version | grep go1.6 > /dev/null) || GOOS=linux GOARCH=s390x go build .
# can be compiled but not functional:
- GOOS=linux GOARCH=386 go build .
diff --git a/vendor/github.com/ishidawataru/sctp/sctp_linux.go b/vendor/github.com/ishidawataru/sctp/sctp_linux.go
index ac340ddfb..d96d09e5c 100644
--- a/vendor/github.com/ishidawataru/sctp/sctp_linux.go
+++ b/vendor/github.com/ishidawataru/sctp/sctp_linux.go
@@ -212,7 +212,7 @@ func listenSCTPExtConfig(network string, laddr *SCTPAddr, options InitMsg, contr
laddr.IPAddrs = append(laddr.IPAddrs, net.IPAddr{IP: net.IPv6zero})
}
}
- err := SCTPBind(sock, laddr, SCTP_BINDX_ADD_ADDR)
+ err = SCTPBind(sock, laddr, SCTP_BINDX_ADD_ADDR)
if err != nil {
return nil, err
}
diff --git a/vendor/github.com/jinzhu/copier/License b/vendor/github.com/jinzhu/copier/License
new file mode 100644
index 000000000..e2dc5381e
--- /dev/null
+++ b/vendor/github.com/jinzhu/copier/License
@@ -0,0 +1,20 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 Jinzhu
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/vendor/github.com/jinzhu/copier/README.md b/vendor/github.com/jinzhu/copier/README.md
new file mode 100644
index 000000000..cff72405c
--- /dev/null
+++ b/vendor/github.com/jinzhu/copier/README.md
@@ -0,0 +1,131 @@
+# Copier
+
+ I am a copier, I copy everything from one to another
+
+[![test status](https://github.com/jinzhu/copier/workflows/tests/badge.svg?branch=master "test status")](https://github.com/jinzhu/copier/actions)
+
+## Features
+
+* Copy from field to field with same name
+* Copy from method to field with same name
+* Copy from field to method with same name
+* Copy from slice to slice
+* Copy from struct to slice
+* Copy from map to map
+* Enforce copying a field with a tag
+* Ignore a field with a tag
+* Deep Copy
+
+## Usage
+
+```go
+package main
+
+import (
+ "fmt"
+ "github.com/jinzhu/copier"
+)
+
+type User struct {
+ Name string
+ Role string
+ Age int32
+
+ // Explicitly ignored in the destination struct.
+ Salary int
+}
+
+func (user *User) DoubleAge() int32 {
+ return 2 * user.Age
+}
+
+// Tags in the destination Struct provide instructions to copier.Copy to ignore
+// or enforce copying and to panic or return an error if a field was not copied.
+type Employee struct {
+ // Tell copier.Copy to panic if this field is not copied.
+ Name string `copier:"must"`
+
+ // Tell copier.Copy to return an error if this field is not copied.
+ Age int32 `copier:"must,nopanic"`
+
+ // Tell copier.Copy to explicitly ignore copying this field.
+ Salary int `copier:"-"`
+
+ DoubleAge int32
+ EmployeId int64
+ SuperRole string
+}
+
+func (employee *Employee) Role(role string) {
+ employee.SuperRole = "Super " + role
+}
+
+func main() {
+ var (
+ user = User{Name: "Jinzhu", Age: 18, Role: "Admin", Salary: 200000}
+ users = []User{{Name: "Jinzhu", Age: 18, Role: "Admin", Salary: 100000}, {Name: "jinzhu 2", Age: 30, Role: "Dev", Salary: 60000}}
+ employee = Employee{Salary: 150000}
+ employees = []Employee{}
+ )
+
+ copier.Copy(&employee, &user)
+
+ fmt.Printf("%#v \n", employee)
+ // Employee{
+ // Name: "Jinzhu", // Copy from field
+ // Age: 18, // Copy from field
+ // Salary:150000, // Copying explicitly ignored
+ // DoubleAge: 36, // Copy from method
+ // EmployeeId: 0, // Ignored
+ // SuperRole: "Super Admin", // Copy to method
+ // }
+
+ // Copy struct to slice
+ copier.Copy(&employees, &user)
+
+ fmt.Printf("%#v \n", employees)
+ // []Employee{
+ // {Name: "Jinzhu", Age: 18, Salary:0, DoubleAge: 36, EmployeId: 0, SuperRole: "Super Admin"}
+ // }
+
+ // Copy slice to slice
+ employees = []Employee{}
+ copier.Copy(&employees, &users)
+
+ fmt.Printf("%#v \n", employees)
+ // []Employee{
+ // {Name: "Jinzhu", Age: 18, Salary:0, DoubleAge: 36, EmployeId: 0, SuperRole: "Super Admin"},
+ // {Name: "jinzhu 2", Age: 30, Salary:0, DoubleAge: 60, EmployeId: 0, SuperRole: "Super Dev"},
+ // }
+
+ // Copy map to map
+ map1 := map[int]int{3: 6, 4: 8}
+ map2 := map[int32]int8{}
+ copier.Copy(&map2, map1)
+
+ fmt.Printf("%#v \n", map2)
+ // map[int32]int8{3:6, 4:8}
+}
+```
+
+### Copy with Option
+
+```go
+copier.CopyWithOption(&to, &from, copier.Option{IgnoreEmpty: true, DeepCopy: true})
+```
+
+## Contributing
+
+You can help to make the project better, check out [http://gorm.io/contribute.html](http://gorm.io/contribute.html) for things you can do.
+
+# Author
+
+**jinzhu**
+
+* <http://github.com/jinzhu>
+* <wosmvp@gmail.com>
+* <http://twitter.com/zhangjinzhu>
+
+## License
+
+Released under the [MIT License](https://github.com/jinzhu/copier/blob/master/License).
diff --git a/vendor/github.com/jinzhu/copier/copier.go b/vendor/github.com/jinzhu/copier/copier.go
new file mode 100644
index 000000000..72bf65c78
--- /dev/null
+++ b/vendor/github.com/jinzhu/copier/copier.go
@@ -0,0 +1,491 @@
+package copier
+
+import (
+ "database/sql"
+ "database/sql/driver"
+ "fmt"
+ "reflect"
+ "strings"
+)
+
+// These flags define options for tag handling
+const (
+ // Denotes that a destination field must be copied to. If copying fails then a panic will ensue.
+ tagMust uint8 = 1 << iota
+
+ // Denotes that the program should not panic when the must flag is on and
+ // value is not copied. The program will return an error instead.
+ tagNoPanic
+
+ // Ignore a destination field from being copied to.
+ tagIgnore
+
+ // Denotes that the value as been copied
+ hasCopied
+)
+
+// Option sets copy options
+type Option struct {
+ // setting this value to true will ignore copying zero values of all the fields, including bools, as well as a
+ // struct having all it's fields set to their zero values respectively (see IsZero() in reflect/value.go)
+ IgnoreEmpty bool
+ DeepCopy bool
+}
+
+// Copy copy things
+func Copy(toValue interface{}, fromValue interface{}) (err error) {
+ return copier(toValue, fromValue, Option{})
+}
+
+// CopyWithOption copy with option
+func CopyWithOption(toValue interface{}, fromValue interface{}, opt Option) (err error) {
+ return copier(toValue, fromValue, opt)
+}
+
+func copier(toValue interface{}, fromValue interface{}, opt Option) (err error) {
+ var (
+ isSlice bool
+ amount = 1
+ from = indirect(reflect.ValueOf(fromValue))
+ to = indirect(reflect.ValueOf(toValue))
+ )
+
+ if !to.CanAddr() {
+ return ErrInvalidCopyDestination
+ }
+
+ // Return is from value is invalid
+ if !from.IsValid() {
+ return ErrInvalidCopyFrom
+ }
+
+ fromType, isPtrFrom := indirectType(from.Type())
+ toType, _ := indirectType(to.Type())
+
+ if fromType.Kind() == reflect.Interface {
+ fromType = reflect.TypeOf(from.Interface())
+ }
+
+ if toType.Kind() == reflect.Interface {
+ toType, _ = indirectType(reflect.TypeOf(to.Interface()))
+ oldTo := to
+ to = reflect.New(reflect.TypeOf(to.Interface())).Elem()
+ defer func() {
+ oldTo.Set(to)
+ }()
+ }
+
+ // Just set it if possible to assign for normal types
+ if from.Kind() != reflect.Slice && from.Kind() != reflect.Struct && from.Kind() != reflect.Map && (from.Type().AssignableTo(to.Type()) || from.Type().ConvertibleTo(to.Type())) {
+ if !isPtrFrom || !opt.DeepCopy {
+ to.Set(from.Convert(to.Type()))
+ } else {
+ fromCopy := reflect.New(from.Type())
+ fromCopy.Set(from.Elem())
+ to.Set(fromCopy.Convert(to.Type()))
+ }
+ return
+ }
+
+ if from.Kind() != reflect.Slice && fromType.Kind() == reflect.Map && toType.Kind() == reflect.Map {
+ if !fromType.Key().ConvertibleTo(toType.Key()) {
+ return ErrMapKeyNotMatch
+ }
+
+ if to.IsNil() {
+ to.Set(reflect.MakeMapWithSize(toType, from.Len()))
+ }
+
+ for _, k := range from.MapKeys() {
+ toKey := indirect(reflect.New(toType.Key()))
+ if !set(toKey, k, opt.DeepCopy) {
+ return fmt.Errorf("%w map, old key: %v, new key: %v", ErrNotSupported, k.Type(), toType.Key())
+ }
+
+ elemType, _ := indirectType(toType.Elem())
+ toValue := indirect(reflect.New(elemType))
+ if !set(toValue, from.MapIndex(k), opt.DeepCopy) {
+ if err = copier(toValue.Addr().Interface(), from.MapIndex(k).Interface(), opt); err != nil {
+ return err
+ }
+ }
+
+ for {
+ if elemType == toType.Elem() {
+ to.SetMapIndex(toKey, toValue)
+ break
+ }
+ elemType = reflect.PtrTo(elemType)
+ toValue = toValue.Addr()
+ }
+ }
+ return
+ }
+
+ if from.Kind() == reflect.Slice && to.Kind() == reflect.Slice && fromType.ConvertibleTo(toType) {
+ if to.IsNil() {
+ slice := reflect.MakeSlice(reflect.SliceOf(to.Type().Elem()), from.Len(), from.Cap())
+ to.Set(slice)
+ }
+
+ for i := 0; i < from.Len(); i++ {
+ if to.Len() < i+1 {
+ to.Set(reflect.Append(to, reflect.New(to.Type().Elem()).Elem()))
+ }
+
+ if !set(to.Index(i), from.Index(i), opt.DeepCopy) {
+ err = CopyWithOption(to.Index(i).Addr().Interface(), from.Index(i).Interface(), opt)
+ if err != nil {
+ continue
+ }
+ }
+ }
+ return
+ }
+
+ if fromType.Kind() != reflect.Struct || toType.Kind() != reflect.Struct {
+ // skip not supported type
+ return
+ }
+
+ if to.Kind() == reflect.Slice {
+ isSlice = true
+ if from.Kind() == reflect.Slice {
+ amount = from.Len()
+ }
+ }
+
+ for i := 0; i < amount; i++ {
+ var dest, source reflect.Value
+
+ if isSlice {
+ // source
+ if from.Kind() == reflect.Slice {
+ source = indirect(from.Index(i))
+ } else {
+ source = indirect(from)
+ }
+ // dest
+ dest = indirect(reflect.New(toType).Elem())
+ } else {
+ source = indirect(from)
+ dest = indirect(to)
+ }
+
+ destKind := dest.Kind()
+ initDest := false
+ if destKind == reflect.Interface {
+ initDest = true
+ dest = indirect(reflect.New(toType))
+ }
+
+ // Get tag options
+ tagBitFlags := map[string]uint8{}
+ if dest.IsValid() {
+ tagBitFlags = getBitFlags(toType)
+ }
+
+ // check source
+ if source.IsValid() {
+ // Copy from source field to dest field or method
+ fromTypeFields := deepFields(fromType)
+ for _, field := range fromTypeFields {
+ name := field.Name
+
+ // Get bit flags for field
+ fieldFlags, _ := tagBitFlags[name]
+
+ // Check if we should ignore copying
+ if (fieldFlags & tagIgnore) != 0 {
+ continue
+ }
+
+ if fromField := source.FieldByName(name); fromField.IsValid() && !shouldIgnore(fromField, opt.IgnoreEmpty) {
+ // process for nested anonymous field
+ destFieldNotSet := false
+ if f, ok := dest.Type().FieldByName(name); ok {
+ for idx := range f.Index {
+ destField := dest.FieldByIndex(f.Index[:idx+1])
+
+ if destField.Kind() != reflect.Ptr {
+ continue
+ }
+
+ if !destField.IsNil() {
+ continue
+ }
+ if !destField.CanSet() {
+ destFieldNotSet = true
+ break
+ }
+
+ // destField is a nil pointer that can be set
+ newValue := reflect.New(destField.Type().Elem())
+ destField.Set(newValue)
+ }
+ }
+
+ if destFieldNotSet {
+ break
+ }
+
+ toField := dest.FieldByName(name)
+ if toField.IsValid() {
+ if toField.CanSet() {
+ if !set(toField, fromField, opt.DeepCopy) {
+ if err := copier(toField.Addr().Interface(), fromField.Interface(), opt); err != nil {
+ return err
+ }
+ }
+ if fieldFlags != 0 {
+ // Note that a copy was made
+ tagBitFlags[name] = fieldFlags | hasCopied
+ }
+ }
+ } else {
+ // try to set to method
+ var toMethod reflect.Value
+ if dest.CanAddr() {
+ toMethod = dest.Addr().MethodByName(name)
+ } else {
+ toMethod = dest.MethodByName(name)
+ }
+
+ if toMethod.IsValid() && toMethod.Type().NumIn() == 1 && fromField.Type().AssignableTo(toMethod.Type().In(0)) {
+ toMethod.Call([]reflect.Value{fromField})
+ }
+ }
+ }
+ }
+
+ // Copy from from method to dest field
+ for _, field := range deepFields(toType) {
+ name := field.Name
+
+ var fromMethod reflect.Value
+ if source.CanAddr() {
+ fromMethod = source.Addr().MethodByName(name)
+ } else {
+ fromMethod = source.MethodByName(name)
+ }
+
+ if fromMethod.IsValid() && fromMethod.Type().NumIn() == 0 && fromMethod.Type().NumOut() == 1 && !shouldIgnore(fromMethod, opt.IgnoreEmpty) {
+ if toField := dest.FieldByName(name); toField.IsValid() && toField.CanSet() {
+ values := fromMethod.Call([]reflect.Value{})
+ if len(values) >= 1 {
+ set(toField, values[0], opt.DeepCopy)
+ }
+ }
+ }
+ }
+ }
+
+ if isSlice {
+ if dest.Addr().Type().AssignableTo(to.Type().Elem()) {
+ if to.Len() < i+1 {
+ to.Set(reflect.Append(to, dest.Addr()))
+ } else {
+ set(to.Index(i), dest.Addr(), opt.DeepCopy)
+ }
+ } else if dest.Type().AssignableTo(to.Type().Elem()) {
+ if to.Len() < i+1 {
+ to.Set(reflect.Append(to, dest))
+ } else {
+ set(to.Index(i), dest, opt.DeepCopy)
+ }
+ }
+ } else if initDest {
+ to.Set(dest)
+ }
+
+ err = checkBitFlags(tagBitFlags)
+ }
+
+ return
+}
+
+func shouldIgnore(v reflect.Value, ignoreEmpty bool) bool {
+ if !ignoreEmpty {
+ return false
+ }
+
+ return v.IsZero()
+}
+
+func deepFields(reflectType reflect.Type) []reflect.StructField {
+ if reflectType, _ = indirectType(reflectType); reflectType.Kind() == reflect.Struct {
+ fields := make([]reflect.StructField, 0, reflectType.NumField())
+
+ for i := 0; i < reflectType.NumField(); i++ {
+ v := reflectType.Field(i)
+ if v.Anonymous {
+ fields = append(fields, deepFields(v.Type)...)
+ } else {
+ fields = append(fields, v)
+ }
+ }
+
+ return fields
+ }
+
+ return nil
+}
+
+func indirect(reflectValue reflect.Value) reflect.Value {
+ for reflectValue.Kind() == reflect.Ptr {
+ reflectValue = reflectValue.Elem()
+ }
+ return reflectValue
+}
+
+func indirectType(reflectType reflect.Type) (_ reflect.Type, isPtr bool) {
+ for reflectType.Kind() == reflect.Ptr || reflectType.Kind() == reflect.Slice {
+ reflectType = reflectType.Elem()
+ isPtr = true
+ }
+ return reflectType, isPtr
+}
+
+func set(to, from reflect.Value, deepCopy bool) bool {
+ if from.IsValid() {
+ if to.Kind() == reflect.Ptr {
+ // set `to` to nil if from is nil
+ if from.Kind() == reflect.Ptr && from.IsNil() {
+ to.Set(reflect.Zero(to.Type()))
+ return true
+ } else if to.IsNil() {
+ // `from` -> `to`
+ // sql.NullString -> *string
+ if fromValuer, ok := driverValuer(from); ok {
+ v, err := fromValuer.Value()
+ if err != nil {
+ return false
+ }
+ // if `from` is not valid do nothing with `to`
+ if v == nil {
+ return true
+ }
+ }
+ // allocate new `to` variable with default value (eg. *string -> new(string))
+ to.Set(reflect.New(to.Type().Elem()))
+ }
+ // depointer `to`
+ to = to.Elem()
+ }
+
+ if deepCopy {
+ toKind := to.Kind()
+ if toKind == reflect.Interface && to.IsNil() {
+ if reflect.TypeOf(from.Interface()) != nil {
+ to.Set(reflect.New(reflect.TypeOf(from.Interface())).Elem())
+ toKind = reflect.TypeOf(to.Interface()).Kind()
+ }
+ }
+ if toKind == reflect.Struct || toKind == reflect.Map || toKind == reflect.Slice {
+ return false
+ }
+ }
+
+ if from.Type().ConvertibleTo(to.Type()) {
+ to.Set(from.Convert(to.Type()))
+ } else if toScanner, ok := to.Addr().Interface().(sql.Scanner); ok {
+ // `from` -> `to`
+ // *string -> sql.NullString
+ if from.Kind() == reflect.Ptr {
+ // if `from` is nil do nothing with `to`
+ if from.IsNil() {
+ return true
+ }
+ // depointer `from`
+ from = indirect(from)
+ }
+ // `from` -> `to`
+ // string -> sql.NullString
+ // set `to` by invoking method Scan(`from`)
+ err := toScanner.Scan(from.Interface())
+ if err != nil {
+ return false
+ }
+ } else if fromValuer, ok := driverValuer(from); ok {
+ // `from` -> `to`
+ // sql.NullString -> string
+ v, err := fromValuer.Value()
+ if err != nil {
+ return false
+ }
+ // if `from` is not valid do nothing with `to`
+ if v == nil {
+ return true
+ }
+ rv := reflect.ValueOf(v)
+ if rv.Type().AssignableTo(to.Type()) {
+ to.Set(rv)
+ }
+ } else if from.Kind() == reflect.Ptr {
+ return set(to, from.Elem(), deepCopy)
+ } else {
+ return false
+ }
+ }
+
+ return true
+}
+
+// parseTags Parses struct tags and returns uint8 bit flags.
+func parseTags(tag string) (flags uint8) {
+ for _, t := range strings.Split(tag, ",") {
+ switch t {
+ case "-":
+ flags = tagIgnore
+ return
+ case "must":
+ flags = flags | tagMust
+ case "nopanic":
+ flags = flags | tagNoPanic
+ }
+ }
+ return
+}
+
+// getBitFlags Parses struct tags for bit flags.
+func getBitFlags(toType reflect.Type) map[string]uint8 {
+ flags := map[string]uint8{}
+ toTypeFields := deepFields(toType)
+
+ // Get a list dest of tags
+ for _, field := range toTypeFields {
+ tags := field.Tag.Get("copier")
+ if tags != "" {
+ flags[field.Name] = parseTags(tags)
+ }
+ }
+ return flags
+}
+
+// checkBitFlags Checks flags for error or panic conditions.
+func checkBitFlags(flagsList map[string]uint8) (err error) {
+ // Check flag conditions were met
+ for name, flags := range flagsList {
+ if flags&hasCopied == 0 {
+ switch {
+ case flags&tagMust != 0 && flags&tagNoPanic != 0:
+ err = fmt.Errorf("field %s has must tag but was not copied", name)
+ return
+ case flags&(tagMust) != 0:
+ panic(fmt.Sprintf("Field %s has must tag but was not copied", name))
+ }
+ }
+ }
+ return
+}
+
+func driverValuer(v reflect.Value) (i driver.Valuer, ok bool) {
+
+ if !v.CanAddr() {
+ i, ok = v.Interface().(driver.Valuer)
+ return
+ }
+
+ i, ok = v.Addr().Interface().(driver.Valuer)
+ return
+}
diff --git a/vendor/github.com/jinzhu/copier/errors.go b/vendor/github.com/jinzhu/copier/errors.go
new file mode 100644
index 000000000..cf7c5e74b
--- /dev/null
+++ b/vendor/github.com/jinzhu/copier/errors.go
@@ -0,0 +1,10 @@
+package copier
+
+import "errors"
+
+var (
+ ErrInvalidCopyDestination = errors.New("copy destination is invalid")
+ ErrInvalidCopyFrom = errors.New("copy from is invalid")
+ ErrMapKeyNotMatch = errors.New("map's key type doesn't match")
+ ErrNotSupported = errors.New("not supported")
+)
diff --git a/vendor/github.com/jinzhu/copier/go.mod b/vendor/github.com/jinzhu/copier/go.mod
new file mode 100644
index 000000000..531422dcb
--- /dev/null
+++ b/vendor/github.com/jinzhu/copier/go.mod
@@ -0,0 +1,3 @@
+module github.com/jinzhu/copier
+
+go 1.15
diff --git a/vendor/github.com/onsi/ginkgo/CHANGELOG.md b/vendor/github.com/onsi/ginkgo/CHANGELOG.md
index 4e0afc291..50631e4a9 100644
--- a/vendor/github.com/onsi/ginkgo/CHANGELOG.md
+++ b/vendor/github.com/onsi/ginkgo/CHANGELOG.md
@@ -1,3 +1,8 @@
+## 1.16.2
+
+### Fixes
+- Deprecations can be suppressed by setting an `ACK_GINKGO_DEPRECATIONS=<semver>` environment variable.
+
## 1.16.1
### Fixes
diff --git a/vendor/github.com/onsi/ginkgo/config/config.go b/vendor/github.com/onsi/ginkgo/config/config.go
index 5f4a4c26e..ab8863d75 100644
--- a/vendor/github.com/onsi/ginkgo/config/config.go
+++ b/vendor/github.com/onsi/ginkgo/config/config.go
@@ -20,7 +20,7 @@ import (
"fmt"
)
-const VERSION = "1.16.1"
+const VERSION = "1.16.2"
type GinkgoConfigType struct {
RandomSeed int64
diff --git a/vendor/github.com/onsi/ginkgo/ginkgo/run_command.go b/vendor/github.com/onsi/ginkgo/ginkgo/run_command.go
index 47b586d93..c7f80d143 100644
--- a/vendor/github.com/onsi/ginkgo/ginkgo/run_command.go
+++ b/vendor/github.com/onsi/ginkgo/ginkgo/run_command.go
@@ -61,6 +61,7 @@ func (r *SpecRunner) RunSpecs(args []string, additionalArgs []string) {
deprecationTracker.TrackDeprecation(types.Deprecation{
Message: "--stream is deprecated and will be removed in Ginkgo 2.0",
DocLink: "removed--stream",
+ Version: "1.16.0",
})
}
@@ -68,6 +69,7 @@ func (r *SpecRunner) RunSpecs(args []string, additionalArgs []string) {
deprecationTracker.TrackDeprecation(types.Deprecation{
Message: "--notify is deprecated and will be removed in Ginkgo 2.0",
DocLink: "removed--notify",
+ Version: "1.16.0",
})
}
diff --git a/vendor/github.com/onsi/ginkgo/types/deprecation_support.go b/vendor/github.com/onsi/ginkgo/types/deprecation_support.go
index 7f7a9aeb8..71420f597 100644
--- a/vendor/github.com/onsi/ginkgo/types/deprecation_support.go
+++ b/vendor/github.com/onsi/ginkgo/types/deprecation_support.go
@@ -1,12 +1,19 @@
package types
import (
+ "os"
+ "strconv"
+ "strings"
+ "unicode"
+
+ "github.com/onsi/ginkgo/config"
"github.com/onsi/ginkgo/formatter"
)
type Deprecation struct {
Message string
DocLink string
+ Version string
}
type deprecations struct{}
@@ -17,6 +24,7 @@ func (d deprecations) CustomReporter() Deprecation {
return Deprecation{
Message: "You are using a custom reporter. Support for custom reporters will likely be removed in V2. Most users were using them to generate junit or teamcity reports and this functionality will be merged into the core reporter. In addition, Ginkgo 2.0 will support emitting a JSON-formatted report that users can then manipulate to generate custom reports.\n\n{{red}}{{bold}}If this change will be impactful to you please leave a comment on {{cyan}}{{underline}}https://github.com/onsi/ginkgo/issues/711{{/}}",
DocLink: "removed-custom-reporters",
+ Version: "1.16.0",
}
}
@@ -24,6 +32,7 @@ func (d deprecations) V1Reporter() Deprecation {
return Deprecation{
Message: "You are using a V1 Ginkgo Reporter. Please update your custom reporter to the new V2 Reporter interface.",
DocLink: "changed-reporter-interface",
+ Version: "1.16.0",
}
}
@@ -31,6 +40,7 @@ func (d deprecations) Async() Deprecation {
return Deprecation{
Message: "You are passing a Done channel to a test node to test asynchronous behavior. This is deprecated in Ginkgo V2. Your test will run synchronously and the timeout will be ignored.",
DocLink: "removed-async-testing",
+ Version: "1.16.0",
}
}
@@ -38,6 +48,7 @@ func (d deprecations) Measure() Deprecation {
return Deprecation{
Message: "Measure is deprecated in Ginkgo V2",
DocLink: "removed-measure",
+ Version: "1.16.0",
}
}
@@ -45,12 +56,14 @@ func (d deprecations) Convert() Deprecation {
return Deprecation{
Message: "The convert command is deprecated in Ginkgo V2",
DocLink: "removed-ginkgo-convert",
+ Version: "1.16.0",
}
}
func (d deprecations) Blur() Deprecation {
return Deprecation{
Message: "The blur command is deprecated in Ginkgo V2. Use 'ginkgo unfocus' instead.",
+ Version: "1.16.0",
}
}
@@ -65,6 +78,15 @@ func NewDeprecationTracker() *DeprecationTracker {
}
func (d *DeprecationTracker) TrackDeprecation(deprecation Deprecation, cl ...CodeLocation) {
+ ackVersion := os.Getenv("ACK_GINKGO_DEPRECATIONS")
+ if deprecation.Version != "" && ackVersion != "" {
+ ack := ParseSemVer(ackVersion)
+ version := ParseSemVer(deprecation.Version)
+ if ack.GreaterThanOrEqualTo(version) {
+ return
+ }
+ }
+
if len(cl) == 1 {
d.deprecations[deprecation] = append(d.deprecations[deprecation], cl[0])
} else {
@@ -92,5 +114,37 @@ func (d *DeprecationTracker) DeprecationsReport() string {
out += formatter.Fi(2, "{{gray}}%s{{/}}\n", location)
}
}
+ out += formatter.F("\n{{gray}}To silence deprecations that can be silenced set the following environment variable:{{/}}\n")
+ out += formatter.Fi(1, "{{gray}}ACK_GINKGO_DEPRECATIONS=%s{{/}}\n", config.VERSION)
+ return out
+}
+
+type SemVer struct {
+ Major int
+ Minor int
+ Patch int
+}
+
+func (s SemVer) GreaterThanOrEqualTo(o SemVer) bool {
+ return (s.Major > o.Major) ||
+ (s.Major == o.Major && s.Minor > o.Minor) ||
+ (s.Major == o.Major && s.Minor == o.Minor && s.Patch >= o.Patch)
+}
+
+func ParseSemVer(semver string) SemVer {
+ out := SemVer{}
+ semver = strings.TrimFunc(semver, func(r rune) bool {
+ return !(unicode.IsNumber(r) || r == '.')
+ })
+ components := strings.Split(semver, ".")
+ if len(components) > 0 {
+ out.Major, _ = strconv.Atoi(components[0])
+ }
+ if len(components) > 1 {
+ out.Minor, _ = strconv.Atoi(components[1])
+ }
+ if len(components) > 2 {
+ out.Patch, _ = strconv.Atoi(components[2])
+ }
return out
}
diff --git a/vendor/github.com/openshift/imagebuilder/README.md b/vendor/github.com/openshift/imagebuilder/README.md
index 748bff971..4acfaa2bb 100644
--- a/vendor/github.com/openshift/imagebuilder/README.md
+++ b/vendor/github.com/openshift/imagebuilder/README.md
@@ -102,6 +102,8 @@ Example of usage from OpenShift's experimental `dockerbuild` [command with mount
## Run conformance tests (very slow):
```
+docker rmi busybox; docker pull busybox
+docker rmi centos:7; docker pull centos:7
chmod -R go-w ./dockerclient/testdata
-go test ./dockerclient/conformance_test.go -tags conformance -timeout 30m
+go test ./dockerclient -tags conformance -timeout 30m
```
diff --git a/vendor/github.com/openshift/imagebuilder/builder.go b/vendor/github.com/openshift/imagebuilder/builder.go
index dd8b09c05..df5269904 100644
--- a/vendor/github.com/openshift/imagebuilder/builder.go
+++ b/vendor/github.com/openshift/imagebuilder/builder.go
@@ -37,6 +37,8 @@ type Copy struct {
type Run struct {
Shell bool
Args []string
+ // Mounts are mounts specified through the --mount flag inside the Containerfile
+ Mounts []string
}
type Executor interface {
@@ -67,7 +69,7 @@ func (logExecutor) Copy(excludes []string, copies ...Copy) error {
}
func (logExecutor) Run(run Run, config docker.Config) error {
- log.Printf("RUN %v %t (%v)", run.Args, run.Shell, config.Env)
+ log.Printf("RUN %v %v %t (%v)", run.Args, run.Mounts, run.Shell, config.Env)
return nil
}
diff --git a/vendor/github.com/openshift/imagebuilder/dispatchers.go b/vendor/github.com/openshift/imagebuilder/dispatchers.go
index 2294ae0a7..0d82136e7 100644
--- a/vendor/github.com/openshift/imagebuilder/dispatchers.go
+++ b/vendor/github.com/openshift/imagebuilder/dispatchers.go
@@ -306,7 +306,26 @@ func run(b *Builder, args []string, attributes map[string]bool, flagArgs []strin
args = handleJSONArgs(args, attributes)
- run := Run{Args: args}
+ var mounts []string
+ userArgs := mergeEnv(envMapAsSlice(b.Args), b.Env)
+ for _, a := range flagArgs {
+ arg, err := ProcessWord(a, userArgs)
+ if err != nil {
+ return err
+ }
+ switch {
+ case strings.HasPrefix(arg, "--mount="):
+ mount := strings.TrimPrefix(arg, "--mount=")
+ mounts = append(mounts, mount)
+ default:
+ return fmt.Errorf("RUN only supports the --mount flag")
+ }
+ }
+
+ run := Run{
+ Args: args,
+ Mounts: mounts,
+ }
if !attributes["json"] {
run.Shell = true
diff --git a/vendor/github.com/openshift/imagebuilder/imagebuilder.spec b/vendor/github.com/openshift/imagebuilder/imagebuilder.spec
index 684946ece..79d16ec39 100644
--- a/vendor/github.com/openshift/imagebuilder/imagebuilder.spec
+++ b/vendor/github.com/openshift/imagebuilder/imagebuilder.spec
@@ -12,7 +12,7 @@
#
%global golang_version 1.8.1
-%{!?version: %global version 1.2.0}
+%{!?version: %global version 1.2.2-dev}
%{!?release: %global release 1}
%global package_name imagebuilder
%global product_name Container Image Builder