summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cirrus.yml6
-rw-r--r--.github/workflows/multi-arch-build.yaml154
-rw-r--r--.pre-commit-config.yaml7
-rw-r--r--Makefile14
-rw-r--r--cmd/podman/common/completion.go4
-rw-r--r--cmd/podman/common/create.go9
-rw-r--r--cmd/podman/common/create_opts.go9
-rw-r--r--cmd/podman/common/specgen.go105
-rw-r--r--cmd/podman/containers/cp.go177
-rw-r--r--cmd/podman/containers/create.go2
-rw-r--r--cmd/podman/containers/logs.go14
-rw-r--r--cmd/podman/containers/restore.go6
-rw-r--r--cmd/podman/images/import.go19
-rw-r--r--cmd/podman/login.go1
-rw-r--r--cmd/podman/logout.go1
-rw-r--r--cmd/podman/parse/net.go7
-rw-r--r--cmd/podman/registry/config.go3
-rw-r--r--cmd/podman/root.go11
-rw-r--r--cmd/podman/system/migrate.go5
-rw-r--r--contrib/podmanimage/stable/Dockerfile2
-rw-r--r--contrib/podmanimage/testing/Dockerfile2
-rw-r--r--contrib/podmanimage/upstream/Dockerfile2
-rw-r--r--docs/source/includes.rst2
-rw-r--r--docs/source/markdown/podman-container-restore.1.md11
-rw-r--r--docs/source/markdown/podman-container-runlabel.1.md77
-rw-r--r--docs/source/markdown/podman-container.1.md2
-rw-r--r--docs/source/markdown/podman-cp.1.md100
-rw-r--r--docs/source/markdown/podman-create.1.md8
-rw-r--r--docs/source/markdown/podman-images.1.md2
-rw-r--r--docs/source/markdown/podman-logs.1.md29
-rw-r--r--docs/source/markdown/podman-rmi.1.md2
-rw-r--r--docs/source/markdown/podman-run.1.md8
-rw-r--r--docs/source/markdown/podman-volume-ls.1.md1
-rw-r--r--docs/source/markdown/podman-volume-prune.1.md6
-rw-r--r--go.mod14
-rw-r--r--go.sum35
-rw-r--r--libpod/container.go40
-rw-r--r--libpod/container_api.go20
-rw-r--r--libpod/container_copy_linux.go3
-rw-r--r--libpod/container_inspect.go33
-rw-r--r--libpod/container_internal.go1
-rw-r--r--libpod/container_internal_linux.go120
-rw-r--r--libpod/container_log_linux.go19
-rw-r--r--libpod/network/network.go6
-rw-r--r--libpod/oci_conmon_linux.go24
-rw-r--r--libpod/runtime_ctr.go38
-rw-r--r--pkg/api/handlers/compat/containers_archive.go17
-rw-r--r--pkg/api/handlers/compat/images.go35
-rw-r--r--pkg/api/handlers/compat/images_build.go19
-rw-r--r--pkg/api/handlers/libpod/containers_create.go1
-rw-r--r--pkg/api/handlers/types.go7
-rw-r--r--pkg/api/server/docs.go2
-rw-r--r--pkg/api/server/register_archive.go4
-rw-r--r--pkg/api/server/register_volumes.go2
-rw-r--r--pkg/api/server/server.go9
-rw-r--r--pkg/bindings/connection.go3
-rw-r--r--pkg/bindings/containers/types.go3
-rw-r--r--pkg/bindings/containers/types_copy_options.go16
-rw-r--r--pkg/bindings/containers/types_restore_options.go16
-rw-r--r--pkg/bindings/images/build.go38
-rw-r--r--pkg/checkpoint/checkpoint_restore.go96
-rw-r--r--pkg/checkpoint/crutils/checkpoint_restore_utils.go11
-rw-r--r--pkg/copy/parse.go12
-rw-r--r--pkg/criu/criu.go10
-rw-r--r--pkg/domain/entities/containers.go5
-rw-r--r--pkg/domain/entities/engine_container.go3
-rw-r--r--pkg/domain/filters/containers.go30
-rw-r--r--pkg/domain/filters/volumes.go28
-rw-r--r--pkg/domain/infra/abi/archive.go2
-rw-r--r--pkg/domain/infra/abi/containers.go4
-rw-r--r--pkg/domain/infra/abi/images_list.go6
-rw-r--r--pkg/domain/infra/abi/manifest.go1
-rw-r--r--pkg/domain/infra/abi/play.go5
-rw-r--r--pkg/domain/infra/abi/system.go12
-rw-r--r--pkg/domain/infra/runtime_abi.go1
-rw-r--r--pkg/domain/infra/tunnel/containers.go6
-rw-r--r--pkg/domain/infra/tunnel/system.go3
-rw-r--r--pkg/rootless/rootless_linux.c25
-rw-r--r--pkg/rootless/rootless_linux.go20
-rw-r--r--pkg/specgen/generate/container_create.go10
-rw-r--r--pkg/specgen/generate/kube/kube.go108
-rw-r--r--pkg/specgen/generate/oci.go4
-rw-r--r--pkg/specgen/specgen.go3
-rw-r--r--test/README.md2
-rw-r--r--test/apiv2/10-images.at5
-rw-r--r--test/apiv2/30-volumes.at2
-rw-r--r--test/apiv2/python/rest_api/test_v2_0_0_container.py10
-rwxr-xr-xtest/apiv2/test-apiv24
-rwxr-xr-xtest/buildah-bud/apply-podman-deltas61
-rw-r--r--test/buildah-bud/buildah-tests.diff93
-rw-r--r--test/buildah-bud/make-new-buildah-diffs8
-rwxr-xr-xtest/buildah-bud/run-buildah-bud-tests4
-rw-r--r--test/e2e/checkpoint_test.go164
-rw-r--r--test/e2e/common_test.go2
-rw-r--r--test/e2e/container_create_volume_test.go127
-rw-r--r--test/e2e/healthcheck_run_test.go10
-rw-r--r--test/e2e/login_logout_test.go223
-rw-r--r--test/e2e/logs_test.go29
-rw-r--r--test/e2e/network_create_test.go49
-rw-r--r--test/e2e/play_kube_test.go102
-rw-r--r--test/e2e/pod_create_test.go16
-rw-r--r--test/e2e/prune_test.go50
-rw-r--r--test/e2e/ps_test.go37
-rw-r--r--test/e2e/pull_test.go2
-rw-r--r--test/e2e/run_exit_test.go6
-rw-r--r--test/e2e/run_test.go4
-rw-r--r--test/e2e/volume_ls_test.go16
-rw-r--r--test/e2e/volume_prune_test.go31
-rw-r--r--test/system/030-run.bats17
-rw-r--r--test/system/035-logs.bats49
-rw-r--r--test/system/050-stop.bats31
-rw-r--r--test/system/065-cp.bats234
-rw-r--r--test/system/070-build.bats13
-rw-r--r--test/system/090-events.bats1
-rw-r--r--test/system/125-import.bats45
-rw-r--r--test/system/250-systemd.bats39
-rw-r--r--test/system/255-auto-update.bats14
-rw-r--r--test/system/270-socket-activation.bats17
-rw-r--r--test/system/271-tcp-cors-server.bats44
-rw-r--r--test/system/500-networking.bats2
-rw-r--r--test/system/helpers.bash18
-rw-r--r--test/system/helpers.systemd.bash30
-rw-r--r--transfer.md4
-rw-r--r--troubleshooting.md2
-rw-r--r--vendor/github.com/checkpoint-restore/go-criu/.gitignore5
-rw-r--r--vendor/github.com/checkpoint-restore/go-criu/.travis.yml25
-rw-r--r--vendor/github.com/checkpoint-restore/go-criu/Makefile60
-rw-r--r--vendor/github.com/checkpoint-restore/go-criu/rpc/rpc.pb.go1211
-rw-r--r--vendor/github.com/checkpoint-restore/go-criu/v5/.gitignore5
-rw-r--r--vendor/github.com/checkpoint-restore/go-criu/v5/.golangci.yml12
-rw-r--r--vendor/github.com/checkpoint-restore/go-criu/v5/LICENSE (renamed from vendor/github.com/checkpoint-restore/go-criu/LICENSE)0
-rw-r--r--vendor/github.com/checkpoint-restore/go-criu/v5/Makefile62
-rw-r--r--vendor/github.com/checkpoint-restore/go-criu/v5/README.md (renamed from vendor/github.com/checkpoint-restore/go-criu/README.md)53
-rw-r--r--vendor/github.com/checkpoint-restore/go-criu/v5/go.mod9
-rw-r--r--vendor/github.com/checkpoint-restore/go-criu/v5/go.sum12
-rw-r--r--vendor/github.com/checkpoint-restore/go-criu/v5/main.go (renamed from vendor/github.com/checkpoint-restore/go-criu/main.go)48
-rw-r--r--vendor/github.com/checkpoint-restore/go-criu/v5/notify.go (renamed from vendor/github.com/checkpoint-restore/go-criu/notify.go)5
-rw-r--r--vendor/github.com/checkpoint-restore/go-criu/v5/rpc/rpc.pb.go2237
-rw-r--r--vendor/github.com/checkpoint-restore/go-criu/v5/rpc/rpc.proto239
-rw-r--r--vendor/github.com/containers/buildah/.cirrus.yml2
-rw-r--r--vendor/github.com/containers/buildah/add.go39
-rw-r--r--vendor/github.com/containers/buildah/chroot/run.go15
-rw-r--r--vendor/github.com/containers/buildah/go.mod8
-rw-r--r--vendor/github.com/containers/buildah/go.sum20
-rw-r--r--vendor/github.com/containers/buildah/imagebuildah/build.go2
-rw-r--r--vendor/github.com/containers/buildah/imagebuildah/executor.go9
-rw-r--r--vendor/github.com/containers/buildah/imagebuildah/stage_executor.go22
-rw-r--r--vendor/github.com/containers/buildah/imagebuildah/util.go17
-rw-r--r--vendor/github.com/containers/buildah/install.md4
-rw-r--r--vendor/github.com/containers/buildah/pkg/parse/parse.go98
-rw-r--r--vendor/github.com/containers/common/libimage/copier.go12
-rw-r--r--vendor/github.com/containers/common/libimage/filters.go10
-rw-r--r--vendor/github.com/containers/common/libimage/image.go76
-rw-r--r--vendor/github.com/containers/common/libimage/import.go2
-rw-r--r--vendor/github.com/containers/common/libimage/layer_tree.go90
-rw-r--r--vendor/github.com/containers/common/libimage/manifests/manifests.go18
-rw-r--r--vendor/github.com/containers/common/libimage/pull.go97
-rw-r--r--vendor/github.com/containers/common/libimage/runtime.go38
-rw-r--r--vendor/github.com/containers/common/libimage/search.go4
-rw-r--r--vendor/github.com/containers/common/pkg/auth/auth.go153
-rw-r--r--vendor/github.com/containers/common/pkg/auth/cli.go20
-rw-r--r--vendor/github.com/containers/common/pkg/config/config.go11
-rw-r--r--vendor/github.com/containers/common/pkg/config/pull_policy.go8
-rw-r--r--vendor/github.com/containers/common/pkg/seccomp/types.go2
-rw-r--r--vendor/github.com/containers/image/v5/copy/copy.go279
-rw-r--r--vendor/github.com/containers/image/v5/copy/manifest.go33
-rw-r--r--vendor/github.com/containers/image/v5/copy/progress_reader.go25
-rw-r--r--vendor/github.com/containers/image/v5/copy/sign.go4
-rw-r--r--vendor/github.com/containers/image/v5/directory/directory_dest.go37
-rw-r--r--vendor/github.com/containers/image/v5/directory/directory_transport.go6
-rw-r--r--vendor/github.com/containers/image/v5/docker/archive/dest.go3
-rw-r--r--vendor/github.com/containers/image/v5/docker/archive/reader.go4
-rw-r--r--vendor/github.com/containers/image/v5/docker/archive/writer.go4
-rw-r--r--vendor/github.com/containers/image/v5/docker/daemon/daemon_dest.go7
-rw-r--r--vendor/github.com/containers/image/v5/docker/daemon/daemon_src.go4
-rw-r--r--vendor/github.com/containers/image/v5/docker/docker_client.go57
-rw-r--r--vendor/github.com/containers/image/v5/docker/docker_image.go8
-rw-r--r--vendor/github.com/containers/image/v5/docker/docker_image_dest.go43
-rw-r--r--vendor/github.com/containers/image/v5/docker/docker_image_src.go213
-rw-r--r--vendor/github.com/containers/image/v5/docker/docker_transport.go2
-rw-r--r--vendor/github.com/containers/image/v5/docker/errors.go7
-rw-r--r--vendor/github.com/containers/image/v5/docker/internal/tarfile/dest.go6
-rw-r--r--vendor/github.com/containers/image/v5/docker/internal/tarfile/reader.go14
-rw-r--r--vendor/github.com/containers/image/v5/docker/internal/tarfile/src.go8
-rw-r--r--vendor/github.com/containers/image/v5/docker/internal/tarfile/writer.go16
-rw-r--r--vendor/github.com/containers/image/v5/docker/lookaside.go2
-rw-r--r--vendor/github.com/containers/image/v5/image/docker_list.go8
-rw-r--r--vendor/github.com/containers/image/v5/image/docker_schema2.go2
-rw-r--r--vendor/github.com/containers/image/v5/image/oci_index.go8
-rw-r--r--vendor/github.com/containers/image/v5/image/unparsed.go2
-rw-r--r--vendor/github.com/containers/image/v5/internal/blobinfocache/blobinfocache.go3
-rw-r--r--vendor/github.com/containers/image/v5/internal/types/types.go30
-rw-r--r--vendor/github.com/containers/image/v5/manifest/common.go8
-rw-r--r--vendor/github.com/containers/image/v5/manifest/docker_schema1.go8
-rw-r--r--vendor/github.com/containers/image/v5/manifest/docker_schema2.go16
-rw-r--r--vendor/github.com/containers/image/v5/manifest/docker_schema2_list.go6
-rw-r--r--vendor/github.com/containers/image/v5/manifest/manifest.go2
-rw-r--r--vendor/github.com/containers/image/v5/manifest/oci.go16
-rw-r--r--vendor/github.com/containers/image/v5/manifest/oci_index.go6
-rw-r--r--vendor/github.com/containers/image/v5/oci/archive/oci_dest.go13
-rw-r--r--vendor/github.com/containers/image/v5/oci/archive/oci_src.go8
-rw-r--r--vendor/github.com/containers/image/v5/oci/archive/oci_transport.go8
-rw-r--r--vendor/github.com/containers/image/v5/oci/layout/oci_dest.go3
-rw-r--r--vendor/github.com/containers/image/v5/oci/layout/oci_src.go4
-rw-r--r--vendor/github.com/containers/image/v5/openshift/openshift-copies.go2
-rw-r--r--vendor/github.com/containers/image/v5/openshift/openshift.go28
-rw-r--r--vendor/github.com/containers/image/v5/pkg/compression/compression.go47
-rw-r--r--vendor/github.com/containers/image/v5/pkg/compression/internal/types.go14
-rw-r--r--vendor/github.com/containers/image/v5/pkg/compression/types/types.go28
-rw-r--r--vendor/github.com/containers/image/v5/pkg/compression/zstd.go4
-rw-r--r--vendor/github.com/containers/image/v5/pkg/docker/config/config.go237
-rw-r--r--vendor/github.com/containers/image/v5/pkg/docker/config/config_linux.go8
-rw-r--r--vendor/github.com/containers/image/v5/pkg/shortnames/shortnames.go6
-rw-r--r--vendor/github.com/containers/image/v5/pkg/sysregistriesv2/shortnames.go18
-rw-r--r--vendor/github.com/containers/image/v5/pkg/sysregistriesv2/system_registries_v2.go43
-rw-r--r--vendor/github.com/containers/image/v5/storage/storage_image.go257
-rw-r--r--vendor/github.com/containers/image/v5/storage/storage_reference.go89
-rw-r--r--vendor/github.com/containers/image/v5/storage/storage_transport.go4
-rw-r--r--vendor/github.com/containers/image/v5/types/types.go9
-rw-r--r--vendor/github.com/containers/image/v5/version/version.go4
-rw-r--r--vendor/github.com/containers/storage/VERSION2
-rw-r--r--vendor/github.com/containers/storage/drivers/overlay/overlay.go39
-rw-r--r--vendor/github.com/containers/storage/drivers/quota/projectquota.go83
-rw-r--r--vendor/github.com/containers/storage/drivers/quota/projectquota_unsupported.go3
-rw-r--r--vendor/github.com/containers/storage/go.mod2
-rw-r--r--vendor/github.com/containers/storage/go.sum6
-rw-r--r--vendor/github.com/containers/storage/pkg/archive/archive.go5
-rw-r--r--vendor/github.com/containers/storage/pkg/archive/archive_unix.go6
-rw-r--r--vendor/github.com/containers/storage/pkg/chunked/compression.go169
-rw-r--r--vendor/github.com/containers/storage/pkg/chunked/compressor/compressor.go220
-rw-r--r--vendor/github.com/containers/storage/pkg/chunked/internal/compression.go172
-rw-r--r--vendor/github.com/containers/storage/pkg/chunked/storage.go26
-rw-r--r--vendor/github.com/containers/storage/pkg/chunked/storage_linux.go875
-rw-r--r--vendor/github.com/containers/storage/pkg/chunked/storage_unsupported.go16
-rw-r--r--vendor/github.com/containers/storage/storage.conf3
-rw-r--r--vendor/github.com/containers/storage/types/utils.go10
-rw-r--r--vendor/github.com/opencontainers/runc/libcontainer/user/user.go92
-rw-r--r--vendor/github.com/vbauerster/mpb/v7/cwriter/util_zos.go7
-rw-r--r--vendor/github.com/vbauerster/mpb/v7/go.mod2
-rw-r--r--vendor/github.com/vbauerster/mpb/v7/go.sum4
-rw-r--r--vendor/golang.org/x/sys/unix/mkerrors.sh1
-rw-r--r--vendor/golang.org/x/sys/unix/syscall_darwin.go33
-rw-r--r--vendor/golang.org/x/sys/unix/zerrors_darwin_amd64.go5
-rw-r--r--vendor/golang.org/x/sys/unix/zerrors_darwin_arm64.go5
-rw-r--r--vendor/golang.org/x/sys/unix/zerrors_freebsd_386.go5
-rw-r--r--vendor/golang.org/x/sys/unix/zerrors_freebsd_amd64.go5
-rw-r--r--vendor/golang.org/x/sys/unix/zerrors_freebsd_arm.go5
-rw-r--r--vendor/golang.org/x/sys/unix/zerrors_freebsd_arm64.go5
-rw-r--r--vendor/golang.org/x/sys/unix/zerrors_linux.go6
-rw-r--r--vendor/golang.org/x/sys/unix/ztypes_darwin_amd64.go104
-rw-r--r--vendor/golang.org/x/sys/unix/ztypes_darwin_arm64.go104
-rw-r--r--vendor/golang.org/x/sys/unix/ztypes_dragonfly_amd64.go3
-rw-r--r--vendor/golang.org/x/sys/unix/ztypes_freebsd_386.go5
-rw-r--r--vendor/golang.org/x/sys/unix/ztypes_freebsd_amd64.go5
-rw-r--r--vendor/golang.org/x/sys/unix/ztypes_freebsd_arm.go5
-rw-r--r--vendor/golang.org/x/sys/unix/ztypes_freebsd_arm64.go5
-rw-r--r--vendor/golang.org/x/sys/unix/ztypes_netbsd_386.go4
-rw-r--r--vendor/golang.org/x/sys/unix/ztypes_netbsd_amd64.go4
-rw-r--r--vendor/golang.org/x/sys/unix/ztypes_netbsd_arm.go4
-rw-r--r--vendor/golang.org/x/sys/unix/ztypes_netbsd_arm64.go4
-rw-r--r--vendor/golang.org/x/sys/unix/ztypes_openbsd_386.go4
-rw-r--r--vendor/golang.org/x/sys/unix/ztypes_openbsd_amd64.go4
-rw-r--r--vendor/golang.org/x/sys/unix/ztypes_openbsd_arm.go4
-rw-r--r--vendor/golang.org/x/sys/unix/ztypes_openbsd_arm64.go4
-rw-r--r--vendor/golang.org/x/sys/unix/ztypes_openbsd_mips64.go4
-rw-r--r--vendor/modules.txt23
266 files changed, 9041 insertions, 2907 deletions
diff --git a/.cirrus.yml b/.cirrus.yml
index 8a79ade78..7218e3e9a 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -601,7 +601,11 @@ buildah_bud_test_task:
CTR_FQIN: ${FEDORA_CONTAINER_FQIN}
# ID for re-use of build output
_BUILD_CACHE_HANDLE: ${FEDORA_NAME}-build-${CIRRUS_BUILD_ID}
- PODBIN_NAME: podman
+ matrix:
+ - env:
+ PODBIN_NAME: podman
+ - env:
+ PODBIN_NAME: remote
gce_instance: *standardvm
timeout_in: 45m
clone_script: *noop
diff --git a/.github/workflows/multi-arch-build.yaml b/.github/workflows/multi-arch-build.yaml
index 9bd98078b..fff617865 100644
--- a/.github/workflows/multi-arch-build.yaml
+++ b/.github/workflows/multi-arch-build.yaml
@@ -1,6 +1,6 @@
---
-# Please see contrib/podmanimage/README.md for details on the intentions
+# Please see contrib/<reponame>image/README.md for details on the intentions
# of this workflow.
#
# BIG FAT WARNING: This workflow is duplicated across containers/skopeo,
@@ -11,7 +11,7 @@
name: build multi-arch images
on:
- # Upstream podman tends to be very active, with many merges per day.
+ # Upstream tends to be very active, with many merges per day.
# Only run this daily via cron schedule, or manually, not by branch push.
schedule:
- cron: '0 8 * * *'
@@ -20,19 +20,23 @@ on:
jobs:
multi:
- name: multi-arch Podman build
+ name: multi-arch image build
env:
- PODMAN_QUAY_REGISTRY: quay.io/podman
+ REPONAME: podman # No easy way to parse this out of $GITHUB_REPOSITORY
+ # Server/namespace value used to format FQIN
+ REPONAME_QUAY_REGISTRY: quay.io/podman
CONTAINERS_QUAY_REGISTRY: quay.io/containers
# list of architectures for build
PLATFORMS: linux/amd64,linux/s390x,linux/ppc64le,linux/arm64
+ # Command to execute in container to obtain project version number
+ VERSION_CMD: "podman --version"
# build several images (upstream, testing, stable) in parallel
strategy:
# By default, failure of one matrix item cancels all others
fail-fast: false
matrix:
- # Builds are located under contrib/podmanimage/<source> directory
+ # Builds are located under contrib/<reponame>image/<source> directory
source:
- upstream
- testing
@@ -57,14 +61,14 @@ jobs:
driver-opts: network=host
install: true
- - name: Build and locally push Podman
+ - name: Build and locally push image
uses: docker/build-push-action@v2
with:
- context: contrib/podmanimage/${{ matrix.source }}
- file: ./contrib/podmanimage/${{ matrix.source }}/Dockerfile
+ context: contrib/${{ env.REPONAME }}image/${{ matrix.source }}
+ file: ./contrib/${{ env.REPONAME }}image/${{ matrix.source }}/Dockerfile
platforms: ${{ env.PLATFORMS }}
push: true
- tags: localhost:5000/podman/${{ matrix.source }}
+ tags: localhost:5000/${{ env.REPONAME }}/${{ matrix.source }}
# Simple verification that stable images work, and
# also grab version number use in forming the FQIN.
@@ -73,41 +77,30 @@ jobs:
id: sniff_test
run: |
podman pull --tls-verify=false \
- localhost:5000/podman/${{ matrix.source }}
- VERSION_OUTPUT="$(podman run \
- localhost:5000/podman/${{ matrix.source }} \
- podman --storage-driver=vfs version)"
+ localhost:5000/$REPONAME/${{ matrix.source }}
+ VERSION_OUTPUT=$(podman run \
+ localhost:5000/$REPONAME/${{ matrix.source }} \
+ $VERSION_CMD)
echo "$VERSION_OUTPUT"
- VERSION=$(grep -Em1 '^Version: ' <<<"$VERSION_OUTPUT" | awk '{print $2}')
+ VERSION=$(awk -r -e "/^${REPONAME} version /"'{print $3}' <<<"$VERSION_OUTPUT")
test -n "$VERSION"
- echo "::set-output name=version::${VERSION}"
+ echo "::set-output name=version::$VERSION"
- - name: Generate podman reg. image FQIN(s)
- id: podman_reg
+ - name: Generate image FQIN(s) to push
+ id: reponame_reg
run: |
if [[ "${{ matrix.source }}" == 'stable' ]]; then
- # The `podman version` in image just built
+ # The command version in image just built
VERSION='v${{ steps.sniff_test.outputs.version }}'
# workaround vim syntax-highlight bug: '
- # Image tags previously pushed to quay
- ALLTAGS=$(skopeo list-tags \
- docker://$PODMAN_QUAY_REGISTRY/stable | \
- jq -r '.Tags[]')
-
- # New version? Push quay.io/podman/stable:vX.X.X and :latest
- if ! fgrep -qx "$VERSION" <<<"$ALLTAGS"; then
- # Assume version-tag is also the most up to date (i.e. "latest")
- FQIN="$PODMAN_QUAY_REGISTRY/stable:$VERSION,$PODMAN_QUAY_REGISTRY/stable:latest"
- else # Not a new version-tagged image
- # Assume other contents changed, so this is the "new" latest.
- FQIN="$PODMAN_QUAY_REGISTRY/stable:latest"
- fi
+ # Push both new|updated version-tag and latest-tag FQINs
+ FQIN="$REPONAME_QUAY_REGISTRY/stable:$VERSION,$REPONAME_QUAY_REGISTRY/stable:latest"
elif [[ "${{ matrix.source }}" == 'testing' ]]; then
# Assume some contents changed, always push latest testing.
- FQIN="$PODMAN_QUAY_REGISTRY/testing:latest"
+ FQIN="$REPONAME_QUAY_REGISTRY/testing:latest"
elif [[ "${{ matrix.source }}" == 'upstream' ]]; then
# Assume some contents changed, always push latest upstream.
- FQIN="$PODMAN_QUAY_REGISTRY/upstream:latest"
+ FQIN="$REPONAME_QUAY_REGISTRY/upstream:latest"
else
echo "::error::Unknown matrix item '${{ matrix.source }}'"
exit 1
@@ -125,16 +118,8 @@ jobs:
run: |
VERSION='v${{ steps.sniff_test.outputs.version }}'
# workaround vim syntax-highlight bug: '
- ALLTAGS=$(skopeo list-tags \
- docker://$CONTAINERS_QUAY_REGISTRY/podman | \
- jq -r '.Tags[]')
-
- # New version? Push quay.io/containers/podman:vX.X.X and latest
- if ! fgrep -qx "$VERSION" <<<"$ALLTAGS"; then
- FQIN="$CONTAINERS_QUAY_REGISTRY/podman:$VERSION,$CONTAINERS_QUAY_REGISTRY/podman:latest"
- else # Not a new version-tagged image, only update latest.
- FQIN="$CONTAINERS_QUAY_REGISTRY/podman:latest"
- fi
+ # Push both new|updated version-tag and latest-tag FQINs
+ FQIN="$CONTAINERS_QUAY_REGISTRY/$REPONAME:$VERSION,$CONTAINERS_QUAY_REGISTRY/$REPONAME:latest"
echo "::warning::Pushing $FQIN"
echo "::set-output name=fqin::${FQIN}"
echo '::set-output name=push::true'
@@ -143,50 +128,65 @@ jobs:
run: |
# This is a really hacky/strange workflow idiom, required
# for setting multi-line $LABELS value for consumption in
- # a future step.
+ # a future step. There is literally no cleaner way to do this :<
# https://docs.github.com/en/actions/reference/workflow-commands-for-github-actions#multiline-strings
- cat << EOF | tee -a $GITHUB_ENV
- LABELS<<DELIMITER
- org.opencontainers.image.source=https://github.com/${{ github.repository }}.git
- org.opencontainers.image.revision=${{ github.sha }}
- org.opencontainers.image.created=$(date -u --iso-8601=seconds)
- DELIMITER
- EOF
-
- # Separate steps to login and push for podman and containers quay
- # repositories are required, because 2 sets of credentials are used and `docker
- # login` as well as `podman login` do not support having 2 different
- # credential sets for 1 registry.
- # At the same time reuse of non-shell steps is not supported by Github Actions
- # via anchors or composite actions
-
- # Push to 'podman' Quay repo for stable, testing. and upstream
- - name: Login to 'podman' Quay registry
+ function set_labels() {
+ echo 'LABELS<<DELIMITER' >> "$GITHUB_ENV"
+ for line; do
+ echo "$line" | tee -a "$GITHUB_ENV"
+ done
+ echo "DELIMITER" >> "$GITHUB_ENV"
+ }
+
+ declare -a lines
+ lines=(\
+ "org.opencontainers.image.source=https://github.com/${GITHUB_REPOSITORY}.git"
+ "org.opencontainers.image.revision=${GITHUB_SHA}"
+ "org.opencontainers.image.created=$(date -u --iso-8601=seconds)"
+ )
+
+ # Only the 'stable' matrix source obtains $VERSION
+ if [[ "${{ matrix.source }}" == "stable" ]]; then
+ lines+=(\
+ "org.opencontainers.image.version=${{ steps.sniff_test.outputs.version }}"
+ )
+ fi
+
+ set_labels "${lines[@]}"
+
+ # Separate steps to login and push for $REPONAME_QUAY_REGISTRY and
+ # $CONTAINERS_QUAY_REGISTRY are required, because 2 sets of credentials
+ # are used and namespaced within the registry. At the same time, reuse
+ # of non-shell steps is not supported by Github Actions nor are YAML
+ # anchors/aliases, nor composite actions.
+
+ # Push to $REPONAME_QUAY_REGISTRY for stable, testing. and upstream
+ - name: Login to ${{ env.REPONAME_QUAY_REGISTRY }}
uses: docker/login-action@v1
- if: steps.podman_reg.outputs.push == 'true'
+ if: steps.reponame_reg.outputs.push == 'true'
with:
- registry: ${{ env.PODMAN_QUAY_REGISTRY }}
+ registry: ${{ env.REPONAME_QUAY_REGISTRY }}
# N/B: Secrets are not passed to workflows that are triggered
# by a pull request from a fork
- username: ${{ secrets.PODMAN_QUAY_USERNAME }}
- password: ${{ secrets.PODMAN_QUAY_PASSWORD }}
+ username: ${{ secrets.REPONAME_QUAY_USERNAME }}
+ password: ${{ secrets.REPONAME_QUAY_PASSWORD }}
- - name: Push images to 'podman' Quay
+ - name: Push images to ${{ steps.reponame_reg.outputs.fqin }}
uses: docker/build-push-action@v2
- if: steps.podman_reg.outputs.push == 'true'
+ if: steps.reponame_reg.outputs.push == 'true'
with:
- cache-from: type=registry,ref=localhost:5000/podman/${{ matrix.source }}
+ cache-from: type=registry,ref=localhost:5000/${{ env.REPONAME }}/${{ matrix.source }}
cache-to: type=inline
- context: contrib/podmanimage/${{ matrix.source }}
- file: ./contrib/podmanimage/${{ matrix.source }}/Dockerfile
+ context: contrib/${{ env.REPONAME }}image/${{ matrix.source }}
+ file: ./contrib/${{ env.REPONAME }}image/${{ matrix.source }}/Dockerfile
platforms: ${{ env.PLATFORMS }}
push: true
- tags: ${{ steps.podman_reg.outputs.fqin }}
+ tags: ${{ steps.reponame_reg.outputs.fqin }}
labels: |
${{ env.LABELS }}
- # Push to 'containers' Quay repo only stable podman
- - name: Login to 'containers' Quay registry
+ # Push to $CONTAINERS_QUAY_REGISTRY only stable
+ - name: Login to ${{ env.CONTAINERS_QUAY_REGISTRY }}
if: steps.containers_reg.outputs.push == 'true'
uses: docker/login-action@v1
with:
@@ -194,14 +194,14 @@ jobs:
username: ${{ secrets.CONTAINERS_QUAY_USERNAME }}
password: ${{ secrets.CONTAINERS_QUAY_PASSWORD }}
- - name: Push images to 'containers' Quay
+ - name: Push images to ${{ steps.containers_reg.outputs.fqin }}
if: steps.containers_reg.outputs.push == 'true'
uses: docker/build-push-action@v2
with:
- cache-from: type=registry,ref=localhost:5000/podman/${{ matrix.source }}
+ cache-from: type=registry,ref=localhost:5000/${{ env.REPONAME }}/${{ matrix.source }}
cache-to: type=inline
- context: contrib/podmanimage/${{ matrix.source }}
- file: ./contrib/podmanimage/${{ matrix.source }}/Dockerfile
+ context: contrib/${{ env.REPONAME }}image/${{ matrix.source }}
+ file: ./contrib/${{ env.REPONAME }}image/${{ matrix.source }}/Dockerfile
platforms: ${{ env.PLATFORMS }}
push: true
tags: ${{ steps.containers_reg.outputs.fqin }}
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index f44b0ea42..91c0fef87 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -4,8 +4,15 @@ repos:
- repo: https://github.com/pre-commit/pre-commit-hooks.git
rev: v3.4.0
hooks:
+ # buildah-tests.diff is generated by 'git format-patch' and includes
+ # trailing whitespace as part of its format. We can work around that,
+ # but unfortunately the buildah repo has some files with tabs, which
+ # git-diff formats as '[+/-]<space><tab>', which these hooks choke on.
+ # Just disable checks on this diff file as a special case.
- id: end-of-file-fixer
+ exclude: test/buildah-bud/buildah-tests.diff
- id: trailing-whitespace
+ exclude: test/buildah-bud/buildah-tests.diff
- id: mixed-line-ending
- id: check-byte-order-marker
- id: check-executables-have-shebangs
diff --git a/Makefile b/Makefile
index 8e66f629a..32d2f44b7 100644
--- a/Makefile
+++ b/Makefile
@@ -214,7 +214,7 @@ endif
.PHONY: .gitvalidation
.gitvalidation: .gopathok
@echo "Validating vs commit '$(call err_if_empty,EPOCH_TEST_COMMIT)'"
- GIT_CHECK_EXCLUDE="./vendor:docs/make.bat" $(GOBIN)/git-validation -run DCO,short-subject,dangling-whitespace -range $(EPOCH_TEST_COMMIT)..$(HEAD)
+ GIT_CHECK_EXCLUDE="./vendor:docs/make.bat:test/buildah-bud/buildah-tests.diff" $(GOBIN)/git-validation -run DCO,short-subject,dangling-whitespace -range $(EPOCH_TEST_COMMIT)..$(HEAD)
.PHONY: lint
lint: golangci-lint
@@ -261,7 +261,7 @@ codespell:
codespell -S bin,vendor,.git,go.sum,changelog.txt,.cirrus.yml,"RELEASE_NOTES.md,*.xz,*.gz,*.tar,*.tgz,bin2img,*ico,*.png,*.1,*.5,copyimg,*.orig,apidoc.go" -L uint,iff,od,seeked,splitted,marge,ERRO,hist,ether -w
.PHONY: validate
-validate: gofmt lint .gitvalidation validate.completions man-page-check swagger-check tests-included
+validate: gofmt lint .gitvalidation validate.completions man-page-check swagger-check tests-included tests-expect-exit
.PHONY: build-all-new-commits
build-all-new-commits:
@@ -605,6 +605,16 @@ test-binaries: test/checkseccomp/checkseccomp test/goecho/goecho install.cataton
tests-included:
contrib/cirrus/pr-should-include-tests
+.PHONY: tests-expect-exit
+tests-expect-exit:
+ @if egrep 'Expect.*ExitCode' test/e2e/*.go | egrep -v ', ".*"\)'; then \
+ echo "^^^ Unhelpful use of Expect(ExitCode())"; \
+ echo " Please use '.Should(Exit(...))' pattern instead."; \
+ echo " If that's not possible, please add an annotation (description) to your assertion:"; \
+ echo " Expect(...).To(..., \"Friendly explanation of this check\")"; \
+ exit 1; \
+ fi
+
###
### Release/Packaging targets
###
diff --git a/cmd/podman/common/completion.go b/cmd/podman/common/completion.go
index 177d094aa..08b2f6235 100644
--- a/cmd/podman/common/completion.go
+++ b/cmd/podman/common/completion.go
@@ -46,7 +46,9 @@ func setupContainerEngine(cmd *cobra.Command) (entities.ContainerEngine, error)
return nil, err
}
if !registry.IsRemote() && rootless.IsRootless() {
- err := containerEngine.SetupRootless(registry.Context(), cmd)
+ _, noMoveProcess := cmd.Annotations[registry.NoMoveProcess]
+
+ err := containerEngine.SetupRootless(registry.Context(), noMoveProcess)
if err != nil {
return nil, err
}
diff --git a/cmd/podman/common/create.go b/cmd/podman/common/create.go
index 64d1956eb..96414add4 100644
--- a/cmd/podman/common/create.go
+++ b/cmd/podman/common/create.go
@@ -655,15 +655,6 @@ func DefineCreateFlags(cmd *cobra.Command, cf *ContainerCLIOpts) {
)
_ = cmd.RegisterFlagCompletionFunc(stopTimeoutFlagName, completion.AutocompleteNone)
- storageOptFlagName := "storage-opt"
- createFlags.StringSliceVar(
- &cf.StorageOpt,
- storageOptFlagName, []string{},
- "Storage driver options per container",
- )
- //FIXME: What should we suggest here? The flag is not in the man page.
- _ = cmd.RegisterFlagCompletionFunc(storageOptFlagName, completion.AutocompleteNone)
-
subgidnameFlagName := "subgidname"
createFlags.StringVar(
&cf.SubUIDName,
diff --git a/cmd/podman/common/create_opts.go b/cmd/podman/common/create_opts.go
index 66778f519..42e0efe5d 100644
--- a/cmd/podman/common/create_opts.go
+++ b/cmd/podman/common/create_opts.go
@@ -517,7 +517,14 @@ func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, rtc *c
cliOpts.OOMKillDisable = *cc.HostConfig.OomKillDisable
}
if cc.Config.Healthcheck != nil {
- cliOpts.HealthCmd = strings.Join(cc.Config.Healthcheck.Test, " ")
+ finCmd := ""
+ for _, str := range cc.Config.Healthcheck.Test {
+ finCmd = finCmd + str + " "
+ }
+ if len(finCmd) > 1 {
+ finCmd = finCmd[:len(finCmd)-1]
+ }
+ cliOpts.HealthCmd = finCmd
cliOpts.HealthInterval = cc.Config.Healthcheck.Interval.String()
cliOpts.HealthRetries = uint(cc.Config.Healthcheck.Retries)
cliOpts.HealthStartPeriod = cc.Config.Healthcheck.StartPeriod.String()
diff --git a/cmd/podman/common/specgen.go b/cmd/podman/common/specgen.go
index 2f45e559d..42f515ace 100644
--- a/cmd/podman/common/specgen.go
+++ b/cmd/podman/common/specgen.go
@@ -516,7 +516,6 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string
if len(con) != 2 {
return fmt.Errorf("invalid --security-opt 1: %q", opt)
}
-
switch con[0] {
case "apparmor":
s.ContainerSecurityConfig.ApparmorProfile = con[1]
@@ -566,6 +565,14 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string
s.Devices = append(s.Devices, specs.LinuxDevice{Path: dev})
}
+ for _, rule := range c.DeviceCGroupRule {
+ dev, err := parseLinuxResourcesDeviceAccess(rule)
+ if err != nil {
+ return err
+ }
+ s.DeviceCGroupRule = append(s.DeviceCGroupRule, dev)
+ }
+
s.Init = c.Init
s.InitPath = c.InitPath
s.Stdin = c.Interactive
@@ -656,25 +663,40 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string
}
func makeHealthCheckFromCli(inCmd, interval string, retries uint, timeout, startPeriod string) (*manifest.Schema2HealthConfig, error) {
+ cmdArr := []string{}
+ isArr := true
+ err := json.Unmarshal([]byte(inCmd), &cmdArr) // array unmarshalling
+ if err != nil {
+ cmdArr = strings.SplitN(inCmd, " ", 2) // default for compat
+ isArr = false
+ }
// Every healthcheck requires a command
- if len(inCmd) == 0 {
+ if len(cmdArr) == 0 {
return nil, errors.New("Must define a healthcheck command for all healthchecks")
}
-
- // first try to parse option value as JSON array of strings...
- cmd := []string{}
-
- if inCmd == "none" {
- cmd = []string{"NONE"}
- } else {
- err := json.Unmarshal([]byte(inCmd), &cmd)
- if err != nil {
- // ...otherwise pass it to "/bin/sh -c" inside the container
- cmd = []string{"CMD-SHELL", inCmd}
+ concat := ""
+ if cmdArr[0] == "CMD" || cmdArr[0] == "none" { // this is for compat, we are already split properly for most compat cases
+ cmdArr = strings.Fields(inCmd)
+ } else if cmdArr[0] != "CMD-SHELL" { // this is for podman side of things, wont contain the keywords
+ if isArr && len(cmdArr) > 1 { // an array of consecutive commands
+ cmdArr = append([]string{"CMD"}, cmdArr...)
+ } else { // one singular command
+ if len(cmdArr) == 1 {
+ concat = cmdArr[0]
+ } else {
+ concat = strings.Join(cmdArr[0:], " ")
+ }
+ cmdArr = append([]string{"CMD-SHELL"}, concat)
}
}
+
+ if cmdArr[0] == "none" { // if specified to remove healtcheck
+ cmdArr = []string{"NONE"}
+ }
+
+ // healthcheck is by default an array, so we simply pass the user input
hc := manifest.Schema2HealthConfig{
- Test: cmd,
+ Test: cmdArr,
}
if interval == "disable" {
@@ -885,3 +907,58 @@ func parseSecrets(secrets []string) ([]specgen.Secret, map[string]string, error)
}
return mount, envs, nil
}
+
+var cgroupDeviceType = map[string]bool{
+ "a": true, // all
+ "b": true, // block device
+ "c": true, // character device
+}
+
+var cgroupDeviceAccess = map[string]bool{
+ "r": true, //read
+ "w": true, //write
+ "m": true, //mknod
+}
+
+// parseLinuxResourcesDeviceAccess parses the raw string passed with the --device-access-add flag
+func parseLinuxResourcesDeviceAccess(device string) (specs.LinuxDeviceCgroup, error) {
+ var devType, access string
+ var major, minor *int64
+
+ value := strings.Split(device, " ")
+ if len(value) != 3 {
+ return specs.LinuxDeviceCgroup{}, fmt.Errorf("invalid device cgroup rule requires type, major:Minor, and access rules: %q", device)
+ }
+
+ devType = value[0]
+ if !cgroupDeviceType[devType] {
+ return specs.LinuxDeviceCgroup{}, fmt.Errorf("invalid device type in device-access-add: %s", devType)
+ }
+
+ number := strings.SplitN(value[1], ":", 2)
+ i, err := strconv.ParseInt(number[0], 10, 64)
+ if err != nil {
+ return specs.LinuxDeviceCgroup{}, err
+ }
+ major = &i
+ if len(number) == 2 && number[1] != "*" {
+ i, err := strconv.ParseInt(number[1], 10, 64)
+ if err != nil {
+ return specs.LinuxDeviceCgroup{}, err
+ }
+ minor = &i
+ }
+ access = value[2]
+ for _, c := range strings.Split(access, "") {
+ if !cgroupDeviceAccess[c] {
+ return specs.LinuxDeviceCgroup{}, fmt.Errorf("invalid device access in device-access-add: %s", c)
+ }
+ }
+ return specs.LinuxDeviceCgroup{
+ Allow: true,
+ Type: devType,
+ Major: major,
+ Minor: minor,
+ Access: access,
+ }, nil
+}
diff --git a/cmd/podman/containers/cp.go b/cmd/podman/containers/cp.go
index c1f1e27f5..7b5846a35 100644
--- a/cmd/podman/containers/cp.go
+++ b/cmd/podman/containers/cp.go
@@ -82,7 +82,9 @@ func cp(cmd *cobra.Command, args []string) error {
return err
}
- if len(sourceContainerStr) > 0 {
+ if len(sourceContainerStr) > 0 && len(destContainerStr) > 0 {
+ return copyContainerToContainer(sourceContainerStr, sourcePath, destContainerStr, destPath)
+ } else if len(sourceContainerStr) > 0 {
return copyFromContainer(sourceContainerStr, sourcePath, destPath)
}
@@ -115,6 +117,84 @@ func doCopy(funcA func() error, funcB func() error) error {
return errorhandling.JoinErrors(copyErrors)
}
+func copyContainerToContainer(sourceContainer string, sourcePath string, destContainer string, destPath string) error {
+ if err := containerMustExist(sourceContainer); err != nil {
+ return err
+ }
+
+ if err := containerMustExist(destContainer); err != nil {
+ return err
+ }
+
+ sourceContainerInfo, err := registry.ContainerEngine().ContainerStat(registry.GetContext(), sourceContainer, sourcePath)
+ if err != nil {
+ return errors.Wrapf(err, "%q could not be found on container %s", sourcePath, sourceContainer)
+ }
+
+ destContainerBaseName, destContainerInfo, destResolvedToParentDir, err := resolvePathOnDestinationContainer(destContainer, destPath, false)
+ if err != nil {
+ return err
+ }
+
+ if sourceContainerInfo.IsDir && !destContainerInfo.IsDir {
+ return errors.New("destination must be a directory when copying a directory")
+ }
+
+ sourceContainerTarget := sourceContainerInfo.LinkTarget
+ destContainerTarget := destContainerInfo.LinkTarget
+ if !destContainerInfo.IsDir {
+ destContainerTarget = filepath.Dir(destPath)
+ }
+
+ // If we copy a directory via the "." notation and the container path
+ // does not exist, we need to make sure that the destination on the
+ // container gets created; otherwise the contents of the source
+ // directory will be written to the destination's parent directory.
+ //
+ // Hence, whenever "." is the source and the destination does not
+ // exist, we copy the source's parent and let the copier package create
+ // the destination via the Rename option.
+ if destResolvedToParentDir && sourceContainerInfo.IsDir && strings.HasSuffix(sourcePath, ".") {
+ sourceContainerTarget = filepath.Dir(sourceContainerTarget)
+ }
+
+ reader, writer := io.Pipe()
+
+ sourceContainerCopy := func() error {
+ defer writer.Close()
+ copyFunc, err := registry.ContainerEngine().ContainerCopyToArchive(registry.GetContext(), sourceContainer, sourceContainerTarget, writer)
+ if err != nil {
+ return err
+ }
+ if err := copyFunc(); err != nil {
+ return errors.Wrap(err, "error copying from container")
+ }
+ return nil
+ }
+
+ destContainerCopy := func() error {
+ defer reader.Close()
+
+ copyOptions := entities.CopyOptions{Chown: chown}
+ if (!sourceContainerInfo.IsDir && !destContainerInfo.IsDir) || destResolvedToParentDir {
+ // If we're having a file-to-file copy, make sure to
+ // rename accordingly.
+ copyOptions.Rename = map[string]string{filepath.Base(sourceContainerTarget): destContainerBaseName}
+ }
+
+ copyFunc, err := registry.ContainerEngine().ContainerCopyFromArchive(registry.GetContext(), destContainer, destContainerTarget, reader, copyOptions)
+ if err != nil {
+ return err
+ }
+ if err := copyFunc(); err != nil {
+ return errors.Wrap(err, "error copying to container")
+ }
+ return nil
+ }
+
+ return doCopy(sourceContainerCopy, destContainerCopy)
+}
+
// copyFromContainer copies from the containerPath on the container to hostPath.
func copyFromContainer(container string, containerPath string, hostPath string) error {
if err := containerMustExist(container); err != nil {
@@ -133,6 +213,7 @@ func copyFromContainer(container string, containerPath string, hostPath string)
}
var hostBaseName string
+ var resolvedToHostParentDir bool
hostInfo, hostInfoErr := copy.ResolveHostPath(hostPath)
if hostInfoErr != nil {
if strings.HasSuffix(hostPath, "/") {
@@ -148,6 +229,7 @@ func copyFromContainer(container string, containerPath string, hostPath string)
// it'll be created while copying. Hence, we use it as the
// base path.
hostBaseName = filepath.Base(hostPath)
+ resolvedToHostParentDir = true
} else {
// If the specified path exists on the host, we must use its
// base path as it may have changed due to symlink evaluations.
@@ -175,7 +257,7 @@ func copyFromContainer(container string, containerPath string, hostPath string)
// we copy the source's parent and let the copier package create the
// destination via the Rename option.
containerTarget := containerInfo.LinkTarget
- if hostInfoErr != nil && containerInfo.IsDir && strings.HasSuffix(containerTarget, ".") {
+ if resolvedToHostParentDir && containerInfo.IsDir && strings.HasSuffix(containerTarget, ".") {
containerTarget = filepath.Dir(containerTarget)
}
@@ -216,7 +298,7 @@ func copyFromContainer(container string, containerPath string, hostPath string)
ChownFiles: &idPair,
IgnoreDevices: true,
}
- if (!containerInfo.IsDir && !hostInfo.IsDir) || hostInfoErr != nil {
+ if (!containerInfo.IsDir && !hostInfo.IsDir) || resolvedToHostParentDir {
// If we're having a file-to-file copy, make sure to
// rename accordingly.
putOptions.Rename = map[string]string{filepath.Base(containerTarget): hostBaseName}
@@ -263,42 +345,9 @@ func copyToContainer(container string, containerPath string, hostPath string) er
return errors.Wrapf(err, "%q could not be found on the host", hostPath)
}
- // If the path on the container does not exist. We need to make sure
- // that it's parent directory exists. The destination may be created
- // while copying.
- var containerBaseName string
- containerInfo, containerInfoErr := registry.ContainerEngine().ContainerStat(registry.GetContext(), container, containerPath)
- if containerInfoErr != nil {
- if strings.HasSuffix(containerPath, "/") {
- return errors.Wrapf(containerInfoErr, "%q could not be found on container %s", containerPath, container)
- }
- if isStdin {
- return errors.New("destination must be a directory when copying from stdin")
- }
- // NOTE: containerInfo may actually be set. That happens when
- // the container path is a symlink into nirvana. In that case,
- // we must use the symlinked path instead.
- path := containerPath
- if containerInfo != nil {
- containerBaseName = filepath.Base(containerInfo.LinkTarget)
- path = containerInfo.LinkTarget
- } else {
- containerBaseName = filepath.Base(containerPath)
- }
-
- parentDir, err := containerParentDir(container, path)
- if err != nil {
- return errors.Wrapf(err, "could not determine parent dir of %q on container %s", path, container)
- }
- containerInfo, err = registry.ContainerEngine().ContainerStat(registry.GetContext(), container, parentDir)
- if err != nil {
- return errors.Wrapf(err, "%q could not be found on container %s", containerPath, container)
- }
- } else {
- // If the specified path exists on the container, we must use
- // its base path as it may have changed due to symlink
- // evaluations.
- containerBaseName = filepath.Base(containerInfo.LinkTarget)
+ containerBaseName, containerInfo, containerResolvedToParentDir, err := resolvePathOnDestinationContainer(container, containerPath, isStdin)
+ if err != nil {
+ return err
}
// If we copy a directory via the "." notation and the container path
@@ -310,7 +359,7 @@ func copyToContainer(container string, containerPath string, hostPath string) er
// exist, we copy the source's parent and let the copier package create
// the destination via the Rename option.
hostTarget := hostInfo.LinkTarget
- if containerInfoErr != nil && hostInfo.IsDir && strings.HasSuffix(hostTarget, ".") {
+ if containerResolvedToParentDir && hostInfo.IsDir && strings.HasSuffix(hostTarget, ".") {
hostTarget = filepath.Dir(hostTarget)
}
@@ -362,7 +411,7 @@ func copyToContainer(container string, containerPath string, hostPath string) er
// copy the base directory.
KeepDirectoryNames: hostInfo.IsDir && filepath.Base(hostTarget) != ".",
}
- if (!hostInfo.IsDir && !containerInfo.IsDir) || containerInfoErr != nil {
+ if (!hostInfo.IsDir && !containerInfo.IsDir) || containerResolvedToParentDir {
// If we're having a file-to-file copy, make sure to
// rename accordingly.
getOptions.Rename = map[string]string{filepath.Base(hostTarget): containerBaseName}
@@ -393,6 +442,52 @@ func copyToContainer(container string, containerPath string, hostPath string) er
return doCopy(hostCopy, containerCopy)
}
+// resolvePathOnDestinationContainer resolves the specified path on the
+// container. If the path does not exist, it attempts to use the parent
+// directory.
+func resolvePathOnDestinationContainer(container string, containerPath string, isStdin bool) (baseName string, containerInfo *entities.ContainerStatReport, resolvedToParentDir bool, err error) {
+ containerInfo, err = registry.ContainerEngine().ContainerStat(registry.GetContext(), container, containerPath)
+ if err == nil {
+ baseName = filepath.Base(containerInfo.LinkTarget)
+ return
+ }
+
+ if strings.HasSuffix(containerPath, "/") {
+ err = errors.Wrapf(err, "%q could not be found on container %s", containerPath, container)
+ return
+ }
+ if isStdin {
+ err = errors.New("destination must be a directory when copying from stdin")
+ return
+ }
+
+ // NOTE: containerInfo may actually be set. That happens when
+ // the container path is a symlink into nirvana. In that case,
+ // we must use the symlinked path instead.
+ path := containerPath
+ if containerInfo != nil {
+ baseName = filepath.Base(containerInfo.LinkTarget)
+ path = containerInfo.LinkTarget
+ } else {
+ baseName = filepath.Base(containerPath)
+ }
+
+ parentDir, err := containerParentDir(container, path)
+ if err != nil {
+ err = errors.Wrapf(err, "could not determine parent dir of %q on container %s", path, container)
+ return
+ }
+
+ containerInfo, err = registry.ContainerEngine().ContainerStat(registry.GetContext(), container, parentDir)
+ if err != nil {
+ err = errors.Wrapf(err, "%q could not be found on container %s", containerPath, container)
+ return
+ }
+
+ resolvedToParentDir = true
+ return baseName, containerInfo, resolvedToParentDir, nil
+}
+
// containerParentDir returns the parent directory of the specified path on the
// container. If the path is relative, it will be resolved relative to the
// container's working directory (or "/" if the work dir isn't set).
diff --git a/cmd/podman/containers/create.go b/cmd/podman/containers/create.go
index df0fa6f9d..c63c074f7 100644
--- a/cmd/podman/containers/create.go
+++ b/cmd/podman/containers/create.go
@@ -146,6 +146,8 @@ func replaceContainer(name string) error {
}
func createInit(c *cobra.Command) error {
+ cliVals.StorageOpt = registry.PodmanConfig().StorageOpts
+
if c.Flag("shm-size").Changed {
cliVals.ShmSize = c.Flag("shm-size").Value.String()
}
diff --git a/cmd/podman/containers/logs.go b/cmd/podman/containers/logs.go
index 0d745291e..00a8d4b52 100644
--- a/cmd/podman/containers/logs.go
+++ b/cmd/podman/containers/logs.go
@@ -19,6 +19,8 @@ type logsOptionsWrapper struct {
entities.ContainerLogsOptions
SinceRaw string
+
+ UntilRaw string
}
var (
@@ -101,6 +103,10 @@ func logsFlags(cmd *cobra.Command) {
flags.StringVar(&logsOptions.SinceRaw, sinceFlagName, "", "Show logs since TIMESTAMP")
_ = cmd.RegisterFlagCompletionFunc(sinceFlagName, completion.AutocompleteNone)
+ untilFlagName := "until"
+ flags.StringVar(&logsOptions.UntilRaw, untilFlagName, "", "Show logs until TIMESTAMP")
+ _ = cmd.RegisterFlagCompletionFunc(untilFlagName, completion.AutocompleteNone)
+
tailFlagName := "tail"
flags.Int64Var(&logsOptions.Tail, tailFlagName, -1, "Output the specified number of LINES at the end of the logs. Defaults to -1, which prints all lines")
_ = cmd.RegisterFlagCompletionFunc(tailFlagName, completion.AutocompleteNone)
@@ -120,6 +126,14 @@ func logs(_ *cobra.Command, args []string) error {
}
logsOptions.Since = since
}
+ if logsOptions.UntilRaw != "" {
+ // parse time, error out if something is wrong
+ until, err := util.ParseInputTime(logsOptions.UntilRaw)
+ if err != nil {
+ return errors.Wrapf(err, "error parsing --until %q", logsOptions.UntilRaw)
+ }
+ logsOptions.Until = until
+ }
logsOptions.StdoutWriter = os.Stdout
logsOptions.StderrWriter = os.Stderr
return registry.ContainerEngine().ContainerLogs(registry.GetContext(), args, logsOptions.ContainerLogsOptions)
diff --git a/cmd/podman/containers/restore.go b/cmd/podman/containers/restore.go
index b908ea493..3b6f74efa 100644
--- a/cmd/podman/containers/restore.go
+++ b/cmd/podman/containers/restore.go
@@ -71,6 +71,9 @@ func init() {
)
_ = restoreCommand.RegisterFlagCompletionFunc("publish", completion.AutocompleteNone)
+ flags.StringVar(&restoreOptions.Pod, "pod", "", "Restore container into existing Pod (only works with --import)")
+ _ = restoreCommand.RegisterFlagCompletionFunc("pod", common.AutocompletePodsRunning)
+
validate.AddLatestFlag(restoreCommand, &restoreOptions.Latest)
}
@@ -91,6 +94,9 @@ func restore(cmd *cobra.Command, args []string) error {
if restoreOptions.Import == "" && restoreOptions.Name != "" {
return errors.Errorf("--name can only be used with --import")
}
+ if restoreOptions.Import == "" && restoreOptions.Pod != "" {
+ return errors.Errorf("--pod can only be used with --import")
+ }
if restoreOptions.Name != "" && restoreOptions.TCPEstablished {
return errors.Errorf("--tcp-established cannot be used with --name")
}
diff --git a/cmd/podman/images/import.go b/cmd/podman/images/import.go
index bed2d4105..bc80417cc 100644
--- a/cmd/podman/images/import.go
+++ b/cmd/podman/images/import.go
@@ -3,6 +3,9 @@ package images
import (
"context"
"fmt"
+ "io"
+ "io/ioutil"
+ "os"
"strings"
"github.com/containers/common/pkg/completion"
@@ -97,6 +100,22 @@ func importCon(cmd *cobra.Command, args []string) error {
default:
return errors.Errorf("too many arguments. Usage TARBALL [REFERENCE]")
}
+
+ if source == "-" {
+ outFile, err := ioutil.TempFile("", "podman")
+ if err != nil {
+ return errors.Errorf("error creating file %v", err)
+ }
+ defer os.Remove(outFile.Name())
+ defer outFile.Close()
+
+ _, err = io.Copy(outFile, os.Stdin)
+ if err != nil {
+ return errors.Errorf("error copying file %v", err)
+ }
+ source = outFile.Name()
+ }
+
errFileName := parse.ValidateFileName(source)
errURL := parse.ValidURL(source)
if errURL == nil {
diff --git a/cmd/podman/login.go b/cmd/podman/login.go
index a8dadf5cd..7e853b38d 100644
--- a/cmd/podman/login.go
+++ b/cmd/podman/login.go
@@ -52,6 +52,7 @@ func init() {
loginOptions.Stdin = os.Stdin
loginOptions.Stdout = os.Stdout
loginOptions.AcceptUnspecifiedRegistry = true
+ loginOptions.AcceptRepositories = true
}
// Implementation of podman-login.
diff --git a/cmd/podman/logout.go b/cmd/podman/logout.go
index 0ee134635..f44b13a1f 100644
--- a/cmd/podman/logout.go
+++ b/cmd/podman/logout.go
@@ -43,6 +43,7 @@ func init() {
logoutOptions.Stdout = os.Stdout
logoutOptions.AcceptUnspecifiedRegistry = true
+ logoutOptions.AcceptRepositories = true
}
// Implementation of podman-logout.
diff --git a/cmd/podman/parse/net.go b/cmd/podman/parse/net.go
index f93c4ab1e..870690db3 100644
--- a/cmd/podman/parse/net.go
+++ b/cmd/podman/parse/net.go
@@ -180,9 +180,12 @@ func ValidateFileName(filename string) error {
// ValidURL checks a string urlStr is a url or not
func ValidURL(urlStr string) error {
- _, err := url.ParseRequestURI(urlStr)
+ url, err := url.ParseRequestURI(urlStr)
if err != nil {
- return errors.Wrapf(err, "invalid url path: %q", urlStr)
+ return errors.Wrapf(err, "invalid url %q", urlStr)
+ }
+ if url.Scheme == "" {
+ return errors.Errorf("invalid url %q: missing scheme", urlStr)
}
return nil
}
diff --git a/cmd/podman/registry/config.go b/cmd/podman/registry/config.go
index 25139a3de..b512ba341 100644
--- a/cmd/podman/registry/config.go
+++ b/cmd/podman/registry/config.go
@@ -15,6 +15,9 @@ import (
)
const (
+ // NoMoveProcess used as cobra.Annotation when command doesn't need Podman to be moved to a separate cgroup
+ NoMoveProcess = "NoMoveProcess"
+
// ParentNSRequired used as cobra.Annotation when command requires root access
ParentNSRequired = "ParentNSRequired"
diff --git a/cmd/podman/root.go b/cmd/podman/root.go
index 9e5d2a236..dc4ebb952 100644
--- a/cmd/podman/root.go
+++ b/cmd/podman/root.go
@@ -208,7 +208,8 @@ func persistentPreRunE(cmd *cobra.Command, args []string) error {
// 3) command doesn't require Parent Namespace
_, found := cmd.Annotations[registry.ParentNSRequired]
if !registry.IsRemote() && rootless.IsRootless() && !found {
- err := registry.ContainerEngine().SetupRootless(registry.Context(), cmd)
+ _, noMoveProcess := cmd.Annotations[registry.NoMoveProcess]
+ err := registry.ContainerEngine().SetupRootless(registry.Context(), noMoveProcess)
if err != nil {
return err
}
@@ -342,10 +343,6 @@ func rootFlags(cmd *cobra.Command, opts *entities.PodmanConfig) {
pFlags.StringVar(&opts.StorageDriver, storageDriverFlagName, "", "Select which storage driver is used to manage storage of images and containers (default is overlay)")
_ = cmd.RegisterFlagCompletionFunc(storageDriverFlagName, completion.AutocompleteNone) //TODO: what can we recommend here?
- storageOptFlagName := "storage-opt"
- pFlags.StringArrayVar(&opts.StorageOpts, storageOptFlagName, []string{}, "Used to pass an option to the storage driver")
- _ = cmd.RegisterFlagCompletionFunc(storageOptFlagName, completion.AutocompleteNone)
-
tmpdirFlagName := "tmpdir"
pFlags.StringVar(&opts.Engine.TmpDir, tmpdirFlagName, "", "Path to the tmp directory for libpod state content.\n\nNote: use the environment variable 'TMPDIR' to change the temporary storage location for container images, '/var/tmp'.\n")
_ = cmd.RegisterFlagCompletionFunc(tmpdirFlagName, completion.AutocompleteDefault)
@@ -365,6 +362,10 @@ func rootFlags(cmd *cobra.Command, opts *entities.PodmanConfig) {
}
}
}
+ storageOptFlagName := "storage-opt"
+ pFlags.StringArrayVar(&opts.StorageOpts, storageOptFlagName, []string{}, "Used to pass an option to the storage driver")
+ _ = cmd.RegisterFlagCompletionFunc(storageOptFlagName, completion.AutocompleteNone)
+
// Override default --help information of `--help` global flag
var dummyHelp bool
pFlags.BoolVar(&dummyHelp, "help", false, "Help for podman")
diff --git a/cmd/podman/system/migrate.go b/cmd/podman/system/migrate.go
index 9940cd063..b9dc272d7 100644
--- a/cmd/podman/system/migrate.go
+++ b/cmd/podman/system/migrate.go
@@ -22,7 +22,10 @@ var (
`
migrateCommand = &cobra.Command{
- Annotations: map[string]string{registry.EngineMode: registry.ABIMode},
+ Annotations: map[string]string{
+ registry.EngineMode: registry.ABIMode,
+ registry.NoMoveProcess: registry.NoMoveProcess,
+ },
Use: "migrate [options]",
Args: validate.NoArgs,
Short: "Migrate containers",
diff --git a/contrib/podmanimage/stable/Dockerfile b/contrib/podmanimage/stable/Dockerfile
index a5d485e7f..f980d15ed 100644
--- a/contrib/podmanimage/stable/Dockerfile
+++ b/contrib/podmanimage/stable/Dockerfile
@@ -11,7 +11,7 @@ FROM registry.fedoraproject.org/fedora:latest
# Don't include container-selinux and remove
# directories used by yum that are just taking
# up space.
-RUN dnf -y update; rpm --restore --quiet shadow-utils; \
+RUN dnf -y update; rpm --restore shadow-utils 2>/dev/null; \
yum -y install podman fuse-overlayfs --exclude container-selinux; \
rm -rf /var/cache /var/log/dnf* /var/log/yum.*
diff --git a/contrib/podmanimage/testing/Dockerfile b/contrib/podmanimage/testing/Dockerfile
index 1090fed00..58b11a20b 100644
--- a/contrib/podmanimage/testing/Dockerfile
+++ b/contrib/podmanimage/testing/Dockerfile
@@ -13,7 +13,7 @@ FROM registry.fedoraproject.org/fedora:latest
# Don't include container-selinux and remove
# directories used by yum that are just taking
# up space.
-RUN yum -y update; rpm --restore --quiet shadow-utils; yum -y install podman fuse-overlayfs --exclude container-selinux --enablerepo updates-testing; rm -rf /var/cache /var/log/dnf* /var/log/yum.*
+RUN yum -y update; rpm --restore shadow-utils 2>/dev/null; yum -y install podman fuse-overlayfs --exclude container-selinux --enablerepo updates-testing; rm -rf /var/cache /var/log/dnf* /var/log/yum.*
RUN useradd podman; \
echo podman:10000:5000 > /etc/subuid; \
diff --git a/contrib/podmanimage/upstream/Dockerfile b/contrib/podmanimage/upstream/Dockerfile
index 01666e453..baad49e08 100644
--- a/contrib/podmanimage/upstream/Dockerfile
+++ b/contrib/podmanimage/upstream/Dockerfile
@@ -17,7 +17,7 @@ ENV GOPATH=/root/podman
# to the container.
# Finally remove the podman directory and a few other packages
# that are needed for building but not running Podman
-RUN yum -y update; rpm --restore --quiet shadow-utils; yum -y install --exclude container-selinux \
+RUN yum -y update; rpm --restore shadow-utils 2>/dev/null; yum -y install --exclude container-selinux \
--enablerepo=updates-testing \
btrfs-progs-devel \
containernetworking-cni \
diff --git a/docs/source/includes.rst b/docs/source/includes.rst
index 6e04d77f4..8d5f18e4d 100644
--- a/docs/source/includes.rst
+++ b/docs/source/includes.rst
@@ -16,4 +16,4 @@
.. _podman run: http://docs.podman.io/en/latest/markdown/podman-run.1.html
.. _podman build: http://docs.podman.io/en/latest/markdown/podman-build.1.html
.. _podman push: http://docs.podman.io/en/latest/markdown/podman-push.1.html
-.. image:: https://github.com/containers/podman/blob/main/logo/podman-logo.png?raw=true
+.. image:: https://raw.githubusercontent.com/containers/podman/main/logo/podman-logo.png
diff --git a/docs/source/markdown/podman-container-restore.1.md b/docs/source/markdown/podman-container-restore.1.md
index 36eb650e5..856008cc0 100644
--- a/docs/source/markdown/podman-container-restore.1.md
+++ b/docs/source/markdown/podman-container-restore.1.md
@@ -93,6 +93,15 @@ be used once and the restored *container* will have another IP address. This als
that **--name, -n** cannot be used in combination with **--tcp-established**.\
*IMPORTANT: This OPTION is only available in combination with **--import, -i**.*
+#### **--pod**=*name*
+
+Restore a container into the pod *name*. The destination pod for this restore
+has to have the same namespaces shared as the pod this container was checkpointed
+from (see **[podman pod create --share](podman-pod-create.1.md#--share)**).
+*IMPORTANT: This OPTION is only available in combination with **--import, -i**.*
+
+This option requires at least CRIU 3.16.
+
#### **--publish**, **-p**=*port*
Replaces the ports that the *container* publishes, as configured during the
@@ -128,7 +137,7 @@ $ podman run --rm -p 2345:80 -d webserver
```
## SEE ALSO
-**[podman(1)](podman.1.md)**, **[podman-container-checkpoint(1)](podman-container-checkpoint.1.md)**, **[podman-run(1)](podman-run.1.md)**
+**[podman(1)](podman.1.md)**, **[podman-container-checkpoint(1)](podman-container-checkpoint.1.md)**, **[podman-run(1)](podman-run.1.md)**, **[podman-pod-create(1)](podman-pod-create.1.md)**
## HISTORY
September 2018, Originally compiled by Adrian Reber <areber@redhat.com>
diff --git a/docs/source/markdown/podman-container-runlabel.1.md b/docs/source/markdown/podman-container-runlabel.1.md
index e343a12fe..ec67a2687 100644
--- a/docs/source/markdown/podman-container-runlabel.1.md
+++ b/docs/source/markdown/podman-container-runlabel.1.md
@@ -1,76 +1,58 @@
% podman-container-runlabel(1)
## NAME
-podman-container-runlabel - Executes a command as described by a container image label
+podman-container-runlabel - Executes a command as described by a container-image label
## SYNOPSIS
**podman container runlabel** [*options*] *label* *image* [*arg...*]
## DESCRIPTION
-**podman container runlabel** reads the provided `LABEL` field in the container
-IMAGE and executes the provided value for the label as a command. If this field does not
-exist, `podman container runlabel` will just exit.
+**podman container runlabel** reads the specified `label` of the `image` and executes it as command on the host. If the label does not exist, Podman will exit with an error. Additional arguments will be appended to the command.
-If the container image has a LABEL INSTALL instruction like the following:
+Historically, container images describe the contents (e.g., layers) and how a container runtime (e.g., crun(1) or runc(1)) should execute the container. For instance, an image may set the environment and the command in its configuration. However, a container image cannot directly specify how a container engine such as Podman should execute it. For instance, an image configuration does not include information about log drivers, namespaces or which capabilities it needs to run correctly.
-`LABEL INSTALL /usr/bin/podman run -t -i --rm \${OPT1} --privileged -v /:/host --net=host --ipc=host --pid=host -e HOST=/host -e NAME=\${NAME} -e IMAGE=\${IMAGE} -e CONFDIR=/etc/\${NAME} -e LOGDIR=/var/log/\${NAME} -e DATADIR=/var/lib/\${NAME} \${IMAGE} \${OPT2} /bin/install.sh \${OPT3}`
+`podman container runlabel` addresses the limitation of container images in a simple yet efficient way. Podman will read the contents of the label and interpret it as a command that will be executed on the host. This way an image can describe exactly how it should be executed by Podman. For instance, a label with the content `/usr/bin/podman run -d --pid=host --privileged \${IMAGE}` instructs the image to be executed in a detached, privileged container that is using the PID namespace of the host. This lifts the self-description of a container image from "what" to "how".
-`podman container runlabel` will set the following environment variables for use in the command:
+Please note that the `runlabel` command is intended to be run in trusted environments exclusively. Using the command on untrusted images is not recommended.
-If the container image does not have the desired label, an error message will be displayed along with a non-zero
-return code. If the image is not found in local storage, Podman will attempt to pull it first.
+## VARIABLES
-**LABEL**
-The label name specified via the command.
+The contents of a label may refer to the following variables which will be substituted while processing the label.
**IMAGE**
-Image name specified via the command.
+The name of the image. When executing `podman container runlabel label fedora` the `IMAGE` variable will be replaced with `fedora`. Valid formats are `IMAGE`, `$IMAGE`, `${IMAGE}` and `=IMAGE`.
-**SUDO_UID**
-The `SUDO_UID` environment variable. This is useful with the podman
-`-u` option for user space tools. If the environment variable is
-not available, the value of `/proc/self/loginuid` is used.
+**NAME**
+As specified by the `--name` option. The format is identical to the one of the IMAGE attribute.
-**SUDO_GID**
-The `SUDO_GID` environment variable. This is useful with the podman
-`-u` option for user space tools. If the environment variable is
-not available, the default GID of the value for `SUDO_UID` is used.
-If this value is not available, the value of `/proc/self/loginuid`
-is used.
-
-Any additional arguments will be appended to the command.
+**PWD**
+Will be replaced with the current working directory.
## OPTIONS
#### **--authfile**=*path*
-Path of the authentication file. Default is ${XDG\_RUNTIME\_DIR}/containers/auth.json, which is set using `podman login`.
-If the authorization state is not found there, $HOME/.docker/config.json is checked, which is set using `docker login`.
+Path of the containers-auth.json(5) file. Default is ${XDG\_RUNTIME\_DIR}/containers/auth.json, which is set using `podman login`. If the authorization state is not found there, $HOME/.docker/config.json is checked, which is set using `docker login`.
-Note: You can also override the default path of the authentication file by setting the REGISTRY\_AUTH\_FILE
-environment variable. `export REGISTRY_AUTH_FILE=path`
+Note: You can also override the default path of the authentication file by setting the REGISTRY\_AUTH\_FILE environment variable. `export REGISTRY_AUTH_FILE=path`
#### **--display**
-Display the label's value of the image having populated its environment variables.
-The runlabel command will not execute if --display is specified.
+Display the label's value of the image having populated its environment variables. The runlabel command will not execute if --display is specified.
#### **--cert-dir**=*path*
-Use certificates at *path* (\*.crt, \*.cert, \*.key) to connect to the registry.
-Please refer to containers-certs.d(5) for details. (This option is not available with the remote Podman client)
+Use certificates at *path* (\*.crt, \*.cert, \*.key) to connect to the registry. Please refer to containers-certs.d(5) for details. (This option is not available with the remote Podman client)
#### **--creds**=*[username[:password]]*
-The [username[:password]] to use to authenticate with the registry if required.
-If one or both values are not supplied, a command line prompt will appear and the
-value can be entered. The password is entered without echo.
+The [username[:password]] to use to authenticate with the registry if required. If one or both values are not supplied, a command line prompt will appear and the value can be entered. The password is entered without echo.
#### **--help**, **-h**
Print usage statement
#### **--name**, **-n**=*name*
-Use this name for creating content for the container. NAME will default to the IMAGENAME if it is not specified.
+Use this name for creating content for the container. If not specified, name defaults to the name of the image.
#### **--quiet**, **-q**
@@ -78,34 +60,33 @@ Suppress output information when pulling images
#### **--replace**
-If a container exists of the default or given name, as needed it will be stopped, deleted and a new container will be
-created from this image.
+If a container exists of the default or given name, as needed it will be stopped, deleted and a new container will be created from this image.
#### **--tls-verify**
-Require HTTPS and verify certificates when contacting registries (default: true). If explicitly set to true,
-then TLS verification will be used. If set to false, then TLS verification will not be used. If not specified,
-TLS verification will be used unless the target registry is listed as an insecure registry in registries.conf.
+Require HTTPS and verify certificates when contacting registries (default: true). If explicitly set to true, then TLS verification will be used. If set to false, then TLS verification will not be used. If not specified, TLS verification will be used unless the target registry is listed as an insecure registry in containers-registries.conf(5).
## EXAMPLES
-Execute the run label of an image called foobar.
+Execute the `run` label of an image called foobar.
```
-$ sudo podman container runlabel run foobar
+$ podman container runlabel run foobar
```
-Execute the install label of an image called foobar with additional arguments.
+Execute the `install` label of an image called foobar with additional arguments.
```
-$ sudo podman container runlabel install foobar apples oranges
+$ podman container runlabel install foobar apples oranges
```
-Display the command that would be executed by runlabel.
+Display the contents of the `run` label of image foobar.
```
-$ sudo podman container runlabel --display run foobar
+$ podman container runlabel --display run foobar
```
## SEE ALSO
-podman(1), containers-certs.d(5)
+podman(1), crun(1), runc(1), containers-auth.json(5), containers-certs.d(5), containers-registries.conf(5)
## HISTORY
+August 2021, Refinements by Valentin Rothberg (rothberg at redhat dot com)
+
September 2018, Originally compiled by Brent Baude (bbaude at redhat dot com)
diff --git a/docs/source/markdown/podman-container.1.md b/docs/source/markdown/podman-container.1.md
index e69c5a170..3cc90d9ec 100644
--- a/docs/source/markdown/podman-container.1.md
+++ b/docs/source/markdown/podman-container.1.md
@@ -38,7 +38,7 @@ The container command allows you to manage containers
| restore | [podman-container-restore(1)](podman-container-restore.1.md) | Restores one or more containers from a checkpoint. |
| rm | [podman-rm(1)](podman-rm.1.md) | Remove one or more containers. |
| run | [podman-run(1)](podman-run.1.md) | Run a command in a container. |
-| runlabel | [podman-container-runlabel(1)](podman-container-runlabel.1.md) | Executes a command as described by a container image label. |
+| runlabel | [podman-container-runlabel(1)](podman-container-runlabel.1.md) | Executes a command as described by a container-image label. |
| start | [podman-start(1)](podman-start.1.md) | Starts one or more containers. |
| stats | [podman-stats(1)](podman-stats.1.md) | Display a live stream of one or more container's resource usage statistics. |
| stop | [podman-stop(1)](podman-stop.1.md) | Stop one or more running containers. |
diff --git a/docs/source/markdown/podman-cp.1.md b/docs/source/markdown/podman-cp.1.md
index 43ee4cdff..79edf26ed 100644
--- a/docs/source/markdown/podman-cp.1.md
+++ b/docs/source/markdown/podman-cp.1.md
@@ -9,111 +9,121 @@ podman\-cp - Copy files/folders between a container and the local filesystem
**podman container cp** [*options*] [*container*:]*src_path* [*container*:]*dest_path*
## DESCRIPTION
-Copy the contents of **src_path** to the **dest_path**. You can copy from the container's filesystem to the local machine or the reverse, from the local filesystem to the container.
-If `-` is specified for either the SRC_PATH or DEST_PATH, you can also stream a tar archive from STDIN or to STDOUT.
+**podman cp** allows copying the contents of **src_path** to the **dest_path**. Files can be copied from a container to the local machine and vice versa or between two containers.
+If `-` is specified for either the `SRC_PATH` or `DEST_PATH`, one can also stream a tar archive from `STDIN` or to `STDOUT`.
-The CONTAINER can be a running or stopped container. The **src_path** or **dest_path** can be a file or directory.
+The containers can be either running or stopped and the *src_path* or *dest_path* can be a file or directory.
-The **podman cp** command assumes container paths are relative to the container's root directory (i.e., `/`).
-
-This means supplying the initial forward slash is optional;
-
-The command sees **compassionate_darwin:/tmp/foo/myfile.txt** and **compassionate_darwin:tmp/foo/myfile.txt** as identical.
+*IMPORTANT: The **podman cp** command assumes container paths are relative to the container's root directory (`/`), which means supplying the initial forward slash is optional and therefore sees `compassionate_darwin:/tmp/foo/myfile.txt` and `compassionate_darwin:tmp/foo/myfile.txt` as identical.*
Local machine paths can be an absolute or relative value.
The command interprets a local machine's relative paths as relative to the current working directory where **podman cp** is run.
-Assuming a path separator of /, a first argument of **src_path** and second argument of **dest_path**, the behavior is as follows:
+Assuming a path separator of `/`, a first argument of **src_path** and second argument of **dest_path**, the behavior is as follows:
-**src_path** specifies a file
+**src_path** specifies a file:
- **dest_path** does not exist
- - the file is saved to a file created at **dest_path** (note that parent directory must exist)
+ - the file is saved to a file created at **dest_path** (note that parent directory must exist).
- **dest_path** exists and is a file
- - the destination is overwritten with the source file's contents
+ - the destination is overwritten with the source file's contents.
- **dest_path** exists and is a directory
- - the file is copied into this directory using the base name from **src_path**
+ - the file is copied into this directory using the base name from **src_path**.
-**src_path** specifies a directory
+**src_path** specifies a directory:
- **dest_path** does not exist
- - **dest_path** is created as a directory and the contents of the source directory are copied into this directory
+ - **dest_path** is created as a directory and the contents of the source directory are copied into this directory.
- **dest_path** exists and is a file
- - Error condition: cannot copy a directory to a file
+ - Error condition: cannot copy a directory to a file.
- **dest_path** exists and is a directory
- **src_path** ends with `/`
- - the source directory is copied into this directory
+ - the source directory is copied into this directory.
- **src_path** ends with `/.` (i.e., slash followed by dot)
- - the content of the source directory is copied into this directory
+ - the content of the source directory is copied into this directory.
The command requires **src_path** and **dest_path** to exist according to the above rules.
If **src_path** is local and is a symbolic link, the symbolic target, is copied by default.
-A colon (:) is used as a delimiter between CONTAINER and its path.
-
-You can also use : when specifying paths to a **src_path** or **dest_path** on a local machine, for example, `file:name.txt`.
+A *colon* ( : ) is used as a delimiter between a container and its path, it can also be used when specifying paths to a **src_path** or **dest_path** on a local machine, for example, `file:name.txt`.
-If you use a : in a local machine path, you must be explicit with a relative or absolute path, for example:
- `/path/to/file:name.txt` or `./file:name.txt`
+*IMPORTANT: while using a *colon* ( : ) in a local machine path, one must be explicit with a relative or absolute path, for example: `/path/to/file:name.txt` or `./file:name.txt`*
-Using `-` as the *src_path* streams the contents of STDIN as a tar archive. The command extracts the content of the tar to the *DEST_PATH* in the container. In this case, *dest_path* must specify a directory. Using `-` as the *dest_path* streams the contents of the resource (can be a directory) as a tar archive to STDOUT.
+Using `-` as the **src_path** streams the contents of `STDIN` as a tar archive. The command extracts the content of the tar to the `DEST_PATH` in the container. In this case, **dest_path** must specify a directory. Using `-` as the **dest_path** streams the contents of the resource (can be a directory) as a tar archive to `STDOUT`.
Note that `podman cp` ignores permission errors when copying from a running rootless container. The TTY devices inside a rootless container are owned by the host's root user and hence cannot be read inside the container's user namespace.
## OPTIONS
-#### **--archive**, **-a**
+#### **--archive**, **-a**=**true** | *false*
Archive mode (copy all uid/gid information).
-When set to true, files copied to a container will have changed ownership to the primary uid/gid of the container.
+When set to true, files copied to a container will have changed ownership to the primary UID/GID of the container.
When set to false, maintain uid/gid from archive sources instead of changing them to the primary uid/gid of the destination container.
-The default is *true*.
+The default is **true**.
## ALTERNATIVES
-Podman has much stronger capabilities than just `podman cp` to achieve copy files between host and container.
+Podman has much stronger capabilities than just `podman cp` to achieve copying files between the host and containers.
-Using standard podman-mount and podman-umount takes advantage of the entire linux tool chain, rather
-then just cp.
+Using standard **[podman-mount(1)](podman-mount.1.md)** and **[podman-unmount(1)](podman-unmount.1.md)** takes advantage of the entire linux tool chain, rather than just cp.
-If a user wants to copy contents out of a container or into a container, they can execute a few simple commands.
+copying contents out of a container or into a container, can be achieved with a few simple commands. For example:
-You can copy from the container's file system to the local machine or the reverse, from the local filesystem to the container.
-
-If you want to copy the /etc/foobar directory out of a container and onto /tmp on the host, you could execute the following commands:
+To copy the `/etc/foobar` directory out of a container and onto `/tmp` on the host, the following commands can be executed:
mnt=$(podman mount CONTAINERID)
cp -R ${mnt}/etc/foobar /tmp
podman umount CONTAINERID
-If you want to untar a tar ball into a container, you can execute these commands:
+To untar a tar ball into a container, following commands can be executed:
mnt=$(podman mount CONTAINERID)
tar xf content.tgz -C ${mnt}
podman umount CONTAINERID
-One last example, if you want to install a package into a container that
-does not have dnf installed, you could execute something like:
+To install a package into a container that
+does not have dnf installed, following commands can be executed:
mnt=$(podman mount CONTAINERID)
dnf install --installroot=${mnt} httpd
chroot ${mnt} rm -rf /var/log/dnf /var/cache/dnf
podman umount CONTAINERID
-This shows that using `podman mount` and `podman umount` you can use all of the
+By using `podman mount` and `podman unmount`, one can use all of the
standard linux tools for moving files into and out of containers, not just
the cp command.
-## EXAMPLE
+## EXAMPLES
+
+- Copy a file from host to a container.
+ ```
+ podman cp /myapp/app.conf containerID:/myapp/app.conf
+ ```
-podman cp /myapp/app.conf containerID:/myapp/app.conf
+- Copy a file from a container to a directory on another container.
+ ```
+ podman cp containerID1:/myfile.txt containerID2:/tmp
+ ```
-podman cp /home/myuser/myfiles.tar containerID:/tmp
+- Copy a directory on a container to a directory on the host.
+ ```
+ podman cp containerID:/myapp/ /myapp/
+ ```
-podman cp containerID:/myapp/ /myapp/
+- Copy the contents of a directory on a container to a directory on the host.
+ ```
+ podman cp containerID:/home/myuser/. /home/myuser/
+ ```
-podman cp containerID:/home/myuser/. /home/myuser/
+- Copy a directory on a container into a directory on another.
+ ```
+ podman cp containerA:/myapp containerB:/yourapp
+ ```
-podman cp - containerID:/myfiles.tar.gz < myfiles.tar.gz
+- Stream a tar archive from `STDIN` to a container.
+ ```
+ podman cp - containerID:/myfiles.tar.gz < myfiles.tar.gz
+ ```
## SEE ALSO
-podman(1), podman-mount(1), podman-umount(1)
+**[podman(1)](podman.1.md)**, **[podman-mount(1)](podman-mount.1.md)**, **[podman-unmount(1)](podman-unmount.1.md)**
diff --git a/docs/source/markdown/podman-create.1.md b/docs/source/markdown/podman-create.1.md
index 1720e6eb6..7f9cf0e75 100644
--- a/docs/source/markdown/podman-create.1.md
+++ b/docs/source/markdown/podman-create.1.md
@@ -181,6 +181,8 @@ Limit the CPU real-time period in microseconds
Limit the container's Real Time CPU usage. This flag tell the kernel to restrict the container's Real Time CPU usage to the period you specify.
+This flag is not supported on cgroups V2 systems.
+
#### **--cpu-rt-runtime**=*microseconds*
Limit the CPU real-time runtime in microseconds
@@ -190,6 +192,8 @@ Period of 1,000,000us and Runtime of 950,000us means that this container could c
The sum of all runtimes across containers cannot exceed the amount allotted to the parent cgroup.
+This flag is not supported on cgroups V2 systems.
+
#### **--cpu-shares**=*shares*
CPU shares (relative weight)
@@ -479,6 +483,8 @@ is not limited. If you specify a limit, it may be rounded up to a multiple
of the operating system's page size and the value can be very large,
millions of trillions.
+This flag is not supported on cgroups V2 systems.
+
#### **--label**, **-l**=*label*
Add metadata to a container (e.g., --label com.example.key=value)
@@ -561,6 +567,8 @@ unit, `b` is used. Set LIMIT to `-1` to enable unlimited swap.
Tune a container's memory swappiness behavior. Accepts an integer between 0 and 100.
+This flag is not supported on cgroups V2 systems.
+
#### **--mount**=*type=TYPE,TYPE-SPECIFIC-OPTION[,...]*
Attach a filesystem mount to the container
diff --git a/docs/source/markdown/podman-images.1.md b/docs/source/markdown/podman-images.1.md
index 23cce450a..02385daec 100644
--- a/docs/source/markdown/podman-images.1.md
+++ b/docs/source/markdown/podman-images.1.md
@@ -36,7 +36,7 @@ Filter output based on conditions provided
Filter on images created before the given IMAGE (name or tag).
**dangling=true|false**
- Show dangling images. Dangling images are a file system layer that was used in a previous build of an image and is no longer referenced by any active images. They are denoted with the `<none>` tag, consume disk space and serve no active purpose.
+ Show dangling images. Dangling images are a file system layer that was used in a previous build of an image and is no longer referenced by any image. They are denoted with the `<none>` tag, consume disk space and serve no active purpose.
**label**
Filter by images labels key and/or value.
diff --git a/docs/source/markdown/podman-logs.1.md b/docs/source/markdown/podman-logs.1.md
index 8f1301102..6b3ef79d7 100644
--- a/docs/source/markdown/podman-logs.1.md
+++ b/docs/source/markdown/podman-logs.1.md
@@ -39,6 +39,14 @@ strings (e.g. 10m, 1h30m) computed relative to the client machine's time. Suppor
time stamps include RFC3339Nano, RFC3339, 2006-01-02T15:04:05, 2006-01-02T15:04:05.999999999, 2006-01-02Z07:00,
and 2006-01-02.
+#### **--until**=*TIMESTAMP*
+
+Show logs until TIMESTAMP. The --until option can be Unix timestamps, date formatted timestamps, or Go duration
+strings (e.g. 10m, 1h30m) computed relative to the client machine's time. Supported formats for date formatted
+time stamps include RFC3339Nano, RFC3339, 2006-01-02T15:04:05, 2006-01-02T15:04:05.999999999, 2006-01-02Z07:00,
+and 2006-01-02.
+
+
#### **--tail**=*LINES*
Output the specified number of LINES at the end of the logs. LINES must be an integer. Defaults to -1,
@@ -74,6 +82,17 @@ podman logs --tail 2 b3f2436bdb97
# Server initialized
```
+To view all containers logs:
+```
+podman logs -t --since 0 myserver
+
+1:M 07 Aug 14:10:09.055 # Server can't set maximum open files to 10032 because of OS error: Operation not permitted.
+1:M 07 Aug 14:10:09.055 # Current maximum open files is 4096. maxclients has been reduced to 4064 to compensate for low ulimit. If you need higher maxclients increase 'ulimit -n'.
+1:M 07 Aug 14:10:09.056 * Running mode=standalone, port=6379.
+1:M 07 Aug 14:10:09.056 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
+1:M 07 Aug 14:10:09.056 # Server initialized
+```
+
To view a containers logs since a certain time:
```
podman logs -t --since 2017-08-07T10:10:09.055837383-04:00 myserver
@@ -93,6 +112,16 @@ podman logs --since 10m myserver
# Current maximum open files is 4096. maxclients has been reduced to 4064 to compensate for low ulimit. If you need higher maxclients increase 'ulimit -n'.
```
+To view a container's logs until 30 minutes ago:
+```
+podman logs --until 30m myserver
+
+AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 10.0.2.100. Set the 'ServerName' directive globally to suppress this message
+AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 10.0.2.100. Set the 'ServerName' directive globally to suppress this message
+[Tue Jul 20 13:18:14.223727 2021] [mpm_event:notice] [pid 1:tid 140021067187328] AH00489: Apache/2.4.48 (Unix) configured -- resuming normal operations
+[Tue Jul 20 13:18:14.223819 2021] [core:notice] [pid 1:tid 140021067187328] AH00094: Command line: 'httpd -D FOREGROUND'
+```
+
## SEE ALSO
podman(1), podman-run(1), podman-container-rm(1)
diff --git a/docs/source/markdown/podman-rmi.1.md b/docs/source/markdown/podman-rmi.1.md
index 1f62d6133..e34b1964b 100644
--- a/docs/source/markdown/podman-rmi.1.md
+++ b/docs/source/markdown/podman-rmi.1.md
@@ -10,7 +10,7 @@ podman\-rmi - Removes one or more locally stored images
## DESCRIPTION
Removes one or more locally stored images.
-Passing an argument _image_ deletes it, along with any of its dangling (untagged) parent images.
+Passing an argument _image_ deletes it, along with any of its dangling parent images. A dangling image is an image without a tag and without being referenced by another image.
## OPTIONS
diff --git a/docs/source/markdown/podman-run.1.md b/docs/source/markdown/podman-run.1.md
index ce0cf1a2f..f08561904 100644
--- a/docs/source/markdown/podman-run.1.md
+++ b/docs/source/markdown/podman-run.1.md
@@ -199,6 +199,8 @@ Limit the CPU real-time period in microseconds.
Limit the container's Real Time CPU usage. This flag tell the kernel to restrict the container's Real Time CPU usage to the period you specify.
+This flag is not supported on cgroups V2 systems.
+
#### **--cpu-rt-runtime**=*microseconds*
Limit the CPU real-time runtime in microseconds.
@@ -208,6 +210,8 @@ Period of 1,000,000us and Runtime of 950,000us means that this container could c
The sum of all runtimes across containers cannot exceed the amount allotted to the parent cgroup.
+This flag is not supported on cgroups V2 systems.
+
#### **--cpu-shares**=*shares*
CPU shares (relative weight).
@@ -518,6 +522,8 @@ is not limited. If you specify a limit, it may be rounded up to a multiple
of the operating system's page size and the value can be very large,
millions of trillions.
+This flag is not supported on cgroups V2 systems.
+
#### **--label**, **-l**=*key*=*value*
Add metadata to a container.
@@ -595,6 +601,8 @@ Set _number_ to **-1** to enable unlimited swap.
Tune a container's memory swappiness behavior. Accepts an integer between *0* and *100*.
+This flag is not supported on cgroups V2 systems.
+
#### **--mount**=*type=TYPE,TYPE-SPECIFIC-OPTION[,...]*
Attach a filesystem mount to the container
diff --git a/docs/source/markdown/podman-volume-ls.1.md b/docs/source/markdown/podman-volume-ls.1.md
index 489057446..b562aff61 100644
--- a/docs/source/markdown/podman-volume-ls.1.md
+++ b/docs/source/markdown/podman-volume-ls.1.md
@@ -24,6 +24,7 @@ Volumes can be filtered by the following attributes:
- name
- opt
- scope
+- until
#### **--format**=*format*
diff --git a/docs/source/markdown/podman-volume-prune.1.md b/docs/source/markdown/podman-volume-prune.1.md
index 9477cb5d5..b9599c200 100644
--- a/docs/source/markdown/podman-volume-prune.1.md
+++ b/docs/source/markdown/podman-volume-prune.1.md
@@ -23,12 +23,8 @@ Do not prompt for confirmation.
Filter volumes to be pruned. Volumes can be filtered by the following attributes:
-- dangling
-- driver
- label
-- name
-- opt
-- scope
+- until
#### **--help**
diff --git a/go.mod b/go.mod
index 49355df7b..623226c48 100644
--- a/go.mod
+++ b/go.mod
@@ -7,17 +7,17 @@ require (
github.com/blang/semver v3.5.1+incompatible
github.com/buger/goterm v0.0.0-20181115115552-c206103e1f37
github.com/checkpoint-restore/checkpointctl v0.0.0-20210301084134-a2024f5584e7
- github.com/checkpoint-restore/go-criu v0.0.0-20190109184317-bdb7599cd87b
+ github.com/checkpoint-restore/go-criu/v5 v5.1.0
github.com/container-orchestrated-devices/container-device-interface v0.0.0-20210325223243-f99e8b6c10b9
github.com/containernetworking/cni v0.8.1
github.com/containernetworking/plugins v0.9.1
- github.com/containers/buildah v1.21.1-0.20210707133512-2eb97b499d74
- github.com/containers/common v0.41.1-0.20210716140645-ffcfe1ff6e70
+ github.com/containers/buildah v1.21.1-0.20210721171232-54cafea4c933
+ github.com/containers/common v0.41.1-0.20210730122913-cd6c45fd20e3
github.com/containers/conmon v2.0.20+incompatible
- github.com/containers/image/v5 v5.13.2
+ github.com/containers/image/v5 v5.15.0
github.com/containers/ocicrypt v1.1.2
github.com/containers/psgo v1.5.2
- github.com/containers/storage v1.32.6
+ github.com/containers/storage v1.33.1
github.com/coreos/go-systemd/v22 v22.3.2
github.com/coreos/stream-metadata-go v0.0.0-20210225230131-70edb9eb47b3
github.com/cri-o/ocicni v0.2.1-0.20210621164014-d0acc7862283
@@ -47,7 +47,7 @@ require (
github.com/onsi/gomega v1.14.0
github.com/opencontainers/go-digest v1.0.0
github.com/opencontainers/image-spec v1.0.2-0.20190823105129-775207bd45b6
- github.com/opencontainers/runc v1.0.0
+ github.com/opencontainers/runc v1.0.1
github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417
github.com/opencontainers/runtime-tools v0.9.0
github.com/opencontainers/selinux v1.8.2
@@ -65,7 +65,7 @@ require (
go.etcd.io/bbolt v1.3.6
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
- golang.org/x/sys v0.0.0-20210603125802-9665404d3644
+ golang.org/x/sys v0.0.0-20210616094352-59db8d763f22
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
k8s.io/api v0.21.3
k8s.io/apimachinery v0.21.3
diff --git a/go.sum b/go.sum
index 61a7ad911..34ecb7f9c 100644
--- a/go.sum
+++ b/go.sum
@@ -128,11 +128,11 @@ github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/checkpoint-restore/checkpointctl v0.0.0-20210301084134-a2024f5584e7 h1:ZmSAEFFtv3mepC4/Ze6E/hi6vGZlhRvywqp1l+w+qqw=
github.com/checkpoint-restore/checkpointctl v0.0.0-20210301084134-a2024f5584e7/go.mod h1:Kp3ezoDVdhfYxZUtgs4OL8sVvgOLz3txk0sbQD0opvw=
-github.com/checkpoint-restore/go-criu v0.0.0-20190109184317-bdb7599cd87b h1:T4nWG1TXIxeor8mAu5bFguPJgSIGhZqv/f0z55KCrJM=
-github.com/checkpoint-restore/go-criu v0.0.0-20190109184317-bdb7599cd87b/go.mod h1:TrMrLQfeENAPYPRsJuq3jsqdlRh3lvi6trTZJG8+tho=
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/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M=
+github.com/checkpoint-restore/go-criu/v5 v5.1.0 h1:BkVH17kcwgmKMnFArsvLrxuBbMwfvPNYRB7mfJ0lzyI=
+github.com/checkpoint-restore/go-criu/v5 v5.1.0/go.mod h1:iaS8bb7p6zKJanp1Qe8mpl7+bnkYBR500psJR6mwma0=
github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8=
@@ -146,6 +146,7 @@ github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX
github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs=
github.com/cilium/ebpf v0.5.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs=
github.com/cilium/ebpf v0.6.1/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs=
+github.com/cilium/ebpf v0.6.2/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs=
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/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
@@ -238,15 +239,17 @@ github.com/containernetworking/plugins v0.8.6/go.mod h1:qnw5mN19D8fIwkqW7oHHYDHV
github.com/containernetworking/plugins v0.8.7/go.mod h1:R7lXeZaBzpfqapcAbHRW8/CYwm0dHzbz0XEjofx0uB0=
github.com/containernetworking/plugins v0.9.1 h1:FD1tADPls2EEi3flPc2OegIY1M9pUa9r2Quag7HMLV8=
github.com/containernetworking/plugins v0.9.1/go.mod h1:xP/idU2ldlzN6m4p5LmGiwRDjeJr6FLK6vuiUwoH7P8=
-github.com/containers/buildah v1.21.1-0.20210707133512-2eb97b499d74 h1:u+Wk1Gv+UgOR0AHmlpbH+ZsdfZt7vkGuiKCyhbI4Ga0=
-github.com/containers/buildah v1.21.1-0.20210707133512-2eb97b499d74/go.mod h1:P0rxPkI7440rWVMkbPkSHX4j1PxjOcx+cY8QrqYgdLE=
-github.com/containers/common v0.40.2-0.20210707094508-0a4a1906d4b2/go.mod h1:thow5Jn7O+rP01njI9COQ16L9g/KQ1LcMcYqP2NhYCU=
-github.com/containers/common v0.41.1-0.20210716140645-ffcfe1ff6e70 h1:9kKqg10PfrLQdsN4lw/n8XIuqLk43JwwAcE4klCvOsI=
-github.com/containers/common v0.41.1-0.20210716140645-ffcfe1ff6e70/go.mod h1:w0CLPB8nH75msgISbE/z8TMIxK9disFsmvFNd2SDid8=
+github.com/containers/buildah v1.21.1-0.20210721171232-54cafea4c933 h1:jqO3hDypBoKM5be+fVcqGHOpX2fOiQy2DFEeb/VKpsk=
+github.com/containers/buildah v1.21.1-0.20210721171232-54cafea4c933/go.mod h1:9gspFNeUJxIK72n1IMIKIHmtcePEZQsv0tjo+1LqkCo=
+github.com/containers/common v0.41.1-0.20210721112610-c95d2f794edf/go.mod h1:Ba5YVNCnyX6xDtg1JqEHa2EMVMW5UbHmIyEqsEwpeGE=
+github.com/containers/common v0.41.1-0.20210730122913-cd6c45fd20e3 h1:lHOZ+G5B7aP2YPsbDo4DtALFAuFG5PWH3Pv5zL2bC08=
+github.com/containers/common v0.41.1-0.20210730122913-cd6c45fd20e3/go.mod h1:UzAAjDsxwd4qkN1mgsk6aspduBY5bspxvKgwQElaBwk=
github.com/containers/conmon v2.0.20+incompatible h1:YbCVSFSCqFjjVwHTPINGdMX1F6JXHGTUje2ZYobNrkg=
github.com/containers/conmon v2.0.20+incompatible/go.mod h1:hgwZ2mtuDrppv78a/cOBNiCm6O0UMWGx1mu7P00nu5I=
-github.com/containers/image/v5 v5.13.2 h1:AgYunV/9d2fRkrmo23wH2MkqeHolFd6oQCkK+1PpuFA=
github.com/containers/image/v5 v5.13.2/go.mod h1:GkWursKDlDcUIT7L7vZf70tADvZCk/Ga0wgS0MuF0ag=
+github.com/containers/image/v5 v5.14.0/go.mod h1:SxiBKOcKuT+4yTjD0AskjO+UwFvNcVOJ9qlAw1HNSPU=
+github.com/containers/image/v5 v5.15.0 h1:NduhN20ptHNlf0uRny5iTJa2OodB9SLMEB4hKKbzBBs=
+github.com/containers/image/v5 v5.15.0/go.mod h1:gzdBcooi6AFdiqfzirUqv90hUyHyI0MMdaqKzACKr2s=
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=
@@ -258,9 +261,10 @@ github.com/containers/psgo v1.5.2 h1:3aoozst/GIwsrr/5jnFy3FrJay98uujPCu9lTuSZ/Cw
github.com/containers/psgo v1.5.2/go.mod h1:2ubh0SsreMZjSXW1Hif58JrEcFudQyIy9EzPUWfawVU=
github.com/containers/storage v1.23.5/go.mod h1:ha26Q6ngehFNhf3AWoXldvAvwI4jFe3ETQAf/CeZPyM=
github.com/containers/storage v1.32.2/go.mod h1:YIBxxjfXZTi04Ah49sh1uSGfmT1V89+I5i3deRobzQo=
-github.com/containers/storage v1.32.5/go.mod h1:8/DVVDqniaUlUV0D0q7cEnXK6Bs2uU3FPqNZVPumwEs=
-github.com/containers/storage v1.32.6 h1:NqdFRewXO/PYPjgCAScoigZc5QUA21yapSEj6kqD8cw=
github.com/containers/storage v1.32.6/go.mod h1:mdB+b89p+jU8zpzLTVXA0gWMmIo0WrkfGMh1R8O2IQw=
+github.com/containers/storage v1.33.0/go.mod h1:FUZPF4nJijX8ixdhByZJXf02cvbyLi6dyDwXdIe8QVY=
+github.com/containers/storage v1.33.1 h1:RHUPZ7vQxwoeOoMoKUDsVun4f9Wi8BTXmr/wQiruBYU=
+github.com/containers/storage v1.33.1/go.mod h1:FUZPF4nJijX8ixdhByZJXf02cvbyLi6dyDwXdIe8QVY=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
@@ -699,7 +703,6 @@ github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+
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.0/go.mod h1:hF8qUzuuC8DJGygJH3726JnCZX4MYbRB8yFfISqnKUg=
-github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E=
github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
@@ -710,7 +713,6 @@ github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7J
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc=
github.com/onsi/gomega v1.10.5/go.mod h1:gza4q3jKQJijlu05nKWRCW/GavJumGt8aNRxWg7mt48=
-github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY=
github.com/onsi/gomega v1.14.0 h1:ep6kpPVwmr/nTbklSx2nrLNSIO62DoYAhnPNIMhK8gI=
github.com/onsi/gomega v1.14.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0=
github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
@@ -731,8 +733,9 @@ github.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rm
github.com/opencontainers/runc v1.0.0-rc91/go.mod h1:3Sm6Dt7OT8z88EbdQqqcRN2oCT54jbi72tT/HqgflT8=
github.com/opencontainers/runc v1.0.0-rc93/go.mod h1:3NOsor4w32B2tC0Zbl8Knk4Wg84SM2ImC1fxBuqJ/H0=
github.com/opencontainers/runc v1.0.0-rc95/go.mod h1:z+bZxa/+Tz/FmYVWkhUajJdzFeOqjc5vrqskhVyHGUM=
-github.com/opencontainers/runc v1.0.0 h1:QOhAQAYUlKeofuyeKdR6ITvOnXLPbEAjPMjz9wCUXcU=
github.com/opencontainers/runc v1.0.0/go.mod h1:MU2S3KEB2ZExnhnAQYbwjdYV6HwKtDlNbA2Z2OeNDeA=
+github.com/opencontainers/runc v1.0.1 h1:G18PGckGdAm3yVQRWDVQ1rLSLntiniKJ0cNRT2Tm5gs=
+github.com/opencontainers/runc v1.0.1/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0=
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=
@@ -899,8 +902,9 @@ github.com/vbatts/tar-split v0.11.1 h1:0Odu65rhcZ3JZaPHxl7tCI3V/C/Q9Zf82UFravl02
github.com/vbatts/tar-split v0.11.1/go.mod h1:LEuURwDEiWjRjwu46yU3KVGuUdVv/dcnpcEPSzR8z6g=
github.com/vbauerster/mpb/v6 v6.0.4 h1:h6J5zM/2wimP5Hj00unQuV8qbo5EPcj6wbkCqgj7KcY=
github.com/vbauerster/mpb/v6 v6.0.4/go.mod h1:a/+JT57gqh6Du0Ay5jSR+uBMfXGdlR7VQlGP52fJxLM=
-github.com/vbauerster/mpb/v7 v7.0.2 h1:eN6AD/ytv1nqCO7Dm8MO0/pGMKmMyH/WMnTJhAUuc/w=
github.com/vbauerster/mpb/v7 v7.0.2/go.mod h1:Mnq3gESXJ9eQhccbGZDggJ1faTCrmaA4iN57fUloRGE=
+github.com/vbauerster/mpb/v7 v7.0.3 h1:NfX0pHWhlDTev15M/C3qmSTM1EiIjcS+/d6qS6H4FnI=
+github.com/vbauerster/mpb/v7 v7.0.3/go.mod h1:NXGsfPGx6G2JssqvEcULtDqUrxuuYs4llpv8W6ZUpzk=
github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk=
github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
github.com/vishvananda/netlink v1.1.1-0.20201029203352-d40f9887b852 h1:cPXZWzzG0NllBLdjWoD1nDfaqu98YMv+OneaKc8sPOA=
@@ -1181,8 +1185,9 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20210603125802-9665404d3644 h1:CA1DEQ4NdKphKeL70tvsWNdT5oFh1lOjihRcEDROi0I=
golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 h1:RqytpXGR1iVNX7psjB3ff8y7sNFinVFvkx1c8SjBkio=
+golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201113234701-d7a72108b828/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=
diff --git a/libpod/container.go b/libpod/container.go
index 4b9bea5fc..f3f4b27b7 100644
--- a/libpod/container.go
+++ b/libpod/container.go
@@ -1173,6 +1173,46 @@ func (c *Container) Networks() ([]string, bool, error) {
return c.networks()
}
+// NetworkMode gets the configured network mode for the container.
+// Get actual value from the database
+func (c *Container) NetworkMode() string {
+ networkMode := ""
+ ctrSpec := c.config.Spec
+
+ switch {
+ case c.config.CreateNetNS:
+ // We actually store the network
+ // mode for Slirp and Bridge, so
+ // we can just use that
+ networkMode = string(c.config.NetMode)
+ case c.config.NetNsCtr != "":
+ networkMode = fmt.Sprintf("container:%s", c.config.NetNsCtr)
+ default:
+ // Find the spec's network namespace.
+ // If there is none, it's host networking.
+ // If there is one and it has a path, it's "ns:".
+ foundNetNS := false
+ for _, ns := range ctrSpec.Linux.Namespaces {
+ if ns.Type == spec.NetworkNamespace {
+ foundNetNS = true
+ if ns.Path != "" {
+ networkMode = fmt.Sprintf("ns:%s", ns.Path)
+ } else {
+ // We're making a network ns, but not
+ // configuring with Slirp or CNI. That
+ // means it's --net=none
+ networkMode = "none"
+ }
+ break
+ }
+ }
+ if !foundNetNS {
+ networkMode = "host"
+ }
+ }
+ return networkMode
+}
+
// Unlocked accessor for networks
func (c *Container) networks() ([]string, bool, error) {
networks, err := c.runtime.state.GetNetworks(c)
diff --git a/libpod/container_api.go b/libpod/container_api.go
index 390bba7bb..637f5b686 100644
--- a/libpod/container_api.go
+++ b/libpod/container_api.go
@@ -780,6 +780,16 @@ type ContainerCheckpointOptions struct {
// Compression tells the API which compression to use for
// the exported checkpoint archive.
Compression archive.Compression
+ // If Pod is set the container should be restored into the
+ // given Pod. If Pod is empty it is a restore without a Pod.
+ // Restoring a non Pod container into a Pod or a Pod container
+ // without a Pod is theoretically possible, but will
+ // probably not work if a PID namespace is shared.
+ // A shared PID namespace means that a Pod container has PID 1
+ // in the infrastructure container, but without the infrastructure
+ // container no PID 1 will be in the namespace and that is not
+ // possible.
+ Pod string
}
// Checkpoint checkpoints a container
@@ -811,7 +821,11 @@ func (c *Container) Checkpoint(ctx context.Context, options ContainerCheckpointO
// Restore restores a container
func (c *Container) Restore(ctx context.Context, options ContainerCheckpointOptions) error {
- logrus.Debugf("Trying to restore container %s", c.ID())
+ if options.Pod == "" {
+ logrus.Debugf("Trying to restore container %s", c.ID())
+ } else {
+ logrus.Debugf("Trying to restore container %s into pod %s", c.ID(), options.Pod)
+ }
if !c.batched {
c.lock.Lock()
defer c.lock.Unlock()
@@ -840,7 +854,7 @@ func (c *Container) ShouldRestart(ctx context.Context) bool {
// CopyFromArchive copies the contents from the specified tarStream to path
// *inside* the container.
-func (c *Container) CopyFromArchive(ctx context.Context, containerPath string, chown bool, tarStream io.Reader) (func() error, error) {
+func (c *Container) CopyFromArchive(ctx context.Context, containerPath string, chown bool, rename map[string]string, tarStream io.Reader) (func() error, error) {
if !c.batched {
c.lock.Lock()
defer c.lock.Unlock()
@@ -850,7 +864,7 @@ func (c *Container) CopyFromArchive(ctx context.Context, containerPath string, c
}
}
- return c.copyFromArchive(ctx, containerPath, chown, tarStream)
+ return c.copyFromArchive(ctx, containerPath, chown, rename, tarStream)
}
// CopyToArchive copies the contents from the specified path *inside* the
diff --git a/libpod/container_copy_linux.go b/libpod/container_copy_linux.go
index 01e7ecacb..a35824289 100644
--- a/libpod/container_copy_linux.go
+++ b/libpod/container_copy_linux.go
@@ -23,7 +23,7 @@ import (
"golang.org/x/sys/unix"
)
-func (c *Container) copyFromArchive(ctx context.Context, path string, chown bool, reader io.Reader) (func() error, error) {
+func (c *Container) copyFromArchive(ctx context.Context, path string, chown bool, rename map[string]string, reader io.Reader) (func() error, error) {
var (
mountPoint string
resolvedRoot string
@@ -89,6 +89,7 @@ func (c *Container) copyFromArchive(ctx context.Context, path string, chown bool
GIDMap: c.config.IDMappings.GIDMap,
ChownDirs: idPair,
ChownFiles: idPair,
+ Rename: rename,
}
return c.joinMountAndExec(ctx,
diff --git a/libpod/container_inspect.go b/libpod/container_inspect.go
index 638e0b756..8c662c488 100644
--- a/libpod/container_inspect.go
+++ b/libpod/container_inspect.go
@@ -618,38 +618,7 @@ func (c *Container) generateInspectContainerHostConfig(ctrSpec *spec.Spec, named
hostConfig.Tmpfs = tmpfs
// Network mode parsing.
- networkMode := ""
- switch {
- case c.config.CreateNetNS:
- // We actually store the network
- // mode for Slirp and Bridge, so
- // we can just use that
- networkMode = string(c.config.NetMode)
- case c.config.NetNsCtr != "":
- networkMode = fmt.Sprintf("container:%s", c.config.NetNsCtr)
- default:
- // Find the spec's network namespace.
- // If there is none, it's host networking.
- // If there is one and it has a path, it's "ns:".
- foundNetNS := false
- for _, ns := range ctrSpec.Linux.Namespaces {
- if ns.Type == spec.NetworkNamespace {
- foundNetNS = true
- if ns.Path != "" {
- networkMode = fmt.Sprintf("ns:%s", ns.Path)
- } else {
- // We're making a network ns, but not
- // configuring with Slirp or CNI. That
- // means it's --net=none
- networkMode = "none"
- }
- break
- }
- }
- if !foundNetNS {
- networkMode = "host"
- }
- }
+ networkMode := c.NetworkMode()
hostConfig.NetworkMode = networkMode
// Port bindings.
diff --git a/libpod/container_internal.go b/libpod/container_internal.go
index 2555f15ec..e7694227a 100644
--- a/libpod/container_internal.go
+++ b/libpod/container_internal.go
@@ -420,7 +420,6 @@ func (c *Container) setupStorage(ctx context.Context) error {
if c.config.Rootfs == "" && (c.config.RootfsImageID == "" || c.config.RootfsImageName == "") {
return errors.Wrapf(define.ErrInvalidArg, "must provide image ID and image name to use an image")
}
-
options := storage.ContainerOptions{
IDMappingOptions: storage.IDMappingOptions{
HostUIDMapping: true,
diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go
index b69ad4105..bff64aa95 100644
--- a/libpod/container_internal_linux.go
+++ b/libpod/container_internal_linux.go
@@ -901,8 +901,27 @@ func (c *Container) addNamespaceContainer(g *generate.Generator, ns LinuxNS, ctr
}
func (c *Container) exportCheckpoint(options ContainerCheckpointOptions) error {
- if len(c.Dependencies()) > 0 {
- return errors.Errorf("Cannot export checkpoints of containers with dependencies")
+ if len(c.Dependencies()) == 1 {
+ // Check if the dependency is an infra container. If it is we can checkpoint
+ // the container out of the Pod.
+ if c.config.Pod == "" {
+ return errors.Errorf("cannot export checkpoints of containers with dependencies")
+ }
+
+ pod, err := c.runtime.state.Pod(c.config.Pod)
+ if err != nil {
+ return errors.Wrapf(err, "container %s is in pod %s, but pod cannot be retrieved", c.ID(), c.config.Pod)
+ }
+ infraID, err := pod.InfraContainerID()
+ if err != nil {
+ return errors.Wrapf(err, "cannot retrieve infra container ID for pod %s", c.config.Pod)
+ }
+ if c.Dependencies()[0] != infraID {
+ return errors.Errorf("cannot export checkpoints of containers with dependencies")
+ }
+ }
+ if len(c.Dependencies()) > 1 {
+ return errors.Errorf("cannot export checkpoints of containers with dependencies")
}
logrus.Debugf("Exporting checkpoint image of container %q to %q", c.ID(), options.TargetFile)
@@ -1021,9 +1040,9 @@ func (c *Container) exportCheckpoint(options ContainerCheckpointOptions) error {
return nil
}
-func (c *Container) checkpointRestoreSupported() error {
- if !criu.CheckForCriu() {
- return errors.Errorf("checkpoint/restore requires at least CRIU %d", criu.MinCriuVersion)
+func (c *Container) checkpointRestoreSupported(version int) error {
+ if !criu.CheckForCriu(version) {
+ return errors.Errorf("checkpoint/restore requires at least CRIU %d", version)
}
if !c.ociRuntime.SupportsCheckpoint() {
return errors.Errorf("configured runtime does not support checkpoint/restore")
@@ -1032,7 +1051,7 @@ func (c *Container) checkpointRestoreSupported() error {
}
func (c *Container) checkpoint(ctx context.Context, options ContainerCheckpointOptions) error {
- if err := c.checkpointRestoreSupported(); err != nil {
+ if err := c.checkpointRestoreSupported(criu.MinCriuVersion); err != nil {
return err
}
@@ -1136,10 +1155,20 @@ func (c *Container) importPreCheckpoint(input string) error {
}
func (c *Container) restore(ctx context.Context, options ContainerCheckpointOptions) (retErr error) {
- if err := c.checkpointRestoreSupported(); err != nil {
+ minCriuVersion := func() int {
+ if options.Pod == "" {
+ return criu.MinCriuVersion
+ }
+ return criu.PodCriuVersion
+ }()
+ if err := c.checkpointRestoreSupported(minCriuVersion); err != nil {
return err
}
+ if options.Pod != "" && !crutils.CRRuntimeSupportsPodCheckpointRestore(c.ociRuntime.Path()) {
+ return errors.Errorf("runtime %s does not support pod restore", c.ociRuntime.Path())
+ }
+
if !c.ensureState(define.ContainerStateConfigured, define.ContainerStateExited) {
return errors.Wrapf(define.ErrCtrStateInvalid, "container %s is running or paused, cannot restore", c.ID())
}
@@ -1247,6 +1276,83 @@ func (c *Container) restore(ctx context.Context, options ContainerCheckpointOpti
}
}
+ if options.Pod != "" {
+ // Running in a Pod means that we have to change all namespace settings to
+ // the ones from the infrastructure container.
+ pod, err := c.runtime.LookupPod(options.Pod)
+ if err != nil {
+ return errors.Wrapf(err, "pod %q cannot be retrieved", options.Pod)
+ }
+
+ infraContainer, err := pod.InfraContainer()
+ if err != nil {
+ return errors.Wrapf(err, "cannot retrieved infra container from pod %q", options.Pod)
+ }
+
+ infraContainer.lock.Lock()
+ if err := infraContainer.syncContainer(); err != nil {
+ infraContainer.lock.Unlock()
+ return errors.Wrapf(err, "Error syncing infrastructure container %s status", infraContainer.ID())
+ }
+ if infraContainer.state.State != define.ContainerStateRunning {
+ if err := infraContainer.initAndStart(ctx); err != nil {
+ infraContainer.lock.Unlock()
+ return errors.Wrapf(err, "Error starting infrastructure container %s status", infraContainer.ID())
+ }
+ }
+ infraContainer.lock.Unlock()
+
+ if c.config.IPCNsCtr != "" {
+ nsPath, err := infraContainer.namespacePath(IPCNS)
+ if err != nil {
+ return errors.Wrapf(err, "cannot retrieve IPC namespace path for Pod %q", options.Pod)
+ }
+ if err := g.AddOrReplaceLinuxNamespace(string(spec.IPCNamespace), nsPath); err != nil {
+ return err
+ }
+ }
+
+ if c.config.NetNsCtr != "" {
+ nsPath, err := infraContainer.namespacePath(NetNS)
+ if err != nil {
+ return errors.Wrapf(err, "cannot retrieve network namespace path for Pod %q", options.Pod)
+ }
+ if err := g.AddOrReplaceLinuxNamespace(string(spec.NetworkNamespace), nsPath); err != nil {
+ return err
+ }
+ }
+
+ if c.config.PIDNsCtr != "" {
+ nsPath, err := infraContainer.namespacePath(PIDNS)
+ if err != nil {
+ return errors.Wrapf(err, "cannot retrieve PID namespace path for Pod %q", options.Pod)
+ }
+ if err := g.AddOrReplaceLinuxNamespace(string(spec.PIDNamespace), nsPath); err != nil {
+ return err
+ }
+ }
+
+ if c.config.UTSNsCtr != "" {
+ nsPath, err := infraContainer.namespacePath(UTSNS)
+ if err != nil {
+ return errors.Wrapf(err, "cannot retrieve UTS namespace path for Pod %q", options.Pod)
+ }
+ if err := g.AddOrReplaceLinuxNamespace(string(spec.UTSNamespace), nsPath); err != nil {
+ return err
+ }
+ }
+
+ if c.config.CgroupNsCtr != "" {
+ nsPath, err := infraContainer.namespacePath(CgroupNS)
+ if err != nil {
+ return errors.Wrapf(err, "cannot retrieve Cgroup namespace path for Pod %q", options.Pod)
+ }
+ if err := g.AddOrReplaceLinuxNamespace(string(spec.CgroupNamespace), nsPath); err != nil {
+ return err
+ }
+ }
+ }
+
if err := c.makeBindMounts(); err != nil {
return err
}
diff --git a/libpod/container_log_linux.go b/libpod/container_log_linux.go
index 9f9dd3b0d..d4afaa52a 100644
--- a/libpod/container_log_linux.go
+++ b/libpod/container_log_linux.go
@@ -97,8 +97,6 @@ func (c *Container) readFromJournal(ctx context.Context, options *logs.LogOption
}
}()
- beforeTimeStamp := true
- afterTimeStamp := false // needed for options.Since
tailQueue := []*logs.LogLine{} // needed for options.Tail
doTail := options.Tail > 0
for {
@@ -150,21 +148,10 @@ func (c *Container) readFromJournal(ctx context.Context, options *logs.LogOption
return
}
- if !afterTimeStamp {
- entryTime := time.Unix(0, int64(entry.RealtimeTimestamp)*int64(time.Microsecond))
- if entryTime.Before(options.Since) {
- continue
- }
- afterTimeStamp = true
- }
- if beforeTimeStamp {
- entryTime := time.Unix(0, int64(entry.RealtimeTimestamp)*int64(time.Microsecond))
- if entryTime.Before(options.Until) || !options.Until.IsZero() {
- continue
- }
- beforeTimeStamp = false
+ entryTime := time.Unix(0, int64(entry.RealtimeTimestamp)*int64(time.Microsecond))
+ if (entryTime.Before(options.Since) && !options.Since.IsZero()) || (entryTime.After(options.Until) && !options.Until.IsZero()) {
+ continue
}
-
// If we're reading an event and the container exited/died,
// then we're done and can return.
event, ok := entry.Fields["PODMAN_EVENT"]
diff --git a/libpod/network/network.go b/libpod/network/network.go
index ed4e6388a..805988432 100644
--- a/libpod/network/network.go
+++ b/libpod/network/network.go
@@ -111,8 +111,10 @@ func allocatorToIPNets(networks []*allocator.Net) []*net.IPNet {
if len(network.IPAM.Ranges) > 0 {
// this is the new IPAM range style
// append each subnet from ipam the rangeset
- for _, r := range network.IPAM.Ranges[0] {
- nets = append(nets, newIPNetFromSubnet(r.Subnet))
+ for _, allocatorRange := range network.IPAM.Ranges {
+ for _, r := range allocatorRange {
+ nets = append(nets, newIPNetFromSubnet(r.Subnet))
+ }
}
} else {
// looks like the old, deprecated style
diff --git a/libpod/oci_conmon_linux.go b/libpod/oci_conmon_linux.go
index 2914bd1a1..846d3815a 100644
--- a/libpod/oci_conmon_linux.go
+++ b/libpod/oci_conmon_linux.go
@@ -1064,6 +1064,30 @@ func (r *ConmonOCIRuntime) createOCIContainer(ctr *Container, restoreOptions *Co
if restoreOptions.TCPEstablished {
args = append(args, "--runtime-opt", "--tcp-established")
}
+ if restoreOptions.Pod != "" {
+ mountLabel := ctr.config.MountLabel
+ processLabel := ctr.config.ProcessLabel
+ if mountLabel != "" {
+ args = append(
+ args,
+ "--runtime-opt",
+ fmt.Sprintf(
+ "--lsm-mount-context=%s",
+ mountLabel,
+ ),
+ )
+ }
+ if processLabel != "" {
+ args = append(
+ args,
+ "--runtime-opt",
+ fmt.Sprintf(
+ "--lsm-profile=selinux:%s",
+ processLabel,
+ ),
+ )
+ }
+ }
}
logrus.WithFields(logrus.Fields{
diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go
index 6c69d1b72..31e2d09ce 100644
--- a/libpod/runtime_ctr.go
+++ b/libpod/runtime_ctr.go
@@ -47,6 +47,32 @@ func (r *Runtime) NewContainer(ctx context.Context, rSpec *spec.Spec, options ..
return r.newContainer(ctx, rSpec, options...)
}
+func (r *Runtime) PrepareVolumeOnCreateContainer(ctx context.Context, ctr *Container) error {
+ // Copy the content from the underlying image into the newly created
+ // volume if configured to do so.
+ if !r.config.Containers.PrepareVolumeOnCreate {
+ return nil
+ }
+
+ defer func() {
+ if err := ctr.cleanupStorage(); err != nil {
+ logrus.Errorf("error cleaning up container storage %s: %v", ctr.ID(), err)
+ }
+ }()
+
+ mountPoint, err := ctr.mountStorage()
+ if err == nil {
+ // Finish up mountStorage
+ ctr.state.Mounted = true
+ ctr.state.Mountpoint = mountPoint
+ if err = ctr.save(); err != nil {
+ logrus.Errorf("Error saving container %s state: %v", ctr.ID(), err)
+ }
+ }
+
+ return err
+}
+
// RestoreContainer re-creates a container from an imported checkpoint
func (r *Runtime) RestoreContainer(ctx context.Context, rSpec *spec.Spec, config *ContainerConfig) (*Container, error) {
r.lock.Lock()
@@ -868,6 +894,18 @@ func (r *Runtime) LookupContainer(idOrName string) (*Container, error) {
return r.state.LookupContainer(idOrName)
}
+// LookupContainerId looks up a container id by its name or a partial ID
+// If a partial ID is not unique, an error will be returned
+func (r *Runtime) LookupContainerID(idOrName string) (string, error) {
+ r.lock.RLock()
+ defer r.lock.RUnlock()
+
+ if !r.valid {
+ return "", define.ErrRuntimeStopped
+ }
+ return r.state.LookupContainerID(idOrName)
+}
+
// GetContainers retrieves all containers from the state
// Filters can be provided which will determine what containers are included in
// the output. Multiple filters are handled by ANDing their output, so only
diff --git a/pkg/api/handlers/compat/containers_archive.go b/pkg/api/handlers/compat/containers_archive.go
index a9d74e5f4..541f702e7 100644
--- a/pkg/api/handlers/compat/containers_archive.go
+++ b/pkg/api/handlers/compat/containers_archive.go
@@ -1,6 +1,7 @@
package compat
import (
+ "encoding/json"
"fmt"
"net/http"
"os"
@@ -93,8 +94,9 @@ func handleHeadAndGet(w http.ResponseWriter, r *http.Request, decoder *schema.De
func handlePut(w http.ResponseWriter, r *http.Request, decoder *schema.Decoder, runtime *libpod.Runtime) {
query := struct {
- Path string `schema:"path"`
- Chown bool `schema:"copyUIDGID"`
+ Path string `schema:"path"`
+ Chown bool `schema:"copyUIDGID"`
+ Rename string `schema:"rename"`
// TODO handle params below
NoOverwriteDirNonDir bool `schema:"noOverwriteDirNonDir"`
}{
@@ -107,10 +109,19 @@ func handlePut(w http.ResponseWriter, r *http.Request, decoder *schema.Decoder,
return
}
+ var rename map[string]string
+ if query.Rename != "" {
+ if err := json.Unmarshal([]byte(query.Rename), &rename); err != nil {
+ utils.Error(w, "Bad Request.", http.StatusBadRequest, errors.Wrap(err, "couldn't decode the query"))
+ return
+ }
+ }
+
containerName := utils.GetName(r)
containerEngine := abi.ContainerEngine{Libpod: runtime}
- copyFunc, err := containerEngine.ContainerCopyFromArchive(r.Context(), containerName, query.Path, r.Body, entities.CopyOptions{Chown: query.Chown})
+ copyOptions := entities.CopyOptions{Chown: query.Chown, Rename: rename}
+ copyFunc, err := containerEngine.ContainerCopyFromArchive(r.Context(), containerName, query.Path, r.Body, copyOptions)
if errors.Cause(err) == define.ErrNoSuchCtr || os.IsNotExist(err) {
// 404 is returned for an absent container and path. The
// clients must deal with it accordingly.
diff --git a/pkg/api/handlers/compat/images.go b/pkg/api/handlers/compat/images.go
index 7baa1145a..6f8fb21f0 100644
--- a/pkg/api/handlers/compat/images.go
+++ b/pkg/api/handlers/compat/images.go
@@ -266,41 +266,26 @@ func CreateImageFromImage(w http.ResponseWriter, r *http.Request) {
}
defer auth.RemoveAuthfile(authfile)
- platformSpecs := strings.Split(query.Platform, "/") // split query into its parts
-
- addOS := true // default assume true due to structure of if/else below
- addArch := false
- addVariant := false
-
- if len(platformSpecs) > 1 { // if we have two arguments then we have os and arch
- addArch = true
- if len(platformSpecs) > 2 { // if we have 3 arguments then we have os arch and variant
- addVariant = true
- }
- } else if len(platformSpecs) == 0 {
- addOS = false
- }
-
pullOptions := &libimage.PullOptions{}
pullOptions.AuthFilePath = authfile
if authConf != nil {
pullOptions.Username = authConf.Username
pullOptions.Password = authConf.Password
pullOptions.IdentityToken = authConf.IdentityToken
- if addOS { // if the len is not 0
- pullOptions.OS = platformSpecs[0]
- if addArch {
- pullOptions.Architecture = platformSpecs[1]
- }
- if addVariant {
- pullOptions.Variant = platformSpecs[2]
- }
- }
}
pullOptions.Writer = os.Stderr // allows for debugging on the server
- progress := make(chan types.ProgressProperties)
+ // Handle the platform.
+ platformSpecs := strings.Split(query.Platform, "/")
+ pullOptions.OS = platformSpecs[0] // may be empty
+ if len(platformSpecs) > 1 {
+ pullOptions.Architecture = platformSpecs[1]
+ if len(platformSpecs) > 2 {
+ pullOptions.Variant = platformSpecs[2]
+ }
+ }
+ progress := make(chan types.ProgressProperties)
pullOptions.Progress = progress
pullResChan := make(chan pullResult)
diff --git a/pkg/api/handlers/compat/images_build.go b/pkg/api/handlers/compat/images_build.go
index 64805b7fa..2c98a5361 100644
--- a/pkg/api/handlers/compat/images_build.go
+++ b/pkg/api/handlers/compat/images_build.go
@@ -393,16 +393,16 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
defer auth.RemoveAuthfile(authfile)
// Channels all mux'ed in select{} below to follow API build protocol
- stdout := channel.NewWriter(make(chan []byte, 1))
+ stdout := channel.NewWriter(make(chan []byte))
defer stdout.Close()
- auxout := channel.NewWriter(make(chan []byte, 1))
+ auxout := channel.NewWriter(make(chan []byte))
defer auxout.Close()
- stderr := channel.NewWriter(make(chan []byte, 1))
+ stderr := channel.NewWriter(make(chan []byte))
defer stderr.Close()
- reporter := channel.NewWriter(make(chan []byte, 1))
+ reporter := channel.NewWriter(make(chan []byte))
defer reporter.Close()
runtime := r.Context().Value("runtime").(*libpod.Runtime)
@@ -529,7 +529,7 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
enc := json.NewEncoder(body)
enc.SetEscapeHTML(true)
-loop:
+
for {
m := struct {
Stream string `json:"stream,omitempty"`
@@ -543,13 +543,13 @@ loop:
stderr.Write([]byte(err.Error()))
}
flush()
- case e := <-auxout.Chan():
+ case e := <-reporter.Chan():
m.Stream = string(e)
if err := enc.Encode(m); err != nil {
stderr.Write([]byte(err.Error()))
}
flush()
- case e := <-reporter.Chan():
+ case e := <-auxout.Chan():
m.Stream = string(e)
if err := enc.Encode(m); err != nil {
stderr.Write([]byte(err.Error()))
@@ -561,8 +561,8 @@ loop:
logrus.Warnf("Failed to json encode error %v", err)
}
flush()
+ return
case <-runCtx.Done():
- flush()
if success {
if !utils.IsLibpodRequest(r) {
m.Stream = fmt.Sprintf("Successfully built %12.12s\n", imageID)
@@ -579,7 +579,8 @@ loop:
}
}
}
- break loop
+ flush()
+ return
case <-r.Context().Done():
cancel()
logrus.Infof("Client disconnect reported for build %q / %q.", registry, query.Dockerfile)
diff --git a/pkg/api/handlers/libpod/containers_create.go b/pkg/api/handlers/libpod/containers_create.go
index b92588346..65951861b 100644
--- a/pkg/api/handlers/libpod/containers_create.go
+++ b/pkg/api/handlers/libpod/containers_create.go
@@ -22,6 +22,7 @@ func CreateContainer(w http.ResponseWriter, r *http.Request) {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "Decode()"))
return
}
+
warn, err := generate.CompleteSpec(r.Context(), runtime, &sg)
if err != nil {
utils.InternalServerError(w, err)
diff --git a/pkg/api/handlers/types.go b/pkg/api/handlers/types.go
index 3cc10d70f..af5878798 100644
--- a/pkg/api/handlers/types.go
+++ b/pkg/api/handlers/types.go
@@ -176,6 +176,11 @@ func ImageToImageSummary(l *libimage.Image) (*entities.ImageSummary, error) {
}
containerCount := len(containers)
+ isDangling, err := l.IsDangling(context.TODO())
+ if err != nil {
+ return nil, errors.Wrapf(err, "failed to check if image %s is dangling", l.ID())
+ }
+
is := entities.ImageSummary{
ID: l.ID(),
ParentId: imageData.Parent,
@@ -188,7 +193,7 @@ func ImageToImageSummary(l *libimage.Image) (*entities.ImageSummary, error) {
Labels: imageData.Labels,
Containers: containerCount,
ReadOnly: l.IsReadOnly(),
- Dangling: l.IsDangling(),
+ Dangling: isDangling,
Names: l.Names(),
Digest: string(imageData.Digest),
ConfigDigest: "", // TODO: libpod/image didn't set it but libimage should
diff --git a/pkg/api/server/docs.go b/pkg/api/server/docs.go
index e72b78221..bf15afbf9 100644
--- a/pkg/api/server/docs.go
+++ b/pkg/api/server/docs.go
@@ -42,7 +42,7 @@
//
// InfoExtensions:
// x-logo:
-// - url: https://raw.githubusercontent.com/containers/libpod/master/logo/podman-logo.png
+// - url: https://raw.githubusercontent.com/containers/libpod/main/logo/podman-logo.png
// - altText: "Podman logo"
//
// Produces:
diff --git a/pkg/api/server/register_archive.go b/pkg/api/server/register_archive.go
index ee7449fbb..82d72ee6a 100644
--- a/pkg/api/server/register_archive.go
+++ b/pkg/api/server/register_archive.go
@@ -151,6 +151,10 @@ func (s *APIServer) registerArchiveHandlers(r *mux.Router) error {
// type: string
// description: Path to a directory in the container to extract
// required: true
+ // - in: query
+ // name: rename
+ // type: string
+ // description: JSON encoded map[string]string to translate paths
// responses:
// 200:
// description: no error
diff --git a/pkg/api/server/register_volumes.go b/pkg/api/server/register_volumes.go
index d58bf0662..fb02cffcf 100644
--- a/pkg/api/server/register_volumes.go
+++ b/pkg/api/server/register_volumes.go
@@ -68,6 +68,7 @@ func (s *APIServer) registerVolumeHandlers(r *mux.Router) error {
// - label=<key> or label=<key>:<value> Matches volumes based on the presence of a label alone or a label and a value.
// - name=<volume-name> Matches all of volume name.
// - opt=<driver-option> Matches a storage driver options
+ // - `until=<timestamp>` List volumes created before this timestamp. The `<timestamp>` can be Unix timestamps, date formatted timestamps, or Go duration strings (e.g. `10m`, `1h30m`) computed relative to the daemon machine’s time.
// responses:
// '200':
// "$ref": "#/responses/VolumeList"
@@ -166,6 +167,7 @@ func (s *APIServer) registerVolumeHandlers(r *mux.Router) error {
// - driver=<volume-driver-name> Matches volumes based on their driver.
// - label=<key> or label=<key>:<value> Matches volumes based on the presence of a label alone or a label and a value.
// - name=<volume-name> Matches all of volume name.
+ // - `until=<timestamp>` List volumes created before this timestamp. The `<timestamp>` can be Unix timestamps, date formatted timestamps, or Go duration strings (e.g. `10m`, `1h30m`) computed relative to the daemon machine’s time.
//
// Note:
// The boolean `dangling` filter is not yet implemented for this endpoint.
diff --git a/pkg/api/server/server.go b/pkg/api/server/server.go
index 1e8faf8f5..72ae27276 100644
--- a/pkg/api/server/server.go
+++ b/pkg/api/server/server.go
@@ -90,11 +90,10 @@ func newServer(runtime *libpod.Runtime, duration time.Duration, listener *net.Li
server := APIServer{
Server: http.Server{
- Handler: router,
- ReadHeaderTimeout: 20 * time.Second,
- IdleTimeout: duration * 2,
- ConnState: idle.ConnState,
- ErrorLog: log.New(logrus.StandardLogger().Out, "", 0),
+ Handler: router,
+ IdleTimeout: duration * 2,
+ ConnState: idle.ConnState,
+ ErrorLog: log.New(logrus.StandardLogger().Out, "", 0),
},
Decoder: handlers.NewAPIDecoder(),
idleTracker: idle,
diff --git a/pkg/bindings/connection.go b/pkg/bindings/connection.go
index fd93c5ac7..62b1655ac 100644
--- a/pkg/bindings/connection.go
+++ b/pkg/bindings/connection.go
@@ -327,7 +327,7 @@ func (c *Connection) DoRequest(httpBody io.Reader, httpMethod, endpoint string,
uri := fmt.Sprintf("http://d/v%d.%d.%d/libpod"+endpoint, params...)
logrus.Debugf("DoRequest Method: %s URI: %v", httpMethod, uri)
- req, err := http.NewRequest(httpMethod, uri, httpBody)
+ req, err := http.NewRequestWithContext(context.WithValue(context.Background(), clientKey, c), httpMethod, uri, httpBody)
if err != nil {
return nil, err
}
@@ -337,7 +337,6 @@ func (c *Connection) DoRequest(httpBody io.Reader, httpMethod, endpoint string,
for key, val := range header {
req.Header.Set(key, val)
}
- req = req.WithContext(context.WithValue(context.Background(), clientKey, c))
// Give the Do three chances in the case of a comm/service hiccup
for i := 0; i < 3; i++ {
response, err = c.Client.Do(req) // nolint
diff --git a/pkg/bindings/containers/types.go b/pkg/bindings/containers/types.go
index 1058c7a48..cf088441f 100644
--- a/pkg/bindings/containers/types.go
+++ b/pkg/bindings/containers/types.go
@@ -62,6 +62,7 @@ type RestoreOptions struct {
Keep *bool
Name *string
TCPEstablished *bool
+ Pod *string
}
//go:generate go run ../generator/generator.go CreateOptions
@@ -263,4 +264,6 @@ type CopyOptions struct {
// If used with CopyFromArchive and set to true it will change ownership of files from the source tar archive
// to the primary uid/gid of the target container.
Chown *bool `schema:"copyUIDGID"`
+ // Map to translate path names.
+ Rename map[string]string
}
diff --git a/pkg/bindings/containers/types_copy_options.go b/pkg/bindings/containers/types_copy_options.go
index 12ad085fd..0624b450e 100644
--- a/pkg/bindings/containers/types_copy_options.go
+++ b/pkg/bindings/containers/types_copy_options.go
@@ -35,3 +35,19 @@ func (o *CopyOptions) GetChown() bool {
}
return *o.Chown
}
+
+// WithRename
+func (o *CopyOptions) WithRename(value map[string]string) *CopyOptions {
+ v := value
+ o.Rename = v
+ return o
+}
+
+// GetRename
+func (o *CopyOptions) GetRename() map[string]string {
+ var rename map[string]string
+ if o.Rename == nil {
+ return rename
+ }
+ return o.Rename
+}
diff --git a/pkg/bindings/containers/types_restore_options.go b/pkg/bindings/containers/types_restore_options.go
index ea6c810a2..820a7696f 100644
--- a/pkg/bindings/containers/types_restore_options.go
+++ b/pkg/bindings/containers/types_restore_options.go
@@ -131,3 +131,19 @@ func (o *RestoreOptions) GetTCPEstablished() bool {
}
return *o.TCPEstablished
}
+
+// WithPod
+func (o *RestoreOptions) WithPod(value string) *RestoreOptions {
+ v := &value
+ o.Pod = v
+ return o
+}
+
+// GetPod
+func (o *RestoreOptions) GetPod() string {
+ var pod string
+ if o.Pod == nil {
+ return pod
+ }
+ return *o.Pod
+}
diff --git a/pkg/bindings/images/build.go b/pkg/bindings/images/build.go
index 142204f27..a35f461a7 100644
--- a/pkg/bindings/images/build.go
+++ b/pkg/bindings/images/build.go
@@ -391,42 +391,50 @@ func Build(ctx context.Context, containerFiles []string, options entities.BuildO
dec := json.NewDecoder(body)
var id string
- var mErr error
for {
var s struct {
Stream string `json:"stream,omitempty"`
Error string `json:"error,omitempty"`
}
- if err := dec.Decode(&s); err != nil {
- if errors.Is(err, io.EOF) {
- if mErr == nil && id == "" {
- mErr = errors.New("stream dropped, unexpected failure")
- }
- break
- }
- s.Error = err.Error() + "\n"
- }
select {
+ // FIXME(vrothberg): it seems we always hit the EOF case below,
+ // even when the server quit but it seems desirable to
+ // distinguish a proper build from a transient EOF.
case <-response.Request.Context().Done():
- return &entities.BuildReport{ID: id}, mErr
+ return &entities.BuildReport{ID: id}, nil
default:
// non-blocking select
}
+ if err := dec.Decode(&s); err != nil {
+ if errors.Is(err, io.ErrUnexpectedEOF) {
+ return nil, errors.Wrap(err, "server probably quit")
+ }
+ // EOF means the stream is over in which case we need
+ // to have read the id.
+ if errors.Is(err, io.EOF) && id != "" {
+ break
+ }
+ return &entities.BuildReport{ID: id}, errors.Wrap(err, "decoding stream")
+ }
+
switch {
case s.Stream != "":
- stdout.Write([]byte(s.Stream))
- if iidRegex.Match([]byte(s.Stream)) {
+ raw := []byte(s.Stream)
+ stdout.Write(raw)
+ if iidRegex.Match(raw) {
id = strings.TrimSuffix(s.Stream, "\n")
}
case s.Error != "":
- mErr = errors.New(s.Error)
+ // If there's an error, return directly. The stream
+ // will be closed on return.
+ return &entities.BuildReport{ID: id}, errors.New(s.Error)
default:
return &entities.BuildReport{ID: id}, errors.New("failed to parse build results stream, unexpected input")
}
}
- return &entities.BuildReport{ID: id}, mErr
+ return &entities.BuildReport{ID: id}, nil
}
func nTar(excludes []string, sources ...string) (io.ReadCloser, error) {
diff --git a/pkg/checkpoint/checkpoint_restore.go b/pkg/checkpoint/checkpoint_restore.go
index 0d45cab5f..9fdf04933 100644
--- a/pkg/checkpoint/checkpoint_restore.go
+++ b/pkg/checkpoint/checkpoint_restore.go
@@ -9,6 +9,9 @@ import (
"github.com/containers/common/libimage"
"github.com/containers/common/pkg/config"
"github.com/containers/podman/v3/libpod"
+ ann "github.com/containers/podman/v3/pkg/annotations"
+ "github.com/containers/podman/v3/pkg/checkpoint/crutils"
+ "github.com/containers/podman/v3/pkg/criu"
"github.com/containers/podman/v3/pkg/domain/entities"
"github.com/containers/podman/v3/pkg/errorhandling"
"github.com/containers/podman/v3/pkg/specgen/generate"
@@ -68,6 +71,14 @@ func CRImportCheckpoint(ctx context.Context, runtime *libpod.Runtime, restoreOpt
return nil, err
}
+ if ctrConfig.Pod != "" && restoreOptions.Pod == "" {
+ return nil, errors.New("cannot restore pod container without --pod")
+ }
+
+ if ctrConfig.Pod == "" && restoreOptions.Pod != "" {
+ return nil, errors.New("cannot restore non pod container into pod")
+ }
+
// This should not happen as checkpoints with these options are not exported.
if len(ctrConfig.Dependencies) > 0 {
return nil, errors.Errorf("Cannot import checkpoints of containers with dependencies")
@@ -96,6 +107,91 @@ func CRImportCheckpoint(ctx context.Context, runtime *libpod.Runtime, restoreOpt
newName = true
}
+ if restoreOptions.Pod != "" {
+ // Restoring into a Pod requires much newer versions of CRIU
+ if !criu.CheckForCriu(criu.PodCriuVersion) {
+ return nil, errors.Errorf("restoring containers into pods requires at least CRIU %d", criu.PodCriuVersion)
+ }
+ // The runtime also has to support it
+ if !crutils.CRRuntimeSupportsPodCheckpointRestore(runtime.GetOCIRuntimePath()) {
+ return nil, errors.Errorf("runtime %s does not support pod restore", runtime.GetOCIRuntimePath())
+ }
+ // Restoring into an existing Pod
+ ctrConfig.Pod = restoreOptions.Pod
+
+ // According to podman pod create a pod can share the following namespaces:
+ // cgroup, ipc, net, pid, uts
+ // Let's make sure we a restoring into a pod with the same shared namespaces.
+ pod, err := runtime.LookupPod(ctrConfig.Pod)
+ if err != nil {
+ return nil, errors.Wrapf(err, "pod %q cannot be retrieved", ctrConfig.Pod)
+ }
+
+ infraContainer, err := pod.InfraContainer()
+ if err != nil {
+ return nil, errors.Wrapf(err, "cannot retrieve infra container from pod %q", ctrConfig.Pod)
+ }
+
+ // If a namespaces was shared (!= "") it needs to be set to the new infrastructure container
+ // If the infrastructure container does not share the same namespaces as the to be restored
+ // container we abort.
+ if ctrConfig.IPCNsCtr != "" {
+ if !pod.SharesIPC() {
+ return nil, errors.Errorf("pod %s does not share the IPC namespace", ctrConfig.Pod)
+ }
+ ctrConfig.IPCNsCtr = infraContainer.ID()
+ }
+
+ if ctrConfig.NetNsCtr != "" {
+ if !pod.SharesNet() {
+ return nil, errors.Errorf("pod %s does not share the network namespace", ctrConfig.Pod)
+ }
+ ctrConfig.NetNsCtr = infraContainer.ID()
+ }
+
+ if ctrConfig.PIDNsCtr != "" {
+ if !pod.SharesPID() {
+ return nil, errors.Errorf("pod %s does not share the PID namespace", ctrConfig.Pod)
+ }
+ ctrConfig.PIDNsCtr = infraContainer.ID()
+ }
+
+ if ctrConfig.UTSNsCtr != "" {
+ if !pod.SharesUTS() {
+ return nil, errors.Errorf("pod %s does not share the UTS namespace", ctrConfig.Pod)
+ }
+ ctrConfig.UTSNsCtr = infraContainer.ID()
+ }
+
+ if ctrConfig.CgroupNsCtr != "" {
+ if !pod.SharesCgroup() {
+ return nil, errors.Errorf("pod %s does not share the cgroup namespace", ctrConfig.Pod)
+ }
+ ctrConfig.CgroupNsCtr = infraContainer.ID()
+ }
+
+ // Change SELinux labels to infrastructure container labels
+ ctrConfig.MountLabel = infraContainer.MountLabel()
+ ctrConfig.ProcessLabel = infraContainer.ProcessLabel()
+
+ // Fix parent cgroup
+ cgroupPath, err := pod.CgroupPath()
+ if err != nil {
+ return nil, errors.Wrapf(err, "cannot retrieve cgroup path from pod %q", ctrConfig.Pod)
+ }
+ ctrConfig.CgroupParent = cgroupPath
+
+ oldPodID := dumpSpec.Annotations[ann.SandboxID]
+ // Fix up SandboxID in the annotations
+ dumpSpec.Annotations[ann.SandboxID] = ctrConfig.Pod
+ // Fix up CreateCommand
+ for i, c := range ctrConfig.CreateCommand {
+ if c == oldPodID {
+ ctrConfig.CreateCommand[i] = ctrConfig.Pod
+ }
+ }
+ }
+
if len(restoreOptions.PublishPorts) > 0 {
ports, _, _, err := generate.ParsePortMapping(restoreOptions.PublishPorts)
if err != nil {
diff --git a/pkg/checkpoint/crutils/checkpoint_restore_utils.go b/pkg/checkpoint/crutils/checkpoint_restore_utils.go
index 53ff55865..3b77368bb 100644
--- a/pkg/checkpoint/crutils/checkpoint_restore_utils.go
+++ b/pkg/checkpoint/crutils/checkpoint_restore_utils.go
@@ -1,6 +1,7 @@
package crutils
import (
+ "bytes"
"io"
"os"
"os/exec"
@@ -189,3 +190,13 @@ func CRRuntimeSupportsCheckpointRestore(runtimePath string) bool {
}
return false
}
+
+// CRRuntimeSupportsCheckpointRestore tests if the runtime at 'runtimePath'
+// supports restoring into existing Pods. The runtime needs to support
+// the CRIU option --lsm-mount-context and the existence of this is checked
+// by this function. In addition it is necessary to at least have CRIU 3.16.
+func CRRuntimeSupportsPodCheckpointRestore(runtimePath string) bool {
+ cmd := exec.Command(runtimePath, "restore", "--lsm-mount-context")
+ out, _ := cmd.CombinedOutput()
+ return bytes.Contains(out, []byte("flag needs an argument"))
+}
diff --git a/pkg/copy/parse.go b/pkg/copy/parse.go
index 39e0e1547..93edec5fa 100644
--- a/pkg/copy/parse.go
+++ b/pkg/copy/parse.go
@@ -18,18 +18,6 @@ func ParseSourceAndDestination(source, destination string) (string, string, stri
sourceContainer, sourcePath := parseUserInput(source)
destContainer, destPath := parseUserInput(destination)
- numContainers := 0
- if len(sourceContainer) > 0 {
- numContainers++
- }
- if len(destContainer) > 0 {
- numContainers++
- }
-
- if numContainers != 1 {
- return "", "", "", "", errors.Errorf("invalid arguments %q, %q: exactly 1 container expected but %d specified", source, destination, numContainers)
- }
-
if len(sourcePath) == 0 || len(destPath) == 0 {
return "", "", "", "", errors.Errorf("invalid arguments %q, %q: you must specify paths", source, destination)
}
diff --git a/pkg/criu/criu.go b/pkg/criu/criu.go
index f4cce238a..2a6805979 100644
--- a/pkg/criu/criu.go
+++ b/pkg/criu/criu.go
@@ -1,17 +1,21 @@
package criu
import (
- "github.com/checkpoint-restore/go-criu"
+ "github.com/checkpoint-restore/go-criu/v5"
)
// MinCriuVersion for Podman at least CRIU 3.11 is required
const MinCriuVersion = 31100
+// PodCriuVersion is the version of CRIU needed for
+// checkpointing and restoring containers out of and into Pods.
+const PodCriuVersion = 31600
+
// CheckForCriu uses CRIU's go bindings to check if the CRIU
// binary exists and if it at least the version Podman needs.
-func CheckForCriu() bool {
+func CheckForCriu(version int) bool {
c := criu.MakeCriu()
- result, err := c.IsCriuAtLeast(MinCriuVersion)
+ result, err := c.IsCriuAtLeast(version)
if err != nil {
return false
}
diff --git a/pkg/domain/entities/containers.go b/pkg/domain/entities/containers.go
index 302b35a47..564921c52 100644
--- a/pkg/domain/entities/containers.go
+++ b/pkg/domain/entities/containers.go
@@ -165,6 +165,8 @@ type CopyOptions struct {
// it will change ownership of files from the source tar archive
// to the primary uid/gid of the destination container.
Chown bool
+ // Map to translate path names.
+ Rename map[string]string
}
type CommitReport struct {
@@ -207,6 +209,7 @@ type RestoreOptions struct {
TCPEstablished bool
ImportPrevious string
PublishPorts []specgen.PortMapping
+ Pod string
}
type RestoreReport struct {
@@ -242,6 +245,8 @@ type ContainerLogsOptions struct {
Names bool
// Show logs since this timestamp.
Since time.Time
+ // Show logs until this timestamp.
+ Until time.Time
// Number of lines to display at the end of the output.
Tail int64
// Show timestamps in the logs.
diff --git a/pkg/domain/entities/engine_container.go b/pkg/domain/entities/engine_container.go
index 62e83fab3..d573e4704 100644
--- a/pkg/domain/entities/engine_container.go
+++ b/pkg/domain/entities/engine_container.go
@@ -8,7 +8,6 @@ import (
"github.com/containers/podman/v3/libpod/define"
"github.com/containers/podman/v3/pkg/domain/entities/reports"
"github.com/containers/podman/v3/pkg/specgen"
- "github.com/spf13/cobra"
)
type ContainerCopyFunc func() error
@@ -82,7 +81,7 @@ type ContainerEngine interface {
PodStop(ctx context.Context, namesOrIds []string, options PodStopOptions) ([]*PodStopReport, error)
PodTop(ctx context.Context, options PodTopOptions) (*StringSliceReport, error)
PodUnpause(ctx context.Context, namesOrIds []string, options PodunpauseOptions) ([]*PodUnpauseReport, error)
- SetupRootless(ctx context.Context, cmd *cobra.Command) error
+ SetupRootless(ctx context.Context, noMoveProcess bool) error
SecretCreate(ctx context.Context, name string, reader io.Reader, options SecretCreateOptions) (*SecretCreateReport, error)
SecretInspect(ctx context.Context, nameOrIDs []string) ([]*SecretInfoReport, []error, error)
SecretList(ctx context.Context) ([]*SecretInfoReport, error)
diff --git a/pkg/domain/filters/containers.go b/pkg/domain/filters/containers.go
index 965a12468..dc9fed2a4 100644
--- a/pkg/domain/filters/containers.go
+++ b/pkg/domain/filters/containers.go
@@ -211,6 +211,36 @@ func GenerateContainerFilterFuncs(filter string, filterValues []string, r *libpo
}, nil
case "network":
return func(c *libpod.Container) bool {
+ networkMode := c.NetworkMode()
+ // support docker like `--filter network=container:<IDorName>`
+ // check if networkMode is configured as `container:<ctr>`
+ // peform a match against filter `container:<IDorName>`
+ // networks is already going to be empty if `container:<ctr>` is configured as Mode
+ if strings.HasPrefix(networkMode, "container:") {
+ networkModeContainerPart := strings.SplitN(networkMode, ":", 2)
+ if len(networkModeContainerPart) < 2 {
+ return false
+ }
+ networkModeContainerID := networkModeContainerPart[1]
+ for _, val := range filterValues {
+ if strings.HasPrefix(val, "container:") {
+ filterNetworkModePart := strings.SplitN(val, ":", 2)
+ if len(filterNetworkModePart) < 2 {
+ return false
+ }
+ filterNetworkModeIDorName := filterNetworkModePart[1]
+ filterID, err := r.LookupContainerID(filterNetworkModeIDorName)
+ if err != nil {
+ return false
+ }
+ if filterID == networkModeContainerID {
+ return true
+ }
+ }
+ }
+ return false
+ }
+
networks, _, err := c.Networks()
// if err or no networks, quick out
if err != nil || len(networks) == 0 {
diff --git a/pkg/domain/filters/volumes.go b/pkg/domain/filters/volumes.go
index df23c31c0..d55c44ef5 100644
--- a/pkg/domain/filters/volumes.go
+++ b/pkg/domain/filters/volumes.go
@@ -51,6 +51,12 @@ func GenerateVolumeFilters(filters url.Values) ([]libpod.VolumeFilter, error) {
}
return false
})
+ case "until":
+ f, err := createUntilFilterVolumeFunction(val)
+ if err != nil {
+ return nil, err
+ }
+ vf = append(vf, f)
case "dangling":
danglingVal := val
invert := false
@@ -93,16 +99,11 @@ func GeneratePruneVolumeFilters(filters url.Values) ([]libpod.VolumeFilter, erro
return util.MatchLabelFilters([]string{filterVal}, v.Labels())
})
case "until":
- until, err := util.ComputeUntilTimestamp([]string{filterVal})
+ f, err := createUntilFilterVolumeFunction(filterVal)
if err != nil {
return nil, err
}
- vf = append(vf, func(v *libpod.Volume) bool {
- if !until.IsZero() && v.CreatedTime().Before(until) {
- return true
- }
- return false
- })
+ vf = append(vf, f)
default:
return nil, errors.Errorf("%q is an invalid volume filter", filter)
}
@@ -110,3 +111,16 @@ func GeneratePruneVolumeFilters(filters url.Values) ([]libpod.VolumeFilter, erro
}
return vf, nil
}
+
+func createUntilFilterVolumeFunction(filter string) (libpod.VolumeFilter, error) {
+ until, err := util.ComputeUntilTimestamp([]string{filter})
+ if err != nil {
+ return nil, err
+ }
+ return func(v *libpod.Volume) bool {
+ if !until.IsZero() && v.CreatedTime().Before(until) {
+ return true
+ }
+ return false
+ }, nil
+}
diff --git a/pkg/domain/infra/abi/archive.go b/pkg/domain/infra/abi/archive.go
index 1a5bb6dc4..b60baa935 100644
--- a/pkg/domain/infra/abi/archive.go
+++ b/pkg/domain/infra/abi/archive.go
@@ -12,7 +12,7 @@ func (ic *ContainerEngine) ContainerCopyFromArchive(ctx context.Context, nameOrI
if err != nil {
return nil, err
}
- return container.CopyFromArchive(ctx, containerPath, options.Chown, reader)
+ return container.CopyFromArchive(ctx, containerPath, options.Chown, options.Rename, reader)
}
func (ic *ContainerEngine) ContainerCopyToArchive(ctx context.Context, nameOrID string, containerPath string, writer io.Writer) (entities.ContainerCopyFunc, error) {
diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go
index 50751aa12..2003879b8 100644
--- a/pkg/domain/infra/abi/containers.go
+++ b/pkg/domain/infra/abi/containers.go
@@ -529,6 +529,7 @@ func (ic *ContainerEngine) ContainerRestore(ctx context.Context, namesOrIds []st
IgnoreStaticIP: options.IgnoreStaticIP,
IgnoreStaticMAC: options.IgnoreStaticMAC,
ImportPrevious: options.ImportPrevious,
+ Pod: options.Pod,
}
filterFuncs := []libpod.ContainerFilter{
@@ -618,7 +619,7 @@ func makeExecConfig(options entities.ExecOptions, rt *libpod.Runtime) (*libpod.E
return nil, errors.Wrapf(err, "error retrieving Libpod configuration to build exec exit command")
}
// TODO: Add some ability to toggle syslog
- exitCommandArgs, err := generate.CreateExitCommandArgs(storageConfig, runtimeConfig, false, true, true)
+ exitCommandArgs, err := generate.CreateExitCommandArgs(storageConfig, runtimeConfig, false, false, true)
if err != nil {
return nil, errors.Wrapf(err, "error constructing exit command for exec session")
}
@@ -998,6 +999,7 @@ func (ic *ContainerEngine) ContainerLogs(ctx context.Context, containers []strin
Details: options.Details,
Follow: options.Follow,
Since: options.Since,
+ Until: options.Until,
Tail: options.Tail,
Timestamps: options.Timestamps,
UseName: options.Names,
diff --git a/pkg/domain/infra/abi/images_list.go b/pkg/domain/infra/abi/images_list.go
index b0e947991..2ec4ad244 100644
--- a/pkg/domain/infra/abi/images_list.go
+++ b/pkg/domain/infra/abi/images_list.go
@@ -30,12 +30,16 @@ func (ir *ImageEngine) List(ctx context.Context, opts entities.ImageListOptions)
for j, d := range img.Digests() {
digests[j] = string(d)
}
+ isDangling, err := img.IsDangling(ctx)
+ if err != nil {
+ return nil, errors.Wrapf(err, "error checking if image %q is dangling", img.ID())
+ }
e := entities.ImageSummary{
ID: img.ID(),
// ConfigDigest: string(img.ConfigDigest),
Created: img.Created().Unix(),
- Dangling: img.IsDangling(),
+ Dangling: isDangling,
Digest: string(img.Digest()),
RepoDigests: digests,
History: img.NamesHistory(),
diff --git a/pkg/domain/infra/abi/manifest.go b/pkg/domain/infra/abi/manifest.go
index 68e29f006..666bc997d 100644
--- a/pkg/domain/infra/abi/manifest.go
+++ b/pkg/domain/infra/abi/manifest.go
@@ -337,6 +337,7 @@ func (ir *ImageEngine) ManifestPush(ctx context.Context, name, destination strin
pushOptions.ManifestMIMEType = manifestType
pushOptions.RemoveSignatures = opts.RemoveSignatures
pushOptions.SignBy = opts.SignBy
+ pushOptions.InsecureSkipTLSVerify = opts.SkipTLSVerify
if opts.All {
pushOptions.ImageListSelection = cp.CopyAllImages
diff --git a/pkg/domain/infra/abi/play.go b/pkg/domain/infra/abi/play.go
index 4782f0d01..d257bad18 100644
--- a/pkg/domain/infra/abi/play.go
+++ b/pkg/domain/infra/abi/play.go
@@ -277,7 +277,10 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
// registry on localhost.
pullPolicy := config.PullPolicyNewer
if len(container.ImagePullPolicy) > 0 {
- pullPolicy, err = config.ParsePullPolicy(string(container.ImagePullPolicy))
+ // Make sure to lower the strings since K8s pull policy
+ // may be capitalized (see bugzilla.redhat.com/show_bug.cgi?id=1985905).
+ rawPolicy := string(container.ImagePullPolicy)
+ pullPolicy, err = config.ParsePullPolicy(strings.ToLower(rawPolicy))
if err != nil {
return nil, err
}
diff --git a/pkg/domain/infra/abi/system.go b/pkg/domain/infra/abi/system.go
index 155cda21d..bc98edd06 100644
--- a/pkg/domain/infra/abi/system.go
+++ b/pkg/domain/infra/abi/system.go
@@ -24,7 +24,6 @@ import (
"github.com/containers/storage/pkg/unshare"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
- "github.com/spf13/cobra"
"github.com/spf13/pflag"
)
@@ -57,7 +56,7 @@ func (ic *ContainerEngine) Info(ctx context.Context) (*define.Info, error) {
return info, err
}
-func (ic *ContainerEngine) SetupRootless(_ context.Context, cmd *cobra.Command) error {
+func (ic *ContainerEngine) SetupRootless(_ context.Context, noMoveProcess bool) error {
// do it only after podman has already re-execed and running with uid==0.
hasCapSysAdmin, err := unshare.HasCapSysAdmin()
if err != nil {
@@ -104,6 +103,9 @@ func (ic *ContainerEngine) SetupRootless(_ context.Context, cmd *cobra.Command)
if became {
os.Exit(ret)
}
+ if noMoveProcess {
+ return nil
+ }
// if there is no pid file, try to join existing containers, and create a pause process.
ctrs, err := ic.Libpod.GetRunningContainers()
@@ -118,9 +120,10 @@ func (ic *ContainerEngine) SetupRootless(_ context.Context, cmd *cobra.Command)
}
became, ret, err = rootless.TryJoinFromFilePaths(pausePidPath, true, paths)
+
if err := movePauseProcessToScope(ic.Libpod); err != nil {
- conf, err := ic.Config(context.Background())
- if err != nil {
+ conf, err2 := ic.Config(context.Background())
+ if err2 != nil {
return err
}
if conf.Engine.CgroupManager == config.SystemdCgroupsManager {
@@ -148,7 +151,6 @@ func movePauseProcessToScope(r *libpod.Runtime) error {
if err != nil {
return errors.Wrapf(err, "could not get pause process pid file path")
}
-
data, err := ioutil.ReadFile(pausePidPath)
if err != nil {
return errors.Wrapf(err, "cannot read pause pid file")
diff --git a/pkg/domain/infra/runtime_abi.go b/pkg/domain/infra/runtime_abi.go
index ca201b5ae..177e9cff4 100644
--- a/pkg/domain/infra/runtime_abi.go
+++ b/pkg/domain/infra/runtime_abi.go
@@ -33,6 +33,7 @@ func NewImageEngine(facts *entities.PodmanConfig) (entities.ImageEngine, error)
r, err := NewLibpodImageRuntime(facts.FlagSet, facts)
return r, err
case entities.TunnelMode:
+ // TODO: look at me!
ctx, err := bindings.NewConnectionWithIdentity(context.Background(), facts.URI, facts.Identity)
return &tunnel.ImageEngine{ClientCtx: ctx}, err
}
diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go
index c17d7b54f..58f9c5fb0 100644
--- a/pkg/domain/infra/tunnel/containers.go
+++ b/pkg/domain/infra/tunnel/containers.go
@@ -369,10 +369,11 @@ func (ic *ContainerEngine) ContainerCreate(ctx context.Context, s *specgen.SpecG
func (ic *ContainerEngine) ContainerLogs(_ context.Context, nameOrIDs []string, opts entities.ContainerLogsOptions) error {
since := opts.Since.Format(time.RFC3339)
+ until := opts.Until.Format(time.RFC3339)
tail := strconv.FormatInt(opts.Tail, 10)
stdout := opts.StdoutWriter != nil
stderr := opts.StderrWriter != nil
- options := new(containers.LogOptions).WithFollow(opts.Follow).WithSince(since).WithStderr(stderr)
+ options := new(containers.LogOptions).WithFollow(opts.Follow).WithSince(since).WithUntil(until).WithStderr(stderr)
options.WithStdout(stdout).WithTail(tail)
var err error
@@ -852,7 +853,8 @@ func (ic *ContainerEngine) ContainerPort(ctx context.Context, nameOrID string, o
}
func (ic *ContainerEngine) ContainerCopyFromArchive(ctx context.Context, nameOrID, path string, reader io.Reader, options entities.CopyOptions) (entities.ContainerCopyFunc, error) {
- return containers.CopyFromArchiveWithOptions(ic.ClientCtx, nameOrID, path, reader, new(containers.CopyOptions).WithChown(options.Chown))
+ copyOptions := new(containers.CopyOptions).WithChown(options.Chown).WithRename(options.Rename)
+ return containers.CopyFromArchiveWithOptions(ic.ClientCtx, nameOrID, path, reader, copyOptions)
}
func (ic *ContainerEngine) ContainerCopyToArchive(ctx context.Context, nameOrID string, path string, writer io.Writer) (entities.ContainerCopyFunc, error) {
diff --git a/pkg/domain/infra/tunnel/system.go b/pkg/domain/infra/tunnel/system.go
index 7400d3771..6b43cf038 100644
--- a/pkg/domain/infra/tunnel/system.go
+++ b/pkg/domain/infra/tunnel/system.go
@@ -7,14 +7,13 @@ import (
"github.com/containers/podman/v3/libpod/define"
"github.com/containers/podman/v3/pkg/bindings/system"
"github.com/containers/podman/v3/pkg/domain/entities"
- "github.com/spf13/cobra"
)
func (ic *ContainerEngine) Info(ctx context.Context) (*define.Info, error) {
return system.Info(ic.ClientCtx, nil)
}
-func (ic *ContainerEngine) SetupRootless(_ context.Context, cmd *cobra.Command) error {
+func (ic *ContainerEngine) SetupRootless(_ context.Context, noMoveProcess bool) error {
panic(errors.New("rootless engine mode is not supported when tunneling"))
}
diff --git a/pkg/rootless/rootless_linux.c b/pkg/rootless/rootless_linux.c
index e5f9e88d9..4d8443fcb 100644
--- a/pkg/rootless/rootless_linux.c
+++ b/pkg/rootless/rootless_linux.c
@@ -465,38 +465,43 @@ reexec_in_user_namespace_wait (int pid, int options)
static int
create_pause_process (const char *pause_pid_file_path, char **argv)
{
- int r, p[2];
+ pid_t pid;
+ int p[2];
if (pipe (p) < 0)
- _exit (EXIT_FAILURE);
+ return -1;
- r = fork ();
- if (r < 0)
- _exit (EXIT_FAILURE);
+ pid = fork ();
+ if (pid < 0)
+ {
+ close (p[0]);
+ close (p[1]);
+ return -1;
+ }
- if (r)
+ if (pid)
{
char b;
+ int r;
close (p[1]);
/* Block until we write the pid file. */
r = TEMP_FAILURE_RETRY (read (p[0], &b, 1));
close (p[0]);
- reexec_in_user_namespace_wait (r, 0);
+ reexec_in_user_namespace_wait (pid, 0);
return r == 1 && b == '0' ? 0 : -1;
}
else
{
- int fd;
- pid_t pid;
+ int r, fd;
close (p[0]);
setsid ();
pid = fork ();
- if (r < 0)
+ if (pid < 0)
_exit (EXIT_FAILURE);
if (pid)
diff --git a/pkg/rootless/rootless_linux.go b/pkg/rootless/rootless_linux.go
index f76eab0e3..9ef56acb4 100644
--- a/pkg/rootless/rootless_linux.go
+++ b/pkg/rootless/rootless_linux.go
@@ -14,11 +14,13 @@ import (
"os/user"
"runtime"
"strconv"
+ "strings"
"sync"
"unsafe"
"github.com/containers/podman/v3/pkg/errorhandling"
"github.com/containers/storage/pkg/idtools"
+ pmount "github.com/containers/storage/pkg/mount"
"github.com/containers/storage/pkg/unshare"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@@ -235,6 +237,24 @@ func becomeRootInUserNS(pausePid, fileToRead string, fileOutput *os.File) (_ boo
return false, 0, nil
}
+ if mounts, err := pmount.GetMounts(); err == nil {
+ for _, m := range mounts {
+ if m.Mountpoint == "/" {
+ isShared := false
+ for _, o := range strings.Split(m.Optional, ",") {
+ if strings.HasPrefix(o, "shared:") {
+ isShared = true
+ break
+ }
+ }
+ if !isShared {
+ logrus.Warningf("%q is not a shared mount, this could cause issues or missing mounts with rootless containers", m.Mountpoint)
+ }
+ break
+ }
+ }
+ }
+
cPausePid := C.CString(pausePid)
defer C.free(unsafe.Pointer(cPausePid))
diff --git a/pkg/specgen/generate/container_create.go b/pkg/specgen/generate/container_create.go
index b569f8390..4e3a86ae4 100644
--- a/pkg/specgen/generate/container_create.go
+++ b/pkg/specgen/generate/container_create.go
@@ -153,7 +153,15 @@ func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGener
if err != nil {
return nil, err
}
- return rt.NewContainer(ctx, runtimeSpec, options...)
+
+ ctr, err := rt.NewContainer(ctx, runtimeSpec, options...)
+ if err != nil {
+ return ctr, err
+ }
+
+ // Copy the content from the underlying image into the newly created
+ // volume if configured to do so.
+ return ctr, rt.PrepareVolumeOnCreateContainer(ctx, ctr)
}
func extractCDIDevices(s *specgen.SpecGenerator) []libpod.CtrCreateOption {
diff --git a/pkg/specgen/generate/kube/kube.go b/pkg/specgen/generate/kube/kube.go
index fb563f935..fb7eb99a2 100644
--- a/pkg/specgen/generate/kube/kube.go
+++ b/pkg/specgen/generate/kube/kube.go
@@ -6,10 +6,12 @@ import (
"fmt"
"net"
"strings"
+ "time"
"github.com/containers/common/libimage"
"github.com/containers/common/pkg/parse"
"github.com/containers/common/pkg/secrets"
+ "github.com/containers/image/v5/manifest"
ann "github.com/containers/podman/v3/pkg/annotations"
"github.com/containers/podman/v3/pkg/specgen"
"github.com/containers/podman/v3/pkg/specgen/generate"
@@ -129,6 +131,10 @@ func ToSpecGen(ctx context.Context, opts *CtrSpecGenOptions) (*specgen.SpecGener
}
setupSecurityContext(s, opts.Container)
+ err := setupLivenessProbe(s, opts.Container, opts.RestartPolicy)
+ if err != nil {
+ return nil, errors.Wrap(err, "Failed to configure livenessProbe")
+ }
// Since we prefix the container name with pod name to work-around the uniqueness requirement,
// the seccomp profile should reference the actual container name from the YAML
@@ -270,10 +276,11 @@ func ToSpecGen(ctx context.Context, opts *CtrSpecGenOptions) (*specgen.SpecGener
return nil, err
}
+ volume.MountPath = dest
switch volumeSource.Type {
case KubeVolumeTypeBindMount:
mount := spec.Mount{
- Destination: dest,
+ Destination: volume.MountPath,
Source: volumeSource.Source,
Type: "bind",
Options: options,
@@ -281,7 +288,7 @@ func ToSpecGen(ctx context.Context, opts *CtrSpecGenOptions) (*specgen.SpecGener
s.Mounts = append(s.Mounts, mount)
case KubeVolumeTypeNamed:
namedVolume := specgen.NamedVolume{
- Dest: dest,
+ Dest: volume.MountPath,
Name: volumeSource.Source,
Options: options,
}
@@ -324,12 +331,105 @@ func parseMountPath(mountPath string, readOnly bool) (string, []string, error) {
options = strings.Split(splitVol[1], ",")
}
if err := parse.ValidateVolumeCtrDir(dest); err != nil {
- return "", options, errors.Wrapf(err, "error in parsing MountPath")
+ return "", options, errors.Wrapf(err, "parsing MountPath")
}
if readOnly {
options = append(options, "ro")
}
- return dest, options, nil
+ opts, err := parse.ValidateVolumeOpts(options)
+ if err != nil {
+ return "", opts, errors.Wrapf(err, "parsing MountOptions")
+ }
+ return dest, opts, nil
+}
+
+func setupLivenessProbe(s *specgen.SpecGenerator, containerYAML v1.Container, restartPolicy string) error {
+ var err error
+ if containerYAML.LivenessProbe == nil {
+ return nil
+ }
+ emptyHandler := v1.Handler{}
+ if containerYAML.LivenessProbe.Handler != emptyHandler {
+ var commandString string
+ failureCmd := "exit 1"
+ probe := containerYAML.LivenessProbe
+ probeHandler := probe.Handler
+
+ // append `exit 1` to `cmd` so healthcheck can be marked as `unhealthy`.
+ // append `kill 1` to `cmd` if appropriate restart policy is configured.
+ if restartPolicy == "always" || restartPolicy == "onfailure" {
+ // container will be restarted so we can kill init.
+ failureCmd = "kill 1"
+ }
+
+ // configure healthcheck on the basis of Handler Actions.
+ if probeHandler.Exec != nil {
+ execString := strings.Join(probeHandler.Exec.Command, " ")
+ commandString = fmt.Sprintf("%s || %s", execString, failureCmd)
+ } else if probeHandler.HTTPGet != nil {
+ commandString = fmt.Sprintf("curl %s://%s:%d/%s || %s", probeHandler.HTTPGet.Scheme, probeHandler.HTTPGet.Host, probeHandler.HTTPGet.Port.IntValue(), probeHandler.HTTPGet.Path, failureCmd)
+ } else if probeHandler.TCPSocket != nil {
+ commandString = fmt.Sprintf("nc -z -v %s %d || %s", probeHandler.TCPSocket.Host, probeHandler.TCPSocket.Port.IntValue(), failureCmd)
+ }
+ s.HealthConfig, err = makeHealthCheck(commandString, probe.PeriodSeconds, probe.FailureThreshold, probe.TimeoutSeconds, probe.InitialDelaySeconds)
+ if err != nil {
+ return err
+ }
+ return nil
+ }
+ return nil
+}
+
+func makeHealthCheck(inCmd string, interval int32, retries int32, timeout int32, startPeriod int32) (*manifest.Schema2HealthConfig, error) {
+ // Every healthcheck requires a command
+ if len(inCmd) == 0 {
+ return nil, errors.New("Must define a healthcheck command for all healthchecks")
+ }
+
+ // first try to parse option value as JSON array of strings...
+ cmd := []string{}
+
+ if inCmd == "none" {
+ cmd = []string{"NONE"}
+ } else {
+ err := json.Unmarshal([]byte(inCmd), &cmd)
+ if err != nil {
+ // ...otherwise pass it to "/bin/sh -c" inside the container
+ cmd = []string{"CMD-SHELL"}
+ cmd = append(cmd, strings.Split(inCmd, " ")...)
+ }
+ }
+ hc := manifest.Schema2HealthConfig{
+ Test: cmd,
+ }
+
+ if interval < 1 {
+ //kubernetes interval defaults to 10 sec and cannot be less than 1
+ interval = 10
+ }
+ hc.Interval = (time.Duration(interval) * time.Second)
+ if retries < 1 {
+ //kubernetes retries defaults to 3
+ retries = 3
+ }
+ hc.Retries = int(retries)
+ if timeout < 1 {
+ //kubernetes timeout defaults to 1
+ timeout = 1
+ }
+ timeoutDuration := (time.Duration(timeout) * time.Second)
+ if timeoutDuration < time.Duration(1) {
+ return nil, errors.New("healthcheck-timeout must be at least 1 second")
+ }
+ hc.Timeout = timeoutDuration
+
+ startPeriodDuration := (time.Duration(startPeriod) * time.Second)
+ if startPeriodDuration < time.Duration(0) {
+ return nil, errors.New("healthcheck-start-period must be 0 seconds or greater")
+ }
+ hc.StartPeriod = startPeriodDuration
+
+ return &hc, nil
}
func setupSecurityContext(s *specgen.SpecGenerator, containerYAML v1.Container) {
diff --git a/pkg/specgen/generate/oci.go b/pkg/specgen/generate/oci.go
index bf8d44ed6..6e310d8a6 100644
--- a/pkg/specgen/generate/oci.go
+++ b/pkg/specgen/generate/oci.go
@@ -321,6 +321,10 @@ func SpecGenToOCI(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runt
}
}
+ for _, dev := range s.DeviceCGroupRule {
+ g.AddLinuxResourcesDevice(true, dev.Type, dev.Major, dev.Minor, dev.Access)
+ }
+
BlockAccessToKernelFilesystems(s.Privileged, s.PidNS.IsHost(), s.Mask, s.Unmask, &g)
for name, val := range s.Env {
diff --git a/pkg/specgen/specgen.go b/pkg/specgen/specgen.go
index c5cc726d7..7eec48a55 100644
--- a/pkg/specgen/specgen.go
+++ b/pkg/specgen/specgen.go
@@ -239,6 +239,9 @@ type ContainerStorageConfig struct {
// Devices are devices that will be added to the container.
// Optional.
Devices []spec.LinuxDevice `json:"devices,omitempty"`
+ // DeviceCGroupRule are device cgroup rules that allow containers
+ // to use additional types of devices.
+ DeviceCGroupRule []spec.LinuxDeviceCgroup `json:"device_cgroup_rule,omitempty"`
// IpcNS is the container's IPC namespace.
// Default is private.
// Conflicts with ShmSize if not set to private.
diff --git a/test/README.md b/test/README.md
index d7710cc95..769bdbfd7 100644
--- a/test/README.md
+++ b/test/README.md
@@ -84,7 +84,7 @@ file itself. Consider the following actual test:
It("podman inspect bogus pod", func() {
session := podmanTest.Podman([]string{"pod", "inspect", "foobar"})
session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Not(Equal(0)))
+ Expect(session).To(ExitWithError())
})
```
diff --git a/test/apiv2/10-images.at b/test/apiv2/10-images.at
index 9e464dbc7..195b11ff0 100644
--- a/test/apiv2/10-images.at
+++ b/test/apiv2/10-images.at
@@ -45,6 +45,11 @@ t POST "images/create?fromImage=alpine" 200 .error~null .status~".*Download comp
t POST "images/create?fromImage=alpine&tag=latest" 200
+# 10977 - handle platform parameter correctly
+t POST "images/create?fromImage=alpine&platform=linux/arm64" 200
+t GET "images/alpine/json" 200 \
+ .Architecture=arm64
+
# Make sure that new images are pulled
old_iid=$(podman image inspect --format "{{.ID}}" docker.io/library/alpine:latest)
podman rmi -f docker.io/library/alpine:latest
diff --git a/test/apiv2/30-volumes.at b/test/apiv2/30-volumes.at
index b639e05f9..fd1542293 100644
--- a/test/apiv2/30-volumes.at
+++ b/test/apiv2/30-volumes.at
@@ -174,6 +174,8 @@ t POST libpod/volumes/create \
# with date way back in the past, volume should not be deleted (compat api)
t POST volumes/prune?filters='{"until":["500000"]}' 200
t GET libpod/volumes/json?filters='{"label":["testuntilcompat"]}' 200 length=1
+t GET libpod/volumes/json?filters='{"until":["500000"]}' 200 length=0
+t GET libpod/volumes/json?filters='{"until":["5000000000"]}' 200 length=1
# with date far in the future, volume should be deleted (compat api)
t POST volumes/prune?filters='{"until":["5000000000"]}' 200
diff --git a/test/apiv2/python/rest_api/test_v2_0_0_container.py b/test/apiv2/python/rest_api/test_v2_0_0_container.py
index f252bd401..30d902d8c 100644
--- a/test/apiv2/python/rest_api/test_v2_0_0_container.py
+++ b/test/apiv2/python/rest_api/test_v2_0_0_container.py
@@ -33,9 +33,10 @@ class ContainerTestCase(APITestCase):
self.assertId(r.content)
_ = parse(r.json()["Created"])
+
r = requests.post(
self.podman_url + "/v1.40/containers/create?name=topcontainer",
- json={"Cmd": ["top"], "Image": "alpine:latest"},
+ json={"Healthcheck": {"Test": ["CMD-SHELL", "exit 0"], "Interval":1000, "Timeout":1000, "Retries": 5}, "Cmd": ["top"], "Image": "alpine:latest"},
)
self.assertEqual(r.status_code, 201, r.text)
payload = r.json()
@@ -49,6 +50,13 @@ class ContainerTestCase(APITestCase):
state = out["State"]["Health"]
self.assertIsInstance(state, dict)
+ r = requests.get(self.uri(f"/containers/{payload['Id']}/json"))
+ self.assertEqual(r.status_code, 200, r.text)
+ self.assertId(r.content)
+ out = r.json()
+ hc = out["Config"]["Healthcheck"]["Test"]
+ self.assertListEqual(["CMD-SHELL", "exit 0"], hc)
+
def test_stats(self):
r = requests.get(self.uri(self.resolve_container("/containers/{}/stats?stream=false")))
self.assertIn(r.status_code, (200, 409), r.text)
diff --git a/test/apiv2/test-apiv2 b/test/apiv2/test-apiv2
index 9f6bf257f..26619ae03 100755
--- a/test/apiv2/test-apiv2
+++ b/test/apiv2/test-apiv2
@@ -442,10 +442,10 @@ function random_string() {
function wait_for_port() {
local host=$1 # Probably "localhost"
local port=$2 # Numeric port
- local timeout=${3:-5} # Optional; default to 5 seconds
+ local _timeout=${3:-5} # Optional; default to 5 seconds
# Wait
- while [ $timeout -gt 0 ]; do
+ while [ $_timeout -gt 0 ]; do
{ exec 3<> /dev/tcp/$host/$port; } &>/dev/null && return
sleep 1
_timeout=$(( $_timeout - 1 ))
diff --git a/test/buildah-bud/apply-podman-deltas b/test/buildah-bud/apply-podman-deltas
index 41c84257f..18b3d56f9 100755
--- a/test/buildah-bud/apply-podman-deltas
+++ b/test/buildah-bud/apply-podman-deltas
@@ -56,22 +56,31 @@ function errmsg() {
done
}
-# skip: used to add a 'skip' to one specific test
-function skip() {
+# _skip: used to add a 'skip' or 'skip_if_remote' to one specific test
+function _skip() {
+ local skip=$1; shift
local reason=$1; shift
# All further arguments are test names
for t in "$@"; do
if fgrep -qx "@test \"$t\" {" $BUD; then
- $ECHO "@test \"$t\" : skip \"$reason\""
+ $ECHO "@test \"$t\" : $skip \"$reason\""
t=${t//\//\\/}
- sed -i -e "/^\@test \"$t\" {/ a \ \ skip \"$reason\"" $BUD
+ sed -i -e "/^\@test \"$t\" {/ a \ \ $skip \"$reason\"" $BUD
else
- warn "[skip] Did not find test \"$t\" in $BUD"
+ warn "[$skip] Did not find test \"$t\" in $BUD"
fi
done
}
+function skip() {
+ _skip "skip" "$@"
+}
+
+function skip_if_remote() {
+ _skip "skip_if_remote" "$@"
+}
+
# END handlers
###############################################################################
# BEGIN user-customizable section
@@ -79,14 +88,14 @@ function skip() {
# These are the hand-maintained exceptions. This is what you want to edit
# or update as needed.
#
-# There are two directives you can use below:
+# There are three directives you can use below:
#
# errmsg "old-message" "new-message" "test name" ["test name"...]
#
# This replaced "old-message" with "new-message" in @test "test name".
# It is used when a podman error message differs from buildah's.
#
-# skip "reason" "test name" ["test name"...]
+# [skip | skip_if_remote] "reason" "test name" ["test name"...]
#
# This adds a 'skip' statement as the first line of @test "test name".
# It is used when a test does not work in podman, either for permanent
@@ -126,6 +135,7 @@ errmsg "no such file or directory" \
###############################################################################
# BEGIN tests that don't make sense under podman due to fundamental differences
+
skip "N/A under podman" \
"bud-flags-order-verification"
@@ -147,13 +157,13 @@ skip "Too much effort to spin up a local registry" \
skip "FIXME FIXME FIXME: argument-order incompatible with podman" \
"bud-squash-hardlinks"
-skip "FIXME FIXME FIXME we'll figure these out later" \
- "bud-multi-stage-nocache-nocommit" \
- "bud with --cgroup-parent"
+skip "FIXME FIXME FIXME: this passes on Ed's laptop, fails in CI??" \
+ "bud-multi-stage-nocache-nocommit"
-# see https://github.com/containers/podman/pull/10147#issuecomment-832503633
-skip "FIXME FIXME FIXME podman save/load has been fixed (but not yet used in Buildah CI)" \
- "bud with --layers and --no-cache flags"
+# This will probably never work: buildah and podman have incompatible defaults
+# Documented in https://github.com/containers/podman/issues/10412
+skip "buildah runs with --cgroup-manager=cgroupfs, podman with systemd" \
+ "bud with --cgroup-parent"
# see https://github.com/containers/podman/pull/10829
skip "FIXME FIXME FIXME - requires updated CI images (#10829)" \
@@ -164,6 +174,31 @@ skip "FIXME FIXME FIXME - requires updated CI images (#10829)" \
###############################################################################
+# BEGIN tests which are skipped because they make no sense under podman-remote
+
+skip_if_remote "--target does not work with podman-remote" \
+ "bud-target"
+
+skip_if_remote "--runtime not meaningful under podman-remote" \
+ "bud with --runtime and --runtime-flag"
+
+skip_if_remote "secret files not implemented under podman-remote" \
+ "bud with containerfile secret" \
+ "bud with containerfile secret accessed on second RUN" \
+ "bud with containerfile secret options"
+
+skip_if_remote "volumes don't work with podman-remote" \
+ "buildah bud --volume" \
+ "buildah-bud-policy"
+
+# See podman #9890 for discussion
+skip_if_remote "--stdin option will not be implemented in podman-remote" \
+ "bud test no --stdin"
+
+###############################################################################
+# BEGIN tests which are skipped due to actual podman-remote bugs.
+
+###############################################################################
# Done.
exit $RC
diff --git a/test/buildah-bud/buildah-tests.diff b/test/buildah-bud/buildah-tests.diff
index 1c8592f7f..66d470648 100644
--- a/test/buildah-bud/buildah-tests.diff
+++ b/test/buildah-bud/buildah-tests.diff
@@ -1,23 +1,75 @@
-From a00508656599b24776982996fdb44d4874338fd4 Mon Sep 17 00:00:00 2001
+From d684753d6f00ee95720d8fb2e09c7ac19b37b01e Mon Sep 17 00:00:00 2001
From: Ed Santiago <santiago@redhat.com>
Date: Tue, 9 Feb 2021 17:28:05 -0700
Subject: [PATCH] tweaks for running buildah tests under podman
Signed-off-by: Ed Santiago <santiago@redhat.com>
---
- tests/helpers.bash | 28 +++++++++++++++++++++++++---
- 1 file changed, 25 insertions(+), 3 deletions(-)
+ tests/helpers.bash | 71 +++++++++++++++++++++++++++++++++++++++++++---
+ 1 file changed, 67 insertions(+), 4 deletions(-)
diff --git a/tests/helpers.bash b/tests/helpers.bash
-index 11deb367..08e73954 100644
+index 11deb367..44c71dad 100644
--- a/tests/helpers.bash
+++ b/tests/helpers.bash
-@@ -164,15 +164,37 @@ function run_buildah() {
+@@ -34,6 +34,23 @@ function setup() {
+ ROOTDIR_OPTS="--root ${TESTDIR}/root --runroot ${TESTDIR}/runroot --storage-driver ${STORAGE_DRIVER}"
+ BUILDAH_REGISTRY_OPTS="--registries-conf ${TESTSDIR}/registries.conf --registries-conf-dir ${TESTDIR}/registries.d --short-name-alias-conf ${TESTDIR}/cache/shortnames.conf"
+ PODMAN_REGISTRY_OPTS="--registries-conf ${TESTSDIR}/registries.conf"
++
++ PODMAN_SERVER_PID=
++ PODMAN_NATIVE="${PODMAN_BINARY} ${ROOTDIR_OPTS} ${PODMAN_REGISTRY_OPTS}"
++ if [[ -n "$REMOTE" ]]; then
++ PODMAN_NATIVE="${PODMAN_BINARY%%-remote} ${ROOTDIR_OPTS} ${PODMAN_REGISTRY_OPTS}"
++ # static CONTAINERS_CONF needed for capabilities test. As of 2021-07-01
++ # no tests in bud.bats override this; if at some point any test does
++ # so, it will probably need to be skip_if_remote()d.
++ env CONTAINERS_CONF=${CONTAINERS_CONF:-$(dirname ${BASH_SOURCE})/containers.conf} $PODMAN_NATIVE system service --timeout=0 &
++ PODMAN_SERVER_PID=$!
++ local timeout=10
++ while ((timeout > 0)); do
++ test -S /run/podman/podman.sock && return
++ sleep 0.2
++ done
++ die "podman server never came up"
++ fi
+ }
+
+ function starthttpd() {
+@@ -57,6 +74,12 @@ function stophttpd() {
+ function teardown() {
+ stophttpd
+
++ if [[ -n "$PODMAN_SERVER_PID" ]]; then
++ kill $PODMAN_SERVER_PID
++ wait $PODMAN_SERVER_PID
++ rm -f /run/podman/podman.sock
++ fi
++
+ # Workaround for #1991 - buildah + overlayfs leaks mount points.
+ # Many tests leave behind /var/tmp/.../root/overlay and sub-mounts;
+ # let's find those and clean them up, otherwise 'rm -rf' fails.
+@@ -129,7 +152,13 @@ function copy() {
+ }
+
+ function podman() {
+- command podman ${PODMAN_REGISTRY_OPTS} ${ROOTDIR_OPTS} "$@"
++ echo "# ... podman $*" >&3
++ ${PODMAN_BINARY} ${PODMAN_REGISTRY_OPTS} ${ROOTDIR_OPTS} "$@"
++}
++
++function podman-remote() {
++ echo "# ... podman-remote $*" >&3
++ ${PODMAN_BINARY} ${ROOTDIR_OPTS} "$@"
+ }
+
+ #################
+@@ -164,15 +193,40 @@ function run_buildah() {
--retry) retry=3; shift;; # retry network flakes
esac
-
+
+ local podman_or_buildah=${BUILDAH_BINARY}
-+ local registry_opts=${BUILDAH_REGISTRY_OPTS}
++ local _opts="${ROOTDIR_OPTS} ${BUILDAH_REGISTRY_OPTS}"
+ if [[ $1 == "bud" || $1 == "build-using-dockerfile" ]]; then
+ shift
+ # podman defaults to --layers=true; buildah to --false.
@@ -29,7 +81,10 @@ index 11deb367..08e73954 100644
+ set "build" "--force-rm=false" "--layers=false" "$@"
+ fi
+ podman_or_buildah=${PODMAN_BINARY}
-+ registry_opts=${PODMAN_REGISTRY_OPTS}
++ _opts="${ROOTDIR_OPTS} ${PODMAN_REGISTRY_OPTS}"
++ if [[ -n "$REMOTE" ]]; then
++ _opts=
++ fi
+
+ # podman always exits 125 where buildah exits 1 or 2
+ case $expected_rc in
@@ -41,17 +96,31 @@ index 11deb367..08e73954 100644
# Remember command args, for possible use in later diagnostic messages
- MOST_RECENT_BUILDAH_COMMAND="buildah $*"
+ MOST_RECENT_BUILDAH_COMMAND="$cmd_basename $*"
-
+
while [ $retry -gt 0 ]; do
retry=$(( retry - 1 ))
-
+
# stdout is only emitted upon error; this echo is to help a debugger
- echo "\$ $BUILDAH_BINARY $*"
- run env CONTAINERS_CONF=${CONTAINERS_CONF:-$(dirname ${BASH_SOURCE})/containers.conf} timeout --foreground --kill=10 $BUILDAH_TIMEOUT ${BUILDAH_BINARY} ${BUILDAH_REGISTRY_OPTS} ${ROOTDIR_OPTS} "$@"
+ echo "\$ $cmd_basename $*"
-+ run env CONTAINERS_CONF=${CONTAINERS_CONF:-$(dirname ${BASH_SOURCE})/containers.conf} timeout --foreground --kill=10 $BUILDAH_TIMEOUT ${podman_or_buildah} ${registry_opts} ${ROOTDIR_OPTS} "$@"
++ run env CONTAINERS_CONF=${CONTAINERS_CONF:-$(dirname ${BASH_SOURCE})/containers.conf} timeout --foreground --kill=10 $BUILDAH_TIMEOUT ${podman_or_buildah} ${_opts} "$@"
# without "quotes", multiple lines are glommed together into one
if [ -n "$output" ]; then
echo "$output"
---
+@@ -396,3 +450,12 @@ function skip_if_no_docker() {
+ skip "this test needs actual docker, not podman-docker"
+ fi
+ }
++
++####################
++# skip_if_remote # (only applicable for podman)
++####################
++function skip_if_remote() {
++ if [[ -n "$REMOTE" ]]; then
++ skip "${1:-test does not work with podman-remote}"
++ fi
++}
+--
2.31.1
+
diff --git a/test/buildah-bud/make-new-buildah-diffs b/test/buildah-bud/make-new-buildah-diffs
index 11987e376..3d0a77008 100644
--- a/test/buildah-bud/make-new-buildah-diffs
+++ b/test/buildah-bud/make-new-buildah-diffs
@@ -56,8 +56,6 @@ if [[ -n "$patch2" ]]; then
die "Internal error: I thought I checked for squashed commits, but still see $patch2"
fi
-# All looks good. Now write that patch into its proper place in the
-# podman repo. The sed and tac mess strips trailing whitespace and
-# empty lines; we need to do this to pass github CI checks.
-sed -e 's/ \+$//' <0001-*.patch |\
- tac | sed -e '/./,$!d' | tac >| ../test/buildah-bud/buildah-tests.diff
+# All looks good. We can now copy that patch into its proper place in the
+# podman repo.
+cp 0001-*.patch ../test/buildah-bud/buildah-tests.diff
diff --git a/test/buildah-bud/run-buildah-bud-tests b/test/buildah-bud/run-buildah-bud-tests
index a37e90dc4..eb8de5618 100755
--- a/test/buildah-bud/run-buildah-bud-tests
+++ b/test/buildah-bud/run-buildah-bud-tests
@@ -69,8 +69,7 @@ REMOTE=
# If remote, start server & change path
if [[ "${PODBIN_NAME:-}" = "remote" ]]; then
REMOTE=1
- echo "$ME: remote tests are not working yet" >&2
- exit 1
+ PODMAN_BINARY+="-remote"
fi
function die() {
@@ -214,6 +213,7 @@ review the test failure and double-check your changes.
(set -x;sudo env TMPDIR=/var/tmp \
PODMAN_BINARY=$PODMAN_BINARY \
+ REMOTE=$REMOTE \
BUILDAH_BINARY=$(pwd)/bin/buildah \
COPY_BINARY=$(pwd)/bin/copy \
bats "${bats_filter[@]}" tests/bud.bats)
diff --git a/test/e2e/checkpoint_test.go b/test/e2e/checkpoint_test.go
index b5bbfcd5c..1c9a8dc6f 100644
--- a/test/e2e/checkpoint_test.go
+++ b/test/e2e/checkpoint_test.go
@@ -1,11 +1,13 @@
package integration
import (
+ "fmt"
"net"
"os"
"os/exec"
"strings"
+ "github.com/containers/podman/v3/pkg/checkpoint/crutils"
"github.com/containers/podman/v3/pkg/criu"
. "github.com/containers/podman/v3/test/utils"
. "github.com/onsi/ginkgo"
@@ -46,7 +48,7 @@ var _ = Describe("Podman checkpoint", func() {
Skip("OCI runtime does not support checkpoint/restore")
}
- if !criu.CheckForCriu() {
+ if !criu.CheckForCriu(criu.MinCriuVersion) {
Skip("CRIU is missing or too old.")
}
// Only Fedora 29 and newer has a new enough selinux-policy and
@@ -977,4 +979,164 @@ var _ = Describe("Podman checkpoint", func() {
// Remove exported checkpoint
os.Remove(fileName)
})
+
+ namespaceCombination := []string{
+ "cgroup,ipc,net,uts,pid",
+ "cgroup,ipc,net,uts",
+ "cgroup,ipc,net",
+ "cgroup,ipc",
+ "ipc,net,uts,pid",
+ "ipc,net,uts",
+ "ipc,net",
+ "net,uts,pid",
+ "net,uts",
+ "uts,pid",
+ }
+ for _, share := range namespaceCombination {
+ testName := fmt.Sprintf(
+ "podman checkpoint and restore container out of and into pod (%s)",
+ share,
+ )
+ It(testName, func() {
+ if !criu.CheckForCriu(criu.PodCriuVersion) {
+ Skip("CRIU is missing or too old.")
+ }
+ if !crutils.CRRuntimeSupportsPodCheckpointRestore(podmanTest.OCIRuntime) {
+ Skip("runtime does not support pod restore")
+ }
+ // Create a pod
+ session := podmanTest.Podman([]string{
+ "pod",
+ "create",
+ "--share",
+ share,
+ })
+ session.WaitWithDefaultTimeout()
+ Expect(session).To(Exit(0))
+ podID := session.OutputToString()
+
+ session = podmanTest.Podman([]string{
+ "run",
+ "-d",
+ "--rm",
+ "--pod",
+ podID,
+ ALPINE,
+ "top",
+ })
+ session.WaitWithDefaultTimeout()
+ Expect(session).To(Exit(0))
+ cid := session.OutputToString()
+
+ fileName := "/tmp/checkpoint-" + cid + ".tar.gz"
+
+ // Checkpoint the container
+ result := podmanTest.Podman([]string{
+ "container",
+ "checkpoint",
+ "-e",
+ fileName,
+ cid,
+ })
+ result.WaitWithDefaultTimeout()
+
+ // As the container has been started with '--rm' it will be completely
+ // cleaned up after checkpointing.
+ Expect(result).To(Exit(0))
+ Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
+ Expect(podmanTest.NumberOfContainers()).To(Equal(1))
+
+ // Remove the pod and create a new pod
+ result = podmanTest.Podman([]string{
+ "pod",
+ "rm",
+ podID,
+ })
+ result.WaitWithDefaultTimeout()
+ Expect(result).To(Exit(0))
+
+ // First create a pod with different shared namespaces.
+ // Restore should fail
+
+ wrongShare := share[:strings.LastIndex(share, ",")]
+
+ session = podmanTest.Podman([]string{
+ "pod",
+ "create",
+ "--share",
+ wrongShare,
+ })
+ session.WaitWithDefaultTimeout()
+ Expect(session).To(Exit(0))
+ podID = session.OutputToString()
+
+ // Restore container with different port mapping
+ result = podmanTest.Podman([]string{
+ "container",
+ "restore",
+ "--pod",
+ podID,
+ "-i",
+ fileName,
+ })
+ result.WaitWithDefaultTimeout()
+ Expect(result).To(Exit(125))
+ Expect(result.ErrorToString()).To(ContainSubstring("does not share the"))
+
+ // Remove the pod and create a new pod
+ result = podmanTest.Podman([]string{
+ "pod",
+ "rm",
+ podID,
+ })
+ result.WaitWithDefaultTimeout()
+ Expect(result).To(Exit(0))
+
+ session = podmanTest.Podman([]string{
+ "pod",
+ "create",
+ "--share",
+ share,
+ })
+ session.WaitWithDefaultTimeout()
+ Expect(session).To(Exit(0))
+ podID = session.OutputToString()
+
+ // Restore container with different port mapping
+ result = podmanTest.Podman([]string{
+ "container",
+ "restore",
+ "--pod",
+ podID,
+ "-i",
+ fileName,
+ })
+ result.WaitWithDefaultTimeout()
+
+ Expect(result).To(Exit(0))
+ Expect(podmanTest.NumberOfContainersRunning()).To(Equal(2))
+ Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up"))
+
+ result = podmanTest.Podman([]string{
+ "rm",
+ "-f",
+ result.OutputToString(),
+ })
+ result.WaitWithDefaultTimeout()
+ Expect(result).To(Exit(0))
+ Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
+ Expect(podmanTest.NumberOfContainers()).To(Equal(1))
+
+ result = podmanTest.Podman([]string{
+ "pod",
+ "rm",
+ "-fa",
+ })
+ result.WaitWithDefaultTimeout()
+ Expect(result).To(Exit(0))
+
+ // Remove exported checkpoint
+ os.Remove(fileName)
+ })
+ }
})
diff --git a/test/e2e/common_test.go b/test/e2e/common_test.go
index 5a6cf7ffb..2e48e1763 100644
--- a/test/e2e/common_test.go
+++ b/test/e2e/common_test.go
@@ -811,7 +811,7 @@ func generateNetworkConfig(p *PodmanTestIntegration) (string, string) {
func (p *PodmanTestIntegration) removeCNINetwork(name string) {
session := p.Podman([]string{"network", "rm", "-f", name})
session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(BeNumerically("<=", 1))
+ Expect(session.ExitCode()).To(BeNumerically("<=", 1), "Exit code must be 0 or 1")
}
func (p *PodmanSessionIntegration) jq(jqCommand string) (string, error) {
diff --git a/test/e2e/container_create_volume_test.go b/test/e2e/container_create_volume_test.go
new file mode 100644
index 000000000..001698239
--- /dev/null
+++ b/test/e2e/container_create_volume_test.go
@@ -0,0 +1,127 @@
+package integration
+
+import (
+ "fmt"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+
+ . "github.com/containers/podman/v3/test/utils"
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+ . "github.com/onsi/gomega/gexec"
+)
+
+func buildDataVolumeImage(pTest *PodmanTestIntegration, image, data, dest string) {
+ // Create a dummy file for data volume
+ dummyFile := filepath.Join(pTest.TempDir, data)
+ err := ioutil.WriteFile(dummyFile, []byte(data), 0644)
+ Expect(err).To(BeNil())
+
+ // Create a data volume container image but no CMD binary in it
+ containerFile := fmt.Sprintf(`FROM scratch
+CMD doesnotexist.sh
+ADD %s %s/
+VOLUME %s/`, data, dest, dest)
+ pTest.BuildImage(containerFile, image, "false")
+}
+
+func createContainersConfFile(pTest *PodmanTestIntegration) {
+ configPath := filepath.Join(pTest.TempDir, "containers.conf")
+ containersConf := []byte(fmt.Sprintf("[containers]\nprepare_volume_on_create = true\n"))
+ err := ioutil.WriteFile(configPath, containersConf, os.ModePerm)
+ Expect(err).To(BeNil())
+
+ // Set custom containers.conf file
+ os.Setenv("CONTAINERS_CONF", configPath)
+ if IsRemote() {
+ pTest.RestartRemoteService()
+ }
+}
+
+func checkDataVolumeContainer(pTest *PodmanTestIntegration, image, cont, dest, data string) {
+ create := pTest.Podman([]string{"create", "--name", cont, image})
+ create.WaitWithDefaultTimeout()
+ Expect(create).Should(Exit(0))
+
+ inspect := pTest.InspectContainer(cont)
+ Expect(len(inspect)).To(Equal(1))
+ Expect(len(inspect[0].Mounts)).To(Equal(1))
+ Expect(inspect[0].Mounts[0].Destination).To(Equal(dest))
+
+ mntName, mntSource := inspect[0].Mounts[0].Name, inspect[0].Mounts[0].Source
+
+ volList := pTest.Podman([]string{"volume", "list", "--quiet"})
+ volList.WaitWithDefaultTimeout()
+ Expect(volList).Should(Exit(0))
+ Expect(len(volList.OutputToStringArray())).To(Equal(1))
+ Expect(volList.OutputToStringArray()[0]).To(Equal(mntName))
+
+ // Check the mount source directory
+ files, err := ioutil.ReadDir(mntSource)
+ Expect(err).To(BeNil())
+
+ if data == "" {
+ Expect(len(files)).To(Equal(0))
+ } else {
+ Expect(len(files)).To(Equal(1))
+ Expect(files[0].Name()).To(Equal(data))
+ }
+}
+
+var _ = Describe("Podman create data volume", func() {
+ var (
+ tempdir string
+ err error
+ podmanTest *PodmanTestIntegration
+ )
+
+ BeforeEach(func() {
+ tempdir, err = CreateTempDirInTempDir()
+ if err != nil {
+ os.Exit(1)
+ }
+ podmanTest = PodmanTestCreate(tempdir)
+ podmanTest.Setup()
+ podmanTest.SeedImages()
+ })
+
+ AfterEach(func() {
+ podmanTest.Cleanup()
+ f := CurrentGinkgoTestDescription()
+ processTestResult(f)
+ os.Unsetenv("CONTAINERS_CONF")
+ })
+
+ It("podman create with volume data copy turned off", func() {
+ imgName, volData, volDest := "dataimg", "dummy", "/test"
+
+ buildDataVolumeImage(podmanTest, imgName, volData, volDest)
+
+ // Create a container with the default containers.conf and
+ // check that the volume is not copied from the image.
+ checkDataVolumeContainer(podmanTest, imgName, "ctr-nocopy", volDest, "")
+ })
+
+ It("podman create with volume data copy turned on", func() {
+ imgName, volData, volDest := "dataimg", "dummy", "/test"
+
+ buildDataVolumeImage(podmanTest, imgName, volData, volDest)
+
+ // Create a container with the custom containers.conf and
+ // check that the volume is copied from the image.
+ createContainersConfFile(podmanTest)
+
+ checkDataVolumeContainer(podmanTest, imgName, "ctr-copy", volDest, volData)
+ })
+
+ It("podman run with volume data copy turned on", func() {
+ // Create a container with the custom containers.conf and
+ // check that the container is run successfully
+ createContainersConfFile(podmanTest)
+
+ session := podmanTest.Podman([]string{"run", "--rm", ALPINE, "echo"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ })
+})
diff --git a/test/e2e/healthcheck_run_test.go b/test/e2e/healthcheck_run_test.go
index 28040ecfd..899c84a14 100644
--- a/test/e2e/healthcheck_run_test.go
+++ b/test/e2e/healthcheck_run_test.go
@@ -174,6 +174,16 @@ var _ = Describe("Podman healthcheck run", func() {
Expect(inspect[0].State.Healthcheck.Status).To(Equal("healthy"))
})
+ It("podman healthcheck unhealthy but valid arguments check", func() {
+ session := podmanTest.Podman([]string{"run", "-dt", "--name", "hc", "--health-retries", "2", "--health-cmd", "[\"ls\", \"/foo\"]", ALPINE, "top"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ hc := podmanTest.Podman([]string{"healthcheck", "run", "hc"})
+ hc.WaitWithDefaultTimeout()
+ Expect(hc).Should(Exit(1))
+ })
+
It("podman healthcheck single healthy result changes failed to healthy", func() {
session := podmanTest.Podman([]string{"run", "-dt", "--name", "hc", "--health-retries", "2", "--health-cmd", "ls /foo || exit 1", ALPINE, "top"})
session.WaitWithDefaultTimeout()
diff --git a/test/e2e/login_logout_test.go b/test/e2e/login_logout_test.go
index 6088d991f..7ad1fc1f2 100644
--- a/test/e2e/login_logout_test.go
+++ b/test/e2e/login_logout_test.go
@@ -97,6 +97,24 @@ var _ = Describe("Podman login and logout", func() {
os.RemoveAll(certDirPath)
})
+ readAuthInfo := func(filePath string) map[string]interface{} {
+ authBytes, err := ioutil.ReadFile(filePath)
+ Expect(err).To(BeNil())
+
+ var authInfo map[string]interface{}
+ err = json.Unmarshal(authBytes, &authInfo)
+ Expect(err).To(BeNil())
+ fmt.Println(authInfo)
+
+ const authsKey = "auths"
+ Expect(authInfo).To(HaveKey(authsKey))
+
+ auths, ok := authInfo[authsKey].(map[string]interface{})
+ Expect(ok).To(BeTrue())
+
+ return auths
+ }
+
It("podman login and logout", func() {
session := podmanTest.Podman([]string{"login", "-u", "podmantest", "-p", "test", server})
session.WaitWithDefaultTimeout()
@@ -151,10 +169,7 @@ var _ = Describe("Podman login and logout", func() {
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
- authInfo, _ := ioutil.ReadFile(authFile)
- var info map[string]interface{}
- json.Unmarshal(authInfo, &info)
- fmt.Println(info)
+ readAuthInfo(authFile)
// push should fail with nonexistent authfile
session = podmanTest.Podman([]string{"push", "--authfile", "/tmp/nonexistent", ALPINE, testImg})
@@ -284,4 +299,204 @@ var _ = Describe("Podman login and logout", func() {
session.WaitWithDefaultTimeout()
Expect(session).To(ExitWithError())
})
+
+ It("podman login and logout with repository", func() {
+ authFile := filepath.Join(podmanTest.TempDir, "auth.json")
+
+ testRepository := server + "/podmantest"
+ session := podmanTest.Podman([]string{
+ "login",
+ "-u", "podmantest",
+ "-p", "test",
+ "--authfile", authFile,
+ testRepository,
+ })
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ authInfo := readAuthInfo(authFile)
+ Expect(authInfo).To(HaveKey(testRepository))
+
+ session = podmanTest.Podman([]string{
+ "logout",
+ "--authfile", authFile,
+ testRepository,
+ })
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ authInfo = readAuthInfo(authFile)
+ Expect(authInfo).NotTo(HaveKey(testRepository))
+ })
+
+ It("podman login and logout with repository and specified image", func() {
+ authFile := filepath.Join(podmanTest.TempDir, "auth.json")
+
+ testTarget := server + "/podmantest/test-alpine"
+ session := podmanTest.Podman([]string{
+ "login",
+ "-u", "podmantest",
+ "-p", "test",
+ "--authfile", authFile,
+ testTarget,
+ })
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ authInfo := readAuthInfo(authFile)
+ Expect(authInfo).To(HaveKey(testTarget))
+
+ session = podmanTest.Podman([]string{
+ "push",
+ "--authfile", authFile,
+ ALPINE, testTarget,
+ })
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ })
+
+ It("podman login and logout with repository with fallback", func() {
+ authFile := filepath.Join(podmanTest.TempDir, "auth.json")
+
+ testRepos := []string{
+ server + "/podmantest",
+ server,
+ }
+ for _, testRepo := range testRepos {
+ session := podmanTest.Podman([]string{
+ "login",
+ "-u", "podmantest",
+ "-p", "test",
+ "--authfile", authFile,
+ testRepo,
+ })
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ }
+
+ authInfo := readAuthInfo(authFile)
+ Expect(authInfo).To(HaveKey(testRepos[0]))
+ Expect(authInfo).To(HaveKey(testRepos[1]))
+
+ session := podmanTest.Podman([]string{
+ "push",
+ "--authfile", authFile,
+ ALPINE, testRepos[0] + "/test-image-alpine",
+ })
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ session = podmanTest.Podman([]string{
+ "logout",
+ "--authfile", authFile,
+ testRepos[0],
+ })
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ session = podmanTest.Podman([]string{
+ "push",
+ "--authfile", authFile,
+ ALPINE, testRepos[0] + "/test-image-alpine",
+ })
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ session = podmanTest.Podman([]string{
+ "logout",
+ "--authfile", authFile,
+ testRepos[1],
+ })
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ authInfo = readAuthInfo(authFile)
+ Expect(authInfo).NotTo(HaveKey(testRepos[0]))
+ Expect(authInfo).NotTo(HaveKey(testRepos[1]))
+ })
+
+ It("podman login with repository invalid arguments", func() {
+ authFile := filepath.Join(podmanTest.TempDir, "auth.json")
+
+ for _, invalidArg := range []string{
+ "https://" + server + "/podmantest",
+ server + "/podmantest/image:latest",
+ } {
+ session := podmanTest.Podman([]string{
+ "login",
+ "-u", "podmantest",
+ "-p", "test",
+ "--authfile", authFile,
+ invalidArg,
+ })
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(ExitWithError())
+ }
+ })
+
+ It("podman login and logout with repository push with invalid auth.json credentials", func() {
+ authFile := filepath.Join(podmanTest.TempDir, "auth.json")
+ // only `server` contains the correct login data
+ err := ioutil.WriteFile(authFile, []byte(fmt.Sprintf(`{"auths": {
+ "%s/podmantest": { "auth": "cG9kbWFudGVzdDp3cm9uZw==" },
+ "%s": { "auth": "cG9kbWFudGVzdDp0ZXN0" }
+ }}`, server, server)), 0644)
+ Expect(err).To(BeNil())
+
+ session := podmanTest.Podman([]string{
+ "push",
+ "--authfile", authFile,
+ ALPINE, server + "/podmantest/test-image",
+ })
+ session.WaitWithDefaultTimeout()
+ Expect(session).To(ExitWithError())
+
+ session = podmanTest.Podman([]string{
+ "push",
+ "--authfile", authFile,
+ ALPINE, server + "/test-image",
+ })
+ session.WaitWithDefaultTimeout()
+ Expect(session).To(Exit(0))
+ })
+
+ It("podman login and logout with repository pull with wrong auth.json credentials", func() {
+ authFile := filepath.Join(podmanTest.TempDir, "auth.json")
+
+ testTarget := server + "/podmantest/test-alpine"
+ session := podmanTest.Podman([]string{
+ "login",
+ "-u", "podmantest",
+ "-p", "test",
+ "--authfile", authFile,
+ testTarget,
+ })
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ session = podmanTest.Podman([]string{
+ "push",
+ "--authfile", authFile,
+ ALPINE, testTarget,
+ })
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ // only `server + /podmantest` and `server` have the correct login data
+ err := ioutil.WriteFile(authFile, []byte(fmt.Sprintf(`{"auths": {
+ "%s/podmantest/test-alpine": { "auth": "cG9kbWFudGVzdDp3cm9uZw==" },
+ "%s/podmantest": { "auth": "cG9kbWFudGVzdDp0ZXN0" },
+ "%s": { "auth": "cG9kbWFudGVzdDp0ZXN0" }
+ }}`, server, server, server)), 0644)
+ Expect(err).To(BeNil())
+
+ session = podmanTest.Podman([]string{
+ "pull",
+ "--authfile", authFile,
+ server + "/podmantest/test-alpine",
+ })
+ session.WaitWithDefaultTimeout()
+ Expect(session).To(ExitWithError())
+ })
})
diff --git a/test/e2e/logs_test.go b/test/e2e/logs_test.go
index 507fab461..0a973b802 100644
--- a/test/e2e/logs_test.go
+++ b/test/e2e/logs_test.go
@@ -5,6 +5,7 @@ import (
"os"
"os/exec"
"strings"
+ "time"
. "github.com/containers/podman/v3/test/utils"
. "github.com/onsi/ginkgo"
@@ -135,6 +136,34 @@ var _ = Describe("Podman logs", func() {
Expect(len(results.OutputToStringArray())).To(Equal(3))
})
+ It("until duration 10m: "+log, func() {
+ logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"})
+ logc.WaitWithDefaultTimeout()
+ Expect(logc).To(Exit(0))
+ cid := logc.OutputToString()
+
+ results := podmanTest.Podman([]string{"logs", "--until", "10m", cid})
+ results.WaitWithDefaultTimeout()
+ Expect(results).To(Exit(0))
+ Expect(len(results.OutputToStringArray())).To(Equal(0))
+ })
+
+ It("until time NOW: "+log, func() {
+
+ logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"})
+ logc.WaitWithDefaultTimeout()
+ Expect(logc).To(Exit(0))
+ cid := logc.OutputToString()
+
+ now := time.Now()
+ now = now.Add(time.Minute * 1)
+ nowS := now.Format(time.RFC3339)
+ results := podmanTest.Podman([]string{"logs", "--until", nowS, cid})
+ results.WaitWithDefaultTimeout()
+ Expect(results).To(Exit(0))
+ Expect(len(results.OutputToStringArray())).To(Equal(3))
+ })
+
It("latest and container name should fail: "+log, func() {
results := podmanTest.Podman([]string{"logs", "-l", "foobar"})
results.WaitWithDefaultTimeout()
diff --git a/test/e2e/network_create_test.go b/test/e2e/network_create_test.go
index 2bec88020..fb4a144fa 100644
--- a/test/e2e/network_create_test.go
+++ b/test/e2e/network_create_test.go
@@ -244,10 +244,59 @@ var _ = Describe("Podman network create", func() {
Expect(bridgePlugin.IPAM.Routes[0].Dest).To(Equal("::/0"))
Expect(bridgePlugin.IPAM.Routes[1].Dest).To(Equal("0.0.0.0/0"))
+ Expect(bridgePlugin.IPAM.Ranges).To(HaveLen(2))
+ Expect(bridgePlugin.IPAM.Ranges[0]).To(HaveLen(1))
+ Expect(bridgePlugin.IPAM.Ranges[0][0].Subnet).ToNot(BeEmpty())
+ Expect(bridgePlugin.IPAM.Ranges[1]).To(HaveLen(1))
+ Expect(bridgePlugin.IPAM.Ranges[1][0].Subnet).ToNot(BeEmpty())
+
+ _, subnet11, err := net.ParseCIDR(bridgePlugin.IPAM.Ranges[0][0].Subnet)
+ Expect(err).To(BeNil())
+ _, subnet12, err := net.ParseCIDR(bridgePlugin.IPAM.Ranges[1][0].Subnet)
+ Expect(err).To(BeNil())
+
// Once a container executes a new network, the nic will be created. We should clean those up
// best we can
defer removeNetworkDevice(bridgePlugin.BrName)
+ // create a second network to check the auto assigned ipv4 subnet does not overlap
+ // https://github.com/containers/podman/issues/11032
+ netName2 := "dual-" + stringid.GenerateNonCryptoID()
+ nc = podmanTest.Podman([]string{"network", "create", "--subnet", "fd00:6:3:2:1::/64", "--ipv6", netName2})
+ nc.WaitWithDefaultTimeout()
+ defer podmanTest.removeCNINetwork(netName2)
+ Expect(nc).Should(Exit(0))
+
+ // Inspect the network configuration
+ inspect = podmanTest.Podman([]string{"network", "inspect", netName2})
+ inspect.WaitWithDefaultTimeout()
+
+ // JSON the network configuration into something usable
+ err = json.Unmarshal([]byte(inspect.OutputToString()), &results)
+ Expect(err).To(BeNil())
+ result = results[0]
+ Expect(result["name"]).To(Equal(netName2))
+
+ // JSON the bridge info
+ bridgePlugin, err = genericPluginsToBridge(result["plugins"], "bridge")
+ Expect(err).To(BeNil())
+ Expect(bridgePlugin.IPAM.Routes[0].Dest).To(Equal("::/0"))
+ Expect(bridgePlugin.IPAM.Routes[1].Dest).To(Equal("0.0.0.0/0"))
+ Expect(bridgePlugin.IPAM.Ranges).To(HaveLen(2))
+ Expect(bridgePlugin.IPAM.Ranges[0]).To(HaveLen(1))
+ Expect(bridgePlugin.IPAM.Ranges[0][0].Subnet).ToNot(BeEmpty())
+ Expect(bridgePlugin.IPAM.Ranges[1]).To(HaveLen(1))
+ Expect(bridgePlugin.IPAM.Ranges[1][0].Subnet).ToNot(BeEmpty())
+
+ _, subnet21, err := net.ParseCIDR(bridgePlugin.IPAM.Ranges[0][0].Subnet)
+ Expect(err).To(BeNil())
+ _, subnet22, err := net.ParseCIDR(bridgePlugin.IPAM.Ranges[1][0].Subnet)
+ Expect(err).To(BeNil())
+
+ // check that the subnets do not overlap
+ Expect(subnet11.Contains(subnet21.IP)).To(BeFalse())
+ Expect(subnet12.Contains(subnet22.IP)).To(BeFalse())
+
try := podmanTest.Podman([]string{"run", "-it", "--rm", "--network", netName, ALPINE, "sh", "-c", "ip addr show eth0 | grep global | awk ' /inet6 / {print $2}'"})
try.WaitWithDefaultTimeout()
diff --git a/test/e2e/play_kube_test.go b/test/e2e/play_kube_test.go
index 42bb0cb64..66bfdefe7 100644
--- a/test/e2e/play_kube_test.go
+++ b/test/e2e/play_kube_test.go
@@ -9,6 +9,7 @@ import (
"strconv"
"strings"
"text/template"
+ "time"
"github.com/containers/podman/v3/pkg/util"
. "github.com/containers/podman/v3/test/utils"
@@ -67,6 +68,75 @@ spec:
shareProcessNamespace: true
status: {}
`
+var livenessProbePodYaml = `
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: liveness-probe
+ labels:
+ app: alpine
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: alpine
+ template:
+ metadata:
+ labels:
+ app: alpine
+ spec:
+ containers:
+ - command:
+ - top
+ - -d
+ - "1.5"
+ name: alpine
+ image: quay.io/libpod/alpine:latest
+ ports:
+ - containerPort: 80
+ livenessProbe:
+ exec:
+ command:
+ - echo
+ - hello
+ initialDelaySeconds: 5
+ periodSeconds: 5
+`
+var livenessProbeUnhealthyPodYaml = `
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: liveness-unhealthy-probe
+ labels:
+ app: alpine
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: alpine
+ template:
+ metadata:
+ labels:
+ app: alpine
+ spec:
+ restartPolicy: Never
+ containers:
+ - command:
+ - top
+ - -d
+ - "1.5"
+ name: alpine
+ image: quay.io/libpod/alpine:latest
+ ports:
+ - containerPort: 80
+ livenessProbe:
+ exec:
+ command:
+ - cat
+ - /randomfile
+ initialDelaySeconds: 0
+ periodSeconds: 1
+`
var selinuxLabelPodYaml = `
apiVersion: v1
@@ -1061,6 +1131,36 @@ var _ = Describe("Podman play kube", func() {
Expect(sharednamespaces).To(ContainSubstring("pid"))
})
+ It("podman play kube support container liveness probe", func() {
+ err := writeYaml(livenessProbePodYaml, kubeYaml)
+ Expect(err).To(BeNil())
+
+ kube := podmanTest.Podman([]string{"play", "kube", kubeYaml})
+ kube.WaitWithDefaultTimeout()
+ Expect(kube).Should(Exit(0))
+
+ inspect := podmanTest.Podman([]string{"inspect", "liveness-probe-pod-0-alpine", "--format", "'{{ .Config.Healthcheck }}'"})
+ inspect.WaitWithDefaultTimeout()
+ healthcheckcmd := inspect.OutputToString()
+ // check if CMD-SHELL based equivalent health check is added to container
+ Expect(healthcheckcmd).To(ContainSubstring("CMD-SHELL"))
+ })
+
+ It("podman play kube liveness probe should fail", func() {
+ err := writeYaml(livenessProbeUnhealthyPodYaml, kubeYaml)
+ Expect(err).To(BeNil())
+
+ kube := podmanTest.Podman([]string{"play", "kube", kubeYaml})
+ kube.WaitWithDefaultTimeout()
+ Expect(kube).Should(Exit(0))
+
+ time.Sleep(2 * time.Second)
+ hc := podmanTest.Podman([]string{"healthcheck", "run", "liveness-unhealthy-probe-pod-0-alpine"})
+ hc.WaitWithDefaultTimeout()
+ hcoutput := hc.OutputToString()
+ Expect(hcoutput).To(ContainSubstring("unhealthy"))
+ })
+
It("podman play kube fail with nonexistent authfile", func() {
err := generateKubeYaml("pod", getPod(), kubeYaml)
Expect(err).To(BeNil())
@@ -1629,7 +1729,7 @@ var _ = Describe("Podman play kube", func() {
})
It("podman play kube with pull policy of missing", func() {
- ctr := getCtr(withPullPolicy("missing"), withImage(BB))
+ ctr := getCtr(withPullPolicy("Missing"), withImage(BB))
err := generateKubeYaml("pod", getPod(withCtr(ctr)), kubeYaml)
Expect(err).To(BeNil())
diff --git a/test/e2e/pod_create_test.go b/test/e2e/pod_create_test.go
index 63f55fb88..4c6788b9d 100644
--- a/test/e2e/pod_create_test.go
+++ b/test/e2e/pod_create_test.go
@@ -566,11 +566,11 @@ ENTRYPOINT ["sleep","99999"]
ns := "ns:/proc/self/ns/"
podCreate := podmanTest.Podman([]string{"pod", "create", "--pid", ns, "--name", podName, "--share", "pid"})
podCreate.WaitWithDefaultTimeout()
- Expect(podCreate.ExitCode()).To(Equal(0))
+ Expect(podCreate).Should(Exit(0))
podInspect := podmanTest.Podman([]string{"pod", "inspect", podName})
podInspect.WaitWithDefaultTimeout()
- Expect(podInspect.ExitCode()).To(Equal(0))
+ Expect(podInspect).Should(Exit(0))
podJSON := podInspect.InspectPodToJSON()
Expect(podJSON.InfraConfig.PidNS).To(Equal("path"))
@@ -579,11 +579,11 @@ ENTRYPOINT ["sleep","99999"]
podCreate = podmanTest.Podman([]string{"pod", "create", "--pid", ns, "--name", podName, "--share", "pid"})
podCreate.WaitWithDefaultTimeout()
- Expect(podCreate.ExitCode()).To(Equal(0))
+ Expect(podCreate).Should(Exit(0))
podInspect = podmanTest.Podman([]string{"pod", "inspect", podName})
podInspect.WaitWithDefaultTimeout()
- Expect(podInspect.ExitCode()).To(Equal(0))
+ Expect(podInspect).Should(Exit(0))
podJSON = podInspect.InspectPodToJSON()
Expect(podJSON.InfraConfig.PidNS).To(Equal("pod"))
@@ -592,11 +592,11 @@ ENTRYPOINT ["sleep","99999"]
podCreate = podmanTest.Podman([]string{"pod", "create", "--pid", ns, "--name", podName, "--share", "pid"})
podCreate.WaitWithDefaultTimeout()
- Expect(podCreate.ExitCode()).To(Equal(0))
+ Expect(podCreate).Should(Exit(0))
podInspect = podmanTest.Podman([]string{"pod", "inspect", podName})
podInspect.WaitWithDefaultTimeout()
- Expect(podInspect.ExitCode()).To(Equal(0))
+ Expect(podInspect).Should(Exit(0))
podJSON = podInspect.InspectPodToJSON()
Expect(podJSON.InfraConfig.PidNS).To(Equal("host"))
@@ -605,11 +605,11 @@ ENTRYPOINT ["sleep","99999"]
podCreate = podmanTest.Podman([]string{"pod", "create", "--pid", ns, "--name", podName, "--share", "pid"})
podCreate.WaitWithDefaultTimeout()
- Expect(podCreate.ExitCode()).To(Equal(0))
+ Expect(podCreate).Should(Exit(0))
podInspect = podmanTest.Podman([]string{"pod", "inspect", podName})
podInspect.WaitWithDefaultTimeout()
- Expect(podInspect.ExitCode()).To(Equal(0))
+ Expect(podInspect).Should(Exit(0))
podJSON = podInspect.InspectPodToJSON()
Expect(podJSON.InfraConfig.PidNS).To(Equal("private"))
diff --git a/test/e2e/prune_test.go b/test/e2e/prune_test.go
index 68ccd0a94..ff70a8cf4 100644
--- a/test/e2e/prune_test.go
+++ b/test/e2e/prune_test.go
@@ -16,6 +16,11 @@ LABEL RUN podman --version
RUN apk update
RUN apk add bash`, ALPINE)
+var emptyPruneImage = `
+FROM scratch
+ENV test1=test1
+ENV test2=test2`
+
var _ = Describe("Podman prune", func() {
var (
tempdir string
@@ -110,8 +115,12 @@ var _ = Describe("Podman prune", func() {
Expect(session).Should(Exit(0))
Expect(len(session.OutputToStringArray())).To(Equal(numImages))
- // Now build a new image with dangling intermediate images.
+ // Now build an image and untag it. The (intermediate) images
+ // should be removed recursively during pruning.
podmanTest.BuildImage(pruneImage, "alpine_bash:latest", "true")
+ session = podmanTest.Podman([]string{"untag", "alpine_bash:latest"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
session = podmanTest.Podman([]string{"images", "-a"})
session.WaitWithDefaultTimeout()
@@ -136,26 +145,33 @@ var _ = Describe("Podman prune", func() {
Expect(len(session.OutputToStringArray())).To(Equal(numImages - numPrunedImages))
})
- It("podman image prune skip cache images", func() {
- podmanTest.BuildImage(pruneImage, "alpine_bash:latest", "true")
+ It("podman image prune - handle empty images", func() {
+ // As shown in #10832, empty images were not treated correctly
+ // in Podman.
+ podmanTest.BuildImage(emptyPruneImage, "empty:scratch", "true")
- none := podmanTest.Podman([]string{"images", "-a"})
- none.WaitWithDefaultTimeout()
- Expect(none).Should(Exit(0))
- hasNone, _ := none.GrepString("<none>")
+ session := podmanTest.Podman([]string{"images", "-a"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ hasNone, _ := session.GrepString("<none>")
Expect(hasNone).To(BeTrue())
- prune := podmanTest.Podman([]string{"image", "prune", "-f"})
- prune.WaitWithDefaultTimeout()
- Expect(prune).Should(Exit(0))
+ // Nothing will be pruned.
+ session = podmanTest.Podman([]string{"image", "prune", "-f"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ Expect(len(session.OutputToStringArray())).To(Equal(0))
- after := podmanTest.Podman([]string{"images", "-a"})
- after.WaitWithDefaultTimeout()
- Expect(none).Should(Exit(0))
- // Check if all "dangling" images were pruned.
- hasNoneAfter, _ := after.GrepString("<none>")
- Expect(hasNoneAfter).To(BeFalse())
- Expect(len(after.OutputToStringArray()) > 1).To(BeTrue())
+ // Now the image will be untagged, and its parent images will
+ // be removed recursively.
+ session = podmanTest.Podman([]string{"untag", "empty:scratch"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ session = podmanTest.Podman([]string{"image", "prune", "-f"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ Expect(len(session.OutputToStringArray())).To(Equal(2))
})
It("podman image prune dangling images", func() {
diff --git a/test/e2e/ps_test.go b/test/e2e/ps_test.go
index e27ff27a4..aeb88e481 100644
--- a/test/e2e/ps_test.go
+++ b/test/e2e/ps_test.go
@@ -172,6 +172,43 @@ var _ = Describe("Podman ps", func() {
Expect(fullCid).To(Equal(result.OutputToStringArray()[0]))
})
+ It("podman ps --filter network=container:<name>", func() {
+ ctrAlpha := "alpha"
+ container := podmanTest.Podman([]string{"run", "-dt", "--name", ctrAlpha, ALPINE, "top"})
+ container.WaitWithDefaultTimeout()
+ Expect(container).Should(Exit(0))
+
+ ctrBravo := "bravo"
+ containerBravo := podmanTest.Podman([]string{"run", "-dt", "--network", "container:alpha", "--name", ctrBravo, ALPINE, "top"})
+ containerBravo.WaitWithDefaultTimeout()
+ Expect(containerBravo).Should(Exit(0))
+
+ result := podmanTest.Podman([]string{"ps", "-a", "--format", "table {{.Names}}", "--filter", "network=container:alpha"})
+ result.WaitWithDefaultTimeout()
+ result.WaitWithDefaultTimeout()
+ Expect(result).Should(Exit(0))
+ Expect(result.OutputToString()).To(ContainSubstring("bravo"))
+ })
+
+ It("podman ps --filter network=container:<id>", func() {
+ ctrAlpha := "first"
+ container := podmanTest.Podman([]string{"run", "-dt", "--name", ctrAlpha, ALPINE, "top"})
+ container.WaitWithDefaultTimeout()
+ cid := container.OutputToString()
+ Expect(container).Should(Exit(0))
+
+ ctrBravo := "second"
+ containerBravo := podmanTest.Podman([]string{"run", "-dt", "--network", "container:" + cid, "--name", ctrBravo, ALPINE, "top"})
+ containerBravo.WaitWithDefaultTimeout()
+ Expect(containerBravo).Should(Exit(0))
+
+ result := podmanTest.Podman([]string{"ps", "-a", "--format", "table {{.Names}}", "--filter", "network=container:" + cid})
+ result.WaitWithDefaultTimeout()
+ result.WaitWithDefaultTimeout()
+ Expect(result).Should(Exit(0))
+ Expect(result.OutputToString()).To(ContainSubstring("second"))
+ })
+
It("podman ps namespace flag", func() {
_, ec, _ := podmanTest.RunLsContainer("")
Expect(ec).To(Equal(0))
diff --git a/test/e2e/pull_test.go b/test/e2e/pull_test.go
index fd9656f4d..c377f158d 100644
--- a/test/e2e/pull_test.go
+++ b/test/e2e/pull_test.go
@@ -44,7 +44,7 @@ var _ = Describe("Podman pull", func() {
session = podmanTest.Podman([]string{"pull", "busybox:latest", "docker.io/library/ibetthisdoesnotexistfr:random", "alpine"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(125))
- expectedError := "Error initializing source docker://ibetthisdoesnotexistfr:random"
+ expectedError := "initializing source docker://ibetthisdoesnotexistfr:random"
found, _ := session.ErrorGrepString(expectedError)
Expect(found).To(Equal(true))
diff --git a/test/e2e/run_exit_test.go b/test/e2e/run_exit_test.go
index 21f1a8650..e86718577 100644
--- a/test/e2e/run_exit_test.go
+++ b/test/e2e/run_exit_test.go
@@ -49,11 +49,7 @@ var _ = Describe("Podman run exit", func() {
It("podman run exit ExecErrorCodeNotFound", func() {
result := podmanTest.Podman([]string{"run", ALPINE, "foobar"})
result.WaitWithDefaultTimeout()
- Expect(result.ExitCode()).To(Not(Equal(define.ExecErrorCodeGeneric)))
- // TODO This is failing we believe because of a race condition
- // Between conmon and podman closing the socket early.
- // Test with the following, once the race condition is solved
- // Expect(result).Should(Exit(define.ExecErrorCodeNotFound))
+ Expect(result).Should(Exit(define.ExecErrorCodeNotFound))
})
It("podman run exit 0", func() {
diff --git a/test/e2e/run_test.go b/test/e2e/run_test.go
index 3bfd59b54..3c65c02d1 100644
--- a/test/e2e/run_test.go
+++ b/test/e2e/run_test.go
@@ -1213,14 +1213,14 @@ USER mail`, BB)
})
It("podman run with bad healthcheck timeout", func() {
- session := podmanTest.Podman([]string{"run", "-dt", "--health-cmd", "[\"foo\"]", "--health-timeout", "0s", ALPINE, "top"})
+ session := podmanTest.Podman([]string{"run", "-dt", "--health-cmd", "foo", "--health-timeout", "0s", ALPINE, "top"})
session.WaitWithDefaultTimeout()
Expect(session).To(ExitWithError())
Expect(session.ErrorToString()).To(ContainSubstring("healthcheck-timeout must be at least 1 second"))
})
It("podman run with bad healthcheck start-period", func() {
- session := podmanTest.Podman([]string{"run", "-dt", "--health-cmd", "[\"foo\"]", "--health-start-period", "-1s", ALPINE, "top"})
+ session := podmanTest.Podman([]string{"run", "-dt", "--health-cmd", "foo", "--health-start-period", "-1s", ALPINE, "top"})
session.WaitWithDefaultTimeout()
Expect(session).To(ExitWithError())
Expect(session.ErrorToString()).To(ContainSubstring("healthcheck-start-period must be 0 seconds or greater"))
diff --git a/test/e2e/volume_ls_test.go b/test/e2e/volume_ls_test.go
index ff3551ad9..0dd1a2b7c 100644
--- a/test/e2e/volume_ls_test.go
+++ b/test/e2e/volume_ls_test.go
@@ -101,6 +101,22 @@ var _ = Describe("Podman volume ls", func() {
Expect(len(session.OutputToStringArray())).To(Equal(0))
})
+ It("podman ls volume with --filter until flag", func() {
+ session := podmanTest.Podman([]string{"volume", "create"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ session = podmanTest.Podman([]string{"volume", "ls", "--filter", "until=5000000000"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ Expect(len(session.OutputToStringArray())).To(Equal(2))
+
+ session = podmanTest.Podman([]string{"volume", "ls", "--filter", "until=50000"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ Expect(len(session.OutputToStringArray())).To(Equal(0))
+ })
+
It("podman volume ls with --filter dangling", func() {
volName1 := "volume1"
session := podmanTest.Podman([]string{"volume", "create", volName1})
diff --git a/test/e2e/volume_prune_test.go b/test/e2e/volume_prune_test.go
index 68a257110..364ca0ab7 100644
--- a/test/e2e/volume_prune_test.go
+++ b/test/e2e/volume_prune_test.go
@@ -63,6 +63,37 @@ var _ = Describe("Podman volume prune", func() {
podmanTest.Cleanup()
})
+ It("podman prune volume --filter until", func() {
+ session := podmanTest.Podman([]string{"volume", "create", "--label", "label1=value1", "myvol1"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ session = podmanTest.Podman([]string{"volume", "ls"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ Expect(len(session.OutputToStringArray())).To(Equal(2))
+
+ session = podmanTest.Podman([]string{"volume", "prune", "--force", "--filter", "until=50"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ session = podmanTest.Podman([]string{"volume", "ls"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ Expect(len(session.OutputToStringArray())).To(Equal(2))
+
+ session = podmanTest.Podman([]string{"volume", "prune", "--force", "--filter", "until=5000000000"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ session = podmanTest.Podman([]string{"volume", "ls"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ Expect(len(session.OutputToStringArray())).To(Equal(0))
+
+ podmanTest.Cleanup()
+ })
+
It("podman prune volume --filter", func() {
session := podmanTest.Podman([]string{"volume", "create", "--label", "label1=value1", "myvol1"})
session.WaitWithDefaultTimeout()
diff --git a/test/system/030-run.bats b/test/system/030-run.bats
index 32fc85c4e..3d9d834b3 100644
--- a/test/system/030-run.bats
+++ b/test/system/030-run.bats
@@ -706,4 +706,21 @@ EOF
run_podman rmi nomtab
}
+@test "podman run --device-cgroup-rule tests" {
+ skip_if_rootless "cannot add devices in rootless mode"
+
+ run_podman run --device-cgroup-rule="b 7:* rmw" --rm $IMAGE
+ run_podman run --device-cgroup-rule="c 7:* rmw" --rm $IMAGE
+ run_podman run --device-cgroup-rule="a 7:1 rmw" --rm $IMAGE
+ run_podman run --device-cgroup-rule="a 7 rmw" --rm $IMAGE
+ run_podman 125 run --device-cgroup-rule="b 7:* rmX" --rm $IMAGE
+ is "$output" "Error: invalid device access in device-access-add: X"
+ run_podman 125 run --device-cgroup-rule="b 7:2" --rm $IMAGE
+ is "$output" 'Error: invalid device cgroup rule requires type, major:Minor, and access rules: "b 7:2"'
+ run_podman 125 run --device-cgroup-rule="x 7:* rmw" --rm $IMAGE
+ is "$output" "Error: invalid device type in device-access-add:"
+ run_podman 125 run --device-cgroup-rule="a a:* rmw" --rm $IMAGE
+ is "$output" "Error: strconv.ParseInt: parsing \"a\": invalid syntax"
+}
+
# vim: filetype=sh
diff --git a/test/system/035-logs.bats b/test/system/035-logs.bats
index ccf83df14..32282c8e1 100644
--- a/test/system/035-logs.bats
+++ b/test/system/035-logs.bats
@@ -24,6 +24,9 @@ load helpers
# test --since with Unix timestamps
run_podman logs --since 1000 $cid
+ # test --until with Unix timestamps
+ run_podman logs --until 1000 $cid
+
run_podman rm $cid
}
@@ -125,4 +128,50 @@ $s_after"
_log_test_since journald
}
+function _log_test_until() {
+ local driver=$1
+
+ s_before="before_$(random_string)_${driver}"
+ s_after="after_$(random_string)_${driver}"
+
+ before=$(date --iso-8601=seconds)
+ sleep 5
+ run_podman run --log-driver=$driver -d --name test $IMAGE sh -c \
+ "echo $s_before; trap 'echo $s_after; exit' SIGTERM; while :; do sleep 1; done"
+
+ # sleep a second to make sure the date is after the first echo
+ sleep 1
+ run_podman stop test
+ # sleep for 20 seconds to get the proper after time
+ sleep 20
+
+ run_podman logs test
+ is "$output" \
+ "$s_before
+$s_after"
+
+ run_podman logs --until $before test
+ is "$output" \
+ ""
+
+ after=$(date --iso-8601=seconds)
+
+ run_podman logs --until $after test
+ is "$output" \
+ "$s_before
+$s_after"
+ run_podman rm -f test
+}
+
+@test "podman logs - until k8s-file" {
+ _log_test_until k8s-file
+}
+
+@test "podman logs - until journald" {
+ # We can't use journald on RHEL as rootless: rhbz#1895105
+ skip_if_journald_unavailable
+
+ _log_test_until journald
+}
+
# vim: filetype=sh
diff --git a/test/system/050-stop.bats b/test/system/050-stop.bats
index 2ed791429..d809507a5 100644
--- a/test/system/050-stop.bats
+++ b/test/system/050-stop.bats
@@ -119,11 +119,31 @@ load helpers
# the container's status.
run_podman run --name stopme -d $IMAGE sh -c \
- "trap 'echo Received SIGTERM, ignoring' SIGTERM; echo READY; while :; do sleep 1; done"
+ "trap 'echo Received SIGTERM, ignoring' SIGTERM; echo READY; while :; do sleep 0.2; done"
- # Stop the container in the background
+ wait_for_ready stopme
+
+ local t0=$SECONDS
+ # Stop the container, but do so in the background so we can inspect
+ # the container status while it's stopping. Use $PODMAN because we
+ # don't want the overhead and error checks of run_podman.
$PODMAN stop -t 20 stopme &
+ # Wait for container to acknowledge the signal. We can't use wait_for_output
+ # because that aborts if .State.Running != true
+ local timeout=5
+ while [[ $timeout -gt 0 ]]; do
+ run_podman logs stopme
+ if [[ "$output" =~ "Received SIGTERM, ignoring" ]]; then
+ break
+ fi
+ timeout=$((timeout - 1))
+ if [[ $timeout -eq 0 ]]; then
+ die "Timed out waiting for container to receive SIGERM"
+ fi
+ sleep 0.5
+ done
+
# Other commands can acquire the lock
run_podman ps -a
@@ -131,6 +151,13 @@ load helpers
run_podman inspect --format '{{.State.Status}}' stopme
is "$output" "stopping" "Status of container should be 'stopping'"
+ # Time check: make sure we were able to run 'ps' before the container
+ # exited. If this takes too long, it means ps had to wait for lock.
+ local delta_t=$(( $SECONDS - t0 ))
+ if [[ $delta_t -gt 5 ]]; then
+ die "Operations took too long ($delta_t seconds)"
+ fi
+
run_podman kill stopme
run_podman wait stopme
diff --git a/test/system/065-cp.bats b/test/system/065-cp.bats
index 5778eb46e..39f439e7b 100644
--- a/test/system/065-cp.bats
+++ b/test/system/065-cp.bats
@@ -22,8 +22,7 @@ load helpers
mkdir -p $srcdir/subdir
echo "${randomcontent[2]}" > $srcdir/subdir/dotfile.
- run_podman run -d --name cpcontainer --workdir=/srv $IMAGE sleep infinity
- run_podman exec cpcontainer mkdir /srv/subdir
+ run_podman run -d --name cpcontainer --workdir=/srv $IMAGE sh -c "mkdir /srv/subdir; sleep infinity"
# Commit the image for testing non-running containers
run_podman commit -q cpcontainer
@@ -41,7 +40,6 @@ load helpers
0 | /tmp | /tmp/hostfile0 | copy to /tmp
1 | /tmp/ | /tmp/hostfile1 | copy to /tmp/
2 | /tmp/. | /tmp/hostfile2 | copy to /tmp/.
-0 | /tmp/hostfile2 | /tmp/hostfile2 | overwrite previous copy
0 | /tmp/anotherbase.txt | /tmp/anotherbase.txt | copy to /tmp, new name
0 | . | /srv/hostfile0 | copy to workdir (rel path), new name
1 | ./ | /srv/hostfile1 | copy to workdir (rel path), new name
@@ -175,11 +173,12 @@ load helpers
random-1-$(random_string 15)
random-2-$(random_string 20)
)
- run_podman run -d --name cpcontainer --workdir=/srv $IMAGE sleep infinity
- run_podman exec cpcontainer sh -c "echo ${randomcontent[0]} > /tmp/containerfile"
- run_podman exec cpcontainer sh -c "echo ${randomcontent[0]} > /tmp/dotfile."
- run_podman exec cpcontainer sh -c "echo ${randomcontent[1]} > /srv/containerfile1"
- run_podman exec cpcontainer sh -c "mkdir /srv/subdir; echo ${randomcontent[2]} > /srv/subdir/containerfile2"
+ run_podman run -d --name cpcontainer --workdir=/srv $IMAGE sh -c "mkdir /srv/subdir;
+ echo ${randomcontent[0]} > /tmp/containerfile;
+ echo ${randomcontent[0]} > /tmp/dotfile.;
+ echo ${randomcontent[1]} > /srv/containerfile1;
+ echo ${randomcontent[2]} > /srv/subdir/containerfile2;
+ sleep infinity"
# Commit the image for testing non-running containers
run_podman commit -q cpcontainer
@@ -226,6 +225,98 @@ load helpers
}
+@test "podman cp file from container to container" {
+ # Create 3 files with random content in the container.
+ local -a randomcontent=(
+ random-0-$(random_string 10)
+ random-1-$(random_string 15)
+ random-2-$(random_string 20)
+ )
+
+ run_podman run -d --name cpcontainer --workdir=/srv $IMAGE sh -c "mkdir /srv/subdir;
+ echo ${randomcontent[0]} > /tmp/containerfile;
+ echo ${randomcontent[0]} > /tmp/dotfile.;
+ echo ${randomcontent[1]} > /srv/containerfile1;
+ echo ${randomcontent[2]} > /srv/subdir/containerfile2;
+ sleep infinity"
+
+ # Commit the image for testing non-running containers
+ run_podman commit -q cpcontainer
+ cpimage="$output"
+
+ # format is: <id> | <source arg to cp> | <destination arg (appended to $srcdir) to cp> | <full dest path (appended to $srcdir)> | <test name>
+ tests="
+0 | /tmp/containerfile | | /containerfile | /
+0 | /tmp/dotfile. | | /dotfile. | /
+0 | /tmp/containerfile | / | /containerfile | /
+0 | /tmp/containerfile | /. | /containerfile | /.
+0 | /tmp/containerfile | /newfile | /newfile | /newfile
+1 | containerfile1 | / | /containerfile1 | copy from workdir (rel path) to /
+2 | subdir/containerfile2 | / | /containerfile2 | copy from workdir/subdir (rel path) to /
+"
+
+ # From RUNNING container
+ while read id src dest dest_fullname description; do
+ # dest may be "''" for empty table cells
+ if [[ $dest == "''" ]];then
+ unset dest
+ fi
+
+ # To RUNNING container
+ run_podman run -d $IMAGE sleep infinity
+ destcontainer="$output"
+ run_podman cp cpcontainer:$src $destcontainer:"/$dest"
+ run_podman exec $destcontainer cat "/$dest_fullname"
+ is "$output" "${randomcontent[$id]}" "$description (cp ctr:$src to /$dest)"
+ run_podman kill $destcontainer
+ run_podman rm -f $destcontainer
+
+ # To CREATED container
+ run_podman create $IMAGE sleep infinity
+ destcontainer="$output"
+ run_podman cp cpcontainer:$src $destcontainer:"/$dest"
+ run_podman start $destcontainer
+ run_podman exec $destcontainer cat "/$dest_fullname"
+ is "$output" "${randomcontent[$id]}" "$description (cp ctr:$src to /$dest)"
+ run_podman kill $destcontainer
+ run_podman rm -f $destcontainer
+ done < <(parse_table "$tests")
+ run_podman kill cpcontainer
+ run_podman rm -f cpcontainer
+
+ # From CREATED container
+ run_podman create --name cpcontainer --workdir=/srv $cpimage
+ while read id src dest dest_fullname description; do
+ # dest may be "''" for empty table cells
+ if [[ $dest == "''" ]];then
+ unset dest
+ fi
+
+ # To RUNNING container
+ run_podman run -d $IMAGE sleep infinity
+ destcontainer="$output"
+ run_podman cp cpcontainer:$src $destcontainer:"/$dest"
+ run_podman exec $destcontainer cat "/$dest_fullname"
+ is "$output" "${randomcontent[$id]}" "$description (cp ctr:$src to /$dest)"
+ run_podman kill $destcontainer
+ run_podman rm -f $destcontainer
+
+ # To CREATED container
+ run_podman create $IMAGE sleep infinity
+ destcontainer="$output"
+ run_podman cp cpcontainer:$src $destcontainer:"/$dest"
+ run_podman start $destcontainer
+ run_podman exec $destcontainer cat "/$dest_fullname"
+ is "$output" "${randomcontent[$id]}" "$description (cp ctr:$src to /$dest)"
+ run_podman kill $destcontainer
+ run_podman rm -f $destcontainer
+ done < <(parse_table "$tests")
+ run_podman rm -f cpcontainer
+
+ run_podman rmi -f $cpimage
+}
+
+
@test "podman cp dir from host to container" {
srcdir=$PODMAN_TMPDIR
mkdir -p $srcdir/dir/sub
@@ -241,8 +332,7 @@ load helpers
mkdir -p $srcdir/dir.
cp -r $srcdir/dir/* $srcdir/dir.
- run_podman run -d --name cpcontainer --workdir=/srv $IMAGE sleep infinity
- run_podman exec cpcontainer mkdir /srv/subdir
+ run_podman run -d --name cpcontainer --workdir=/srv $IMAGE sh -c "mkdir /srv/subdir; sleep infinity"
# Commit the image for testing non-running containers
run_podman commit -q cpcontainer
@@ -309,12 +399,12 @@ load helpers
random-0-$(random_string 10)
random-1-$(random_string 15)
)
- run_podman run -d --name cpcontainer --workdir=/srv $IMAGE sleep infinity
- run_podman exec cpcontainer sh -c "mkdir /srv/subdir; echo ${randomcontent[0]} > /srv/subdir/containerfile0"
- run_podman exec cpcontainer sh -c "echo ${randomcontent[1]} > /srv/subdir/containerfile1"
- # "." and "dir/." will copy the contents, so make sure that a dir ending
- # with dot is treated correctly.
- run_podman exec cpcontainer sh -c 'mkdir /tmp/subdir.; cp /srv/subdir/* /tmp/subdir./'
+
+ run_podman run -d --name cpcontainer --workdir=/srv $IMAGE sh -c "mkdir /srv/subdir;
+ echo ${randomcontent[0]} > /srv/subdir/containerfile0; \
+ echo ${randomcontent[1]} > /srv/subdir/containerfile1; \
+ mkdir /tmp/subdir.; cp /srv/subdir/* /tmp/subdir./; \
+ sleep infinity"
# Commit the image for testing non-running containers
run_podman commit -q cpcontainer
@@ -377,6 +467,110 @@ load helpers
}
+@test "podman cp dir from container to container" {
+ # Create 2 files with random content in the container.
+ local -a randomcontent=(
+ random-0-$(random_string 10)
+ random-1-$(random_string 15)
+ )
+
+ run_podman run -d --name cpcontainer --workdir=/srv $IMAGE sh -c "mkdir /srv/subdir;
+ echo ${randomcontent[0]} > /srv/subdir/containerfile0; \
+ echo ${randomcontent[1]} > /srv/subdir/containerfile1; \
+ mkdir /tmp/subdir.; cp /srv/subdir/* /tmp/subdir./; \
+ sleep infinity"
+
+ # Commit the image for testing non-running containers
+ run_podman commit -q cpcontainer
+ cpimage="$output"
+
+ # format is: <source arg to cp (appended to /srv)> | <dest> | <full dest path> | <test name>
+ tests="
+/srv | | /srv/subdir | copy /srv
+/srv | /newdir | /newdir/subdir | copy /srv to /newdir
+/srv/ | | /srv/subdir | copy /srv/
+/srv/. | | /subdir | copy /srv/.
+/srv/. | /newdir | /newdir/subdir | copy /srv/. to /newdir
+/srv/subdir/. | | | copy /srv/subdir/.
+/tmp/subdir. | | /subdir. | copy /tmp/subdir.
+"
+
+ # From RUNNING container
+ while read src dest dest_fullname description; do
+ if [[ $src == "''" ]];then
+ unset src
+ fi
+ if [[ $dest == "''" ]];then
+ unset dest
+ fi
+ if [[ $dest_fullname == "''" ]];then
+ unset dest_fullname
+ fi
+
+ # To RUNNING container
+ run_podman run -d $IMAGE sleep infinity
+ destcontainer="$output"
+ run_podman cp cpcontainer:$src $destcontainer:"/$dest"
+ run_podman exec $destcontainer cat "/$dest_fullname/containerfile0" "/$dest_fullname/containerfile1"
+ is "$output" "${randomcontent[0]}
+${randomcontent[1]}" "$description"
+ run_podman kill $destcontainer
+ run_podman rm -f $destcontainer
+
+ # To CREATED container
+ run_podman create $IMAGE sleep infinity
+ destcontainer="$output"
+ run_podman cp cpcontainer:$src $destcontainer:"/$dest"
+ run_podman start $destcontainer
+ run_podman exec $destcontainer cat "/$dest_fullname/containerfile0" "/$dest_fullname/containerfile1"
+ is "$output" "${randomcontent[0]}
+${randomcontent[1]}" "$description"
+ run_podman kill $destcontainer
+ run_podman rm -f $destcontainer
+ done < <(parse_table "$tests")
+ run_podman kill cpcontainer
+ run_podman rm -f cpcontainer
+
+ # From CREATED container
+ run_podman create --name cpcontainer --workdir=/srv $cpimage
+ while read src dest dest_fullname description; do
+ if [[ $src == "''" ]];then
+ unset src
+ fi
+ if [[ $dest == "''" ]];then
+ unset dest
+ fi
+ if [[ $dest_fullname == "''" ]];then
+ unset dest_fullname
+ fi
+
+ # To RUNNING container
+ run_podman run -d $IMAGE sleep infinity
+ destcontainer="$output"
+ run_podman cp cpcontainer:$src $destcontainer:"/$dest"
+ run_podman exec $destcontainer cat "/$dest_fullname/containerfile0" "/$dest_fullname/containerfile1"
+ is "$output" "${randomcontent[0]}
+${randomcontent[1]}" "$description"
+ run_podman kill $destcontainer
+ run_podman rm -f $destcontainer
+
+ # To CREATED container
+ run_podman create $IMAGE sleep infinity
+ destcontainer="$output"
+ run_podman start $destcontainer
+ run_podman cp cpcontainer:$src $destcontainer:"/$dest"
+ run_podman exec $destcontainer cat "/$dest_fullname/containerfile0" "/$dest_fullname/containerfile1"
+ is "$output" "${randomcontent[0]}
+${randomcontent[1]}" "$description"
+ run_podman kill $destcontainer
+ run_podman rm -f $destcontainer
+ done < <(parse_table "$tests")
+
+ run_podman rm -f cpcontainer
+ run_podman rmi -f $cpimage
+}
+
+
@test "podman cp symlinked directory from container" {
destdir=$PODMAN_TMPDIR/cp-weird-symlink
mkdir -p $destdir
@@ -387,10 +581,10 @@ load helpers
random-1-$(random_string 15)
)
- run_podman run -d --name cpcontainer $IMAGE sleep infinity
- run_podman exec cpcontainer sh -c "echo ${randomcontent[0]} > /tmp/containerfile0"
- run_podman exec cpcontainer sh -c "echo ${randomcontent[1]} > /tmp/containerfile1"
- run_podman exec cpcontainer sh -c "mkdir /tmp/sub && cd /tmp/sub && ln -s .. weirdlink"
+ run_podman run -d --name cpcontainer $IMAGE sh -c "echo ${randomcontent[0]} > /tmp/containerfile0; \
+ echo ${randomcontent[1]} > /tmp/containerfile1; \
+ mkdir /tmp/sub && cd /tmp/sub && ln -s .. weirdlink; \
+ sleep infinity"
# Commit the image for testing non-running containers
run_podman commit -q cpcontainer
diff --git a/test/system/070-build.bats b/test/system/070-build.bats
index 7b76c585f..26113e45c 100644
--- a/test/system/070-build.bats
+++ b/test/system/070-build.bats
@@ -749,16 +749,9 @@ RUN echo $random_string
EOF
run_podman 125 build -t build_test --pull-never $tmpdir
- # FIXME: this is just ridiculous. Even after #10030 and #10034, Ubuntu
- # remote *STILL* flakes this test! It fails with the correct exit status,
- # but the error output is 'Error: stream dropped, unexpected failure'
- # Let's just stop checking on podman-remote. As long as it exits 125,
- # we're happy.
- if ! is_remote; then
- is "$output" \
- ".*Error: error creating build container: quay.io/libpod/nosuchimage:nosuchtag: image not known" \
- "--pull-never fails with expected error message"
- fi
+ is "$output" \
+ ".*Error: error creating build container: quay.io/libpod/nosuchimage:nosuchtag: image not known" \
+ "--pull-never fails with expected error message"
}
@test "podman build --logfile test" {
diff --git a/test/system/090-events.bats b/test/system/090-events.bats
index d889bd7f9..22edaeee9 100644
--- a/test/system/090-events.bats
+++ b/test/system/090-events.bats
@@ -81,6 +81,7 @@ function _events_disjunctive_filters() {
@test "events with disjunctive filters - journald" {
skip_if_remote "remote does not support --events-backend"
+ skip_if_journald_unavailable "system does not support journald events"
_events_disjunctive_filters --events-backend=journald
}
diff --git a/test/system/125-import.bats b/test/system/125-import.bats
new file mode 100644
index 000000000..c53711618
--- /dev/null
+++ b/test/system/125-import.bats
@@ -0,0 +1,45 @@
+#!/usr/bin/env bats -*- bats -*-
+#
+# tests for podman import
+#
+
+load helpers
+
+@test "podman import" {
+ local archive=$PODMAN_TMPDIR/archive.tar
+ local random_content=$(random_string 12)
+ # Generate a random name and tag (must be lower-case)
+ local random_name=x0$(random_string 12 | tr A-Z a-z)
+ local random_tag=t0$(random_string 7 | tr A-Z a-z)
+ local fqin=localhost/$random_name:$random_tag
+
+ run_podman run --name import $IMAGE sh -c "echo ${random_content} > /random.txt"
+ run_podman export import -o $archive
+ run_podman rm -f import
+
+ # Simple import
+ run_podman import -q $archive
+ iid="$output"
+ run_podman run -t --rm $iid cat /random.txt
+ is "$output" "$random_content" "simple import"
+ run_podman rmi -f $iid
+
+ # Simple import via stdin
+ run_podman import -q - < <(cat $archive)
+ iid="$output"
+ run_podman run -t --rm $iid cat /random.txt
+ is "$output" "$random_content" "simple import via stdin"
+ run_podman rmi -f $iid
+
+ # Tagged import
+ run_podman import -q $archive $fqin
+ run_podman run -t --rm $fqin cat /random.txt
+ is "$output" "$random_content" "tagged import"
+ run_podman rmi -f $fqin
+
+ # Tagged import via stdin
+ run_podman import -q - $fqin < <(cat $archive)
+ run_podman run -t --rm $fqin cat /random.txt
+ is "$output" "$random_content" "tagged import via stdin"
+ run_podman rmi -f $fqin
+}
diff --git a/test/system/250-systemd.bats b/test/system/250-systemd.bats
index aafe385c8..ee951ff21 100644
--- a/test/system/250-systemd.bats
+++ b/test/system/250-systemd.bats
@@ -4,17 +4,10 @@
#
load helpers
+load helpers.systemd
SERVICE_NAME="podman_test_$(random_string)"
-SYSTEMCTL="systemctl"
-UNIT_DIR="/usr/lib/systemd/system"
-if is_rootless; then
- UNIT_DIR="$HOME/.config/systemd/user"
- mkdir -p $UNIT_DIR
-
- SYSTEMCTL="$SYSTEMCTL --user"
-fi
UNIT_FILE="$UNIT_DIR/$SERVICE_NAME.service"
function setup() {
@@ -24,38 +17,28 @@ function setup() {
}
function teardown() {
- run '?' $SYSTEMCTL stop "$SERVICE_NAME"
+ run '?' systemctl stop "$SERVICE_NAME"
rm -f "$UNIT_FILE"
- $SYSTEMCTL daemon-reload
+ systemctl daemon-reload
run_podman rmi -a
basic_teardown
}
-# Helper to setup xdg runtime for rootless
-function xdg_rootless() {
- # podman initializes this if unset, but systemctl doesn't
- if is_rootless; then
- if [ -z "$XDG_RUNTIME_DIR" ]; then
- export XDG_RUNTIME_DIR=/run/user/$(id -u)
- fi
- fi
-}
-
# Helper to start a systemd service running a container
function service_setup() {
run_podman generate systemd --new $cname
echo "$output" > "$UNIT_FILE"
run_podman rm $cname
- $SYSTEMCTL daemon-reload
+ systemctl daemon-reload
- run $SYSTEMCTL start "$SERVICE_NAME"
+ run systemctl start "$SERVICE_NAME"
if [ $status -ne 0 ]; then
die "Error starting systemd unit $SERVICE_NAME, output: $output"
fi
- run $SYSTEMCTL status "$SERVICE_NAME"
+ run systemctl status "$SERVICE_NAME"
if [ $status -ne 0 ]; then
die "Non-zero status of systemd unit $SERVICE_NAME, output: $output"
fi
@@ -63,20 +46,18 @@ function service_setup() {
# Helper to stop a systemd service running a container
function service_cleanup() {
- run $SYSTEMCTL stop "$SERVICE_NAME"
+ run systemctl stop "$SERVICE_NAME"
if [ $status -ne 0 ]; then
die "Error stopping systemd unit $SERVICE_NAME, output: $output"
fi
rm -f "$UNIT_FILE"
- $SYSTEMCTL daemon-reload
+ systemctl daemon-reload
}
# These tests can fail in dev. environment because of SELinux.
# quick fix: chcon -t container_runtime_exec_t ./bin/podman
@test "podman generate - systemd - basic" {
- xdg_rootless
-
cname=$(random_string)
# See #7407 for --pull=always.
run_podman create --pull=always --name $cname --label "io.containers.autoupdate=registry" $IMAGE top
@@ -100,8 +81,6 @@ function service_cleanup() {
}
@test "podman autoupdate local" {
- xdg_rootless
-
cname=$(random_string)
run_podman create --name $cname --label "io.containers.autoupdate=local" $IMAGE top
@@ -128,8 +107,6 @@ function service_cleanup() {
# These tests can fail in dev. environment because of SELinux.
# quick fix: chcon -t container_runtime_exec_t ./bin/podman
@test "podman generate systemd - envar" {
- xdg_rootless
-
cname=$(random_string)
FOO=value BAR=%s run_podman create --name $cname --env FOO -e BAR --env MYVAR=myval \
$IMAGE sh -c 'printenv && sleep 100'
diff --git a/test/system/255-auto-update.bats b/test/system/255-auto-update.bats
index a73ed94e8..6fb40f41e 100644
--- a/test/system/255-auto-update.bats
+++ b/test/system/255-auto-update.bats
@@ -4,14 +4,12 @@
#
load helpers
+load helpers.systemd
-UNIT_DIR="/usr/lib/systemd/system"
SNAME_FILE=$BATS_TMPDIR/services
function setup() {
skip_if_remote "systemd tests are meaningless over remote"
- skip_if_rootless
-
basic_setup
}
@@ -29,7 +27,7 @@ function teardown() {
rm -f $SNAME_FILE
run_podman ? rmi quay.io/libpod/alpine:latest
- run_podman ? rmi quay.io/libpod/alpine_nginx:latest
+ run_podman ? rmi quay.io/libpod/busybox:latest
run_podman ? rmi quay.io/libpod/localtest:latest
basic_teardown
}
@@ -58,8 +56,7 @@ function generate_service() {
fi
run_podman run -d --name $cname $label $target_img top -d 120
- run_podman generate systemd --new $cname
- echo "$output" > "$UNIT_DIR/container-$cname.service"
+ (cd $UNIT_DIR; run_podman generate systemd --new --files --name $cname)
echo "container-$cname" >> $SNAME_FILE
run_podman rm -f $cname
@@ -185,7 +182,7 @@ function _confirm_update() {
do
local img_base="alpine"
if [[ $auto_update == "registry" ]]; then
- img_base="alpine_nginx"
+ img_base="busybox"
elif [[ $auto_update == "local" ]]; then
img_base="localtest"
fi
@@ -264,7 +261,8 @@ EOF
systemctl enable --now podman-auto-update-$cname.timer
systemctl list-timers --all
- local expect='Finished Podman auto-update testing service'
+ # While systemd v245 and later uses 'Finished', older versions uses 'Started' for oneshot services
+ local expect='(Finished|Started) Podman auto-update testing service'
local failed_start=failed
local count=0
while [ $count -lt 120 ]; do
diff --git a/test/system/270-socket-activation.bats b/test/system/270-socket-activation.bats
index 25206c6a7..031ba161b 100644
--- a/test/system/270-socket-activation.bats
+++ b/test/system/270-socket-activation.bats
@@ -4,21 +4,12 @@
#
load helpers
+load helpers.systemd
SERVICE_NAME="podman_test_$(random_string)"
-SYSTEMCTL="systemctl"
-UNIT_DIR="/usr/lib/systemd/system"
SERVICE_SOCK_ADDR="/run/podman/podman.sock"
-
if is_rootless; then
- UNIT_DIR="$HOME/.config/systemd/user"
- mkdir -p $UNIT_DIR
-
- SYSTEMCTL="$SYSTEMCTL --user"
- if [ -z "$XDG_RUNTIME_DIR" ]; then
- export XDG_RUNTIME_DIR=/run/user/$(id -u)
- fi
SERVICE_SOCK_ADDR="$XDG_RUNTIME_DIR/podman/podman.sock"
fi
@@ -66,13 +57,13 @@ EOF
rm -f $pause_pid
fi
fi
- $SYSTEMCTL start "$SERVICE_NAME.socket"
+ systemctl start "$SERVICE_NAME.socket"
}
function teardown() {
- $SYSTEMCTL stop "$SERVICE_NAME.socket"
+ systemctl stop "$SERVICE_NAME.socket"
rm -f "$SERVICE_FILE" "$SOCKET_FILE"
- $SYSTEMCTL daemon-reload
+ systemctl daemon-reload
basic_teardown
}
diff --git a/test/system/271-tcp-cors-server.bats b/test/system/271-tcp-cors-server.bats
new file mode 100644
index 000000000..cdfa82e82
--- /dev/null
+++ b/test/system/271-tcp-cors-server.bats
@@ -0,0 +1,44 @@
+#!/usr/bin/env bats -*- bats -*-
+#
+# Tests podman system service CORS enabled
+#
+
+load helpers
+
+SERVICE_NAME="podman_test_$(random_string)"
+
+SERVICE_TCP_HOST="localhost"
+
+SERVICE_FILE="$UNIT_DIR/$SERVICE_NAME.service"
+SOCKET_FILE="$UNIT_DIR/$SERVICE_NAME.socket"
+
+@test "podman system service - tcp CORS" {
+ skip_if_remote "system service tests are meaningless over remote"
+ PORT=$(( ((RANDOM<<15)|RANDOM) % 63001 + 2000 ))
+ run_podman system service --cors="*" tcp:$SERVICE_TCP_HOST:$PORT -t 20 &
+ podman_pid="$!"
+ sleep 5s
+ run curl -s --max-time 10 -vvv $SERVICE_TCP_HOST:$PORT/_ping 2>&1
+ is "$output" ".*< Access-Control-Allow-Origin: \*.*" "access-control-allow-origin verifies CORS is set"
+ kill $podman_pid
+ wait $podman_pid || true
+}
+
+@test "podman system service - tcp without CORS" {
+ skip_if_remote "system service tests are meaningless over remote"
+ PORT=$(( ((RANDOM<<15)|RANDOM) % 63001 + 2000 ))
+ run_podman system service tcp:$SERVICE_TCP_HOST:$PORT -t 20 &
+ podman_pid="$!"
+ sleep 5s
+ (curl -s --max-time 10 -vvv $SERVICE_TCP_HOST:$PORT/_ping 2>&1 | grep -Eq "Access-Control-Allow-Origin:") && false || true
+ kill $podman_pid
+ wait $podman_pid || true
+}
+
+@test "podman system service - CORS enabled in logs" {
+ skip_if_remote "system service tests are meaningless over remote"
+ run_podman system service --log-level="debug" --cors="*" -t 1
+ is "$output" ".*CORS Headers were set to \*.*" "debug log confirms CORS headers set"
+}
+
+# vim: filetype=sh
diff --git a/test/system/500-networking.bats b/test/system/500-networking.bats
index 4feb57807..495c7948b 100644
--- a/test/system/500-networking.bats
+++ b/test/system/500-networking.bats
@@ -139,6 +139,8 @@ load helpers
$IMAGE nc -l -n -v -p $myport
cid="$output"
+ wait_for_output "listening on .*:$myport .*" $cid
+
# emit random string, and check it
teststring=$(random_string 30)
echo "$teststring" | nc 127.0.0.1 $myport
diff --git a/test/system/helpers.bash b/test/system/helpers.bash
index 1859a2168..bd9471ace 100644
--- a/test/system/helpers.bash
+++ b/test/system/helpers.bash
@@ -278,6 +278,24 @@ function wait_for_ready {
wait_for_output 'READY' "$@"
}
+###################
+# wait_for_port # Returns once port is available on host
+###################
+function wait_for_port() {
+ local host=$1 # Probably "localhost"
+ local port=$2 # Numeric port
+ local _timeout=${3:-5} # Optional; default to 5 seconds
+
+ # Wait
+ while [ $_timeout -gt 0 ]; do
+ { exec 5<> /dev/tcp/$host/$port; } &>/dev/null && return
+ sleep 1
+ _timeout=$(( $_timeout - 1 ))
+ done
+
+ die "Timed out waiting for $host:$port"
+}
+
# END podman helpers
###############################################################################
# BEGIN miscellaneous tools
diff --git a/test/system/helpers.systemd.bash b/test/system/helpers.systemd.bash
new file mode 100644
index 000000000..4bde912a4
--- /dev/null
+++ b/test/system/helpers.systemd.bash
@@ -0,0 +1,30 @@
+# -*- bash -*-
+#
+# BATS helpers for systemd-related functionality
+#
+
+# podman initializes this if unset, but systemctl doesn't
+if [ -z "$XDG_RUNTIME_DIR" ]; then
+ if is_rootless; then
+ export XDG_RUNTIME_DIR=/run/user/$(id -u)
+ fi
+fi
+
+# For tests which write systemd unit files
+UNIT_DIR="/run/systemd/system"
+_DASHUSER=
+if is_rootless; then
+ UNIT_DIR="${XDG_RUNTIME_DIR}/systemd/user"
+ # Why isn't systemd smart enough to figure this out on its own?
+ _DASHUSER="--user"
+fi
+
+mkdir -p $UNIT_DIR
+
+systemctl() {
+ command systemctl $_DASHUSER "$@"
+}
+
+journalctl() {
+ command journalctl $_DASHUSER "$@"
+}
diff --git a/transfer.md b/transfer.md
index c37592384..765094dc9 100644
--- a/transfer.md
+++ b/transfer.md
@@ -141,8 +141,8 @@ The following podman commands do not have a Docker equivalent:
* [`podman generate `](./docs/source/markdown/podman-generate.1.md)
* [`podman generate kube`](./docs/source/markdown/podman-generate-kube.1.md)
* [`podman generate systemd`](./docs/source/markdown/podman-generate-systemd.1.md)
-* [`podman healthcheck `](/docs/source/markdown/podmanh-healthcheck.1.md)
-* [`podman healthcheck run`](/docs/source/markdown/podmanh-healthcheck-run.1.md)
+* [`podman healthcheck `](/docs/source/markdown/podman-healthcheck.1.md)
+* [`podman healthcheck run`](/docs/source/markdown/podman-healthcheck-run.1.md)
* [`podman image diff`](./docs/source/markdown/podman-image-diff.1.md)
* [`podman image exists`](./docs/source/markdown/podman-image-exists.1.md)
* [`podman image mount`](./docs/source/markdown/podman-image-mount.1.md)
diff --git a/troubleshooting.md b/troubleshooting.md
index 575ee16b8..24dcb8e35 100644
--- a/troubleshooting.md
+++ b/troubleshooting.md
@@ -356,7 +356,7 @@ If you do mount in the host's `/var/lib/containers/storage`, however, you must a
Not doing this will cause Podman in the container to detect that temporary files have been cleared, leading it to assume a system restart has taken place.
This can cause Podman to reset container states and lose track of running containers.
-For running containers on the host from inside a container, we also recommend the [Podman remote client](remote_client.md), which only requires a single socket to be mounted into the container.
+For running containers on the host from inside a container, we also recommend the [Podman remote client](docs/tutorials/remote_client.md), which only requires a single socket to be mounted into the container.
### 14) Rootless 'podman build' fails EPERM on NFS:
diff --git a/vendor/github.com/checkpoint-restore/go-criu/.gitignore b/vendor/github.com/checkpoint-restore/go-criu/.gitignore
deleted file mode 100644
index f1c90e3d5..000000000
--- a/vendor/github.com/checkpoint-restore/go-criu/.gitignore
+++ /dev/null
@@ -1,5 +0,0 @@
-test/test
-test/piggie
-test/phaul
-image
-rpc/rpc.proto
diff --git a/vendor/github.com/checkpoint-restore/go-criu/.travis.yml b/vendor/github.com/checkpoint-restore/go-criu/.travis.yml
deleted file mode 100644
index 741dbf0a1..000000000
--- a/vendor/github.com/checkpoint-restore/go-criu/.travis.yml
+++ /dev/null
@@ -1,25 +0,0 @@
-language: go
-sudo: required
-os:
- - linux
-go:
- - "1.8"
- - "1.9"
- - "1.10"
-env:
- # Run the tests with CRIU master and criu-dev
- - CRIU_BRANCH="master"
- - CRIU_BRANCH="criu-dev"
-install:
- - sudo apt-get update
- - sudo apt-get install -y libprotobuf-dev libprotobuf-c0-dev protobuf-c-compiler protobuf-compiler python-protobuf libnl-3-dev libnet-dev libcap-dev
- - go get github.com/checkpoint-restore/go-criu
- - git clone --single-branch -b ${CRIU_BRANCH} https://github.com/checkpoint-restore/criu.git
- - cd criu; make
- - sudo install -D -m 755 criu/criu /usr/sbin/
- - cd ..
-script:
- # This builds the code without running the tests.
- - make build phaul test/test test/phaul test/piggie
- # Run actual test as root as it uses CRIU.
- - sudo make test phaul-test
diff --git a/vendor/github.com/checkpoint-restore/go-criu/Makefile b/vendor/github.com/checkpoint-restore/go-criu/Makefile
deleted file mode 100644
index ee44ee448..000000000
--- a/vendor/github.com/checkpoint-restore/go-criu/Makefile
+++ /dev/null
@@ -1,60 +0,0 @@
-GO ?= go
-CC ?= gcc
-ifeq ($(GOPATH),)
-export GOPATH := $(shell $(GO) env GOPATH)
-endif
-FIRST_GOPATH := $(firstword $(subst :, ,$(GOPATH)))
-GOBIN := $(shell $(GO) env GOBIN)
-ifeq ($(GOBIN),)
- GOBIN := $(FIRST_GOPATH)/bin
-endif
-
-all: build test phaul phaul-test
-
-lint:
- @golint . test phaul
-build:
- @$(GO) build -v
-
-test/piggie: test/piggie.c
- @$(CC) $^ -o $@
-
-test/test: test/main.go
- @$(GO) build -v -o test/test test/main.go
-
-test: test/test test/piggie
- mkdir -p image
- test/piggie
- test/test dump `pidof piggie` image
- test/test restore image
- pkill -9 piggie || :
-
-phaul:
- @cd phaul; go build -v
-
-test/phaul: test/phaul-main.go
- @$(GO) build -v -o test/phaul test/phaul-main.go
-
-phaul-test: test/phaul test/piggie
- rm -rf image
- test/piggie
- test/phaul `pidof piggie`
- pkill -9 piggie || :
-
-clean:
- @rm -f test/test test/piggie test/phaul
- @rm -rf image
- @rm -f rpc/rpc.proto
-
-install.tools:
- if [ ! -x "$(GOBIN)/golint" ]; then \
- $(GO) get -u golang.org/x/lint/golint; \
- fi
-
-rpc/rpc.proto:
- curl -s https://raw.githubusercontent.com/checkpoint-restore/criu/master/images/rpc.proto -o $@
-
-rpc/rpc.pb.go: rpc/rpc.proto
- protoc --go_out=. $^
-
-.PHONY: build test clean lint phaul
diff --git a/vendor/github.com/checkpoint-restore/go-criu/rpc/rpc.pb.go b/vendor/github.com/checkpoint-restore/go-criu/rpc/rpc.pb.go
deleted file mode 100644
index 230faace5..000000000
--- a/vendor/github.com/checkpoint-restore/go-criu/rpc/rpc.pb.go
+++ /dev/null
@@ -1,1211 +0,0 @@
-// Code generated by protoc-gen-go. DO NOT EDIT.
-// source: rpc/rpc.proto
-
-/*
-Package rpc is a generated protocol buffer package.
-
-It is generated from these files:
- rpc/rpc.proto
-
-It has these top-level messages:
- CriuPageServerInfo
- CriuVethPair
- ExtMountMap
- JoinNamespace
- InheritFd
- CgroupRoot
- UnixSk
- CriuOpts
- CriuDumpResp
- CriuRestoreResp
- CriuNotify
- CriuFeatures
- CriuReq
- CriuResp
- CriuVersion
-*/
-package rpc
-
-import proto "github.com/golang/protobuf/proto"
-import fmt "fmt"
-import math "math"
-
-// Reference imports to suppress errors if they are not otherwise used.
-var _ = proto.Marshal
-var _ = fmt.Errorf
-var _ = math.Inf
-
-// This is a compile-time assertion to ensure that this generated file
-// is compatible with the proto package it is being compiled against.
-// A compilation error at this line likely means your copy of the
-// proto package needs to be updated.
-const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
-
-type CriuCgMode int32
-
-const (
- CriuCgMode_IGNORE CriuCgMode = 0
- CriuCgMode_CG_NONE CriuCgMode = 1
- CriuCgMode_PROPS CriuCgMode = 2
- CriuCgMode_SOFT CriuCgMode = 3
- CriuCgMode_FULL CriuCgMode = 4
- CriuCgMode_STRICT CriuCgMode = 5
- CriuCgMode_DEFAULT CriuCgMode = 6
-)
-
-var CriuCgMode_name = map[int32]string{
- 0: "IGNORE",
- 1: "CG_NONE",
- 2: "PROPS",
- 3: "SOFT",
- 4: "FULL",
- 5: "STRICT",
- 6: "DEFAULT",
-}
-var CriuCgMode_value = map[string]int32{
- "IGNORE": 0,
- "CG_NONE": 1,
- "PROPS": 2,
- "SOFT": 3,
- "FULL": 4,
- "STRICT": 5,
- "DEFAULT": 6,
-}
-
-func (x CriuCgMode) Enum() *CriuCgMode {
- p := new(CriuCgMode)
- *p = x
- return p
-}
-func (x CriuCgMode) String() string {
- return proto.EnumName(CriuCgMode_name, int32(x))
-}
-func (x *CriuCgMode) UnmarshalJSON(data []byte) error {
- value, err := proto.UnmarshalJSONEnum(CriuCgMode_value, data, "CriuCgMode")
- if err != nil {
- return err
- }
- *x = CriuCgMode(value)
- return nil
-}
-func (CriuCgMode) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
-
-type CriuReqType int32
-
-const (
- CriuReqType_EMPTY CriuReqType = 0
- CriuReqType_DUMP CriuReqType = 1
- CriuReqType_RESTORE CriuReqType = 2
- CriuReqType_CHECK CriuReqType = 3
- CriuReqType_PRE_DUMP CriuReqType = 4
- CriuReqType_PAGE_SERVER CriuReqType = 5
- CriuReqType_NOTIFY CriuReqType = 6
- CriuReqType_CPUINFO_DUMP CriuReqType = 7
- CriuReqType_CPUINFO_CHECK CriuReqType = 8
- CriuReqType_FEATURE_CHECK CriuReqType = 9
- CriuReqType_VERSION CriuReqType = 10
- CriuReqType_WAIT_PID CriuReqType = 11
- CriuReqType_PAGE_SERVER_CHLD CriuReqType = 12
-)
-
-var CriuReqType_name = map[int32]string{
- 0: "EMPTY",
- 1: "DUMP",
- 2: "RESTORE",
- 3: "CHECK",
- 4: "PRE_DUMP",
- 5: "PAGE_SERVER",
- 6: "NOTIFY",
- 7: "CPUINFO_DUMP",
- 8: "CPUINFO_CHECK",
- 9: "FEATURE_CHECK",
- 10: "VERSION",
- 11: "WAIT_PID",
- 12: "PAGE_SERVER_CHLD",
-}
-var CriuReqType_value = map[string]int32{
- "EMPTY": 0,
- "DUMP": 1,
- "RESTORE": 2,
- "CHECK": 3,
- "PRE_DUMP": 4,
- "PAGE_SERVER": 5,
- "NOTIFY": 6,
- "CPUINFO_DUMP": 7,
- "CPUINFO_CHECK": 8,
- "FEATURE_CHECK": 9,
- "VERSION": 10,
- "WAIT_PID": 11,
- "PAGE_SERVER_CHLD": 12,
-}
-
-func (x CriuReqType) Enum() *CriuReqType {
- p := new(CriuReqType)
- *p = x
- return p
-}
-func (x CriuReqType) String() string {
- return proto.EnumName(CriuReqType_name, int32(x))
-}
-func (x *CriuReqType) UnmarshalJSON(data []byte) error {
- value, err := proto.UnmarshalJSONEnum(CriuReqType_value, data, "CriuReqType")
- if err != nil {
- return err
- }
- *x = CriuReqType(value)
- return nil
-}
-func (CriuReqType) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
-
-type CriuPageServerInfo struct {
- Address *string `protobuf:"bytes,1,opt,name=address" json:"address,omitempty"`
- Port *int32 `protobuf:"varint,2,opt,name=port" json:"port,omitempty"`
- Pid *int32 `protobuf:"varint,3,opt,name=pid" json:"pid,omitempty"`
- Fd *int32 `protobuf:"varint,4,opt,name=fd" json:"fd,omitempty"`
- XXX_unrecognized []byte `json:"-"`
-}
-
-func (m *CriuPageServerInfo) Reset() { *m = CriuPageServerInfo{} }
-func (m *CriuPageServerInfo) String() string { return proto.CompactTextString(m) }
-func (*CriuPageServerInfo) ProtoMessage() {}
-func (*CriuPageServerInfo) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
-
-func (m *CriuPageServerInfo) GetAddress() string {
- if m != nil && m.Address != nil {
- return *m.Address
- }
- return ""
-}
-
-func (m *CriuPageServerInfo) GetPort() int32 {
- if m != nil && m.Port != nil {
- return *m.Port
- }
- return 0
-}
-
-func (m *CriuPageServerInfo) GetPid() int32 {
- if m != nil && m.Pid != nil {
- return *m.Pid
- }
- return 0
-}
-
-func (m *CriuPageServerInfo) GetFd() int32 {
- if m != nil && m.Fd != nil {
- return *m.Fd
- }
- return 0
-}
-
-type CriuVethPair struct {
- IfIn *string `protobuf:"bytes,1,req,name=if_in,json=ifIn" json:"if_in,omitempty"`
- IfOut *string `protobuf:"bytes,2,req,name=if_out,json=ifOut" json:"if_out,omitempty"`
- XXX_unrecognized []byte `json:"-"`
-}
-
-func (m *CriuVethPair) Reset() { *m = CriuVethPair{} }
-func (m *CriuVethPair) String() string { return proto.CompactTextString(m) }
-func (*CriuVethPair) ProtoMessage() {}
-func (*CriuVethPair) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
-
-func (m *CriuVethPair) GetIfIn() string {
- if m != nil && m.IfIn != nil {
- return *m.IfIn
- }
- return ""
-}
-
-func (m *CriuVethPair) GetIfOut() string {
- if m != nil && m.IfOut != nil {
- return *m.IfOut
- }
- return ""
-}
-
-type ExtMountMap struct {
- Key *string `protobuf:"bytes,1,req,name=key" json:"key,omitempty"`
- Val *string `protobuf:"bytes,2,req,name=val" json:"val,omitempty"`
- XXX_unrecognized []byte `json:"-"`
-}
-
-func (m *ExtMountMap) Reset() { *m = ExtMountMap{} }
-func (m *ExtMountMap) String() string { return proto.CompactTextString(m) }
-func (*ExtMountMap) ProtoMessage() {}
-func (*ExtMountMap) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} }
-
-func (m *ExtMountMap) GetKey() string {
- if m != nil && m.Key != nil {
- return *m.Key
- }
- return ""
-}
-
-func (m *ExtMountMap) GetVal() string {
- if m != nil && m.Val != nil {
- return *m.Val
- }
- return ""
-}
-
-type JoinNamespace struct {
- Ns *string `protobuf:"bytes,1,req,name=ns" json:"ns,omitempty"`
- NsFile *string `protobuf:"bytes,2,req,name=ns_file,json=nsFile" json:"ns_file,omitempty"`
- ExtraOpt *string `protobuf:"bytes,3,opt,name=extra_opt,json=extraOpt" json:"extra_opt,omitempty"`
- XXX_unrecognized []byte `json:"-"`
-}
-
-func (m *JoinNamespace) Reset() { *m = JoinNamespace{} }
-func (m *JoinNamespace) String() string { return proto.CompactTextString(m) }
-func (*JoinNamespace) ProtoMessage() {}
-func (*JoinNamespace) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} }
-
-func (m *JoinNamespace) GetNs() string {
- if m != nil && m.Ns != nil {
- return *m.Ns
- }
- return ""
-}
-
-func (m *JoinNamespace) GetNsFile() string {
- if m != nil && m.NsFile != nil {
- return *m.NsFile
- }
- return ""
-}
-
-func (m *JoinNamespace) GetExtraOpt() string {
- if m != nil && m.ExtraOpt != nil {
- return *m.ExtraOpt
- }
- return ""
-}
-
-type InheritFd struct {
- Key *string `protobuf:"bytes,1,req,name=key" json:"key,omitempty"`
- Fd *int32 `protobuf:"varint,2,req,name=fd" json:"fd,omitempty"`
- XXX_unrecognized []byte `json:"-"`
-}
-
-func (m *InheritFd) Reset() { *m = InheritFd{} }
-func (m *InheritFd) String() string { return proto.CompactTextString(m) }
-func (*InheritFd) ProtoMessage() {}
-func (*InheritFd) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} }
-
-func (m *InheritFd) GetKey() string {
- if m != nil && m.Key != nil {
- return *m.Key
- }
- return ""
-}
-
-func (m *InheritFd) GetFd() int32 {
- if m != nil && m.Fd != nil {
- return *m.Fd
- }
- return 0
-}
-
-type CgroupRoot struct {
- Ctrl *string `protobuf:"bytes,1,opt,name=ctrl" json:"ctrl,omitempty"`
- Path *string `protobuf:"bytes,2,req,name=path" json:"path,omitempty"`
- XXX_unrecognized []byte `json:"-"`
-}
-
-func (m *CgroupRoot) Reset() { *m = CgroupRoot{} }
-func (m *CgroupRoot) String() string { return proto.CompactTextString(m) }
-func (*CgroupRoot) ProtoMessage() {}
-func (*CgroupRoot) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} }
-
-func (m *CgroupRoot) GetCtrl() string {
- if m != nil && m.Ctrl != nil {
- return *m.Ctrl
- }
- return ""
-}
-
-func (m *CgroupRoot) GetPath() string {
- if m != nil && m.Path != nil {
- return *m.Path
- }
- return ""
-}
-
-type UnixSk struct {
- Inode *uint32 `protobuf:"varint,1,req,name=inode" json:"inode,omitempty"`
- XXX_unrecognized []byte `json:"-"`
-}
-
-func (m *UnixSk) Reset() { *m = UnixSk{} }
-func (m *UnixSk) String() string { return proto.CompactTextString(m) }
-func (*UnixSk) ProtoMessage() {}
-func (*UnixSk) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{6} }
-
-func (m *UnixSk) GetInode() uint32 {
- if m != nil && m.Inode != nil {
- return *m.Inode
- }
- return 0
-}
-
-type CriuOpts struct {
- ImagesDirFd *int32 `protobuf:"varint,1,req,name=images_dir_fd,json=imagesDirFd" json:"images_dir_fd,omitempty"`
- Pid *int32 `protobuf:"varint,2,opt,name=pid" json:"pid,omitempty"`
- LeaveRunning *bool `protobuf:"varint,3,opt,name=leave_running,json=leaveRunning" json:"leave_running,omitempty"`
- ExtUnixSk *bool `protobuf:"varint,4,opt,name=ext_unix_sk,json=extUnixSk" json:"ext_unix_sk,omitempty"`
- TcpEstablished *bool `protobuf:"varint,5,opt,name=tcp_established,json=tcpEstablished" json:"tcp_established,omitempty"`
- EvasiveDevices *bool `protobuf:"varint,6,opt,name=evasive_devices,json=evasiveDevices" json:"evasive_devices,omitempty"`
- ShellJob *bool `protobuf:"varint,7,opt,name=shell_job,json=shellJob" json:"shell_job,omitempty"`
- FileLocks *bool `protobuf:"varint,8,opt,name=file_locks,json=fileLocks" json:"file_locks,omitempty"`
- LogLevel *int32 `protobuf:"varint,9,opt,name=log_level,json=logLevel,def=2" json:"log_level,omitempty"`
- LogFile *string `protobuf:"bytes,10,opt,name=log_file,json=logFile" json:"log_file,omitempty"`
- Ps *CriuPageServerInfo `protobuf:"bytes,11,opt,name=ps" json:"ps,omitempty"`
- NotifyScripts *bool `protobuf:"varint,12,opt,name=notify_scripts,json=notifyScripts" json:"notify_scripts,omitempty"`
- Root *string `protobuf:"bytes,13,opt,name=root" json:"root,omitempty"`
- ParentImg *string `protobuf:"bytes,14,opt,name=parent_img,json=parentImg" json:"parent_img,omitempty"`
- TrackMem *bool `protobuf:"varint,15,opt,name=track_mem,json=trackMem" json:"track_mem,omitempty"`
- AutoDedup *bool `protobuf:"varint,16,opt,name=auto_dedup,json=autoDedup" json:"auto_dedup,omitempty"`
- WorkDirFd *int32 `protobuf:"varint,17,opt,name=work_dir_fd,json=workDirFd" json:"work_dir_fd,omitempty"`
- LinkRemap *bool `protobuf:"varint,18,opt,name=link_remap,json=linkRemap" json:"link_remap,omitempty"`
- Veths []*CriuVethPair `protobuf:"bytes,19,rep,name=veths" json:"veths,omitempty"`
- CpuCap *uint32 `protobuf:"varint,20,opt,name=cpu_cap,json=cpuCap,def=4294967295" json:"cpu_cap,omitempty"`
- ForceIrmap *bool `protobuf:"varint,21,opt,name=force_irmap,json=forceIrmap" json:"force_irmap,omitempty"`
- ExecCmd []string `protobuf:"bytes,22,rep,name=exec_cmd,json=execCmd" json:"exec_cmd,omitempty"`
- ExtMnt []*ExtMountMap `protobuf:"bytes,23,rep,name=ext_mnt,json=extMnt" json:"ext_mnt,omitempty"`
- ManageCgroups *bool `protobuf:"varint,24,opt,name=manage_cgroups,json=manageCgroups" json:"manage_cgroups,omitempty"`
- CgRoot []*CgroupRoot `protobuf:"bytes,25,rep,name=cg_root,json=cgRoot" json:"cg_root,omitempty"`
- RstSibling *bool `protobuf:"varint,26,opt,name=rst_sibling,json=rstSibling" json:"rst_sibling,omitempty"`
- InheritFd []*InheritFd `protobuf:"bytes,27,rep,name=inherit_fd,json=inheritFd" json:"inherit_fd,omitempty"`
- AutoExtMnt *bool `protobuf:"varint,28,opt,name=auto_ext_mnt,json=autoExtMnt" json:"auto_ext_mnt,omitempty"`
- ExtSharing *bool `protobuf:"varint,29,opt,name=ext_sharing,json=extSharing" json:"ext_sharing,omitempty"`
- ExtMasters *bool `protobuf:"varint,30,opt,name=ext_masters,json=extMasters" json:"ext_masters,omitempty"`
- SkipMnt []string `protobuf:"bytes,31,rep,name=skip_mnt,json=skipMnt" json:"skip_mnt,omitempty"`
- EnableFs []string `protobuf:"bytes,32,rep,name=enable_fs,json=enableFs" json:"enable_fs,omitempty"`
- UnixSkIno []*UnixSk `protobuf:"bytes,33,rep,name=unix_sk_ino,json=unixSkIno" json:"unix_sk_ino,omitempty"`
- ManageCgroupsMode *CriuCgMode `protobuf:"varint,34,opt,name=manage_cgroups_mode,json=manageCgroupsMode,enum=CriuCgMode" json:"manage_cgroups_mode,omitempty"`
- GhostLimit *uint32 `protobuf:"varint,35,opt,name=ghost_limit,json=ghostLimit,def=1048576" json:"ghost_limit,omitempty"`
- IrmapScanPaths []string `protobuf:"bytes,36,rep,name=irmap_scan_paths,json=irmapScanPaths" json:"irmap_scan_paths,omitempty"`
- External []string `protobuf:"bytes,37,rep,name=external" json:"external,omitempty"`
- EmptyNs *uint32 `protobuf:"varint,38,opt,name=empty_ns,json=emptyNs" json:"empty_ns,omitempty"`
- JoinNs []*JoinNamespace `protobuf:"bytes,39,rep,name=join_ns,json=joinNs" json:"join_ns,omitempty"`
- CgroupProps *string `protobuf:"bytes,41,opt,name=cgroup_props,json=cgroupProps" json:"cgroup_props,omitempty"`
- CgroupPropsFile *string `protobuf:"bytes,42,opt,name=cgroup_props_file,json=cgroupPropsFile" json:"cgroup_props_file,omitempty"`
- CgroupDumpController []string `protobuf:"bytes,43,rep,name=cgroup_dump_controller,json=cgroupDumpController" json:"cgroup_dump_controller,omitempty"`
- FreezeCgroup *string `protobuf:"bytes,44,opt,name=freeze_cgroup,json=freezeCgroup" json:"freeze_cgroup,omitempty"`
- Timeout *uint32 `protobuf:"varint,45,opt,name=timeout" json:"timeout,omitempty"`
- TcpSkipInFlight *bool `protobuf:"varint,46,opt,name=tcp_skip_in_flight,json=tcpSkipInFlight" json:"tcp_skip_in_flight,omitempty"`
- WeakSysctls *bool `protobuf:"varint,47,opt,name=weak_sysctls,json=weakSysctls" json:"weak_sysctls,omitempty"`
- LazyPages *bool `protobuf:"varint,48,opt,name=lazy_pages,json=lazyPages" json:"lazy_pages,omitempty"`
- StatusFd *int32 `protobuf:"varint,49,opt,name=status_fd,json=statusFd" json:"status_fd,omitempty"`
- OrphanPtsMaster *bool `protobuf:"varint,50,opt,name=orphan_pts_master,json=orphanPtsMaster" json:"orphan_pts_master,omitempty"`
- ConfigFile *string `protobuf:"bytes,51,opt,name=config_file,json=configFile" json:"config_file,omitempty"`
- XXX_unrecognized []byte `json:"-"`
-}
-
-func (m *CriuOpts) Reset() { *m = CriuOpts{} }
-func (m *CriuOpts) String() string { return proto.CompactTextString(m) }
-func (*CriuOpts) ProtoMessage() {}
-func (*CriuOpts) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{7} }
-
-const Default_CriuOpts_LogLevel int32 = 2
-const Default_CriuOpts_CpuCap uint32 = 4294967295
-const Default_CriuOpts_GhostLimit uint32 = 1048576
-
-func (m *CriuOpts) GetImagesDirFd() int32 {
- if m != nil && m.ImagesDirFd != nil {
- return *m.ImagesDirFd
- }
- return 0
-}
-
-func (m *CriuOpts) GetPid() int32 {
- if m != nil && m.Pid != nil {
- return *m.Pid
- }
- return 0
-}
-
-func (m *CriuOpts) GetLeaveRunning() bool {
- if m != nil && m.LeaveRunning != nil {
- return *m.LeaveRunning
- }
- return false
-}
-
-func (m *CriuOpts) GetExtUnixSk() bool {
- if m != nil && m.ExtUnixSk != nil {
- return *m.ExtUnixSk
- }
- return false
-}
-
-func (m *CriuOpts) GetTcpEstablished() bool {
- if m != nil && m.TcpEstablished != nil {
- return *m.TcpEstablished
- }
- return false
-}
-
-func (m *CriuOpts) GetEvasiveDevices() bool {
- if m != nil && m.EvasiveDevices != nil {
- return *m.EvasiveDevices
- }
- return false
-}
-
-func (m *CriuOpts) GetShellJob() bool {
- if m != nil && m.ShellJob != nil {
- return *m.ShellJob
- }
- return false
-}
-
-func (m *CriuOpts) GetFileLocks() bool {
- if m != nil && m.FileLocks != nil {
- return *m.FileLocks
- }
- return false
-}
-
-func (m *CriuOpts) GetLogLevel() int32 {
- if m != nil && m.LogLevel != nil {
- return *m.LogLevel
- }
- return Default_CriuOpts_LogLevel
-}
-
-func (m *CriuOpts) GetLogFile() string {
- if m != nil && m.LogFile != nil {
- return *m.LogFile
- }
- return ""
-}
-
-func (m *CriuOpts) GetPs() *CriuPageServerInfo {
- if m != nil {
- return m.Ps
- }
- return nil
-}
-
-func (m *CriuOpts) GetNotifyScripts() bool {
- if m != nil && m.NotifyScripts != nil {
- return *m.NotifyScripts
- }
- return false
-}
-
-func (m *CriuOpts) GetRoot() string {
- if m != nil && m.Root != nil {
- return *m.Root
- }
- return ""
-}
-
-func (m *CriuOpts) GetParentImg() string {
- if m != nil && m.ParentImg != nil {
- return *m.ParentImg
- }
- return ""
-}
-
-func (m *CriuOpts) GetTrackMem() bool {
- if m != nil && m.TrackMem != nil {
- return *m.TrackMem
- }
- return false
-}
-
-func (m *CriuOpts) GetAutoDedup() bool {
- if m != nil && m.AutoDedup != nil {
- return *m.AutoDedup
- }
- return false
-}
-
-func (m *CriuOpts) GetWorkDirFd() int32 {
- if m != nil && m.WorkDirFd != nil {
- return *m.WorkDirFd
- }
- return 0
-}
-
-func (m *CriuOpts) GetLinkRemap() bool {
- if m != nil && m.LinkRemap != nil {
- return *m.LinkRemap
- }
- return false
-}
-
-func (m *CriuOpts) GetVeths() []*CriuVethPair {
- if m != nil {
- return m.Veths
- }
- return nil
-}
-
-func (m *CriuOpts) GetCpuCap() uint32 {
- if m != nil && m.CpuCap != nil {
- return *m.CpuCap
- }
- return Default_CriuOpts_CpuCap
-}
-
-func (m *CriuOpts) GetForceIrmap() bool {
- if m != nil && m.ForceIrmap != nil {
- return *m.ForceIrmap
- }
- return false
-}
-
-func (m *CriuOpts) GetExecCmd() []string {
- if m != nil {
- return m.ExecCmd
- }
- return nil
-}
-
-func (m *CriuOpts) GetExtMnt() []*ExtMountMap {
- if m != nil {
- return m.ExtMnt
- }
- return nil
-}
-
-func (m *CriuOpts) GetManageCgroups() bool {
- if m != nil && m.ManageCgroups != nil {
- return *m.ManageCgroups
- }
- return false
-}
-
-func (m *CriuOpts) GetCgRoot() []*CgroupRoot {
- if m != nil {
- return m.CgRoot
- }
- return nil
-}
-
-func (m *CriuOpts) GetRstSibling() bool {
- if m != nil && m.RstSibling != nil {
- return *m.RstSibling
- }
- return false
-}
-
-func (m *CriuOpts) GetInheritFd() []*InheritFd {
- if m != nil {
- return m.InheritFd
- }
- return nil
-}
-
-func (m *CriuOpts) GetAutoExtMnt() bool {
- if m != nil && m.AutoExtMnt != nil {
- return *m.AutoExtMnt
- }
- return false
-}
-
-func (m *CriuOpts) GetExtSharing() bool {
- if m != nil && m.ExtSharing != nil {
- return *m.ExtSharing
- }
- return false
-}
-
-func (m *CriuOpts) GetExtMasters() bool {
- if m != nil && m.ExtMasters != nil {
- return *m.ExtMasters
- }
- return false
-}
-
-func (m *CriuOpts) GetSkipMnt() []string {
- if m != nil {
- return m.SkipMnt
- }
- return nil
-}
-
-func (m *CriuOpts) GetEnableFs() []string {
- if m != nil {
- return m.EnableFs
- }
- return nil
-}
-
-func (m *CriuOpts) GetUnixSkIno() []*UnixSk {
- if m != nil {
- return m.UnixSkIno
- }
- return nil
-}
-
-func (m *CriuOpts) GetManageCgroupsMode() CriuCgMode {
- if m != nil && m.ManageCgroupsMode != nil {
- return *m.ManageCgroupsMode
- }
- return CriuCgMode_IGNORE
-}
-
-func (m *CriuOpts) GetGhostLimit() uint32 {
- if m != nil && m.GhostLimit != nil {
- return *m.GhostLimit
- }
- return Default_CriuOpts_GhostLimit
-}
-
-func (m *CriuOpts) GetIrmapScanPaths() []string {
- if m != nil {
- return m.IrmapScanPaths
- }
- return nil
-}
-
-func (m *CriuOpts) GetExternal() []string {
- if m != nil {
- return m.External
- }
- return nil
-}
-
-func (m *CriuOpts) GetEmptyNs() uint32 {
- if m != nil && m.EmptyNs != nil {
- return *m.EmptyNs
- }
- return 0
-}
-
-func (m *CriuOpts) GetJoinNs() []*JoinNamespace {
- if m != nil {
- return m.JoinNs
- }
- return nil
-}
-
-func (m *CriuOpts) GetCgroupProps() string {
- if m != nil && m.CgroupProps != nil {
- return *m.CgroupProps
- }
- return ""
-}
-
-func (m *CriuOpts) GetCgroupPropsFile() string {
- if m != nil && m.CgroupPropsFile != nil {
- return *m.CgroupPropsFile
- }
- return ""
-}
-
-func (m *CriuOpts) GetCgroupDumpController() []string {
- if m != nil {
- return m.CgroupDumpController
- }
- return nil
-}
-
-func (m *CriuOpts) GetFreezeCgroup() string {
- if m != nil && m.FreezeCgroup != nil {
- return *m.FreezeCgroup
- }
- return ""
-}
-
-func (m *CriuOpts) GetTimeout() uint32 {
- if m != nil && m.Timeout != nil {
- return *m.Timeout
- }
- return 0
-}
-
-func (m *CriuOpts) GetTcpSkipInFlight() bool {
- if m != nil && m.TcpSkipInFlight != nil {
- return *m.TcpSkipInFlight
- }
- return false
-}
-
-func (m *CriuOpts) GetWeakSysctls() bool {
- if m != nil && m.WeakSysctls != nil {
- return *m.WeakSysctls
- }
- return false
-}
-
-func (m *CriuOpts) GetLazyPages() bool {
- if m != nil && m.LazyPages != nil {
- return *m.LazyPages
- }
- return false
-}
-
-func (m *CriuOpts) GetStatusFd() int32 {
- if m != nil && m.StatusFd != nil {
- return *m.StatusFd
- }
- return 0
-}
-
-func (m *CriuOpts) GetOrphanPtsMaster() bool {
- if m != nil && m.OrphanPtsMaster != nil {
- return *m.OrphanPtsMaster
- }
- return false
-}
-
-func (m *CriuOpts) GetConfigFile() string {
- if m != nil && m.ConfigFile != nil {
- return *m.ConfigFile
- }
- return ""
-}
-
-type CriuDumpResp struct {
- Restored *bool `protobuf:"varint,1,opt,name=restored" json:"restored,omitempty"`
- XXX_unrecognized []byte `json:"-"`
-}
-
-func (m *CriuDumpResp) Reset() { *m = CriuDumpResp{} }
-func (m *CriuDumpResp) String() string { return proto.CompactTextString(m) }
-func (*CriuDumpResp) ProtoMessage() {}
-func (*CriuDumpResp) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{8} }
-
-func (m *CriuDumpResp) GetRestored() bool {
- if m != nil && m.Restored != nil {
- return *m.Restored
- }
- return false
-}
-
-type CriuRestoreResp struct {
- Pid *int32 `protobuf:"varint,1,req,name=pid" json:"pid,omitempty"`
- XXX_unrecognized []byte `json:"-"`
-}
-
-func (m *CriuRestoreResp) Reset() { *m = CriuRestoreResp{} }
-func (m *CriuRestoreResp) String() string { return proto.CompactTextString(m) }
-func (*CriuRestoreResp) ProtoMessage() {}
-func (*CriuRestoreResp) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{9} }
-
-func (m *CriuRestoreResp) GetPid() int32 {
- if m != nil && m.Pid != nil {
- return *m.Pid
- }
- return 0
-}
-
-type CriuNotify struct {
- Script *string `protobuf:"bytes,1,opt,name=script" json:"script,omitempty"`
- Pid *int32 `protobuf:"varint,2,opt,name=pid" json:"pid,omitempty"`
- XXX_unrecognized []byte `json:"-"`
-}
-
-func (m *CriuNotify) Reset() { *m = CriuNotify{} }
-func (m *CriuNotify) String() string { return proto.CompactTextString(m) }
-func (*CriuNotify) ProtoMessage() {}
-func (*CriuNotify) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{10} }
-
-func (m *CriuNotify) GetScript() string {
- if m != nil && m.Script != nil {
- return *m.Script
- }
- return ""
-}
-
-func (m *CriuNotify) GetPid() int32 {
- if m != nil && m.Pid != nil {
- return *m.Pid
- }
- return 0
-}
-
-//
-// List of features which can queried via
-// CRIU_REQ_TYPE__FEATURE_CHECK
-type CriuFeatures struct {
- MemTrack *bool `protobuf:"varint,1,opt,name=mem_track,json=memTrack" json:"mem_track,omitempty"`
- LazyPages *bool `protobuf:"varint,2,opt,name=lazy_pages,json=lazyPages" json:"lazy_pages,omitempty"`
- XXX_unrecognized []byte `json:"-"`
-}
-
-func (m *CriuFeatures) Reset() { *m = CriuFeatures{} }
-func (m *CriuFeatures) String() string { return proto.CompactTextString(m) }
-func (*CriuFeatures) ProtoMessage() {}
-func (*CriuFeatures) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{11} }
-
-func (m *CriuFeatures) GetMemTrack() bool {
- if m != nil && m.MemTrack != nil {
- return *m.MemTrack
- }
- return false
-}
-
-func (m *CriuFeatures) GetLazyPages() bool {
- if m != nil && m.LazyPages != nil {
- return *m.LazyPages
- }
- return false
-}
-
-type CriuReq struct {
- Type *CriuReqType `protobuf:"varint,1,req,name=type,enum=CriuReqType" json:"type,omitempty"`
- Opts *CriuOpts `protobuf:"bytes,2,opt,name=opts" json:"opts,omitempty"`
- NotifySuccess *bool `protobuf:"varint,3,opt,name=notify_success,json=notifySuccess" json:"notify_success,omitempty"`
- //
- // When set service won't close the connection but
- // will wait for more req-s to appear. Works not
- // for all request types.
- KeepOpen *bool `protobuf:"varint,4,opt,name=keep_open,json=keepOpen" json:"keep_open,omitempty"`
- //
- // 'features' can be used to query which features
- // are supported by the installed criu/kernel
- // via RPC.
- Features *CriuFeatures `protobuf:"bytes,5,opt,name=features" json:"features,omitempty"`
- // 'pid' is used for WAIT_PID
- Pid *uint32 `protobuf:"varint,6,opt,name=pid" json:"pid,omitempty"`
- XXX_unrecognized []byte `json:"-"`
-}
-
-func (m *CriuReq) Reset() { *m = CriuReq{} }
-func (m *CriuReq) String() string { return proto.CompactTextString(m) }
-func (*CriuReq) ProtoMessage() {}
-func (*CriuReq) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{12} }
-
-func (m *CriuReq) GetType() CriuReqType {
- if m != nil && m.Type != nil {
- return *m.Type
- }
- return CriuReqType_EMPTY
-}
-
-func (m *CriuReq) GetOpts() *CriuOpts {
- if m != nil {
- return m.Opts
- }
- return nil
-}
-
-func (m *CriuReq) GetNotifySuccess() bool {
- if m != nil && m.NotifySuccess != nil {
- return *m.NotifySuccess
- }
- return false
-}
-
-func (m *CriuReq) GetKeepOpen() bool {
- if m != nil && m.KeepOpen != nil {
- return *m.KeepOpen
- }
- return false
-}
-
-func (m *CriuReq) GetFeatures() *CriuFeatures {
- if m != nil {
- return m.Features
- }
- return nil
-}
-
-func (m *CriuReq) GetPid() uint32 {
- if m != nil && m.Pid != nil {
- return *m.Pid
- }
- return 0
-}
-
-type CriuResp struct {
- Type *CriuReqType `protobuf:"varint,1,req,name=type,enum=CriuReqType" json:"type,omitempty"`
- Success *bool `protobuf:"varint,2,req,name=success" json:"success,omitempty"`
- Dump *CriuDumpResp `protobuf:"bytes,3,opt,name=dump" json:"dump,omitempty"`
- Restore *CriuRestoreResp `protobuf:"bytes,4,opt,name=restore" json:"restore,omitempty"`
- Notify *CriuNotify `protobuf:"bytes,5,opt,name=notify" json:"notify,omitempty"`
- Ps *CriuPageServerInfo `protobuf:"bytes,6,opt,name=ps" json:"ps,omitempty"`
- CrErrno *int32 `protobuf:"varint,7,opt,name=cr_errno,json=crErrno" json:"cr_errno,omitempty"`
- Features *CriuFeatures `protobuf:"bytes,8,opt,name=features" json:"features,omitempty"`
- CrErrmsg *string `protobuf:"bytes,9,opt,name=cr_errmsg,json=crErrmsg" json:"cr_errmsg,omitempty"`
- Version *CriuVersion `protobuf:"bytes,10,opt,name=version" json:"version,omitempty"`
- Status *int32 `protobuf:"varint,11,opt,name=status" json:"status,omitempty"`
- XXX_unrecognized []byte `json:"-"`
-}
-
-func (m *CriuResp) Reset() { *m = CriuResp{} }
-func (m *CriuResp) String() string { return proto.CompactTextString(m) }
-func (*CriuResp) ProtoMessage() {}
-func (*CriuResp) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{13} }
-
-func (m *CriuResp) GetType() CriuReqType {
- if m != nil && m.Type != nil {
- return *m.Type
- }
- return CriuReqType_EMPTY
-}
-
-func (m *CriuResp) GetSuccess() bool {
- if m != nil && m.Success != nil {
- return *m.Success
- }
- return false
-}
-
-func (m *CriuResp) GetDump() *CriuDumpResp {
- if m != nil {
- return m.Dump
- }
- return nil
-}
-
-func (m *CriuResp) GetRestore() *CriuRestoreResp {
- if m != nil {
- return m.Restore
- }
- return nil
-}
-
-func (m *CriuResp) GetNotify() *CriuNotify {
- if m != nil {
- return m.Notify
- }
- return nil
-}
-
-func (m *CriuResp) GetPs() *CriuPageServerInfo {
- if m != nil {
- return m.Ps
- }
- return nil
-}
-
-func (m *CriuResp) GetCrErrno() int32 {
- if m != nil && m.CrErrno != nil {
- return *m.CrErrno
- }
- return 0
-}
-
-func (m *CriuResp) GetFeatures() *CriuFeatures {
- if m != nil {
- return m.Features
- }
- return nil
-}
-
-func (m *CriuResp) GetCrErrmsg() string {
- if m != nil && m.CrErrmsg != nil {
- return *m.CrErrmsg
- }
- return ""
-}
-
-func (m *CriuResp) GetVersion() *CriuVersion {
- if m != nil {
- return m.Version
- }
- return nil
-}
-
-func (m *CriuResp) GetStatus() int32 {
- if m != nil && m.Status != nil {
- return *m.Status
- }
- return 0
-}
-
-// Answer for criu_req_type.VERSION requests
-type CriuVersion struct {
- Major *int32 `protobuf:"varint,1,req,name=major" json:"major,omitempty"`
- Minor *int32 `protobuf:"varint,2,req,name=minor" json:"minor,omitempty"`
- Gitid *string `protobuf:"bytes,3,opt,name=gitid" json:"gitid,omitempty"`
- Sublevel *int32 `protobuf:"varint,4,opt,name=sublevel" json:"sublevel,omitempty"`
- Extra *int32 `protobuf:"varint,5,opt,name=extra" json:"extra,omitempty"`
- Name *string `protobuf:"bytes,6,opt,name=name" json:"name,omitempty"`
- XXX_unrecognized []byte `json:"-"`
-}
-
-func (m *CriuVersion) Reset() { *m = CriuVersion{} }
-func (m *CriuVersion) String() string { return proto.CompactTextString(m) }
-func (*CriuVersion) ProtoMessage() {}
-func (*CriuVersion) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{14} }
-
-func (m *CriuVersion) GetMajor() int32 {
- if m != nil && m.Major != nil {
- return *m.Major
- }
- return 0
-}
-
-func (m *CriuVersion) GetMinor() int32 {
- if m != nil && m.Minor != nil {
- return *m.Minor
- }
- return 0
-}
-
-func (m *CriuVersion) GetGitid() string {
- if m != nil && m.Gitid != nil {
- return *m.Gitid
- }
- return ""
-}
-
-func (m *CriuVersion) GetSublevel() int32 {
- if m != nil && m.Sublevel != nil {
- return *m.Sublevel
- }
- return 0
-}
-
-func (m *CriuVersion) GetExtra() int32 {
- if m != nil && m.Extra != nil {
- return *m.Extra
- }
- return 0
-}
-
-func (m *CriuVersion) GetName() string {
- if m != nil && m.Name != nil {
- return *m.Name
- }
- return ""
-}
-
-func init() {
- proto.RegisterType((*CriuPageServerInfo)(nil), "criu_page_server_info")
- proto.RegisterType((*CriuVethPair)(nil), "criu_veth_pair")
- proto.RegisterType((*ExtMountMap)(nil), "ext_mount_map")
- proto.RegisterType((*JoinNamespace)(nil), "join_namespace")
- proto.RegisterType((*InheritFd)(nil), "inherit_fd")
- proto.RegisterType((*CgroupRoot)(nil), "cgroup_root")
- proto.RegisterType((*UnixSk)(nil), "unix_sk")
- proto.RegisterType((*CriuOpts)(nil), "criu_opts")
- proto.RegisterType((*CriuDumpResp)(nil), "criu_dump_resp")
- proto.RegisterType((*CriuRestoreResp)(nil), "criu_restore_resp")
- proto.RegisterType((*CriuNotify)(nil), "criu_notify")
- proto.RegisterType((*CriuFeatures)(nil), "criu_features")
- proto.RegisterType((*CriuReq)(nil), "criu_req")
- proto.RegisterType((*CriuResp)(nil), "criu_resp")
- proto.RegisterType((*CriuVersion)(nil), "criu_version")
- proto.RegisterEnum("CriuCgMode", CriuCgMode_name, CriuCgMode_value)
- proto.RegisterEnum("CriuReqType", CriuReqType_name, CriuReqType_value)
-}
-
-func init() { proto.RegisterFile("rpc/rpc.proto", fileDescriptor0) }
-
-var fileDescriptor0 = []byte{
- // 1835 bytes of a gzipped FileDescriptorProto
- 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x56, 0xeb, 0x72, 0x5b, 0xb7,
- 0x11, 0x0e, 0x29, 0xf1, 0x06, 0x5e, 0x7c, 0x0c, 0x5f, 0x02, 0xc7, 0xb5, 0xad, 0xd0, 0x51, 0xa2,
- 0x2a, 0x2e, 0x93, 0x30, 0x76, 0x5c, 0x67, 0xda, 0x1f, 0x1e, 0x8a, 0x74, 0xd8, 0x48, 0x22, 0x07,
- 0xa4, 0xdc, 0xc9, 0x2f, 0xcc, 0xd1, 0x39, 0x20, 0x05, 0xf3, 0xdc, 0x0a, 0x80, 0x8a, 0xe4, 0x97,
- 0xe8, 0xbf, 0x3e, 0x57, 0xde, 0xa4, 0xaf, 0xd0, 0xd9, 0x05, 0x28, 0x4b, 0x49, 0x66, 0xd2, 0x7f,
- 0xd8, 0x0f, 0xbb, 0xc0, 0xde, 0x77, 0x49, 0x5b, 0x17, 0xd1, 0x57, 0xba, 0x88, 0x7a, 0x85, 0xce,
- 0x6d, 0xde, 0x5d, 0x92, 0x7b, 0x91, 0x56, 0x6b, 0x51, 0x84, 0x4b, 0x29, 0x8c, 0xd4, 0xe7, 0x52,
- 0x0b, 0x95, 0x2d, 0x72, 0xca, 0x48, 0x2d, 0x8c, 0x63, 0x2d, 0x8d, 0x61, 0xa5, 0x9d, 0xd2, 0x5e,
- 0x83, 0x6f, 0x48, 0x4a, 0xc9, 0x76, 0x91, 0x6b, 0xcb, 0xca, 0x3b, 0xa5, 0xbd, 0x0a, 0xc7, 0x33,
- 0x0d, 0xc8, 0x56, 0xa1, 0x62, 0xb6, 0x85, 0x10, 0x1c, 0x69, 0x87, 0x94, 0x17, 0x31, 0xdb, 0x46,
- 0xa0, 0xbc, 0x88, 0xbb, 0x7f, 0x23, 0x1d, 0xfc, 0xe8, 0x5c, 0xda, 0x33, 0x51, 0x84, 0x4a, 0xd3,
- 0x3b, 0xa4, 0xa2, 0x16, 0x42, 0x65, 0xac, 0xb4, 0x53, 0xde, 0x6b, 0xf0, 0x6d, 0xb5, 0x18, 0x67,
- 0xf4, 0x1e, 0xa9, 0xaa, 0x85, 0xc8, 0xd7, 0xf0, 0x3c, 0xa0, 0x15, 0xb5, 0x98, 0xac, 0x6d, 0xf7,
- 0x5b, 0xd2, 0x96, 0x17, 0x56, 0xa4, 0xf9, 0x3a, 0xb3, 0x22, 0x0d, 0x0b, 0xf8, 0x70, 0x25, 0x2f,
- 0xbd, 0x28, 0x1c, 0x01, 0x39, 0x0f, 0x13, 0x2f, 0x06, 0xc7, 0xee, 0x5b, 0xd2, 0x79, 0x97, 0xab,
- 0x4c, 0x64, 0x61, 0x2a, 0x4d, 0x11, 0x46, 0x12, 0x94, 0xca, 0x8c, 0x17, 0x2a, 0x67, 0x86, 0x7e,
- 0x4c, 0x6a, 0x99, 0x11, 0x0b, 0x95, 0x48, 0x2f, 0x57, 0xcd, 0xcc, 0x48, 0x25, 0x92, 0x3e, 0x24,
- 0x0d, 0x79, 0x61, 0x75, 0x28, 0xf2, 0xc2, 0xa2, 0x55, 0x0d, 0x5e, 0x47, 0x60, 0x52, 0xd8, 0x6e,
- 0x8f, 0x10, 0x95, 0x9d, 0x49, 0xad, 0xac, 0x58, 0xc4, 0xbf, 0xa3, 0x89, 0x33, 0x1d, 0x1e, 0x74,
- 0xa6, 0xbf, 0x20, 0xcd, 0x68, 0xa9, 0xf3, 0x75, 0x21, 0x74, 0x9e, 0x5b, 0xf0, 0x5f, 0x64, 0x75,
- 0xe2, 0xdd, 0x8a, 0x67, 0xf4, 0x69, 0x68, 0xcf, 0xbc, 0x16, 0x78, 0xee, 0x3e, 0x21, 0xb5, 0x75,
- 0xa6, 0x2e, 0x84, 0x59, 0xd1, 0xbb, 0xa4, 0xa2, 0xb2, 0x3c, 0x96, 0xf8, 0x4b, 0x9b, 0x3b, 0xa2,
- 0xfb, 0xdf, 0x36, 0x69, 0xa0, 0x4f, 0xf3, 0xc2, 0x1a, 0xda, 0x25, 0x6d, 0x95, 0x86, 0x4b, 0x69,
- 0x44, 0xac, 0xb4, 0x58, 0xc4, 0xc8, 0x5b, 0xe1, 0x4d, 0x07, 0x1e, 0x28, 0x3d, 0x8a, 0x37, 0x61,
- 0x2a, 0x7f, 0x08, 0xd3, 0x53, 0xd2, 0x4e, 0x64, 0x78, 0x2e, 0x85, 0x5e, 0x67, 0x99, 0xca, 0x96,
- 0x68, 0x6c, 0x9d, 0xb7, 0x10, 0xe4, 0x0e, 0xa3, 0x8f, 0x49, 0x13, 0xbc, 0xef, 0xb5, 0xc1, 0xa0,
- 0xd6, 0x39, 0x38, 0xe8, 0x24, 0x53, 0x17, 0xb3, 0x15, 0xfd, 0x82, 0xdc, 0xb2, 0x51, 0x21, 0xa4,
- 0xb1, 0xe1, 0x69, 0xa2, 0xcc, 0x99, 0x8c, 0x59, 0x05, 0x79, 0x3a, 0x36, 0x2a, 0x86, 0x1f, 0x50,
- 0x60, 0x94, 0xe7, 0xa1, 0x51, 0xe7, 0x52, 0xc4, 0xf2, 0x5c, 0x45, 0xd2, 0xb0, 0xaa, 0x63, 0xf4,
- 0xf0, 0x81, 0x43, 0xc1, 0xff, 0xe6, 0x4c, 0x26, 0x89, 0x78, 0x97, 0x9f, 0xb2, 0x1a, 0xb2, 0xd4,
- 0x11, 0xf8, 0x47, 0x7e, 0x4a, 0x1f, 0x11, 0x02, 0x21, 0x13, 0x49, 0x1e, 0xad, 0x0c, 0xab, 0x3b,
- 0x6d, 0x00, 0x39, 0x04, 0x80, 0x3e, 0x26, 0x8d, 0x24, 0x5f, 0x8a, 0x44, 0x9e, 0xcb, 0x84, 0x35,
- 0xc0, 0xd4, 0xef, 0x4b, 0x7d, 0x5e, 0x4f, 0xf2, 0xe5, 0x21, 0x40, 0xf4, 0x01, 0x81, 0xb3, 0x8b,
- 0x3a, 0x71, 0xa9, 0x9d, 0xe4, 0x4b, 0x0c, 0xfb, 0xe7, 0xa4, 0x5c, 0x18, 0xd6, 0xdc, 0x29, 0xed,
- 0x35, 0xfb, 0xf7, 0x7b, 0xbf, 0x5b, 0x18, 0xbc, 0x5c, 0x18, 0xba, 0x4b, 0x3a, 0x59, 0x6e, 0xd5,
- 0xe2, 0x52, 0x98, 0x48, 0xab, 0xc2, 0x1a, 0xd6, 0x42, 0x2d, 0xda, 0x0e, 0x9d, 0x39, 0x10, 0xa2,
- 0x0a, 0x11, 0x67, 0x6d, 0x17, 0x69, 0x8c, 0xfe, 0x23, 0x42, 0x8a, 0x50, 0xcb, 0xcc, 0x0a, 0x95,
- 0x2e, 0x59, 0x07, 0x6f, 0x1a, 0x0e, 0x19, 0xa7, 0x4b, 0x30, 0xdc, 0xea, 0x30, 0x5a, 0x89, 0x54,
- 0xa6, 0xec, 0x96, 0x33, 0x1c, 0x81, 0x23, 0x99, 0x82, 0x6c, 0xb8, 0xb6, 0xb9, 0x88, 0x65, 0xbc,
- 0x2e, 0x58, 0xe0, 0x0c, 0x07, 0xe4, 0x00, 0x00, 0x08, 0xd3, 0xcf, 0xb9, 0x5e, 0x6d, 0xe2, 0x7f,
- 0x1b, 0xa3, 0xdc, 0x00, 0xc8, 0x45, 0xff, 0x11, 0x21, 0x89, 0xca, 0x56, 0x42, 0xcb, 0x34, 0x2c,
- 0x18, 0x75, 0xe2, 0x80, 0x70, 0x00, 0xe8, 0x2e, 0xa9, 0x40, 0x71, 0x1a, 0x76, 0x67, 0x67, 0x6b,
- 0xaf, 0xd9, 0xbf, 0xd5, 0xbb, 0x59, 0xaf, 0xdc, 0xdd, 0xd2, 0xa7, 0xa4, 0x16, 0x15, 0x6b, 0x11,
- 0x85, 0x05, 0xbb, 0xbb, 0x53, 0xda, 0x6b, 0x7f, 0x4f, 0x9e, 0xf7, 0x5f, 0x3d, 0x7f, 0xf5, 0xdd,
- 0xcb, 0xfe, 0xab, 0x17, 0xbc, 0x1a, 0x15, 0xeb, 0x41, 0x58, 0xd0, 0x27, 0xa4, 0xb9, 0xc8, 0x75,
- 0x24, 0x85, 0xd2, 0xf0, 0xd7, 0x3d, 0xfc, 0x8b, 0x20, 0x34, 0x06, 0x04, 0x82, 0x20, 0x2f, 0x64,
- 0x24, 0xa2, 0x34, 0x66, 0xf7, 0x77, 0xb6, 0x20, 0x08, 0x40, 0x0f, 0x52, 0x48, 0x92, 0x1a, 0xd6,
- 0x7a, 0x66, 0xd9, 0xc7, 0xa8, 0x49, 0xa7, 0x77, 0xa3, 0xf6, 0x79, 0x55, 0x5e, 0xd8, 0xa3, 0xcc,
- 0x42, 0x14, 0xd2, 0x30, 0x83, 0xf8, 0xb8, 0xf2, 0x32, 0x8c, 0xb9, 0x28, 0x38, 0x74, 0xe0, 0x40,
- 0xba, 0x4b, 0x6a, 0xd1, 0x12, 0x4b, 0x8f, 0x3d, 0xc0, 0xf7, 0x5a, 0xbd, 0x6b, 0xe5, 0xc8, 0xab,
- 0xd1, 0x92, 0x43, 0x60, 0x9e, 0x90, 0xa6, 0x36, 0x56, 0x18, 0x75, 0x9a, 0x40, 0x1d, 0x7c, 0xe2,
- 0x54, 0xd6, 0xc6, 0xce, 0x1c, 0x42, 0xf7, 0xaf, 0x97, 0x3d, 0x7b, 0x88, 0x4f, 0x35, 0x7b, 0x1f,
- 0x20, 0xde, 0xf0, 0xe7, 0x51, 0x4c, 0x77, 0x48, 0x0b, 0x23, 0xb5, 0x31, 0xe4, 0x4f, 0xee, 0x35,
- 0xc0, 0x86, 0x4e, 0xf9, 0x27, 0xae, 0xa6, 0xcc, 0x59, 0xa8, 0xe1, 0xbb, 0x47, 0x8e, 0x41, 0x5e,
- 0xd8, 0x99, 0x43, 0x36, 0x0c, 0x69, 0x68, 0xac, 0xd4, 0x86, 0x3d, 0xbe, 0x62, 0x38, 0x72, 0x08,
- 0xb8, 0xd0, 0xac, 0x54, 0x81, 0xef, 0x3f, 0x71, 0x2e, 0x04, 0x1a, 0x1e, 0x87, 0xf6, 0x95, 0x85,
- 0xa7, 0x89, 0x14, 0x0b, 0xc3, 0x76, 0xf0, 0xae, 0xee, 0x80, 0x91, 0xa1, 0x7b, 0xa4, 0xe9, 0x2b,
- 0x59, 0xa8, 0x2c, 0x67, 0x9f, 0xa2, 0x21, 0xf5, 0x9e, 0xc7, 0x78, 0x63, 0x8d, 0x45, 0x3d, 0xce,
- 0x72, 0xfa, 0x77, 0x72, 0xe7, 0xa6, 0x83, 0x45, 0x0a, 0x4d, 0xa8, 0xbb, 0x53, 0xda, 0xeb, 0xf4,
- 0xdb, 0x2e, 0x3f, 0xa2, 0x25, 0x82, 0xfc, 0xf6, 0x0d, 0xa7, 0x1f, 0xe5, 0xb1, 0x84, 0x8f, 0x96,
- 0x67, 0xb9, 0xb1, 0x22, 0x51, 0xa9, 0xb2, 0xec, 0x29, 0x66, 0x4b, 0xed, 0x9b, 0xaf, 0x9f, 0xff,
- 0xf5, 0xc5, 0xcb, 0xef, 0x38, 0xc1, 0xbb, 0x43, 0xb8, 0xa2, 0x7b, 0x24, 0xc0, 0x44, 0x11, 0x26,
- 0x0a, 0x33, 0x01, 0xdd, 0xcf, 0xb0, 0xcf, 0x50, 0xed, 0x0e, 0xe2, 0xb3, 0x28, 0xcc, 0xa6, 0x80,
- 0xd2, 0x4f, 0x20, 0x6f, 0xac, 0xd4, 0x59, 0x98, 0xb0, 0x5d, 0x6f, 0x98, 0xa7, 0x31, 0xa7, 0xd2,
- 0xc2, 0x5e, 0x8a, 0xcc, 0xb0, 0xcf, 0xe1, 0x33, 0x5e, 0x43, 0xfa, 0x18, 0x6c, 0xae, 0xb9, 0x51,
- 0x60, 0xd8, 0x17, 0x3e, 0xbb, 0x6f, 0x8e, 0x06, 0x5e, 0x05, 0xfa, 0xd8, 0xd0, 0x4f, 0x49, 0xcb,
- 0x67, 0x47, 0xa1, 0xf3, 0xc2, 0xb0, 0x3f, 0x63, 0x85, 0xfa, 0x06, 0x3e, 0x05, 0x88, 0xee, 0x93,
- 0xdb, 0xd7, 0x59, 0x5c, 0x27, 0xd9, 0x47, 0xbe, 0x5b, 0xd7, 0xf8, 0xb0, 0xa3, 0x3c, 0x27, 0xf7,
- 0x3d, 0x6f, 0xbc, 0x4e, 0x0b, 0x11, 0xe5, 0x99, 0xd5, 0x79, 0x92, 0x48, 0xcd, 0xbe, 0x44, 0xed,
- 0xef, 0xba, 0xdb, 0x83, 0x75, 0x5a, 0x0c, 0xae, 0xee, 0xa0, 0x2b, 0x2f, 0xb4, 0x94, 0xef, 0x37,
- 0x8e, 0x67, 0xcf, 0xf0, 0xf5, 0x96, 0x03, 0x9d, 0x8f, 0x61, 0x42, 0x5b, 0x95, 0x4a, 0x98, 0x95,
- 0x7f, 0x71, 0xd6, 0x7a, 0x92, 0x7e, 0x49, 0x28, 0xf4, 0x63, 0xcc, 0x0e, 0x95, 0x89, 0x45, 0xa2,
- 0x96, 0x67, 0x96, 0xf5, 0x30, 0x83, 0xa0, 0x53, 0xcf, 0x56, 0xaa, 0x18, 0x67, 0x23, 0x84, 0xc1,
- 0xe0, 0x9f, 0x65, 0xb8, 0x12, 0xe6, 0xd2, 0x44, 0x36, 0x31, 0xec, 0x2b, 0x64, 0x6b, 0x02, 0x36,
- 0x73, 0x10, 0x36, 0x8e, 0xf0, 0xfd, 0x25, 0xf6, 0x42, 0xc3, 0xbe, 0xf6, 0x8d, 0x23, 0x7c, 0x7f,
- 0x39, 0x05, 0x00, 0x9b, 0xb5, 0x0d, 0xed, 0xda, 0x40, 0x5d, 0x7c, 0x83, 0x5d, 0xa7, 0xee, 0x80,
- 0x51, 0x0c, 0xce, 0xca, 0x75, 0x71, 0x06, 0x61, 0xb5, 0xc6, 0x67, 0x33, 0xeb, 0x3b, 0x55, 0xdc,
- 0xc5, 0xd4, 0x1a, 0x97, 0xd2, 0x90, 0xf2, 0x51, 0x9e, 0x2d, 0x94, 0x6f, 0xce, 0xdf, 0xa2, 0xd1,
- 0xc4, 0x41, 0xe0, 0xcd, 0xee, 0x33, 0xbf, 0x44, 0xa0, 0x2f, 0xb5, 0x34, 0x05, 0xe4, 0x83, 0x96,
- 0xc6, 0xe6, 0x5a, 0xc6, 0x38, 0x50, 0xeb, 0xfc, 0x8a, 0xee, 0xee, 0x92, 0xdb, 0xc8, 0xed, 0x01,
- 0x27, 0xe0, 0x47, 0xa0, 0x1b, 0x8e, 0x70, 0xec, 0xbe, 0x24, 0x4d, 0x64, 0x73, 0xbd, 0x9b, 0xde,
- 0x27, 0x55, 0xd7, 0xd4, 0xfd, 0x80, 0xf6, 0xd4, 0x6f, 0x67, 0x67, 0xf7, 0x47, 0xd2, 0x46, 0xc1,
- 0x85, 0x0c, 0xed, 0x5a, 0x3b, 0x47, 0xa4, 0x32, 0x15, 0xd8, 0xaf, 0x37, 0xda, 0xa4, 0x32, 0x9d,
- 0x03, 0xfd, 0x2b, 0x27, 0x96, 0x7f, 0xe5, 0xc4, 0xee, 0x2f, 0x25, 0x52, 0xf7, 0xda, 0xfe, 0x8b,
- 0x76, 0xc9, 0xb6, 0xbd, 0x2c, 0xdc, 0xb8, 0xef, 0xf4, 0x3b, 0xbd, 0xcd, 0x85, 0x00, 0x94, 0xe3,
- 0x1d, 0x7d, 0x4c, 0xb6, 0x61, 0xee, 0xe3, 0x4b, 0xcd, 0x3e, 0xe9, 0x5d, 0x6d, 0x02, 0x1c, 0xf1,
- 0xeb, 0x33, 0x6a, 0x1d, 0x45, 0xb0, 0xc7, 0x6d, 0xdd, 0x98, 0x51, 0x0e, 0x04, 0x9d, 0x57, 0x52,
- 0x16, 0x22, 0x2f, 0x64, 0xe6, 0x27, 0x7b, 0x1d, 0x80, 0x49, 0x21, 0x33, 0xba, 0x4f, 0xea, 0x1b,
- 0xe3, 0x70, 0xa2, 0x37, 0x37, 0xba, 0x6c, 0x50, 0x7e, 0x75, 0xbf, 0xf1, 0x4f, 0x15, 0x53, 0x11,
- 0xfd, 0xf3, 0xef, 0x2d, 0xbf, 0x9f, 0xa0, 0xe3, 0xff, 0x1f, 0x9b, 0x18, 0xa9, 0x6d, 0x94, 0x85,
- 0x4d, 0xa8, 0xce, 0x37, 0x24, 0x7d, 0x4a, 0xb6, 0x21, 0xe8, 0x68, 0xc3, 0xd5, 0x6c, 0xba, 0x4a,
- 0x03, 0x8e, 0x97, 0xf4, 0x19, 0xa9, 0xf9, 0x58, 0xa3, 0x25, 0xcd, 0x3e, 0xed, 0xfd, 0x26, 0x01,
- 0xf8, 0x86, 0x85, 0x7e, 0x46, 0xaa, 0xce, 0x15, 0xde, 0xb4, 0x56, 0xef, 0x5a, 0x1a, 0x70, 0x7f,
- 0xe7, 0x57, 0x82, 0xea, 0x1f, 0xae, 0x04, 0x0f, 0x20, 0x7c, 0x42, 0x6a, 0x9d, 0xe5, 0xb8, 0xb0,
- 0x54, 0x78, 0x2d, 0xd2, 0x43, 0x20, 0x6f, 0x78, 0xb1, 0xfe, 0x07, 0x5e, 0x7c, 0x08, 0x2e, 0x83,
- 0x67, 0x52, 0xb3, 0xc4, 0xe5, 0xa5, 0xc1, 0xeb, 0xf8, 0x4e, 0x6a, 0x96, 0x30, 0x19, 0xcf, 0xa5,
- 0x36, 0x2a, 0xcf, 0x70, 0x71, 0x69, 0x6e, 0x7a, 0xb0, 0x07, 0xf9, 0xe6, 0x16, 0x73, 0x18, 0x0b,
- 0x10, 0x77, 0x99, 0x0a, 0xf7, 0x54, 0xf7, 0x3f, 0x25, 0xd2, 0xba, 0x2e, 0x01, 0x8b, 0x65, 0x1a,
- 0xbe, 0xcb, 0xb5, 0xaf, 0x07, 0x47, 0x20, 0xaa, 0xb2, 0x5c, 0xfb, 0x1d, 0xd6, 0x11, 0x80, 0x2e,
- 0x95, 0xf5, 0x5b, 0x7e, 0x83, 0x3b, 0x02, 0x0a, 0xd0, 0xac, 0x4f, 0xdd, 0xb2, 0xb5, 0xed, 0x6b,
- 0xdf, 0xd3, 0x20, 0x81, 0x4b, 0x33, 0x3a, 0xb8, 0xc2, 0x1d, 0x01, 0x5b, 0x11, 0xb4, 0x5d, 0xf4,
- 0x69, 0x83, 0xe3, 0x79, 0x5f, 0x78, 0xbd, 0xfc, 0x34, 0xa1, 0x84, 0x54, 0xc7, 0x6f, 0x8e, 0x27,
- 0x7c, 0x18, 0x7c, 0x44, 0x9b, 0xa4, 0x36, 0x78, 0x23, 0x8e, 0x27, 0xc7, 0xc3, 0xa0, 0x44, 0x1b,
- 0xa4, 0x32, 0xe5, 0x93, 0xe9, 0x2c, 0x28, 0xd3, 0x3a, 0xd9, 0x9e, 0x4d, 0x46, 0xf3, 0x60, 0x0b,
- 0x4e, 0xa3, 0x93, 0xc3, 0xc3, 0x60, 0x1b, 0xe4, 0x66, 0x73, 0x3e, 0x1e, 0xcc, 0x83, 0x0a, 0xc8,
- 0x1d, 0x0c, 0x47, 0xaf, 0x4f, 0x0e, 0xe7, 0x41, 0x75, 0xff, 0x97, 0x92, 0x2f, 0xd6, 0x4d, 0xc6,
- 0xc1, 0x4b, 0xc3, 0xa3, 0xe9, 0xfc, 0xa7, 0xe0, 0x23, 0x90, 0x3f, 0x38, 0x39, 0x9a, 0x06, 0x25,
- 0x90, 0xe1, 0xc3, 0xd9, 0x1c, 0x3e, 0x2e, 0x03, 0xc7, 0xe0, 0x87, 0xe1, 0xe0, 0xc7, 0x60, 0x8b,
- 0xb6, 0x48, 0x7d, 0xca, 0x87, 0x02, 0xb9, 0xb6, 0xe9, 0x2d, 0xd2, 0x9c, 0xbe, 0x7e, 0x33, 0x14,
- 0xb3, 0x21, 0x7f, 0x3b, 0xe4, 0x41, 0x05, 0xbe, 0x3d, 0x9e, 0xcc, 0xc7, 0xa3, 0x9f, 0x82, 0x2a,
- 0x0d, 0x48, 0x6b, 0x30, 0x3d, 0x19, 0x1f, 0x8f, 0x26, 0x8e, 0xbd, 0x46, 0x6f, 0x93, 0xf6, 0x06,
- 0x71, 0xef, 0xd5, 0x01, 0x1a, 0x0d, 0x5f, 0xcf, 0x4f, 0xf8, 0xd0, 0x43, 0x0d, 0xf8, 0xfa, 0xed,
- 0x90, 0xcf, 0xc6, 0x93, 0xe3, 0x80, 0xc0, 0x7f, 0xff, 0x7c, 0x3d, 0x9e, 0x8b, 0xe9, 0xf8, 0x20,
- 0x68, 0xd2, 0xbb, 0x24, 0xb8, 0xf6, 0x9f, 0x18, 0xfc, 0x70, 0x78, 0x10, 0xb4, 0xfe, 0x17, 0x00,
- 0x00, 0xff, 0xff, 0xf8, 0x9f, 0x0e, 0x7d, 0xca, 0x0d, 0x00, 0x00,
-}
diff --git a/vendor/github.com/checkpoint-restore/go-criu/v5/.gitignore b/vendor/github.com/checkpoint-restore/go-criu/v5/.gitignore
new file mode 100644
index 000000000..6c7385fa2
--- /dev/null
+++ b/vendor/github.com/checkpoint-restore/go-criu/v5/.gitignore
@@ -0,0 +1,5 @@
+test/test
+test/piggie/piggie
+test/phaul
+image
+stats/stats.proto
diff --git a/vendor/github.com/checkpoint-restore/go-criu/v5/.golangci.yml b/vendor/github.com/checkpoint-restore/go-criu/v5/.golangci.yml
new file mode 100644
index 000000000..fbbac4b41
--- /dev/null
+++ b/vendor/github.com/checkpoint-restore/go-criu/v5/.golangci.yml
@@ -0,0 +1,12 @@
+run:
+ skip_dirs:
+ - rpc
+ - stats
+
+linters:
+ disable-all: false
+ presets:
+ - bugs
+ - performance
+ - unused
+ - format
diff --git a/vendor/github.com/checkpoint-restore/go-criu/LICENSE b/vendor/github.com/checkpoint-restore/go-criu/v5/LICENSE
index 8dada3eda..8dada3eda 100644
--- a/vendor/github.com/checkpoint-restore/go-criu/LICENSE
+++ b/vendor/github.com/checkpoint-restore/go-criu/v5/LICENSE
diff --git a/vendor/github.com/checkpoint-restore/go-criu/v5/Makefile b/vendor/github.com/checkpoint-restore/go-criu/v5/Makefile
new file mode 100644
index 000000000..a5c5f5542
--- /dev/null
+++ b/vendor/github.com/checkpoint-restore/go-criu/v5/Makefile
@@ -0,0 +1,62 @@
+GO ?= go
+CC ?= gcc
+
+all: build test phaul-test
+
+lint:
+ golangci-lint run ./...
+
+build:
+ $(GO) build -v ./...
+
+TEST_BINARIES := test/test test/piggie/piggie test/phaul/phaul
+test-bin: $(TEST_BINARIES)
+
+test/piggie/piggie: test/piggie/piggie.c
+ $(CC) $^ -o $@
+
+test/test: test/*.go
+ $(GO) build -v -o $@ $^
+
+test: $(TEST_BINARIES)
+ mkdir -p image
+ PID=$$(test/piggie/piggie) && { \
+ test/test dump $$PID image && \
+ test/test restore image; \
+ pkill -9 piggie; \
+ }
+ rm -rf image
+
+test/phaul/phaul: test/phaul/*.go
+ $(GO) build -v -o $@ $^
+
+phaul-test: $(TEST_BINARIES)
+ rm -rf image
+ PID=$$(test/piggie/piggie) && { \
+ test/phaul/phaul $$PID; \
+ pkill -9 piggie; \
+ }
+
+clean:
+ @rm -f $(TEST_BINARIES)
+ @rm -rf image
+ @rm -f rpc/rpc.proto stats/stats.proto
+
+rpc/rpc.proto:
+ curl -sSL https://raw.githubusercontent.com/checkpoint-restore/criu/master/images/rpc.proto -o $@
+
+stats/stats.proto:
+ curl -sSL https://raw.githubusercontent.com/checkpoint-restore/criu/master/images/stats.proto -o $@
+
+rpc/rpc.pb.go: rpc/rpc.proto
+ protoc --go_out=. --go_opt=Mrpc/rpc.proto=rpc/ $^
+
+stats/stats.pb.go: stats/stats.proto
+ protoc --go_out=. $^
+
+vendor:
+ GO111MODULE=on $(GO) mod tidy
+ GO111MODULE=on $(GO) mod vendor
+ GO111MODULE=on $(GO) mod verify
+
+.PHONY: build test phaul-test test-bin clean lint vendor
diff --git a/vendor/github.com/checkpoint-restore/go-criu/README.md b/vendor/github.com/checkpoint-restore/go-criu/v5/README.md
index 539627324..390da3e98 100644
--- a/vendor/github.com/checkpoint-restore/go-criu/README.md
+++ b/vendor/github.com/checkpoint-restore/go-criu/v5/README.md
@@ -1,8 +1,10 @@
-[![master](https://travis-ci.org/checkpoint-restore/go-criu.svg?branch=master)](https://travis-ci.org/checkpoint-restore/go-criu)
+[![test](https://github.com/checkpoint-restore/go-criu/workflows/ci/badge.svg?branch=master)](https://github.com/checkpoint-restore/go-criu/actions?query=workflow%3Aci)
+[![verify](https://github.com/checkpoint-restore/go-criu/workflows/verify/badge.svg?branch=master)](https://github.com/checkpoint-restore/go-criu/actions?query=workflow%3Averify)
+[![Go Reference](https://pkg.go.dev/badge/github.com/checkpoint-restore/go-criu.svg)](https://pkg.go.dev/github.com/checkpoint-restore/go-criu)
-## go-criu -- Go bindings for [CRIU](https://criu.org/)
+## go-criu -- Go bindings for CRIU
-This repository provides Go bindings for CRIU. The code is based on the Go based PHaul
+This repository provides Go bindings for [CRIU](https://criu.org/). The code is based on the Go-based PHaul
implementation from the CRIU repository. For easier inclusion into other Go projects the
CRIU Go bindings have been moved to this repository.
@@ -10,24 +12,46 @@ The Go bindings provide an easy way to use the CRIU RPC calls from Go without th
to set up all the infrastructure to make the actual RPC connection to CRIU.
The following example would print the version of CRIU:
-```
+```go
+import (
+ "log"
+
+ "github.com/checkpoint/restore/go-criu/v5"
+)
+
+func main() {
c := criu.MakeCriu()
version, err := c.GetCriuVersion()
- fmt.Println(version)
+ if err != nil {
+ log.Fatalln(err)
+ }
+ log.Println(version)
+}
```
+
or to just check if at least a certain CRIU version is installed:
-```
+
+```go
c := criu.MakeCriu()
result, err := c.IsCriuAtLeast(31100)
```
## Releases
-go-criu will carry the same version number as CRIU. This implies that each
-go-criu release will pull in the necessary changes from CRIU before making a
-release.
+The first go-criu release was 3.11 based on CRIU 3.11. The initial plan
+was to follow CRIU so that go-criu would carry the same version number as
+CRIU.
+
+As go-criu is imported in other projects and as Go modules are expected
+to follow Semantic Versioning go-criu will also follow Semantic Versioning
+starting with the 4.0.0 release.
-The first go-criu release was 3.11 based on CRIU 3.11.
+The following table shows the relation between go-criu and criu versions:
+
+| Major version | Latest release | CRIU version |
+| -------------- | -------------- | ------------ |
+| v5             | 5.0.0         | 3.15         |
+| v4             | 4.1.0         | 3.14         |
## How to contribute
@@ -61,6 +85,11 @@ by adding a "Signed-off-by" line containing the contributor's name and e-mail
to every commit message. Your signature certifies that you wrote the patch or
otherwise have the right to pass it on as an open-source patch.
-### License
+### License and copyright
+
+Unless mentioned otherwise in a specific file's header, all code in
+this project is released under the Apache 2.0 license.
-The license of go-criu is the Apache 2.0 license.
+The author of a change remains the copyright holder of their code
+(no copyright assignment). The list of authors and contributors can be
+retrieved from the git commit history and in some cases, the file headers.
diff --git a/vendor/github.com/checkpoint-restore/go-criu/v5/go.mod b/vendor/github.com/checkpoint-restore/go-criu/v5/go.mod
new file mode 100644
index 000000000..69595701f
--- /dev/null
+++ b/vendor/github.com/checkpoint-restore/go-criu/v5/go.mod
@@ -0,0 +1,9 @@
+module github.com/checkpoint-restore/go-criu/v5
+
+go 1.13
+
+require (
+ github.com/golang/protobuf v1.5.2
+ golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c
+ google.golang.org/protobuf v1.26.0
+)
diff --git a/vendor/github.com/checkpoint-restore/go-criu/v5/go.sum b/vendor/github.com/checkpoint-restore/go-criu/v5/go.sum
new file mode 100644
index 000000000..7e17df214
--- /dev/null
+++ b/vendor/github.com/checkpoint-restore/go-criu/v5/go.sum
@@ -0,0 +1,12 @@
+github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
+github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
+github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
+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=
+golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk=
+golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
+google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
+google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
diff --git a/vendor/github.com/checkpoint-restore/go-criu/main.go b/vendor/github.com/checkpoint-restore/go-criu/v5/main.go
index cf94c376e..78811c309 100644
--- a/vendor/github.com/checkpoint-restore/go-criu/main.go
+++ b/vendor/github.com/checkpoint-restore/go-criu/v5/main.go
@@ -8,19 +8,28 @@ import (
"strconv"
"syscall"
- "github.com/checkpoint-restore/go-criu/rpc"
- "github.com/golang/protobuf/proto"
+ "github.com/checkpoint-restore/go-criu/v5/rpc"
+ "google.golang.org/protobuf/proto"
)
// Criu struct
type Criu struct {
- swrkCmd *exec.Cmd
- swrkSk *os.File
+ swrkCmd *exec.Cmd
+ swrkSk *os.File
+ swrkPath string
}
// MakeCriu returns the Criu object required for most operations
func MakeCriu() *Criu {
- return &Criu{}
+ return &Criu{
+ swrkPath: "criu",
+ }
+}
+
+// SetCriuPath allows setting the path to the CRIU binary
+// if it is in a non standard location
+func (c *Criu) SetCriuPath(path string) {
+ c.swrkPath = path
}
// Prepare sets up everything for the RPC communication to CRIU
@@ -36,7 +45,8 @@ func (c *Criu) Prepare() error {
defer srv.Close()
args := []string{"swrk", strconv.Itoa(fds[1])}
- cmd := exec.Command("criu", args...)
+ // #nosec G204
+ cmd := exec.Command(c.swrkPath, args...)
err = cmd.Start()
if err != nil {
@@ -55,7 +65,7 @@ func (c *Criu) Cleanup() {
if c.swrkCmd != nil {
c.swrkSk.Close()
c.swrkSk = nil
- c.swrkCmd.Wait()
+ _ = c.swrkCmd.Wait()
c.swrkCmd = nil
}
}
@@ -178,28 +188,28 @@ func (c *Criu) doSwrkWithResp(reqType rpc.CriuReqType, opts *rpc.CriuOpts, nfy N
}
// Dump dumps a process
-func (c *Criu) Dump(opts rpc.CriuOpts, nfy Notify) error {
- return c.doSwrk(rpc.CriuReqType_DUMP, &opts, nfy)
+func (c *Criu) Dump(opts *rpc.CriuOpts, nfy Notify) error {
+ return c.doSwrk(rpc.CriuReqType_DUMP, opts, nfy)
}
// Restore restores a process
-func (c *Criu) Restore(opts rpc.CriuOpts, nfy Notify) error {
- return c.doSwrk(rpc.CriuReqType_RESTORE, &opts, nfy)
+func (c *Criu) Restore(opts *rpc.CriuOpts, nfy Notify) error {
+ return c.doSwrk(rpc.CriuReqType_RESTORE, opts, nfy)
}
// PreDump does a pre-dump
-func (c *Criu) PreDump(opts rpc.CriuOpts, nfy Notify) error {
- return c.doSwrk(rpc.CriuReqType_PRE_DUMP, &opts, nfy)
+func (c *Criu) PreDump(opts *rpc.CriuOpts, nfy Notify) error {
+ return c.doSwrk(rpc.CriuReqType_PRE_DUMP, opts, nfy)
}
// StartPageServer starts the page server
-func (c *Criu) StartPageServer(opts rpc.CriuOpts) error {
- return c.doSwrk(rpc.CriuReqType_PAGE_SERVER, &opts, nil)
+func (c *Criu) StartPageServer(opts *rpc.CriuOpts) error {
+ return c.doSwrk(rpc.CriuReqType_PAGE_SERVER, opts, nil)
}
// StartPageServerChld starts the page server and returns PID and port
-func (c *Criu) StartPageServerChld(opts rpc.CriuOpts) (int, int, error) {
- resp, err := c.doSwrkWithResp(rpc.CriuReqType_PAGE_SERVER_CHLD, &opts, nil)
+func (c *Criu) StartPageServerChld(opts *rpc.CriuOpts) (int, int, error) {
+ resp, err := c.doSwrkWithResp(rpc.CriuReqType_PAGE_SERVER_CHLD, opts, nil)
if err != nil {
return 0, 0, err
}
@@ -219,8 +229,8 @@ func (c *Criu) GetCriuVersion() (int, error) {
return 0, fmt.Errorf("Unexpected CRIU RPC response")
}
- version := int(*resp.GetVersion().Major) * 10000
- version += int(*resp.GetVersion().Minor) * 100
+ version := int(*resp.GetVersion().MajorNumber) * 10000
+ version += int(*resp.GetVersion().MinorNumber) * 100
if resp.GetVersion().Sublevel != nil {
version += int(*resp.GetVersion().Sublevel)
}
diff --git a/vendor/github.com/checkpoint-restore/go-criu/notify.go b/vendor/github.com/checkpoint-restore/go-criu/v5/notify.go
index 1c8547b43..a177f2bb5 100644
--- a/vendor/github.com/checkpoint-restore/go-criu/notify.go
+++ b/vendor/github.com/checkpoint-restore/go-criu/v5/notify.go
@@ -1,6 +1,6 @@
package criu
-//Notify interface
+// Notify interface
type Notify interface {
PreDump() error
PostDump() error
@@ -14,8 +14,7 @@ type Notify interface {
}
// NoNotify struct
-type NoNotify struct {
-}
+type NoNotify struct{}
// PreDump NoNotify
func (c NoNotify) PreDump() error {
diff --git a/vendor/github.com/checkpoint-restore/go-criu/v5/rpc/rpc.pb.go b/vendor/github.com/checkpoint-restore/go-criu/v5/rpc/rpc.pb.go
new file mode 100644
index 000000000..9f22f1539
--- /dev/null
+++ b/vendor/github.com/checkpoint-restore/go-criu/v5/rpc/rpc.pb.go
@@ -0,0 +1,2237 @@
+// SPDX-License-Identifier: MIT
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// protoc-gen-go v1.26.0
+// protoc v3.14.0
+// source: rpc/rpc.proto
+
+package rpc
+
+import (
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ reflect "reflect"
+ sync "sync"
+)
+
+const (
+ // Verify that this generated code is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+ // Verify that runtime/protoimpl is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type CriuCgMode int32
+
+const (
+ CriuCgMode_IGNORE CriuCgMode = 0
+ CriuCgMode_CG_NONE CriuCgMode = 1
+ CriuCgMode_PROPS CriuCgMode = 2
+ CriuCgMode_SOFT CriuCgMode = 3
+ CriuCgMode_FULL CriuCgMode = 4
+ CriuCgMode_STRICT CriuCgMode = 5
+ CriuCgMode_DEFAULT CriuCgMode = 6
+)
+
+// Enum value maps for CriuCgMode.
+var (
+ CriuCgMode_name = map[int32]string{
+ 0: "IGNORE",
+ 1: "CG_NONE",
+ 2: "PROPS",
+ 3: "SOFT",
+ 4: "FULL",
+ 5: "STRICT",
+ 6: "DEFAULT",
+ }
+ CriuCgMode_value = map[string]int32{
+ "IGNORE": 0,
+ "CG_NONE": 1,
+ "PROPS": 2,
+ "SOFT": 3,
+ "FULL": 4,
+ "STRICT": 5,
+ "DEFAULT": 6,
+ }
+)
+
+func (x CriuCgMode) Enum() *CriuCgMode {
+ p := new(CriuCgMode)
+ *p = x
+ return p
+}
+
+func (x CriuCgMode) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (CriuCgMode) Descriptor() protoreflect.EnumDescriptor {
+ return file_rpc_rpc_proto_enumTypes[0].Descriptor()
+}
+
+func (CriuCgMode) Type() protoreflect.EnumType {
+ return &file_rpc_rpc_proto_enumTypes[0]
+}
+
+func (x CriuCgMode) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *CriuCgMode) UnmarshalJSON(b []byte) error {
+ num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+ if err != nil {
+ return err
+ }
+ *x = CriuCgMode(num)
+ return nil
+}
+
+// Deprecated: Use CriuCgMode.Descriptor instead.
+func (CriuCgMode) EnumDescriptor() ([]byte, []int) {
+ return file_rpc_rpc_proto_rawDescGZIP(), []int{0}
+}
+
+type CriuPreDumpMode int32
+
+const (
+ CriuPreDumpMode_SPLICE CriuPreDumpMode = 1
+ CriuPreDumpMode_VM_READ CriuPreDumpMode = 2
+)
+
+// Enum value maps for CriuPreDumpMode.
+var (
+ CriuPreDumpMode_name = map[int32]string{
+ 1: "SPLICE",
+ 2: "VM_READ",
+ }
+ CriuPreDumpMode_value = map[string]int32{
+ "SPLICE": 1,
+ "VM_READ": 2,
+ }
+)
+
+func (x CriuPreDumpMode) Enum() *CriuPreDumpMode {
+ p := new(CriuPreDumpMode)
+ *p = x
+ return p
+}
+
+func (x CriuPreDumpMode) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (CriuPreDumpMode) Descriptor() protoreflect.EnumDescriptor {
+ return file_rpc_rpc_proto_enumTypes[1].Descriptor()
+}
+
+func (CriuPreDumpMode) Type() protoreflect.EnumType {
+ return &file_rpc_rpc_proto_enumTypes[1]
+}
+
+func (x CriuPreDumpMode) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *CriuPreDumpMode) UnmarshalJSON(b []byte) error {
+ num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+ if err != nil {
+ return err
+ }
+ *x = CriuPreDumpMode(num)
+ return nil
+}
+
+// Deprecated: Use CriuPreDumpMode.Descriptor instead.
+func (CriuPreDumpMode) EnumDescriptor() ([]byte, []int) {
+ return file_rpc_rpc_proto_rawDescGZIP(), []int{1}
+}
+
+type CriuReqType int32
+
+const (
+ CriuReqType_EMPTY CriuReqType = 0
+ CriuReqType_DUMP CriuReqType = 1
+ CriuReqType_RESTORE CriuReqType = 2
+ CriuReqType_CHECK CriuReqType = 3
+ CriuReqType_PRE_DUMP CriuReqType = 4
+ CriuReqType_PAGE_SERVER CriuReqType = 5
+ CriuReqType_NOTIFY CriuReqType = 6
+ CriuReqType_CPUINFO_DUMP CriuReqType = 7
+ CriuReqType_CPUINFO_CHECK CriuReqType = 8
+ CriuReqType_FEATURE_CHECK CriuReqType = 9
+ CriuReqType_VERSION CriuReqType = 10
+ CriuReqType_WAIT_PID CriuReqType = 11
+ CriuReqType_PAGE_SERVER_CHLD CriuReqType = 12
+)
+
+// Enum value maps for CriuReqType.
+var (
+ CriuReqType_name = map[int32]string{
+ 0: "EMPTY",
+ 1: "DUMP",
+ 2: "RESTORE",
+ 3: "CHECK",
+ 4: "PRE_DUMP",
+ 5: "PAGE_SERVER",
+ 6: "NOTIFY",
+ 7: "CPUINFO_DUMP",
+ 8: "CPUINFO_CHECK",
+ 9: "FEATURE_CHECK",
+ 10: "VERSION",
+ 11: "WAIT_PID",
+ 12: "PAGE_SERVER_CHLD",
+ }
+ CriuReqType_value = map[string]int32{
+ "EMPTY": 0,
+ "DUMP": 1,
+ "RESTORE": 2,
+ "CHECK": 3,
+ "PRE_DUMP": 4,
+ "PAGE_SERVER": 5,
+ "NOTIFY": 6,
+ "CPUINFO_DUMP": 7,
+ "CPUINFO_CHECK": 8,
+ "FEATURE_CHECK": 9,
+ "VERSION": 10,
+ "WAIT_PID": 11,
+ "PAGE_SERVER_CHLD": 12,
+ }
+)
+
+func (x CriuReqType) Enum() *CriuReqType {
+ p := new(CriuReqType)
+ *p = x
+ return p
+}
+
+func (x CriuReqType) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (CriuReqType) Descriptor() protoreflect.EnumDescriptor {
+ return file_rpc_rpc_proto_enumTypes[2].Descriptor()
+}
+
+func (CriuReqType) Type() protoreflect.EnumType {
+ return &file_rpc_rpc_proto_enumTypes[2]
+}
+
+func (x CriuReqType) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *CriuReqType) UnmarshalJSON(b []byte) error {
+ num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+ if err != nil {
+ return err
+ }
+ *x = CriuReqType(num)
+ return nil
+}
+
+// Deprecated: Use CriuReqType.Descriptor instead.
+func (CriuReqType) EnumDescriptor() ([]byte, []int) {
+ return file_rpc_rpc_proto_rawDescGZIP(), []int{2}
+}
+
+type CriuPageServerInfo struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Address *string `protobuf:"bytes,1,opt,name=address" json:"address,omitempty"`
+ Port *int32 `protobuf:"varint,2,opt,name=port" json:"port,omitempty"`
+ Pid *int32 `protobuf:"varint,3,opt,name=pid" json:"pid,omitempty"`
+ Fd *int32 `protobuf:"varint,4,opt,name=fd" json:"fd,omitempty"`
+}
+
+func (x *CriuPageServerInfo) Reset() {
+ *x = CriuPageServerInfo{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_rpc_rpc_proto_msgTypes[0]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *CriuPageServerInfo) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CriuPageServerInfo) ProtoMessage() {}
+
+func (x *CriuPageServerInfo) ProtoReflect() protoreflect.Message {
+ mi := &file_rpc_rpc_proto_msgTypes[0]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use CriuPageServerInfo.ProtoReflect.Descriptor instead.
+func (*CriuPageServerInfo) Descriptor() ([]byte, []int) {
+ return file_rpc_rpc_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *CriuPageServerInfo) GetAddress() string {
+ if x != nil && x.Address != nil {
+ return *x.Address
+ }
+ return ""
+}
+
+func (x *CriuPageServerInfo) GetPort() int32 {
+ if x != nil && x.Port != nil {
+ return *x.Port
+ }
+ return 0
+}
+
+func (x *CriuPageServerInfo) GetPid() int32 {
+ if x != nil && x.Pid != nil {
+ return *x.Pid
+ }
+ return 0
+}
+
+func (x *CriuPageServerInfo) GetFd() int32 {
+ if x != nil && x.Fd != nil {
+ return *x.Fd
+ }
+ return 0
+}
+
+type CriuVethPair struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ IfIn *string `protobuf:"bytes,1,req,name=if_in,json=ifIn" json:"if_in,omitempty"`
+ IfOut *string `protobuf:"bytes,2,req,name=if_out,json=ifOut" json:"if_out,omitempty"`
+}
+
+func (x *CriuVethPair) Reset() {
+ *x = CriuVethPair{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_rpc_rpc_proto_msgTypes[1]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *CriuVethPair) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CriuVethPair) ProtoMessage() {}
+
+func (x *CriuVethPair) ProtoReflect() protoreflect.Message {
+ mi := &file_rpc_rpc_proto_msgTypes[1]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use CriuVethPair.ProtoReflect.Descriptor instead.
+func (*CriuVethPair) Descriptor() ([]byte, []int) {
+ return file_rpc_rpc_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *CriuVethPair) GetIfIn() string {
+ if x != nil && x.IfIn != nil {
+ return *x.IfIn
+ }
+ return ""
+}
+
+func (x *CriuVethPair) GetIfOut() string {
+ if x != nil && x.IfOut != nil {
+ return *x.IfOut
+ }
+ return ""
+}
+
+type ExtMountMap struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Key *string `protobuf:"bytes,1,req,name=key" json:"key,omitempty"`
+ Val *string `protobuf:"bytes,2,req,name=val" json:"val,omitempty"`
+}
+
+func (x *ExtMountMap) Reset() {
+ *x = ExtMountMap{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_rpc_rpc_proto_msgTypes[2]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *ExtMountMap) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ExtMountMap) ProtoMessage() {}
+
+func (x *ExtMountMap) ProtoReflect() protoreflect.Message {
+ mi := &file_rpc_rpc_proto_msgTypes[2]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use ExtMountMap.ProtoReflect.Descriptor instead.
+func (*ExtMountMap) Descriptor() ([]byte, []int) {
+ return file_rpc_rpc_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *ExtMountMap) GetKey() string {
+ if x != nil && x.Key != nil {
+ return *x.Key
+ }
+ return ""
+}
+
+func (x *ExtMountMap) GetVal() string {
+ if x != nil && x.Val != nil {
+ return *x.Val
+ }
+ return ""
+}
+
+type JoinNamespace struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Ns *string `protobuf:"bytes,1,req,name=ns" json:"ns,omitempty"`
+ NsFile *string `protobuf:"bytes,2,req,name=ns_file,json=nsFile" json:"ns_file,omitempty"`
+ ExtraOpt *string `protobuf:"bytes,3,opt,name=extra_opt,json=extraOpt" json:"extra_opt,omitempty"`
+}
+
+func (x *JoinNamespace) Reset() {
+ *x = JoinNamespace{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_rpc_rpc_proto_msgTypes[3]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *JoinNamespace) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*JoinNamespace) ProtoMessage() {}
+
+func (x *JoinNamespace) ProtoReflect() protoreflect.Message {
+ mi := &file_rpc_rpc_proto_msgTypes[3]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use JoinNamespace.ProtoReflect.Descriptor instead.
+func (*JoinNamespace) Descriptor() ([]byte, []int) {
+ return file_rpc_rpc_proto_rawDescGZIP(), []int{3}
+}
+
+func (x *JoinNamespace) GetNs() string {
+ if x != nil && x.Ns != nil {
+ return *x.Ns
+ }
+ return ""
+}
+
+func (x *JoinNamespace) GetNsFile() string {
+ if x != nil && x.NsFile != nil {
+ return *x.NsFile
+ }
+ return ""
+}
+
+func (x *JoinNamespace) GetExtraOpt() string {
+ if x != nil && x.ExtraOpt != nil {
+ return *x.ExtraOpt
+ }
+ return ""
+}
+
+type InheritFd struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Key *string `protobuf:"bytes,1,req,name=key" json:"key,omitempty"`
+ Fd *int32 `protobuf:"varint,2,req,name=fd" json:"fd,omitempty"`
+}
+
+func (x *InheritFd) Reset() {
+ *x = InheritFd{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_rpc_rpc_proto_msgTypes[4]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *InheritFd) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*InheritFd) ProtoMessage() {}
+
+func (x *InheritFd) ProtoReflect() protoreflect.Message {
+ mi := &file_rpc_rpc_proto_msgTypes[4]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use InheritFd.ProtoReflect.Descriptor instead.
+func (*InheritFd) Descriptor() ([]byte, []int) {
+ return file_rpc_rpc_proto_rawDescGZIP(), []int{4}
+}
+
+func (x *InheritFd) GetKey() string {
+ if x != nil && x.Key != nil {
+ return *x.Key
+ }
+ return ""
+}
+
+func (x *InheritFd) GetFd() int32 {
+ if x != nil && x.Fd != nil {
+ return *x.Fd
+ }
+ return 0
+}
+
+type CgroupRoot struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Ctrl *string `protobuf:"bytes,1,opt,name=ctrl" json:"ctrl,omitempty"`
+ Path *string `protobuf:"bytes,2,req,name=path" json:"path,omitempty"`
+}
+
+func (x *CgroupRoot) Reset() {
+ *x = CgroupRoot{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_rpc_rpc_proto_msgTypes[5]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *CgroupRoot) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CgroupRoot) ProtoMessage() {}
+
+func (x *CgroupRoot) ProtoReflect() protoreflect.Message {
+ mi := &file_rpc_rpc_proto_msgTypes[5]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use CgroupRoot.ProtoReflect.Descriptor instead.
+func (*CgroupRoot) Descriptor() ([]byte, []int) {
+ return file_rpc_rpc_proto_rawDescGZIP(), []int{5}
+}
+
+func (x *CgroupRoot) GetCtrl() string {
+ if x != nil && x.Ctrl != nil {
+ return *x.Ctrl
+ }
+ return ""
+}
+
+func (x *CgroupRoot) GetPath() string {
+ if x != nil && x.Path != nil {
+ return *x.Path
+ }
+ return ""
+}
+
+type UnixSk struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Inode *uint32 `protobuf:"varint,1,req,name=inode" json:"inode,omitempty"`
+}
+
+func (x *UnixSk) Reset() {
+ *x = UnixSk{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_rpc_rpc_proto_msgTypes[6]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *UnixSk) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UnixSk) ProtoMessage() {}
+
+func (x *UnixSk) ProtoReflect() protoreflect.Message {
+ mi := &file_rpc_rpc_proto_msgTypes[6]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use UnixSk.ProtoReflect.Descriptor instead.
+func (*UnixSk) Descriptor() ([]byte, []int) {
+ return file_rpc_rpc_proto_rawDescGZIP(), []int{6}
+}
+
+func (x *UnixSk) GetInode() uint32 {
+ if x != nil && x.Inode != nil {
+ return *x.Inode
+ }
+ return 0
+}
+
+type CriuOpts struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ ImagesDirFd *int32 `protobuf:"varint,1,req,name=images_dir_fd,json=imagesDirFd" json:"images_dir_fd,omitempty"`
+ Pid *int32 `protobuf:"varint,2,opt,name=pid" json:"pid,omitempty"` // if not set on dump, will dump requesting process
+ LeaveRunning *bool `protobuf:"varint,3,opt,name=leave_running,json=leaveRunning" json:"leave_running,omitempty"`
+ ExtUnixSk *bool `protobuf:"varint,4,opt,name=ext_unix_sk,json=extUnixSk" json:"ext_unix_sk,omitempty"`
+ TcpEstablished *bool `protobuf:"varint,5,opt,name=tcp_established,json=tcpEstablished" json:"tcp_established,omitempty"`
+ EvasiveDevices *bool `protobuf:"varint,6,opt,name=evasive_devices,json=evasiveDevices" json:"evasive_devices,omitempty"`
+ ShellJob *bool `protobuf:"varint,7,opt,name=shell_job,json=shellJob" json:"shell_job,omitempty"`
+ FileLocks *bool `protobuf:"varint,8,opt,name=file_locks,json=fileLocks" json:"file_locks,omitempty"`
+ LogLevel *int32 `protobuf:"varint,9,opt,name=log_level,json=logLevel,def=2" json:"log_level,omitempty"`
+ LogFile *string `protobuf:"bytes,10,opt,name=log_file,json=logFile" json:"log_file,omitempty"` // No subdirs are allowed. Consider using work-dir
+ Ps *CriuPageServerInfo `protobuf:"bytes,11,opt,name=ps" json:"ps,omitempty"`
+ NotifyScripts *bool `protobuf:"varint,12,opt,name=notify_scripts,json=notifyScripts" json:"notify_scripts,omitempty"`
+ Root *string `protobuf:"bytes,13,opt,name=root" json:"root,omitempty"`
+ ParentImg *string `protobuf:"bytes,14,opt,name=parent_img,json=parentImg" json:"parent_img,omitempty"`
+ TrackMem *bool `protobuf:"varint,15,opt,name=track_mem,json=trackMem" json:"track_mem,omitempty"`
+ AutoDedup *bool `protobuf:"varint,16,opt,name=auto_dedup,json=autoDedup" json:"auto_dedup,omitempty"`
+ WorkDirFd *int32 `protobuf:"varint,17,opt,name=work_dir_fd,json=workDirFd" json:"work_dir_fd,omitempty"`
+ LinkRemap *bool `protobuf:"varint,18,opt,name=link_remap,json=linkRemap" json:"link_remap,omitempty"`
+ Veths []*CriuVethPair `protobuf:"bytes,19,rep,name=veths" json:"veths,omitempty"` // DEPRECATED, use external instead
+ CpuCap *uint32 `protobuf:"varint,20,opt,name=cpu_cap,json=cpuCap,def=4294967295" json:"cpu_cap,omitempty"`
+ ForceIrmap *bool `protobuf:"varint,21,opt,name=force_irmap,json=forceIrmap" json:"force_irmap,omitempty"`
+ ExecCmd []string `protobuf:"bytes,22,rep,name=exec_cmd,json=execCmd" json:"exec_cmd,omitempty"`
+ ExtMnt []*ExtMountMap `protobuf:"bytes,23,rep,name=ext_mnt,json=extMnt" json:"ext_mnt,omitempty"` // DEPRECATED, use external instead
+ ManageCgroups *bool `protobuf:"varint,24,opt,name=manage_cgroups,json=manageCgroups" json:"manage_cgroups,omitempty"` // backward compatibility
+ CgRoot []*CgroupRoot `protobuf:"bytes,25,rep,name=cg_root,json=cgRoot" json:"cg_root,omitempty"`
+ RstSibling *bool `protobuf:"varint,26,opt,name=rst_sibling,json=rstSibling" json:"rst_sibling,omitempty"` // swrk only
+ InheritFd []*InheritFd `protobuf:"bytes,27,rep,name=inherit_fd,json=inheritFd" json:"inherit_fd,omitempty"` // swrk only
+ AutoExtMnt *bool `protobuf:"varint,28,opt,name=auto_ext_mnt,json=autoExtMnt" json:"auto_ext_mnt,omitempty"`
+ ExtSharing *bool `protobuf:"varint,29,opt,name=ext_sharing,json=extSharing" json:"ext_sharing,omitempty"`
+ ExtMasters *bool `protobuf:"varint,30,opt,name=ext_masters,json=extMasters" json:"ext_masters,omitempty"`
+ SkipMnt []string `protobuf:"bytes,31,rep,name=skip_mnt,json=skipMnt" json:"skip_mnt,omitempty"`
+ EnableFs []string `protobuf:"bytes,32,rep,name=enable_fs,json=enableFs" json:"enable_fs,omitempty"`
+ UnixSkIno []*UnixSk `protobuf:"bytes,33,rep,name=unix_sk_ino,json=unixSkIno" json:"unix_sk_ino,omitempty"` // DEPRECATED, use external instead
+ ManageCgroupsMode *CriuCgMode `protobuf:"varint,34,opt,name=manage_cgroups_mode,json=manageCgroupsMode,enum=CriuCgMode" json:"manage_cgroups_mode,omitempty"`
+ GhostLimit *uint32 `protobuf:"varint,35,opt,name=ghost_limit,json=ghostLimit,def=1048576" json:"ghost_limit,omitempty"`
+ IrmapScanPaths []string `protobuf:"bytes,36,rep,name=irmap_scan_paths,json=irmapScanPaths" json:"irmap_scan_paths,omitempty"`
+ External []string `protobuf:"bytes,37,rep,name=external" json:"external,omitempty"`
+ EmptyNs *uint32 `protobuf:"varint,38,opt,name=empty_ns,json=emptyNs" json:"empty_ns,omitempty"`
+ JoinNs []*JoinNamespace `protobuf:"bytes,39,rep,name=join_ns,json=joinNs" json:"join_ns,omitempty"`
+ CgroupProps *string `protobuf:"bytes,41,opt,name=cgroup_props,json=cgroupProps" json:"cgroup_props,omitempty"`
+ CgroupPropsFile *string `protobuf:"bytes,42,opt,name=cgroup_props_file,json=cgroupPropsFile" json:"cgroup_props_file,omitempty"`
+ CgroupDumpController []string `protobuf:"bytes,43,rep,name=cgroup_dump_controller,json=cgroupDumpController" json:"cgroup_dump_controller,omitempty"`
+ FreezeCgroup *string `protobuf:"bytes,44,opt,name=freeze_cgroup,json=freezeCgroup" json:"freeze_cgroup,omitempty"`
+ Timeout *uint32 `protobuf:"varint,45,opt,name=timeout" json:"timeout,omitempty"`
+ TcpSkipInFlight *bool `protobuf:"varint,46,opt,name=tcp_skip_in_flight,json=tcpSkipInFlight" json:"tcp_skip_in_flight,omitempty"`
+ WeakSysctls *bool `protobuf:"varint,47,opt,name=weak_sysctls,json=weakSysctls" json:"weak_sysctls,omitempty"`
+ LazyPages *bool `protobuf:"varint,48,opt,name=lazy_pages,json=lazyPages" json:"lazy_pages,omitempty"`
+ StatusFd *int32 `protobuf:"varint,49,opt,name=status_fd,json=statusFd" json:"status_fd,omitempty"`
+ OrphanPtsMaster *bool `protobuf:"varint,50,opt,name=orphan_pts_master,json=orphanPtsMaster" json:"orphan_pts_master,omitempty"`
+ ConfigFile *string `protobuf:"bytes,51,opt,name=config_file,json=configFile" json:"config_file,omitempty"`
+ TcpClose *bool `protobuf:"varint,52,opt,name=tcp_close,json=tcpClose" json:"tcp_close,omitempty"`
+ LsmProfile *string `protobuf:"bytes,53,opt,name=lsm_profile,json=lsmProfile" json:"lsm_profile,omitempty"`
+ TlsCacert *string `protobuf:"bytes,54,opt,name=tls_cacert,json=tlsCacert" json:"tls_cacert,omitempty"`
+ TlsCacrl *string `protobuf:"bytes,55,opt,name=tls_cacrl,json=tlsCacrl" json:"tls_cacrl,omitempty"`
+ TlsCert *string `protobuf:"bytes,56,opt,name=tls_cert,json=tlsCert" json:"tls_cert,omitempty"`
+ TlsKey *string `protobuf:"bytes,57,opt,name=tls_key,json=tlsKey" json:"tls_key,omitempty"`
+ Tls *bool `protobuf:"varint,58,opt,name=tls" json:"tls,omitempty"`
+ TlsNoCnVerify *bool `protobuf:"varint,59,opt,name=tls_no_cn_verify,json=tlsNoCnVerify" json:"tls_no_cn_verify,omitempty"`
+ CgroupYard *string `protobuf:"bytes,60,opt,name=cgroup_yard,json=cgroupYard" json:"cgroup_yard,omitempty"`
+ PreDumpMode *CriuPreDumpMode `protobuf:"varint,61,opt,name=pre_dump_mode,json=preDumpMode,enum=CriuPreDumpMode,def=1" json:"pre_dump_mode,omitempty"`
+ PidfdStoreSk *int32 `protobuf:"varint,62,opt,name=pidfd_store_sk,json=pidfdStoreSk" json:"pidfd_store_sk,omitempty"`
+ LsmMountContext *string `protobuf:"bytes,63,opt,name=lsm_mount_context,json=lsmMountContext" json:"lsm_mount_context,omitempty"` // optional bool check_mounts = 128;
+}
+
+// Default values for CriuOpts fields.
+const (
+ Default_CriuOpts_LogLevel = int32(2)
+ Default_CriuOpts_CpuCap = uint32(4294967295)
+ Default_CriuOpts_GhostLimit = uint32(1048576)
+ Default_CriuOpts_PreDumpMode = CriuPreDumpMode_SPLICE
+)
+
+func (x *CriuOpts) Reset() {
+ *x = CriuOpts{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_rpc_rpc_proto_msgTypes[7]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *CriuOpts) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CriuOpts) ProtoMessage() {}
+
+func (x *CriuOpts) ProtoReflect() protoreflect.Message {
+ mi := &file_rpc_rpc_proto_msgTypes[7]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use CriuOpts.ProtoReflect.Descriptor instead.
+func (*CriuOpts) Descriptor() ([]byte, []int) {
+ return file_rpc_rpc_proto_rawDescGZIP(), []int{7}
+}
+
+func (x *CriuOpts) GetImagesDirFd() int32 {
+ if x != nil && x.ImagesDirFd != nil {
+ return *x.ImagesDirFd
+ }
+ return 0
+}
+
+func (x *CriuOpts) GetPid() int32 {
+ if x != nil && x.Pid != nil {
+ return *x.Pid
+ }
+ return 0
+}
+
+func (x *CriuOpts) GetLeaveRunning() bool {
+ if x != nil && x.LeaveRunning != nil {
+ return *x.LeaveRunning
+ }
+ return false
+}
+
+func (x *CriuOpts) GetExtUnixSk() bool {
+ if x != nil && x.ExtUnixSk != nil {
+ return *x.ExtUnixSk
+ }
+ return false
+}
+
+func (x *CriuOpts) GetTcpEstablished() bool {
+ if x != nil && x.TcpEstablished != nil {
+ return *x.TcpEstablished
+ }
+ return false
+}
+
+func (x *CriuOpts) GetEvasiveDevices() bool {
+ if x != nil && x.EvasiveDevices != nil {
+ return *x.EvasiveDevices
+ }
+ return false
+}
+
+func (x *CriuOpts) GetShellJob() bool {
+ if x != nil && x.ShellJob != nil {
+ return *x.ShellJob
+ }
+ return false
+}
+
+func (x *CriuOpts) GetFileLocks() bool {
+ if x != nil && x.FileLocks != nil {
+ return *x.FileLocks
+ }
+ return false
+}
+
+func (x *CriuOpts) GetLogLevel() int32 {
+ if x != nil && x.LogLevel != nil {
+ return *x.LogLevel
+ }
+ return Default_CriuOpts_LogLevel
+}
+
+func (x *CriuOpts) GetLogFile() string {
+ if x != nil && x.LogFile != nil {
+ return *x.LogFile
+ }
+ return ""
+}
+
+func (x *CriuOpts) GetPs() *CriuPageServerInfo {
+ if x != nil {
+ return x.Ps
+ }
+ return nil
+}
+
+func (x *CriuOpts) GetNotifyScripts() bool {
+ if x != nil && x.NotifyScripts != nil {
+ return *x.NotifyScripts
+ }
+ return false
+}
+
+func (x *CriuOpts) GetRoot() string {
+ if x != nil && x.Root != nil {
+ return *x.Root
+ }
+ return ""
+}
+
+func (x *CriuOpts) GetParentImg() string {
+ if x != nil && x.ParentImg != nil {
+ return *x.ParentImg
+ }
+ return ""
+}
+
+func (x *CriuOpts) GetTrackMem() bool {
+ if x != nil && x.TrackMem != nil {
+ return *x.TrackMem
+ }
+ return false
+}
+
+func (x *CriuOpts) GetAutoDedup() bool {
+ if x != nil && x.AutoDedup != nil {
+ return *x.AutoDedup
+ }
+ return false
+}
+
+func (x *CriuOpts) GetWorkDirFd() int32 {
+ if x != nil && x.WorkDirFd != nil {
+ return *x.WorkDirFd
+ }
+ return 0
+}
+
+func (x *CriuOpts) GetLinkRemap() bool {
+ if x != nil && x.LinkRemap != nil {
+ return *x.LinkRemap
+ }
+ return false
+}
+
+func (x *CriuOpts) GetVeths() []*CriuVethPair {
+ if x != nil {
+ return x.Veths
+ }
+ return nil
+}
+
+func (x *CriuOpts) GetCpuCap() uint32 {
+ if x != nil && x.CpuCap != nil {
+ return *x.CpuCap
+ }
+ return Default_CriuOpts_CpuCap
+}
+
+func (x *CriuOpts) GetForceIrmap() bool {
+ if x != nil && x.ForceIrmap != nil {
+ return *x.ForceIrmap
+ }
+ return false
+}
+
+func (x *CriuOpts) GetExecCmd() []string {
+ if x != nil {
+ return x.ExecCmd
+ }
+ return nil
+}
+
+func (x *CriuOpts) GetExtMnt() []*ExtMountMap {
+ if x != nil {
+ return x.ExtMnt
+ }
+ return nil
+}
+
+func (x *CriuOpts) GetManageCgroups() bool {
+ if x != nil && x.ManageCgroups != nil {
+ return *x.ManageCgroups
+ }
+ return false
+}
+
+func (x *CriuOpts) GetCgRoot() []*CgroupRoot {
+ if x != nil {
+ return x.CgRoot
+ }
+ return nil
+}
+
+func (x *CriuOpts) GetRstSibling() bool {
+ if x != nil && x.RstSibling != nil {
+ return *x.RstSibling
+ }
+ return false
+}
+
+func (x *CriuOpts) GetInheritFd() []*InheritFd {
+ if x != nil {
+ return x.InheritFd
+ }
+ return nil
+}
+
+func (x *CriuOpts) GetAutoExtMnt() bool {
+ if x != nil && x.AutoExtMnt != nil {
+ return *x.AutoExtMnt
+ }
+ return false
+}
+
+func (x *CriuOpts) GetExtSharing() bool {
+ if x != nil && x.ExtSharing != nil {
+ return *x.ExtSharing
+ }
+ return false
+}
+
+func (x *CriuOpts) GetExtMasters() bool {
+ if x != nil && x.ExtMasters != nil {
+ return *x.ExtMasters
+ }
+ return false
+}
+
+func (x *CriuOpts) GetSkipMnt() []string {
+ if x != nil {
+ return x.SkipMnt
+ }
+ return nil
+}
+
+func (x *CriuOpts) GetEnableFs() []string {
+ if x != nil {
+ return x.EnableFs
+ }
+ return nil
+}
+
+func (x *CriuOpts) GetUnixSkIno() []*UnixSk {
+ if x != nil {
+ return x.UnixSkIno
+ }
+ return nil
+}
+
+func (x *CriuOpts) GetManageCgroupsMode() CriuCgMode {
+ if x != nil && x.ManageCgroupsMode != nil {
+ return *x.ManageCgroupsMode
+ }
+ return CriuCgMode_IGNORE
+}
+
+func (x *CriuOpts) GetGhostLimit() uint32 {
+ if x != nil && x.GhostLimit != nil {
+ return *x.GhostLimit
+ }
+ return Default_CriuOpts_GhostLimit
+}
+
+func (x *CriuOpts) GetIrmapScanPaths() []string {
+ if x != nil {
+ return x.IrmapScanPaths
+ }
+ return nil
+}
+
+func (x *CriuOpts) GetExternal() []string {
+ if x != nil {
+ return x.External
+ }
+ return nil
+}
+
+func (x *CriuOpts) GetEmptyNs() uint32 {
+ if x != nil && x.EmptyNs != nil {
+ return *x.EmptyNs
+ }
+ return 0
+}
+
+func (x *CriuOpts) GetJoinNs() []*JoinNamespace {
+ if x != nil {
+ return x.JoinNs
+ }
+ return nil
+}
+
+func (x *CriuOpts) GetCgroupProps() string {
+ if x != nil && x.CgroupProps != nil {
+ return *x.CgroupProps
+ }
+ return ""
+}
+
+func (x *CriuOpts) GetCgroupPropsFile() string {
+ if x != nil && x.CgroupPropsFile != nil {
+ return *x.CgroupPropsFile
+ }
+ return ""
+}
+
+func (x *CriuOpts) GetCgroupDumpController() []string {
+ if x != nil {
+ return x.CgroupDumpController
+ }
+ return nil
+}
+
+func (x *CriuOpts) GetFreezeCgroup() string {
+ if x != nil && x.FreezeCgroup != nil {
+ return *x.FreezeCgroup
+ }
+ return ""
+}
+
+func (x *CriuOpts) GetTimeout() uint32 {
+ if x != nil && x.Timeout != nil {
+ return *x.Timeout
+ }
+ return 0
+}
+
+func (x *CriuOpts) GetTcpSkipInFlight() bool {
+ if x != nil && x.TcpSkipInFlight != nil {
+ return *x.TcpSkipInFlight
+ }
+ return false
+}
+
+func (x *CriuOpts) GetWeakSysctls() bool {
+ if x != nil && x.WeakSysctls != nil {
+ return *x.WeakSysctls
+ }
+ return false
+}
+
+func (x *CriuOpts) GetLazyPages() bool {
+ if x != nil && x.LazyPages != nil {
+ return *x.LazyPages
+ }
+ return false
+}
+
+func (x *CriuOpts) GetStatusFd() int32 {
+ if x != nil && x.StatusFd != nil {
+ return *x.StatusFd
+ }
+ return 0
+}
+
+func (x *CriuOpts) GetOrphanPtsMaster() bool {
+ if x != nil && x.OrphanPtsMaster != nil {
+ return *x.OrphanPtsMaster
+ }
+ return false
+}
+
+func (x *CriuOpts) GetConfigFile() string {
+ if x != nil && x.ConfigFile != nil {
+ return *x.ConfigFile
+ }
+ return ""
+}
+
+func (x *CriuOpts) GetTcpClose() bool {
+ if x != nil && x.TcpClose != nil {
+ return *x.TcpClose
+ }
+ return false
+}
+
+func (x *CriuOpts) GetLsmProfile() string {
+ if x != nil && x.LsmProfile != nil {
+ return *x.LsmProfile
+ }
+ return ""
+}
+
+func (x *CriuOpts) GetTlsCacert() string {
+ if x != nil && x.TlsCacert != nil {
+ return *x.TlsCacert
+ }
+ return ""
+}
+
+func (x *CriuOpts) GetTlsCacrl() string {
+ if x != nil && x.TlsCacrl != nil {
+ return *x.TlsCacrl
+ }
+ return ""
+}
+
+func (x *CriuOpts) GetTlsCert() string {
+ if x != nil && x.TlsCert != nil {
+ return *x.TlsCert
+ }
+ return ""
+}
+
+func (x *CriuOpts) GetTlsKey() string {
+ if x != nil && x.TlsKey != nil {
+ return *x.TlsKey
+ }
+ return ""
+}
+
+func (x *CriuOpts) GetTls() bool {
+ if x != nil && x.Tls != nil {
+ return *x.Tls
+ }
+ return false
+}
+
+func (x *CriuOpts) GetTlsNoCnVerify() bool {
+ if x != nil && x.TlsNoCnVerify != nil {
+ return *x.TlsNoCnVerify
+ }
+ return false
+}
+
+func (x *CriuOpts) GetCgroupYard() string {
+ if x != nil && x.CgroupYard != nil {
+ return *x.CgroupYard
+ }
+ return ""
+}
+
+func (x *CriuOpts) GetPreDumpMode() CriuPreDumpMode {
+ if x != nil && x.PreDumpMode != nil {
+ return *x.PreDumpMode
+ }
+ return Default_CriuOpts_PreDumpMode
+}
+
+func (x *CriuOpts) GetPidfdStoreSk() int32 {
+ if x != nil && x.PidfdStoreSk != nil {
+ return *x.PidfdStoreSk
+ }
+ return 0
+}
+
+func (x *CriuOpts) GetLsmMountContext() string {
+ if x != nil && x.LsmMountContext != nil {
+ return *x.LsmMountContext
+ }
+ return ""
+}
+
+type CriuDumpResp struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Restored *bool `protobuf:"varint,1,opt,name=restored" json:"restored,omitempty"`
+}
+
+func (x *CriuDumpResp) Reset() {
+ *x = CriuDumpResp{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_rpc_rpc_proto_msgTypes[8]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *CriuDumpResp) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CriuDumpResp) ProtoMessage() {}
+
+func (x *CriuDumpResp) ProtoReflect() protoreflect.Message {
+ mi := &file_rpc_rpc_proto_msgTypes[8]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use CriuDumpResp.ProtoReflect.Descriptor instead.
+func (*CriuDumpResp) Descriptor() ([]byte, []int) {
+ return file_rpc_rpc_proto_rawDescGZIP(), []int{8}
+}
+
+func (x *CriuDumpResp) GetRestored() bool {
+ if x != nil && x.Restored != nil {
+ return *x.Restored
+ }
+ return false
+}
+
+type CriuRestoreResp struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Pid *int32 `protobuf:"varint,1,req,name=pid" json:"pid,omitempty"`
+}
+
+func (x *CriuRestoreResp) Reset() {
+ *x = CriuRestoreResp{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_rpc_rpc_proto_msgTypes[9]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *CriuRestoreResp) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CriuRestoreResp) ProtoMessage() {}
+
+func (x *CriuRestoreResp) ProtoReflect() protoreflect.Message {
+ mi := &file_rpc_rpc_proto_msgTypes[9]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use CriuRestoreResp.ProtoReflect.Descriptor instead.
+func (*CriuRestoreResp) Descriptor() ([]byte, []int) {
+ return file_rpc_rpc_proto_rawDescGZIP(), []int{9}
+}
+
+func (x *CriuRestoreResp) GetPid() int32 {
+ if x != nil && x.Pid != nil {
+ return *x.Pid
+ }
+ return 0
+}
+
+type CriuNotify struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Script *string `protobuf:"bytes,1,opt,name=script" json:"script,omitempty"`
+ Pid *int32 `protobuf:"varint,2,opt,name=pid" json:"pid,omitempty"`
+}
+
+func (x *CriuNotify) Reset() {
+ *x = CriuNotify{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_rpc_rpc_proto_msgTypes[10]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *CriuNotify) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CriuNotify) ProtoMessage() {}
+
+func (x *CriuNotify) ProtoReflect() protoreflect.Message {
+ mi := &file_rpc_rpc_proto_msgTypes[10]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use CriuNotify.ProtoReflect.Descriptor instead.
+func (*CriuNotify) Descriptor() ([]byte, []int) {
+ return file_rpc_rpc_proto_rawDescGZIP(), []int{10}
+}
+
+func (x *CriuNotify) GetScript() string {
+ if x != nil && x.Script != nil {
+ return *x.Script
+ }
+ return ""
+}
+
+func (x *CriuNotify) GetPid() int32 {
+ if x != nil && x.Pid != nil {
+ return *x.Pid
+ }
+ return 0
+}
+
+//
+// List of features which can queried via
+// CRIU_REQ_TYPE__FEATURE_CHECK
+type CriuFeatures struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ MemTrack *bool `protobuf:"varint,1,opt,name=mem_track,json=memTrack" json:"mem_track,omitempty"`
+ LazyPages *bool `protobuf:"varint,2,opt,name=lazy_pages,json=lazyPages" json:"lazy_pages,omitempty"`
+ PidfdStore *bool `protobuf:"varint,3,opt,name=pidfd_store,json=pidfdStore" json:"pidfd_store,omitempty"`
+}
+
+func (x *CriuFeatures) Reset() {
+ *x = CriuFeatures{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_rpc_rpc_proto_msgTypes[11]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *CriuFeatures) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CriuFeatures) ProtoMessage() {}
+
+func (x *CriuFeatures) ProtoReflect() protoreflect.Message {
+ mi := &file_rpc_rpc_proto_msgTypes[11]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use CriuFeatures.ProtoReflect.Descriptor instead.
+func (*CriuFeatures) Descriptor() ([]byte, []int) {
+ return file_rpc_rpc_proto_rawDescGZIP(), []int{11}
+}
+
+func (x *CriuFeatures) GetMemTrack() bool {
+ if x != nil && x.MemTrack != nil {
+ return *x.MemTrack
+ }
+ return false
+}
+
+func (x *CriuFeatures) GetLazyPages() bool {
+ if x != nil && x.LazyPages != nil {
+ return *x.LazyPages
+ }
+ return false
+}
+
+func (x *CriuFeatures) GetPidfdStore() bool {
+ if x != nil && x.PidfdStore != nil {
+ return *x.PidfdStore
+ }
+ return false
+}
+
+type CriuReq struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Type *CriuReqType `protobuf:"varint,1,req,name=type,enum=CriuReqType" json:"type,omitempty"`
+ Opts *CriuOpts `protobuf:"bytes,2,opt,name=opts" json:"opts,omitempty"`
+ NotifySuccess *bool `protobuf:"varint,3,opt,name=notify_success,json=notifySuccess" json:"notify_success,omitempty"`
+ //
+ // When set service won't close the connection but
+ // will wait for more req-s to appear. Works not
+ // for all request types.
+ KeepOpen *bool `protobuf:"varint,4,opt,name=keep_open,json=keepOpen" json:"keep_open,omitempty"`
+ //
+ // 'features' can be used to query which features
+ // are supported by the installed criu/kernel
+ // via RPC.
+ Features *CriuFeatures `protobuf:"bytes,5,opt,name=features" json:"features,omitempty"`
+ // 'pid' is used for WAIT_PID
+ Pid *uint32 `protobuf:"varint,6,opt,name=pid" json:"pid,omitempty"`
+}
+
+func (x *CriuReq) Reset() {
+ *x = CriuReq{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_rpc_rpc_proto_msgTypes[12]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *CriuReq) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CriuReq) ProtoMessage() {}
+
+func (x *CriuReq) ProtoReflect() protoreflect.Message {
+ mi := &file_rpc_rpc_proto_msgTypes[12]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use CriuReq.ProtoReflect.Descriptor instead.
+func (*CriuReq) Descriptor() ([]byte, []int) {
+ return file_rpc_rpc_proto_rawDescGZIP(), []int{12}
+}
+
+func (x *CriuReq) GetType() CriuReqType {
+ if x != nil && x.Type != nil {
+ return *x.Type
+ }
+ return CriuReqType_EMPTY
+}
+
+func (x *CriuReq) GetOpts() *CriuOpts {
+ if x != nil {
+ return x.Opts
+ }
+ return nil
+}
+
+func (x *CriuReq) GetNotifySuccess() bool {
+ if x != nil && x.NotifySuccess != nil {
+ return *x.NotifySuccess
+ }
+ return false
+}
+
+func (x *CriuReq) GetKeepOpen() bool {
+ if x != nil && x.KeepOpen != nil {
+ return *x.KeepOpen
+ }
+ return false
+}
+
+func (x *CriuReq) GetFeatures() *CriuFeatures {
+ if x != nil {
+ return x.Features
+ }
+ return nil
+}
+
+func (x *CriuReq) GetPid() uint32 {
+ if x != nil && x.Pid != nil {
+ return *x.Pid
+ }
+ return 0
+}
+
+type CriuResp struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Type *CriuReqType `protobuf:"varint,1,req,name=type,enum=CriuReqType" json:"type,omitempty"`
+ Success *bool `protobuf:"varint,2,req,name=success" json:"success,omitempty"`
+ Dump *CriuDumpResp `protobuf:"bytes,3,opt,name=dump" json:"dump,omitempty"`
+ Restore *CriuRestoreResp `protobuf:"bytes,4,opt,name=restore" json:"restore,omitempty"`
+ Notify *CriuNotify `protobuf:"bytes,5,opt,name=notify" json:"notify,omitempty"`
+ Ps *CriuPageServerInfo `protobuf:"bytes,6,opt,name=ps" json:"ps,omitempty"`
+ CrErrno *int32 `protobuf:"varint,7,opt,name=cr_errno,json=crErrno" json:"cr_errno,omitempty"`
+ Features *CriuFeatures `protobuf:"bytes,8,opt,name=features" json:"features,omitempty"`
+ CrErrmsg *string `protobuf:"bytes,9,opt,name=cr_errmsg,json=crErrmsg" json:"cr_errmsg,omitempty"`
+ Version *CriuVersion `protobuf:"bytes,10,opt,name=version" json:"version,omitempty"`
+ Status *int32 `protobuf:"varint,11,opt,name=status" json:"status,omitempty"`
+}
+
+func (x *CriuResp) Reset() {
+ *x = CriuResp{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_rpc_rpc_proto_msgTypes[13]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *CriuResp) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CriuResp) ProtoMessage() {}
+
+func (x *CriuResp) ProtoReflect() protoreflect.Message {
+ mi := &file_rpc_rpc_proto_msgTypes[13]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use CriuResp.ProtoReflect.Descriptor instead.
+func (*CriuResp) Descriptor() ([]byte, []int) {
+ return file_rpc_rpc_proto_rawDescGZIP(), []int{13}
+}
+
+func (x *CriuResp) GetType() CriuReqType {
+ if x != nil && x.Type != nil {
+ return *x.Type
+ }
+ return CriuReqType_EMPTY
+}
+
+func (x *CriuResp) GetSuccess() bool {
+ if x != nil && x.Success != nil {
+ return *x.Success
+ }
+ return false
+}
+
+func (x *CriuResp) GetDump() *CriuDumpResp {
+ if x != nil {
+ return x.Dump
+ }
+ return nil
+}
+
+func (x *CriuResp) GetRestore() *CriuRestoreResp {
+ if x != nil {
+ return x.Restore
+ }
+ return nil
+}
+
+func (x *CriuResp) GetNotify() *CriuNotify {
+ if x != nil {
+ return x.Notify
+ }
+ return nil
+}
+
+func (x *CriuResp) GetPs() *CriuPageServerInfo {
+ if x != nil {
+ return x.Ps
+ }
+ return nil
+}
+
+func (x *CriuResp) GetCrErrno() int32 {
+ if x != nil && x.CrErrno != nil {
+ return *x.CrErrno
+ }
+ return 0
+}
+
+func (x *CriuResp) GetFeatures() *CriuFeatures {
+ if x != nil {
+ return x.Features
+ }
+ return nil
+}
+
+func (x *CriuResp) GetCrErrmsg() string {
+ if x != nil && x.CrErrmsg != nil {
+ return *x.CrErrmsg
+ }
+ return ""
+}
+
+func (x *CriuResp) GetVersion() *CriuVersion {
+ if x != nil {
+ return x.Version
+ }
+ return nil
+}
+
+func (x *CriuResp) GetStatus() int32 {
+ if x != nil && x.Status != nil {
+ return *x.Status
+ }
+ return 0
+}
+
+// Answer for criu_req_type.VERSION requests
+type CriuVersion struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ MajorNumber *int32 `protobuf:"varint,1,req,name=major_number,json=majorNumber" json:"major_number,omitempty"`
+ MinorNumber *int32 `protobuf:"varint,2,req,name=minor_number,json=minorNumber" json:"minor_number,omitempty"`
+ Gitid *string `protobuf:"bytes,3,opt,name=gitid" json:"gitid,omitempty"`
+ Sublevel *int32 `protobuf:"varint,4,opt,name=sublevel" json:"sublevel,omitempty"`
+ Extra *int32 `protobuf:"varint,5,opt,name=extra" json:"extra,omitempty"`
+ Name *string `protobuf:"bytes,6,opt,name=name" json:"name,omitempty"`
+}
+
+func (x *CriuVersion) Reset() {
+ *x = CriuVersion{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_rpc_rpc_proto_msgTypes[14]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *CriuVersion) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CriuVersion) ProtoMessage() {}
+
+func (x *CriuVersion) ProtoReflect() protoreflect.Message {
+ mi := &file_rpc_rpc_proto_msgTypes[14]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use CriuVersion.ProtoReflect.Descriptor instead.
+func (*CriuVersion) Descriptor() ([]byte, []int) {
+ return file_rpc_rpc_proto_rawDescGZIP(), []int{14}
+}
+
+func (x *CriuVersion) GetMajorNumber() int32 {
+ if x != nil && x.MajorNumber != nil {
+ return *x.MajorNumber
+ }
+ return 0
+}
+
+func (x *CriuVersion) GetMinorNumber() int32 {
+ if x != nil && x.MinorNumber != nil {
+ return *x.MinorNumber
+ }
+ return 0
+}
+
+func (x *CriuVersion) GetGitid() string {
+ if x != nil && x.Gitid != nil {
+ return *x.Gitid
+ }
+ return ""
+}
+
+func (x *CriuVersion) GetSublevel() int32 {
+ if x != nil && x.Sublevel != nil {
+ return *x.Sublevel
+ }
+ return 0
+}
+
+func (x *CriuVersion) GetExtra() int32 {
+ if x != nil && x.Extra != nil {
+ return *x.Extra
+ }
+ return 0
+}
+
+func (x *CriuVersion) GetName() string {
+ if x != nil && x.Name != nil {
+ return *x.Name
+ }
+ return ""
+}
+
+var File_rpc_rpc_proto protoreflect.FileDescriptor
+
+var file_rpc_rpc_proto_rawDesc = []byte{
+ 0x0a, 0x0d, 0x72, 0x70, 0x63, 0x2f, 0x72, 0x70, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22,
+ 0x67, 0x0a, 0x15, 0x63, 0x72, 0x69, 0x75, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x65, 0x72,
+ 0x76, 0x65, 0x72, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72,
+ 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65,
+ 0x73, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05,
+ 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x69, 0x64, 0x18, 0x03, 0x20,
+ 0x01, 0x28, 0x05, 0x52, 0x03, 0x70, 0x69, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x66, 0x64, 0x18, 0x04,
+ 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x66, 0x64, 0x22, 0x3c, 0x0a, 0x0e, 0x63, 0x72, 0x69, 0x75,
+ 0x5f, 0x76, 0x65, 0x74, 0x68, 0x5f, 0x70, 0x61, 0x69, 0x72, 0x12, 0x13, 0x0a, 0x05, 0x69, 0x66,
+ 0x5f, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x02, 0x28, 0x09, 0x52, 0x04, 0x69, 0x66, 0x49, 0x6e, 0x12,
+ 0x15, 0x0a, 0x06, 0x69, 0x66, 0x5f, 0x6f, 0x75, 0x74, 0x18, 0x02, 0x20, 0x02, 0x28, 0x09, 0x52,
+ 0x05, 0x69, 0x66, 0x4f, 0x75, 0x74, 0x22, 0x33, 0x0a, 0x0d, 0x65, 0x78, 0x74, 0x5f, 0x6d, 0x6f,
+ 0x75, 0x6e, 0x74, 0x5f, 0x6d, 0x61, 0x70, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01,
+ 0x20, 0x02, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x76, 0x61, 0x6c,
+ 0x18, 0x02, 0x20, 0x02, 0x28, 0x09, 0x52, 0x03, 0x76, 0x61, 0x6c, 0x22, 0x56, 0x0a, 0x0e, 0x6a,
+ 0x6f, 0x69, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x0e, 0x0a,
+ 0x02, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x02, 0x28, 0x09, 0x52, 0x02, 0x6e, 0x73, 0x12, 0x17, 0x0a,
+ 0x07, 0x6e, 0x73, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x02, 0x28, 0x09, 0x52, 0x06,
+ 0x6e, 0x73, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x65, 0x78, 0x74, 0x72, 0x61, 0x5f,
+ 0x6f, 0x70, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x65, 0x78, 0x74, 0x72, 0x61,
+ 0x4f, 0x70, 0x74, 0x22, 0x2e, 0x0a, 0x0a, 0x69, 0x6e, 0x68, 0x65, 0x72, 0x69, 0x74, 0x5f, 0x66,
+ 0x64, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x02, 0x28, 0x09, 0x52, 0x03,
+ 0x6b, 0x65, 0x79, 0x12, 0x0e, 0x0a, 0x02, 0x66, 0x64, 0x18, 0x02, 0x20, 0x02, 0x28, 0x05, 0x52,
+ 0x02, 0x66, 0x64, 0x22, 0x35, 0x0a, 0x0b, 0x63, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x72, 0x6f,
+ 0x6f, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x74, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
+ 0x52, 0x04, 0x63, 0x74, 0x72, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02,
+ 0x20, 0x02, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x22, 0x1f, 0x0a, 0x07, 0x75, 0x6e,
+ 0x69, 0x78, 0x5f, 0x73, 0x6b, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x01,
+ 0x20, 0x02, 0x28, 0x0d, 0x52, 0x05, 0x69, 0x6e, 0x6f, 0x64, 0x65, 0x22, 0x8c, 0x11, 0x0a, 0x09,
+ 0x63, 0x72, 0x69, 0x75, 0x5f, 0x6f, 0x70, 0x74, 0x73, 0x12, 0x22, 0x0a, 0x0d, 0x69, 0x6d, 0x61,
+ 0x67, 0x65, 0x73, 0x5f, 0x64, 0x69, 0x72, 0x5f, 0x66, 0x64, 0x18, 0x01, 0x20, 0x02, 0x28, 0x05,
+ 0x52, 0x0b, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x73, 0x44, 0x69, 0x72, 0x46, 0x64, 0x12, 0x10, 0x0a,
+ 0x03, 0x70, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x70, 0x69, 0x64, 0x12,
+ 0x23, 0x0a, 0x0d, 0x6c, 0x65, 0x61, 0x76, 0x65, 0x5f, 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67,
+ 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x6c, 0x65, 0x61, 0x76, 0x65, 0x52, 0x75, 0x6e,
+ 0x6e, 0x69, 0x6e, 0x67, 0x12, 0x1e, 0x0a, 0x0b, 0x65, 0x78, 0x74, 0x5f, 0x75, 0x6e, 0x69, 0x78,
+ 0x5f, 0x73, 0x6b, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x65, 0x78, 0x74, 0x55, 0x6e,
+ 0x69, 0x78, 0x53, 0x6b, 0x12, 0x27, 0x0a, 0x0f, 0x74, 0x63, 0x70, 0x5f, 0x65, 0x73, 0x74, 0x61,
+ 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x74,
+ 0x63, 0x70, 0x45, 0x73, 0x74, 0x61, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x12, 0x27, 0x0a,
+ 0x0f, 0x65, 0x76, 0x61, 0x73, 0x69, 0x76, 0x65, 0x5f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73,
+ 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x65, 0x76, 0x61, 0x73, 0x69, 0x76, 0x65, 0x44,
+ 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x68, 0x65, 0x6c, 0x6c, 0x5f,
+ 0x6a, 0x6f, 0x62, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x73, 0x68, 0x65, 0x6c, 0x6c,
+ 0x4a, 0x6f, 0x62, 0x12, 0x1d, 0x0a, 0x0a, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x6c, 0x6f, 0x63, 0x6b,
+ 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x66, 0x69, 0x6c, 0x65, 0x4c, 0x6f, 0x63,
+ 0x6b, 0x73, 0x12, 0x1e, 0x0a, 0x09, 0x6c, 0x6f, 0x67, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18,
+ 0x09, 0x20, 0x01, 0x28, 0x05, 0x3a, 0x01, 0x32, 0x52, 0x08, 0x6c, 0x6f, 0x67, 0x4c, 0x65, 0x76,
+ 0x65, 0x6c, 0x12, 0x19, 0x0a, 0x08, 0x6c, 0x6f, 0x67, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x0a,
+ 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6c, 0x6f, 0x67, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x26, 0x0a,
+ 0x02, 0x70, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x63, 0x72, 0x69, 0x75,
+ 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x69, 0x6e, 0x66,
+ 0x6f, 0x52, 0x02, 0x70, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x5f,
+ 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x73, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x6e,
+ 0x6f, 0x74, 0x69, 0x66, 0x79, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x73, 0x12, 0x12, 0x0a, 0x04,
+ 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x74,
+ 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x6d, 0x67, 0x18, 0x0e,
+ 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x49, 0x6d, 0x67, 0x12,
+ 0x1b, 0x0a, 0x09, 0x74, 0x72, 0x61, 0x63, 0x6b, 0x5f, 0x6d, 0x65, 0x6d, 0x18, 0x0f, 0x20, 0x01,
+ 0x28, 0x08, 0x52, 0x08, 0x74, 0x72, 0x61, 0x63, 0x6b, 0x4d, 0x65, 0x6d, 0x12, 0x1d, 0x0a, 0x0a,
+ 0x61, 0x75, 0x74, 0x6f, 0x5f, 0x64, 0x65, 0x64, 0x75, 0x70, 0x18, 0x10, 0x20, 0x01, 0x28, 0x08,
+ 0x52, 0x09, 0x61, 0x75, 0x74, 0x6f, 0x44, 0x65, 0x64, 0x75, 0x70, 0x12, 0x1e, 0x0a, 0x0b, 0x77,
+ 0x6f, 0x72, 0x6b, 0x5f, 0x64, 0x69, 0x72, 0x5f, 0x66, 0x64, 0x18, 0x11, 0x20, 0x01, 0x28, 0x05,
+ 0x52, 0x09, 0x77, 0x6f, 0x72, 0x6b, 0x44, 0x69, 0x72, 0x46, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x6c,
+ 0x69, 0x6e, 0x6b, 0x5f, 0x72, 0x65, 0x6d, 0x61, 0x70, 0x18, 0x12, 0x20, 0x01, 0x28, 0x08, 0x52,
+ 0x09, 0x6c, 0x69, 0x6e, 0x6b, 0x52, 0x65, 0x6d, 0x61, 0x70, 0x12, 0x25, 0x0a, 0x05, 0x76, 0x65,
+ 0x74, 0x68, 0x73, 0x18, 0x13, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x63, 0x72, 0x69, 0x75,
+ 0x5f, 0x76, 0x65, 0x74, 0x68, 0x5f, 0x70, 0x61, 0x69, 0x72, 0x52, 0x05, 0x76, 0x65, 0x74, 0x68,
+ 0x73, 0x12, 0x23, 0x0a, 0x07, 0x63, 0x70, 0x75, 0x5f, 0x63, 0x61, 0x70, 0x18, 0x14, 0x20, 0x01,
+ 0x28, 0x0d, 0x3a, 0x0a, 0x34, 0x32, 0x39, 0x34, 0x39, 0x36, 0x37, 0x32, 0x39, 0x35, 0x52, 0x06,
+ 0x63, 0x70, 0x75, 0x43, 0x61, 0x70, 0x12, 0x1f, 0x0a, 0x0b, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x5f,
+ 0x69, 0x72, 0x6d, 0x61, 0x70, 0x18, 0x15, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x66, 0x6f, 0x72,
+ 0x63, 0x65, 0x49, 0x72, 0x6d, 0x61, 0x70, 0x12, 0x19, 0x0a, 0x08, 0x65, 0x78, 0x65, 0x63, 0x5f,
+ 0x63, 0x6d, 0x64, 0x18, 0x16, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x65, 0x78, 0x65, 0x63, 0x43,
+ 0x6d, 0x64, 0x12, 0x27, 0x0a, 0x07, 0x65, 0x78, 0x74, 0x5f, 0x6d, 0x6e, 0x74, 0x18, 0x17, 0x20,
+ 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x65, 0x78, 0x74, 0x5f, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x5f,
+ 0x6d, 0x61, 0x70, 0x52, 0x06, 0x65, 0x78, 0x74, 0x4d, 0x6e, 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x6d,
+ 0x61, 0x6e, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x18, 0x18, 0x20,
+ 0x01, 0x28, 0x08, 0x52, 0x0d, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x43, 0x67, 0x72, 0x6f, 0x75,
+ 0x70, 0x73, 0x12, 0x25, 0x0a, 0x07, 0x63, 0x67, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x19, 0x20,
+ 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x63, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x72, 0x6f, 0x6f,
+ 0x74, 0x52, 0x06, 0x63, 0x67, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x73, 0x74,
+ 0x5f, 0x73, 0x69, 0x62, 0x6c, 0x69, 0x6e, 0x67, 0x18, 0x1a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a,
+ 0x72, 0x73, 0x74, 0x53, 0x69, 0x62, 0x6c, 0x69, 0x6e, 0x67, 0x12, 0x2a, 0x0a, 0x0a, 0x69, 0x6e,
+ 0x68, 0x65, 0x72, 0x69, 0x74, 0x5f, 0x66, 0x64, 0x18, 0x1b, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0b,
+ 0x2e, 0x69, 0x6e, 0x68, 0x65, 0x72, 0x69, 0x74, 0x5f, 0x66, 0x64, 0x52, 0x09, 0x69, 0x6e, 0x68,
+ 0x65, 0x72, 0x69, 0x74, 0x46, 0x64, 0x12, 0x20, 0x0a, 0x0c, 0x61, 0x75, 0x74, 0x6f, 0x5f, 0x65,
+ 0x78, 0x74, 0x5f, 0x6d, 0x6e, 0x74, 0x18, 0x1c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x61, 0x75,
+ 0x74, 0x6f, 0x45, 0x78, 0x74, 0x4d, 0x6e, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x65, 0x78, 0x74, 0x5f,
+ 0x73, 0x68, 0x61, 0x72, 0x69, 0x6e, 0x67, 0x18, 0x1d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x65,
+ 0x78, 0x74, 0x53, 0x68, 0x61, 0x72, 0x69, 0x6e, 0x67, 0x12, 0x1f, 0x0a, 0x0b, 0x65, 0x78, 0x74,
+ 0x5f, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x73, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a,
+ 0x65, 0x78, 0x74, 0x4d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x6b,
+ 0x69, 0x70, 0x5f, 0x6d, 0x6e, 0x74, 0x18, 0x1f, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x73, 0x6b,
+ 0x69, 0x70, 0x4d, 0x6e, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f,
+ 0x66, 0x73, 0x18, 0x20, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65,
+ 0x46, 0x73, 0x12, 0x28, 0x0a, 0x0b, 0x75, 0x6e, 0x69, 0x78, 0x5f, 0x73, 0x6b, 0x5f, 0x69, 0x6e,
+ 0x6f, 0x18, 0x21, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x75, 0x6e, 0x69, 0x78, 0x5f, 0x73,
+ 0x6b, 0x52, 0x09, 0x75, 0x6e, 0x69, 0x78, 0x53, 0x6b, 0x49, 0x6e, 0x6f, 0x12, 0x3d, 0x0a, 0x13,
+ 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x5f, 0x6d,
+ 0x6f, 0x64, 0x65, 0x18, 0x22, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0d, 0x2e, 0x63, 0x72, 0x69, 0x75,
+ 0x5f, 0x63, 0x67, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x52, 0x11, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65,
+ 0x43, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x28, 0x0a, 0x0b, 0x67,
+ 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x23, 0x20, 0x01, 0x28, 0x0d,
+ 0x3a, 0x07, 0x31, 0x30, 0x34, 0x38, 0x35, 0x37, 0x36, 0x52, 0x0a, 0x67, 0x68, 0x6f, 0x73, 0x74,
+ 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x28, 0x0a, 0x10, 0x69, 0x72, 0x6d, 0x61, 0x70, 0x5f, 0x73,
+ 0x63, 0x61, 0x6e, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x73, 0x18, 0x24, 0x20, 0x03, 0x28, 0x09, 0x52,
+ 0x0e, 0x69, 0x72, 0x6d, 0x61, 0x70, 0x53, 0x63, 0x61, 0x6e, 0x50, 0x61, 0x74, 0x68, 0x73, 0x12,
+ 0x1a, 0x0a, 0x08, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x18, 0x25, 0x20, 0x03, 0x28,
+ 0x09, 0x52, 0x08, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x12, 0x19, 0x0a, 0x08, 0x65,
+ 0x6d, 0x70, 0x74, 0x79, 0x5f, 0x6e, 0x73, 0x18, 0x26, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x65,
+ 0x6d, 0x70, 0x74, 0x79, 0x4e, 0x73, 0x12, 0x28, 0x0a, 0x07, 0x6a, 0x6f, 0x69, 0x6e, 0x5f, 0x6e,
+ 0x73, 0x18, 0x27, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x6a, 0x6f, 0x69, 0x6e, 0x5f, 0x6e,
+ 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x52, 0x06, 0x6a, 0x6f, 0x69, 0x6e, 0x4e, 0x73,
+ 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x70, 0x72, 0x6f, 0x70, 0x73,
+ 0x18, 0x29, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x50, 0x72,
+ 0x6f, 0x70, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x63, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x70, 0x72,
+ 0x6f, 0x70, 0x73, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x2a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f,
+ 0x63, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x50, 0x72, 0x6f, 0x70, 0x73, 0x46, 0x69, 0x6c, 0x65, 0x12,
+ 0x34, 0x0a, 0x16, 0x63, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x64, 0x75, 0x6d, 0x70, 0x5f, 0x63,
+ 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x18, 0x2b, 0x20, 0x03, 0x28, 0x09, 0x52,
+ 0x14, 0x63, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x44, 0x75, 0x6d, 0x70, 0x43, 0x6f, 0x6e, 0x74, 0x72,
+ 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x12, 0x23, 0x0a, 0x0d, 0x66, 0x72, 0x65, 0x65, 0x7a, 0x65, 0x5f,
+ 0x63, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x2c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x66, 0x72,
+ 0x65, 0x65, 0x7a, 0x65, 0x43, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x69,
+ 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x2d, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x74, 0x69, 0x6d,
+ 0x65, 0x6f, 0x75, 0x74, 0x12, 0x2b, 0x0a, 0x12, 0x74, 0x63, 0x70, 0x5f, 0x73, 0x6b, 0x69, 0x70,
+ 0x5f, 0x69, 0x6e, 0x5f, 0x66, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x18, 0x2e, 0x20, 0x01, 0x28, 0x08,
+ 0x52, 0x0f, 0x74, 0x63, 0x70, 0x53, 0x6b, 0x69, 0x70, 0x49, 0x6e, 0x46, 0x6c, 0x69, 0x67, 0x68,
+ 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x77, 0x65, 0x61, 0x6b, 0x5f, 0x73, 0x79, 0x73, 0x63, 0x74, 0x6c,
+ 0x73, 0x18, 0x2f, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x77, 0x65, 0x61, 0x6b, 0x53, 0x79, 0x73,
+ 0x63, 0x74, 0x6c, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x61, 0x7a, 0x79, 0x5f, 0x70, 0x61, 0x67,
+ 0x65, 0x73, 0x18, 0x30, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x6c, 0x61, 0x7a, 0x79, 0x50, 0x61,
+ 0x67, 0x65, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x5f, 0x66, 0x64,
+ 0x18, 0x31, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x46, 0x64,
+ 0x12, 0x2a, 0x0a, 0x11, 0x6f, 0x72, 0x70, 0x68, 0x61, 0x6e, 0x5f, 0x70, 0x74, 0x73, 0x5f, 0x6d,
+ 0x61, 0x73, 0x74, 0x65, 0x72, 0x18, 0x32, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x6f, 0x72, 0x70,
+ 0x68, 0x61, 0x6e, 0x50, 0x74, 0x73, 0x4d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x12, 0x1f, 0x0a, 0x0b,
+ 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x33, 0x20, 0x01, 0x28,
+ 0x09, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x1b, 0x0a,
+ 0x09, 0x74, 0x63, 0x70, 0x5f, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x18, 0x34, 0x20, 0x01, 0x28, 0x08,
+ 0x52, 0x08, 0x74, 0x63, 0x70, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x6c, 0x73,
+ 0x6d, 0x5f, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x35, 0x20, 0x01, 0x28, 0x09, 0x52,
+ 0x0a, 0x6c, 0x73, 0x6d, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x74,
+ 0x6c, 0x73, 0x5f, 0x63, 0x61, 0x63, 0x65, 0x72, 0x74, 0x18, 0x36, 0x20, 0x01, 0x28, 0x09, 0x52,
+ 0x09, 0x74, 0x6c, 0x73, 0x43, 0x61, 0x63, 0x65, 0x72, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x6c,
+ 0x73, 0x5f, 0x63, 0x61, 0x63, 0x72, 0x6c, 0x18, 0x37, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74,
+ 0x6c, 0x73, 0x43, 0x61, 0x63, 0x72, 0x6c, 0x12, 0x19, 0x0a, 0x08, 0x74, 0x6c, 0x73, 0x5f, 0x63,
+ 0x65, 0x72, 0x74, 0x18, 0x38, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x74, 0x6c, 0x73, 0x43, 0x65,
+ 0x72, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x74, 0x6c, 0x73, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x39, 0x20,
+ 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x6c, 0x73, 0x4b, 0x65, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x74,
+ 0x6c, 0x73, 0x18, 0x3a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x03, 0x74, 0x6c, 0x73, 0x12, 0x27, 0x0a,
+ 0x10, 0x74, 0x6c, 0x73, 0x5f, 0x6e, 0x6f, 0x5f, 0x63, 0x6e, 0x5f, 0x76, 0x65, 0x72, 0x69, 0x66,
+ 0x79, 0x18, 0x3b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x74, 0x6c, 0x73, 0x4e, 0x6f, 0x43, 0x6e,
+ 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x67, 0x72, 0x6f, 0x75, 0x70,
+ 0x5f, 0x79, 0x61, 0x72, 0x64, 0x18, 0x3c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x67, 0x72,
+ 0x6f, 0x75, 0x70, 0x59, 0x61, 0x72, 0x64, 0x12, 0x3f, 0x0a, 0x0d, 0x70, 0x72, 0x65, 0x5f, 0x64,
+ 0x75, 0x6d, 0x70, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x3d, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x13,
+ 0x2e, 0x63, 0x72, 0x69, 0x75, 0x5f, 0x70, 0x72, 0x65, 0x5f, 0x64, 0x75, 0x6d, 0x70, 0x5f, 0x6d,
+ 0x6f, 0x64, 0x65, 0x3a, 0x06, 0x53, 0x50, 0x4c, 0x49, 0x43, 0x45, 0x52, 0x0b, 0x70, 0x72, 0x65,
+ 0x44, 0x75, 0x6d, 0x70, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x24, 0x0a, 0x0e, 0x70, 0x69, 0x64, 0x66,
+ 0x64, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x73, 0x6b, 0x18, 0x3e, 0x20, 0x01, 0x28, 0x05,
+ 0x52, 0x0c, 0x70, 0x69, 0x64, 0x66, 0x64, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x53, 0x6b, 0x12, 0x2a,
+ 0x0a, 0x11, 0x6c, 0x73, 0x6d, 0x5f, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x74,
+ 0x65, 0x78, 0x74, 0x18, 0x3f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x6c, 0x73, 0x6d, 0x4d, 0x6f,
+ 0x75, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x22, 0x2c, 0x0a, 0x0e, 0x63, 0x72,
+ 0x69, 0x75, 0x5f, 0x64, 0x75, 0x6d, 0x70, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x12, 0x1a, 0x0a, 0x08,
+ 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08,
+ 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x64, 0x22, 0x25, 0x0a, 0x11, 0x63, 0x72, 0x69, 0x75,
+ 0x5f, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x12, 0x10, 0x0a,
+ 0x03, 0x70, 0x69, 0x64, 0x18, 0x01, 0x20, 0x02, 0x28, 0x05, 0x52, 0x03, 0x70, 0x69, 0x64, 0x22,
+ 0x37, 0x0a, 0x0b, 0x63, 0x72, 0x69, 0x75, 0x5f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x12, 0x16,
+ 0x0a, 0x06, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06,
+ 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x69, 0x64, 0x18, 0x02, 0x20,
+ 0x01, 0x28, 0x05, 0x52, 0x03, 0x70, 0x69, 0x64, 0x22, 0x6c, 0x0a, 0x0d, 0x63, 0x72, 0x69, 0x75,
+ 0x5f, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x65, 0x6d,
+ 0x5f, 0x74, 0x72, 0x61, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x6d, 0x65,
+ 0x6d, 0x54, 0x72, 0x61, 0x63, 0x6b, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x61, 0x7a, 0x79, 0x5f, 0x70,
+ 0x61, 0x67, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x6c, 0x61, 0x7a, 0x79,
+ 0x50, 0x61, 0x67, 0x65, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x69, 0x64, 0x66, 0x64, 0x5f, 0x73,
+ 0x74, 0x6f, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x70, 0x69, 0x64, 0x66,
+ 0x64, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x22, 0xd0, 0x01, 0x0a, 0x08, 0x63, 0x72, 0x69, 0x75, 0x5f,
+ 0x72, 0x65, 0x71, 0x12, 0x22, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x02, 0x28,
+ 0x0e, 0x32, 0x0e, 0x2e, 0x63, 0x72, 0x69, 0x75, 0x5f, 0x72, 0x65, 0x71, 0x5f, 0x74, 0x79, 0x70,
+ 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x1e, 0x0a, 0x04, 0x6f, 0x70, 0x74, 0x73, 0x18,
+ 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x63, 0x72, 0x69, 0x75, 0x5f, 0x6f, 0x70, 0x74,
+ 0x73, 0x52, 0x04, 0x6f, 0x70, 0x74, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x6e, 0x6f, 0x74, 0x69, 0x66,
+ 0x79, 0x5f, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52,
+ 0x0d, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x1b,
+ 0x0a, 0x09, 0x6b, 0x65, 0x65, 0x70, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28,
+ 0x08, 0x52, 0x08, 0x6b, 0x65, 0x65, 0x70, 0x4f, 0x70, 0x65, 0x6e, 0x12, 0x2a, 0x0a, 0x08, 0x66,
+ 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e,
+ 0x63, 0x72, 0x69, 0x75, 0x5f, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x52, 0x08, 0x66,
+ 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x69, 0x64, 0x18, 0x06,
+ 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x70, 0x69, 0x64, 0x22, 0x8f, 0x03, 0x0a, 0x09, 0x63, 0x72,
+ 0x69, 0x75, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x12, 0x22, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18,
+ 0x01, 0x20, 0x02, 0x28, 0x0e, 0x32, 0x0e, 0x2e, 0x63, 0x72, 0x69, 0x75, 0x5f, 0x72, 0x65, 0x71,
+ 0x5f, 0x74, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73,
+ 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x02, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75,
+ 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x23, 0x0a, 0x04, 0x64, 0x75, 0x6d, 0x70, 0x18, 0x03, 0x20,
+ 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x63, 0x72, 0x69, 0x75, 0x5f, 0x64, 0x75, 0x6d, 0x70, 0x5f,
+ 0x72, 0x65, 0x73, 0x70, 0x52, 0x04, 0x64, 0x75, 0x6d, 0x70, 0x12, 0x2c, 0x0a, 0x07, 0x72, 0x65,
+ 0x73, 0x74, 0x6f, 0x72, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x63, 0x72,
+ 0x69, 0x75, 0x5f, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x52,
+ 0x07, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x12, 0x24, 0x0a, 0x06, 0x6e, 0x6f, 0x74, 0x69,
+ 0x66, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x63, 0x72, 0x69, 0x75, 0x5f,
+ 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x52, 0x06, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x12, 0x26,
+ 0x0a, 0x02, 0x70, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x63, 0x72, 0x69,
+ 0x75, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x69, 0x6e,
+ 0x66, 0x6f, 0x52, 0x02, 0x70, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x63, 0x72, 0x5f, 0x65, 0x72, 0x72,
+ 0x6e, 0x6f, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x63, 0x72, 0x45, 0x72, 0x72, 0x6e,
+ 0x6f, 0x12, 0x2a, 0x0a, 0x08, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x18, 0x08, 0x20,
+ 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x63, 0x72, 0x69, 0x75, 0x5f, 0x66, 0x65, 0x61, 0x74, 0x75,
+ 0x72, 0x65, 0x73, 0x52, 0x08, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x12, 0x1b, 0x0a,
+ 0x09, 0x63, 0x72, 0x5f, 0x65, 0x72, 0x72, 0x6d, 0x73, 0x67, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09,
+ 0x52, 0x08, 0x63, 0x72, 0x45, 0x72, 0x72, 0x6d, 0x73, 0x67, 0x12, 0x27, 0x0a, 0x07, 0x76, 0x65,
+ 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x63, 0x72,
+ 0x69, 0x75, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73,
+ 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x0b, 0x20,
+ 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0xb0, 0x01, 0x0a, 0x0c,
+ 0x63, 0x72, 0x69, 0x75, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x21, 0x0a, 0x0c,
+ 0x6d, 0x61, 0x6a, 0x6f, 0x72, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x02,
+ 0x28, 0x05, 0x52, 0x0b, 0x6d, 0x61, 0x6a, 0x6f, 0x72, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12,
+ 0x21, 0x0a, 0x0c, 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18,
+ 0x02, 0x20, 0x02, 0x28, 0x05, 0x52, 0x0b, 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x4e, 0x75, 0x6d, 0x62,
+ 0x65, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x67, 0x69, 0x74, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28,
+ 0x09, 0x52, 0x05, 0x67, 0x69, 0x74, 0x69, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x75, 0x62, 0x6c,
+ 0x65, 0x76, 0x65, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x73, 0x75, 0x62, 0x6c,
+ 0x65, 0x76, 0x65, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x78, 0x74, 0x72, 0x61, 0x18, 0x05, 0x20,
+ 0x01, 0x28, 0x05, 0x52, 0x05, 0x65, 0x78, 0x74, 0x72, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61,
+ 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x2a, 0x5f,
+ 0x0a, 0x0c, 0x63, 0x72, 0x69, 0x75, 0x5f, 0x63, 0x67, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x12, 0x0a,
+ 0x0a, 0x06, 0x49, 0x47, 0x4e, 0x4f, 0x52, 0x45, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x43, 0x47,
+ 0x5f, 0x4e, 0x4f, 0x4e, 0x45, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x50, 0x52, 0x4f, 0x50, 0x53,
+ 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x53, 0x4f, 0x46, 0x54, 0x10, 0x03, 0x12, 0x08, 0x0a, 0x04,
+ 0x46, 0x55, 0x4c, 0x4c, 0x10, 0x04, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x54, 0x52, 0x49, 0x43, 0x54,
+ 0x10, 0x05, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x10, 0x06, 0x2a,
+ 0x2d, 0x0a, 0x12, 0x63, 0x72, 0x69, 0x75, 0x5f, 0x70, 0x72, 0x65, 0x5f, 0x64, 0x75, 0x6d, 0x70,
+ 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x50, 0x4c, 0x49, 0x43, 0x45, 0x10,
+ 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x56, 0x4d, 0x5f, 0x52, 0x45, 0x41, 0x44, 0x10, 0x02, 0x2a, 0xd0,
+ 0x01, 0x0a, 0x0d, 0x63, 0x72, 0x69, 0x75, 0x5f, 0x72, 0x65, 0x71, 0x5f, 0x74, 0x79, 0x70, 0x65,
+ 0x12, 0x09, 0x0a, 0x05, 0x45, 0x4d, 0x50, 0x54, 0x59, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x44,
+ 0x55, 0x4d, 0x50, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x52, 0x45, 0x53, 0x54, 0x4f, 0x52, 0x45,
+ 0x10, 0x02, 0x12, 0x09, 0x0a, 0x05, 0x43, 0x48, 0x45, 0x43, 0x4b, 0x10, 0x03, 0x12, 0x0c, 0x0a,
+ 0x08, 0x50, 0x52, 0x45, 0x5f, 0x44, 0x55, 0x4d, 0x50, 0x10, 0x04, 0x12, 0x0f, 0x0a, 0x0b, 0x50,
+ 0x41, 0x47, 0x45, 0x5f, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x10, 0x05, 0x12, 0x0a, 0x0a, 0x06,
+ 0x4e, 0x4f, 0x54, 0x49, 0x46, 0x59, 0x10, 0x06, 0x12, 0x10, 0x0a, 0x0c, 0x43, 0x50, 0x55, 0x49,
+ 0x4e, 0x46, 0x4f, 0x5f, 0x44, 0x55, 0x4d, 0x50, 0x10, 0x07, 0x12, 0x11, 0x0a, 0x0d, 0x43, 0x50,
+ 0x55, 0x49, 0x4e, 0x46, 0x4f, 0x5f, 0x43, 0x48, 0x45, 0x43, 0x4b, 0x10, 0x08, 0x12, 0x11, 0x0a,
+ 0x0d, 0x46, 0x45, 0x41, 0x54, 0x55, 0x52, 0x45, 0x5f, 0x43, 0x48, 0x45, 0x43, 0x4b, 0x10, 0x09,
+ 0x12, 0x0b, 0x0a, 0x07, 0x56, 0x45, 0x52, 0x53, 0x49, 0x4f, 0x4e, 0x10, 0x0a, 0x12, 0x0c, 0x0a,
+ 0x08, 0x57, 0x41, 0x49, 0x54, 0x5f, 0x50, 0x49, 0x44, 0x10, 0x0b, 0x12, 0x14, 0x0a, 0x10, 0x50,
+ 0x41, 0x47, 0x45, 0x5f, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x43, 0x48, 0x4c, 0x44, 0x10,
+ 0x0c,
+}
+
+var (
+ file_rpc_rpc_proto_rawDescOnce sync.Once
+ file_rpc_rpc_proto_rawDescData = file_rpc_rpc_proto_rawDesc
+)
+
+func file_rpc_rpc_proto_rawDescGZIP() []byte {
+ file_rpc_rpc_proto_rawDescOnce.Do(func() {
+ file_rpc_rpc_proto_rawDescData = protoimpl.X.CompressGZIP(file_rpc_rpc_proto_rawDescData)
+ })
+ return file_rpc_rpc_proto_rawDescData
+}
+
+var file_rpc_rpc_proto_enumTypes = make([]protoimpl.EnumInfo, 3)
+var file_rpc_rpc_proto_msgTypes = make([]protoimpl.MessageInfo, 15)
+var file_rpc_rpc_proto_goTypes = []interface{}{
+ (CriuCgMode)(0), // 0: criu_cg_mode
+ (CriuPreDumpMode)(0), // 1: criu_pre_dump_mode
+ (CriuReqType)(0), // 2: criu_req_type
+ (*CriuPageServerInfo)(nil), // 3: criu_page_server_info
+ (*CriuVethPair)(nil), // 4: criu_veth_pair
+ (*ExtMountMap)(nil), // 5: ext_mount_map
+ (*JoinNamespace)(nil), // 6: join_namespace
+ (*InheritFd)(nil), // 7: inherit_fd
+ (*CgroupRoot)(nil), // 8: cgroup_root
+ (*UnixSk)(nil), // 9: unix_sk
+ (*CriuOpts)(nil), // 10: criu_opts
+ (*CriuDumpResp)(nil), // 11: criu_dump_resp
+ (*CriuRestoreResp)(nil), // 12: criu_restore_resp
+ (*CriuNotify)(nil), // 13: criu_notify
+ (*CriuFeatures)(nil), // 14: criu_features
+ (*CriuReq)(nil), // 15: criu_req
+ (*CriuResp)(nil), // 16: criu_resp
+ (*CriuVersion)(nil), // 17: criu_version
+}
+var file_rpc_rpc_proto_depIdxs = []int32{
+ 3, // 0: criu_opts.ps:type_name -> criu_page_server_info
+ 4, // 1: criu_opts.veths:type_name -> criu_veth_pair
+ 5, // 2: criu_opts.ext_mnt:type_name -> ext_mount_map
+ 8, // 3: criu_opts.cg_root:type_name -> cgroup_root
+ 7, // 4: criu_opts.inherit_fd:type_name -> inherit_fd
+ 9, // 5: criu_opts.unix_sk_ino:type_name -> unix_sk
+ 0, // 6: criu_opts.manage_cgroups_mode:type_name -> criu_cg_mode
+ 6, // 7: criu_opts.join_ns:type_name -> join_namespace
+ 1, // 8: criu_opts.pre_dump_mode:type_name -> criu_pre_dump_mode
+ 2, // 9: criu_req.type:type_name -> criu_req_type
+ 10, // 10: criu_req.opts:type_name -> criu_opts
+ 14, // 11: criu_req.features:type_name -> criu_features
+ 2, // 12: criu_resp.type:type_name -> criu_req_type
+ 11, // 13: criu_resp.dump:type_name -> criu_dump_resp
+ 12, // 14: criu_resp.restore:type_name -> criu_restore_resp
+ 13, // 15: criu_resp.notify:type_name -> criu_notify
+ 3, // 16: criu_resp.ps:type_name -> criu_page_server_info
+ 14, // 17: criu_resp.features:type_name -> criu_features
+ 17, // 18: criu_resp.version:type_name -> criu_version
+ 19, // [19:19] is the sub-list for method output_type
+ 19, // [19:19] is the sub-list for method input_type
+ 19, // [19:19] is the sub-list for extension type_name
+ 19, // [19:19] is the sub-list for extension extendee
+ 0, // [0:19] is the sub-list for field type_name
+}
+
+func init() { file_rpc_rpc_proto_init() }
+func file_rpc_rpc_proto_init() {
+ if File_rpc_rpc_proto != nil {
+ return
+ }
+ if !protoimpl.UnsafeEnabled {
+ file_rpc_rpc_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*CriuPageServerInfo); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_rpc_rpc_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*CriuVethPair); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_rpc_rpc_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*ExtMountMap); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_rpc_rpc_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*JoinNamespace); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_rpc_rpc_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*InheritFd); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_rpc_rpc_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*CgroupRoot); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_rpc_rpc_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*UnixSk); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_rpc_rpc_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*CriuOpts); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_rpc_rpc_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*CriuDumpResp); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_rpc_rpc_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*CriuRestoreResp); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_rpc_rpc_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*CriuNotify); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_rpc_rpc_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*CriuFeatures); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_rpc_rpc_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*CriuReq); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_rpc_rpc_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*CriuResp); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_rpc_rpc_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*CriuVersion); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ }
+ type x struct{}
+ out := protoimpl.TypeBuilder{
+ File: protoimpl.DescBuilder{
+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+ RawDescriptor: file_rpc_rpc_proto_rawDesc,
+ NumEnums: 3,
+ NumMessages: 15,
+ NumExtensions: 0,
+ NumServices: 0,
+ },
+ GoTypes: file_rpc_rpc_proto_goTypes,
+ DependencyIndexes: file_rpc_rpc_proto_depIdxs,
+ EnumInfos: file_rpc_rpc_proto_enumTypes,
+ MessageInfos: file_rpc_rpc_proto_msgTypes,
+ }.Build()
+ File_rpc_rpc_proto = out.File
+ file_rpc_rpc_proto_rawDesc = nil
+ file_rpc_rpc_proto_goTypes = nil
+ file_rpc_rpc_proto_depIdxs = nil
+}
diff --git a/vendor/github.com/checkpoint-restore/go-criu/v5/rpc/rpc.proto b/vendor/github.com/checkpoint-restore/go-criu/v5/rpc/rpc.proto
new file mode 100644
index 000000000..61e1b24f4
--- /dev/null
+++ b/vendor/github.com/checkpoint-restore/go-criu/v5/rpc/rpc.proto
@@ -0,0 +1,239 @@
+// SPDX-License-Identifier: MIT
+
+syntax = "proto2";
+
+message criu_page_server_info {
+ optional string address = 1;
+ optional int32 port = 2;
+ optional int32 pid = 3;
+ optional int32 fd = 4;
+}
+
+message criu_veth_pair {
+ required string if_in = 1;
+ required string if_out = 2;
+};
+
+message ext_mount_map {
+ required string key = 1;
+ required string val = 2;
+};
+
+message join_namespace {
+ required string ns = 1;
+ required string ns_file = 2;
+ optional string extra_opt = 3;
+}
+
+message inherit_fd {
+ required string key = 1;
+ required int32 fd = 2;
+};
+
+message cgroup_root {
+ optional string ctrl = 1;
+ required string path = 2;
+};
+
+message unix_sk {
+ required uint32 inode = 1;
+};
+
+enum criu_cg_mode {
+ IGNORE = 0;
+ CG_NONE = 1;
+ PROPS = 2;
+ SOFT = 3;
+ FULL = 4;
+ STRICT = 5;
+ DEFAULT = 6;
+};
+
+enum criu_pre_dump_mode {
+ SPLICE = 1;
+ VM_READ = 2;
+};
+
+message criu_opts {
+ required int32 images_dir_fd = 1;
+ optional int32 pid = 2; /* if not set on dump, will dump requesting process */
+
+ optional bool leave_running = 3;
+ optional bool ext_unix_sk = 4;
+ optional bool tcp_established = 5;
+ optional bool evasive_devices = 6;
+ optional bool shell_job = 7;
+ optional bool file_locks = 8;
+ optional int32 log_level = 9 [default = 2];
+ optional string log_file = 10; /* No subdirs are allowed. Consider using work-dir */
+
+ optional criu_page_server_info ps = 11;
+
+ optional bool notify_scripts = 12;
+
+ optional string root = 13;
+ optional string parent_img = 14;
+ optional bool track_mem = 15;
+ optional bool auto_dedup = 16;
+
+ optional int32 work_dir_fd = 17;
+ optional bool link_remap = 18;
+ repeated criu_veth_pair veths = 19; /* DEPRECATED, use external instead */
+
+ optional uint32 cpu_cap = 20 [default = 0xffffffff];
+ optional bool force_irmap = 21;
+ repeated string exec_cmd = 22;
+
+ repeated ext_mount_map ext_mnt = 23; /* DEPRECATED, use external instead */
+ optional bool manage_cgroups = 24; /* backward compatibility */
+ repeated cgroup_root cg_root = 25;
+
+ optional bool rst_sibling = 26; /* swrk only */
+ repeated inherit_fd inherit_fd = 27; /* swrk only */
+
+ optional bool auto_ext_mnt = 28;
+ optional bool ext_sharing = 29;
+ optional bool ext_masters = 30;
+
+ repeated string skip_mnt = 31;
+ repeated string enable_fs = 32;
+
+ repeated unix_sk unix_sk_ino = 33; /* DEPRECATED, use external instead */
+
+ optional criu_cg_mode manage_cgroups_mode = 34;
+ optional uint32 ghost_limit = 35 [default = 0x100000];
+ repeated string irmap_scan_paths = 36;
+ repeated string external = 37;
+ optional uint32 empty_ns = 38;
+ repeated join_namespace join_ns = 39;
+
+ optional string cgroup_props = 41;
+ optional string cgroup_props_file = 42;
+ repeated string cgroup_dump_controller = 43;
+
+ optional string freeze_cgroup = 44;
+ optional uint32 timeout = 45;
+ optional bool tcp_skip_in_flight = 46;
+ optional bool weak_sysctls = 47;
+ optional bool lazy_pages = 48;
+ optional int32 status_fd = 49;
+ optional bool orphan_pts_master = 50;
+ optional string config_file = 51;
+ optional bool tcp_close = 52;
+ optional string lsm_profile = 53;
+ optional string tls_cacert = 54;
+ optional string tls_cacrl = 55;
+ optional string tls_cert = 56;
+ optional string tls_key = 57;
+ optional bool tls = 58;
+ optional bool tls_no_cn_verify = 59;
+ optional string cgroup_yard = 60;
+ optional criu_pre_dump_mode pre_dump_mode = 61 [default = SPLICE];
+ optional int32 pidfd_store_sk = 62;
+ optional string lsm_mount_context = 63;
+/* optional bool check_mounts = 128; */
+}
+
+message criu_dump_resp {
+ optional bool restored = 1;
+}
+
+message criu_restore_resp {
+ required int32 pid = 1;
+}
+
+message criu_notify {
+ optional string script = 1;
+ optional int32 pid = 2;
+}
+
+enum criu_req_type {
+ EMPTY = 0;
+ DUMP = 1;
+ RESTORE = 2;
+ CHECK = 3;
+ PRE_DUMP = 4;
+ PAGE_SERVER = 5;
+
+ NOTIFY = 6;
+
+ CPUINFO_DUMP = 7;
+ CPUINFO_CHECK = 8;
+
+ FEATURE_CHECK = 9;
+
+ VERSION = 10;
+
+ WAIT_PID = 11;
+ PAGE_SERVER_CHLD = 12;
+}
+
+/*
+ * List of features which can queried via
+ * CRIU_REQ_TYPE__FEATURE_CHECK
+ */
+message criu_features {
+ optional bool mem_track = 1;
+ optional bool lazy_pages = 2;
+ optional bool pidfd_store = 3;
+}
+
+/*
+ * Request -- each type corresponds to must-be-there
+ * request arguments of respective type
+ */
+
+message criu_req {
+ required criu_req_type type = 1;
+
+ optional criu_opts opts = 2;
+ optional bool notify_success = 3;
+
+ /*
+ * When set service won't close the connection but
+ * will wait for more req-s to appear. Works not
+ * for all request types.
+ */
+ optional bool keep_open = 4;
+ /*
+ * 'features' can be used to query which features
+ * are supported by the installed criu/kernel
+ * via RPC.
+ */
+ optional criu_features features = 5;
+
+ /* 'pid' is used for WAIT_PID */
+ optional uint32 pid = 6;
+}
+
+/*
+ * Response -- it states whether the request was served
+ * and additional request-specific information
+ */
+
+message criu_resp {
+ required criu_req_type type = 1;
+ required bool success = 2;
+
+ optional criu_dump_resp dump = 3;
+ optional criu_restore_resp restore = 4;
+ optional criu_notify notify = 5;
+ optional criu_page_server_info ps = 6;
+
+ optional int32 cr_errno = 7;
+ optional criu_features features = 8;
+ optional string cr_errmsg = 9;
+ optional criu_version version = 10;
+
+ optional int32 status = 11;
+}
+
+/* Answer for criu_req_type.VERSION requests */
+message criu_version {
+ required int32 major_number = 1;
+ required int32 minor_number = 2;
+ optional string gitid = 3;
+ optional int32 sublevel = 4;
+ optional int32 extra = 5;
+ optional string name = 6;
+}
diff --git a/vendor/github.com/containers/buildah/.cirrus.yml b/vendor/github.com/containers/buildah/.cirrus.yml
index 849e45f8a..73ab4fc11 100644
--- a/vendor/github.com/containers/buildah/.cirrus.yml
+++ b/vendor/github.com/containers/buildah/.cirrus.yml
@@ -30,7 +30,7 @@ env:
UBUNTU_NAME: "ubuntu-2104"
PRIOR_UBUNTU_NAME: "ubuntu-2010"
- IMAGE_SUFFIX: "c6534244118822912"
+ IMAGE_SUFFIX: "c6248193773010944"
FEDORA_CACHE_IMAGE_NAME: "fedora-${IMAGE_SUFFIX}"
PRIOR_FEDORA_CACHE_IMAGE_NAME: "prior-fedora-${IMAGE_SUFFIX}"
UBUNTU_CACHE_IMAGE_NAME: "ubuntu-${IMAGE_SUFFIX}"
diff --git a/vendor/github.com/containers/buildah/add.go b/vendor/github.com/containers/buildah/add.go
index ad178dc6b..f17e3a9c9 100644
--- a/vendor/github.com/containers/buildah/add.go
+++ b/vendor/github.com/containers/buildah/add.go
@@ -602,12 +602,43 @@ func (b *Builder) userForRun(mountPoint string, userspec string) (specs.User, st
// userForRun() does, except for the case where we're passed a single numeric
// value, where we need to use that value for both the UID and the GID.
func (b *Builder) userForCopy(mountPoint string, userspec string) (uint32, uint32, error) {
- if id, err := strconv.ParseUint(userspec, 10, 32); err == nil {
- return uint32(id), uint32(id), nil
+ var (
+ user, group string
+ uid, gid uint64
+ err error
+ )
+
+ split := strings.SplitN(userspec, ":", 2)
+ user = split[0]
+ if len(split) > 1 {
+ group = split[1]
+ }
+
+ // If userspec did not specify any values for user or group, then fail
+ if user == "" && group == "" {
+ return 0, 0, errors.Errorf("can't find uid for user %s", userspec)
+ }
+
+ // If userspec specifies values for user or group, check for numeric values
+ // and return early. If not, then translate username/groupname
+ if user != "" {
+ uid, err = strconv.ParseUint(user, 10, 32)
+ }
+ if err == nil {
+ // default gid to uid
+ gid = uid
+ if group != "" {
+ gid, err = strconv.ParseUint(group, 10, 32)
+ }
}
- user, _, err := b.userForRun(mountPoint, userspec)
+ // If err != nil, then user or group not numeric, check filesystem
+ if err == nil {
+ return uint32(uid), uint32(gid), nil
+ }
+
+ owner, _, err := b.userForRun(mountPoint, userspec)
if err != nil {
return 0xffffffff, 0xffffffff, err
}
- return user.UID, user.GID, nil
+ return owner.UID, owner.GID, nil
}
diff --git a/vendor/github.com/containers/buildah/chroot/run.go b/vendor/github.com/containers/buildah/chroot/run.go
index 7cb1d710e..591003568 100644
--- a/vendor/github.com/containers/buildah/chroot/run.go
+++ b/vendor/github.com/containers/buildah/chroot/run.go
@@ -161,7 +161,7 @@ func RunUsingChroot(spec *specs.Spec, bundlePath, homeDir string, stdin io.Reade
cmd := unshare.Command(runUsingChrootCommand)
cmd.Stdin, cmd.Stdout, cmd.Stderr = stdin, stdout, stderr
cmd.Dir = "/"
- cmd.Env = append([]string{fmt.Sprintf("LOGLEVEL=%d", logrus.GetLevel())}, os.Environ()...)
+ cmd.Env = []string{fmt.Sprintf("LOGLEVEL=%d", logrus.GetLevel())}
logrus.Debugf("Running %#v in %#v", cmd.Cmd, cmd)
confwg.Add(1)
@@ -207,7 +207,7 @@ func runUsingChrootMain() {
os.Exit(1)
}
- if options.Spec == nil {
+ if options.Spec == nil || options.Spec.Process == nil {
fmt.Fprintf(os.Stderr, "invalid options spec in runUsingChrootMain\n")
os.Exit(1)
}
@@ -573,7 +573,7 @@ func runUsingChroot(spec *specs.Spec, bundlePath string, ctty *os.File, stdin io
cmd := unshare.Command(append([]string{runUsingChrootExecCommand}, spec.Process.Args...)...)
cmd.Stdin, cmd.Stdout, cmd.Stderr = stdin, stdout, stderr
cmd.Dir = "/"
- cmd.Env = append([]string{fmt.Sprintf("LOGLEVEL=%d", logrus.GetLevel())}, os.Environ()...)
+ cmd.Env = []string{fmt.Sprintf("LOGLEVEL=%d", logrus.GetLevel())}
cmd.UnshareFlags = syscall.CLONE_NEWUTS | syscall.CLONE_NEWNS
requestedUserNS := false
for _, ns := range spec.Linux.Namespaces {
@@ -663,7 +663,7 @@ func runUsingChrootExecMain() {
// Set the hostname. We're already in a distinct UTS namespace and are admins in the user
// namespace which created it, so we shouldn't get a permissions error, but seccomp policy
// might deny our attempt to call sethostname() anyway, so log a debug message for that.
- if options.Spec == nil {
+ if options.Spec == nil || options.Spec.Process == nil {
fmt.Fprintf(os.Stderr, "invalid options spec passed in\n")
os.Exit(1)
}
@@ -819,7 +819,6 @@ func runUsingChrootExecMain() {
// Output debug messages when that differs from what we're being asked to do.
func logNamespaceDiagnostics(spec *specs.Spec) {
sawMountNS := false
- sawUserNS := false
sawUTSNS := false
for _, ns := range spec.Linux.Namespaces {
switch ns.Type {
@@ -854,9 +853,8 @@ func logNamespaceDiagnostics(spec *specs.Spec) {
}
case specs.UserNamespace:
if ns.Path != "" {
- logrus.Debugf("unable to join user namespace %q, creating a new one", ns.Path)
+ logrus.Debugf("unable to join user namespace, sorry about that")
}
- sawUserNS = true
case specs.UTSNamespace:
if ns.Path != "" {
logrus.Debugf("unable to join UTS namespace %q, creating a new one", ns.Path)
@@ -867,9 +865,6 @@ func logNamespaceDiagnostics(spec *specs.Spec) {
if !sawMountNS {
logrus.Debugf("mount namespace not requested, but creating a new one anyway")
}
- if !sawUserNS {
- logrus.Debugf("user namespace not requested, but creating a new one anyway")
- }
if !sawUTSNS {
logrus.Debugf("UTS namespace not requested, but creating a new one anyway")
}
diff --git a/vendor/github.com/containers/buildah/go.mod b/vendor/github.com/containers/buildah/go.mod
index 494d1e211..68721b73c 100644
--- a/vendor/github.com/containers/buildah/go.mod
+++ b/vendor/github.com/containers/buildah/go.mod
@@ -4,10 +4,10 @@ go 1.12
require (
github.com/containernetworking/cni v0.8.1
- github.com/containers/common v0.40.2-0.20210707094508-0a4a1906d4b2
+ github.com/containers/common v0.41.1-0.20210721112610-c95d2f794edf
github.com/containers/image/v5 v5.13.2
github.com/containers/ocicrypt v1.1.2
- github.com/containers/storage v1.32.5
+ github.com/containers/storage v1.32.6
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
@@ -18,10 +18,10 @@ require (
github.com/konsorten/go-windows-terminal-sequences v1.0.3 // indirect
github.com/mattn/go-shellwords v1.0.12
github.com/onsi/ginkgo v1.16.4
- github.com/onsi/gomega v1.13.0
+ github.com/onsi/gomega v1.14.0
github.com/opencontainers/go-digest v1.0.0
github.com/opencontainers/image-spec v1.0.2-0.20190823105129-775207bd45b6
- github.com/opencontainers/runc v1.0.0
+ github.com/opencontainers/runc v1.0.1
github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417
github.com/opencontainers/runtime-tools v0.9.0
github.com/opencontainers/selinux v1.8.2
diff --git a/vendor/github.com/containers/buildah/go.sum b/vendor/github.com/containers/buildah/go.sum
index 5616f98b5..ce7eb6c74 100644
--- a/vendor/github.com/containers/buildah/go.sum
+++ b/vendor/github.com/containers/buildah/go.sum
@@ -73,8 +73,9 @@ github.com/Microsoft/hcsshim v0.8.9/go.mod h1:5692vkUqntj1idxauYlpoINNKeqCiG6Sg3
github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2ow3VK6a9Lg=
github.com/Microsoft/hcsshim v0.8.15/go.mod h1:x38A4YbHbdxJtc0sF6oIz+RG0npwSCAvn69iY6URG00=
github.com/Microsoft/hcsshim v0.8.16/go.mod h1:o5/SZqmR7x9JNKsW3pu+nqHm0MF8vbA+VxGOoXdC600=
-github.com/Microsoft/hcsshim v0.8.17 h1:yFHH5bghP9ij5Y34PPaMOE8g//oXZ0uJQeMENVo2zcI=
github.com/Microsoft/hcsshim v0.8.17/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4=
+github.com/Microsoft/hcsshim v0.8.20 h1:ZTwcx3NS8n07kPf/JZ1qwU6vnjhVPMUWlXBF8r9UxrE=
+github.com/Microsoft/hcsshim v0.8.20/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4=
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=
@@ -136,6 +137,7 @@ github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX
github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs=
github.com/cilium/ebpf v0.5.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs=
github.com/cilium/ebpf v0.6.1/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs=
+github.com/cilium/ebpf v0.6.2/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs=
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/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
@@ -223,8 +225,8 @@ github.com/containernetworking/cni v0.8.1 h1:7zpDnQ3T3s4ucOuJ/ZCLrYBxzkg0AELFfII
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/containernetworking/plugins v0.9.1/go.mod h1:xP/idU2ldlzN6m4p5LmGiwRDjeJr6FLK6vuiUwoH7P8=
-github.com/containers/common v0.40.2-0.20210707094508-0a4a1906d4b2 h1:2ApmOS9jSnJXuSOkZNEAZ7j0/9i8zjoi67b/UpUjPxY=
-github.com/containers/common v0.40.2-0.20210707094508-0a4a1906d4b2/go.mod h1:thow5Jn7O+rP01njI9COQ16L9g/KQ1LcMcYqP2NhYCU=
+github.com/containers/common v0.41.1-0.20210721112610-c95d2f794edf h1:z0ciG0ByyJG3WCBpLYd2XLThCC7UBaH7GeSfXY4sAqc=
+github.com/containers/common v0.41.1-0.20210721112610-c95d2f794edf/go.mod h1:Ba5YVNCnyX6xDtg1JqEHa2EMVMW5UbHmIyEqsEwpeGE=
github.com/containers/image/v5 v5.13.2 h1:AgYunV/9d2fRkrmo23wH2MkqeHolFd6oQCkK+1PpuFA=
github.com/containers/image/v5 v5.13.2/go.mod h1:GkWursKDlDcUIT7L7vZf70tADvZCk/Ga0wgS0MuF0ag=
github.com/containers/libtrust v0.0.0-20190913040956-14b96171aa3b h1:Q8ePgVfHDplZ7U33NwHZkrVELsZP5fYj9pM5WBZB2GE=
@@ -235,8 +237,8 @@ github.com/containers/ocicrypt v1.1.1/go.mod h1:Dm55fwWm1YZAjYRaJ94z2mfZikIyIN4B
github.com/containers/ocicrypt v1.1.2 h1:Ez+GAMP/4GLix5Ywo/fL7O0nY771gsBIigiqUm1aXz0=
github.com/containers/ocicrypt v1.1.2/go.mod h1:Dm55fwWm1YZAjYRaJ94z2mfZikIyIN4B0oB3dj3jFxY=
github.com/containers/storage v1.32.2/go.mod h1:YIBxxjfXZTi04Ah49sh1uSGfmT1V89+I5i3deRobzQo=
-github.com/containers/storage v1.32.5 h1:DXgmyA+oOs7YAzKkEqgC5O8l2UuDGJcwEFbdt49qiak=
-github.com/containers/storage v1.32.5/go.mod h1:8/DVVDqniaUlUV0D0q7cEnXK6Bs2uU3FPqNZVPumwEs=
+github.com/containers/storage v1.32.6 h1:NqdFRewXO/PYPjgCAScoigZc5QUA21yapSEj6kqD8cw=
+github.com/containers/storage v1.32.6/go.mod h1:mdB+b89p+jU8zpzLTVXA0gWMmIo0WrkfGMh1R8O2IQw=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-iptables v0.4.5/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU=
@@ -609,7 +611,6 @@ 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.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E=
github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
@@ -618,8 +619,8 @@ github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1Cpa
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc=
-github.com/onsi/gomega v1.13.0 h1:7lLHu94wT9Ij0o6EWWclhu0aOh32VxhkwEJvzuWPeak=
-github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY=
+github.com/onsi/gomega v1.14.0 h1:ep6kpPVwmr/nTbklSx2nrLNSIO62DoYAhnPNIMhK8gI=
+github.com/onsi/gomega v1.14.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0=
github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
@@ -636,8 +637,9 @@ github.com/opencontainers/runc v1.0.0-rc8.0.20190926000215-3e425f80a8c9/go.mod h
github.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
github.com/opencontainers/runc v1.0.0-rc93/go.mod h1:3NOsor4w32B2tC0Zbl8Knk4Wg84SM2ImC1fxBuqJ/H0=
github.com/opencontainers/runc v1.0.0-rc95/go.mod h1:z+bZxa/+Tz/FmYVWkhUajJdzFeOqjc5vrqskhVyHGUM=
-github.com/opencontainers/runc v1.0.0 h1:QOhAQAYUlKeofuyeKdR6ITvOnXLPbEAjPMjz9wCUXcU=
github.com/opencontainers/runc v1.0.0/go.mod h1:MU2S3KEB2ZExnhnAQYbwjdYV6HwKtDlNbA2Z2OeNDeA=
+github.com/opencontainers/runc v1.0.1 h1:G18PGckGdAm3yVQRWDVQ1rLSLntiniKJ0cNRT2Tm5gs=
+github.com/opencontainers/runc v1.0.1/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0=
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=
diff --git a/vendor/github.com/containers/buildah/imagebuildah/build.go b/vendor/github.com/containers/buildah/imagebuildah/build.go
index a315d7f7d..954ef7f8a 100644
--- a/vendor/github.com/containers/buildah/imagebuildah/build.go
+++ b/vendor/github.com/containers/buildah/imagebuildah/build.go
@@ -39,7 +39,7 @@ const (
)
// Mount is a mountpoint for the build container.
-type Mount specs.Mount
+type Mount = specs.Mount
type BuildOptions = define.BuildOptions
diff --git a/vendor/github.com/containers/buildah/imagebuildah/executor.go b/vendor/github.com/containers/buildah/imagebuildah/executor.go
index c754ae3c0..606015ba7 100644
--- a/vendor/github.com/containers/buildah/imagebuildah/executor.go
+++ b/vendor/github.com/containers/buildah/imagebuildah/executor.go
@@ -165,8 +165,7 @@ func NewExecutor(logger *logrus.Logger, store storage.Store, options define.Buil
if err != nil {
return nil, err
}
-
- transientMounts = append([]Mount{Mount(mount)}, transientMounts...)
+ transientMounts = append([]Mount{mount}, transientMounts...)
}
secrets, err := parse.Secrets(options.CommonBuildOpts.Secrets)
@@ -569,7 +568,7 @@ func (b *Executor) Build(ctx context.Context, stages imagebuilder.Stages) (image
// Build maps of every named base image and every referenced stage root
// filesystem. Individual stages can use them to determine whether or
// not they can skip certain steps near the end of their stages.
- for _, stage := range stages {
+ for stageIndex, stage := range stages {
node := stage.Node // first line
for node != nil { // each line
for _, child := range node.Children { // tokens on this line, though we only care about the first
@@ -589,7 +588,7 @@ func (b *Executor) Build(ctx context.Context, stages imagebuilder.Stages) (image
// FROM instruction uses argument values,
// we might not record the right value here.
b.baseMap[base] = true
- logrus.Debugf("base: %q", base)
+ logrus.Debugf("base for stage %d: %q", stageIndex, base)
}
}
case "ADD", "COPY":
@@ -601,7 +600,7 @@ func (b *Executor) Build(ctx context.Context, stages imagebuilder.Stages) (image
// not record the right value here.
rootfs := strings.TrimPrefix(flag, "--from=")
b.rootfsMap[rootfs] = true
- logrus.Debugf("rootfs: %q", rootfs)
+ logrus.Debugf("rootfs needed for COPY in stage %d: %q", stageIndex, rootfs)
}
}
}
diff --git a/vendor/github.com/containers/buildah/imagebuildah/stage_executor.go b/vendor/github.com/containers/buildah/imagebuildah/stage_executor.go
index be105901b..d3d5cc7c4 100644
--- a/vendor/github.com/containers/buildah/imagebuildah/stage_executor.go
+++ b/vendor/github.com/containers/buildah/imagebuildah/stage_executor.go
@@ -434,7 +434,7 @@ func (s *StageExecutor) Run(run imagebuilder.Run, config docker.Config) error {
Runtime: s.executor.runtime,
Args: s.executor.runtimeArgs,
NoPivot: os.Getenv("BUILDAH_NOPIVOT") != "",
- Mounts: convertMounts(s.executor.transientMounts),
+ Mounts: append([]Mount{}, s.executor.transientMounts...),
Env: config.Env,
User: config.User,
WorkingDir: config.WorkingDir,
@@ -557,13 +557,6 @@ func (s *StageExecutor) prepare(ctx context.Context, from string, initializeIBCo
OciDecryptConfig: s.executor.ociDecryptConfig,
}
- // Check and see if the image is a pseudonym for the end result of a
- // previous stage, named by an AS clause in the Dockerfile.
- s.executor.stagesLock.Lock()
- if asImageFound, ok := s.executor.imageMap[from]; ok {
- builderOptions.FromImage = asImageFound
- }
- s.executor.stagesLock.Unlock()
builder, err = buildah.NewBuilder(ctx, s.executor.store, builderOptions)
if err != nil {
return nil, errors.Wrapf(err, "error creating build container")
@@ -684,15 +677,20 @@ func (s *StageExecutor) Execute(ctx context.Context, base string) (imgID string,
// If the base image's name corresponds to the result of an earlier
// stage, make sure that stage has finished building an image, and
- // substitute that image's ID for the base image's name here. If not,
- // then go on assuming that it's just a regular image that's either in
- // local storage, or one that we have to pull from a registry.
+ // substitute that image's ID for the base image's name here and force
+ // the pull policy to "never" to avoid triggering an error when it's
+ // set to "always", which doesn't make sense for image IDs.
+ // If not, then go on assuming that it's just a regular image that's
+ // either in local storage, or one that we have to pull from a
+ // registry, subject to the passed-in pull policy.
if isStage, err := s.executor.waitForStage(ctx, base, s.stages[:s.index]); isStage && err != nil {
return "", nil, err
}
+ pullPolicy := s.executor.pullPolicy
s.executor.stagesLock.Lock()
if stageImage, isPreviousStage := s.executor.imageMap[base]; isPreviousStage {
base = stageImage
+ pullPolicy = define.PullNever
}
s.executor.stagesLock.Unlock()
@@ -723,7 +721,7 @@ func (s *StageExecutor) Execute(ctx context.Context, base string) (imgID string,
// Create the (first) working container for this stage. Reinitializing
// the imagebuilder configuration may alter the list of steps we have,
// so take a snapshot of them *after* that.
- if _, err := s.prepare(ctx, base, true, true, s.executor.pullPolicy); err != nil {
+ if _, err := s.prepare(ctx, base, true, true, pullPolicy); err != nil {
return "", nil, err
}
children := stage.Node.Children
diff --git a/vendor/github.com/containers/buildah/imagebuildah/util.go b/vendor/github.com/containers/buildah/imagebuildah/util.go
index 7519672bf..598e407a8 100644
--- a/vendor/github.com/containers/buildah/imagebuildah/util.go
+++ b/vendor/github.com/containers/buildah/imagebuildah/util.go
@@ -2,26 +2,11 @@ package imagebuildah
import (
"github.com/containers/buildah"
- "github.com/opencontainers/runtime-spec/specs-go"
)
// InitReexec is a wrapper for buildah.InitReexec(). It should be called at
// the start of main(), and if it returns true, main() should return
-// immediately.
+// successfully immediately.
func InitReexec() bool {
return buildah.InitReexec()
}
-
-func convertMounts(mounts []Mount) []specs.Mount {
- specmounts := []specs.Mount{}
- for _, m := range mounts {
- s := specs.Mount{
- Destination: m.Destination,
- Type: m.Type,
- Source: m.Source,
- Options: m.Options,
- }
- specmounts = append(specmounts, s)
- }
- return specmounts
-}
diff --git a/vendor/github.com/containers/buildah/install.md b/vendor/github.com/containers/buildah/install.md
index 0cec56c75..30ec26cc3 100644
--- a/vendor/github.com/containers/buildah/install.md
+++ b/vendor/github.com/containers/buildah/install.md
@@ -153,9 +153,7 @@ sudo apt-get -qq -y install buildah
### Kernel Version Requirements
To run Buildah on Red Hat Enterprise Linux or CentOS, version 7.4 or higher is required.
-On other Linux distributions Buildah requires a kernel version of 4.0 or
-higher in order to support the OverlayFS filesystem. The kernel version can be checked
-with the 'uname -a' command.
+On other Linux distributions Buildah requires a kernel version that supports the OverlayFS and/or fuse-overlayfs filesystem -- you'll need to consult your distribution's documentation to determine a minimum version number.
### runc Requirement
diff --git a/vendor/github.com/containers/buildah/pkg/parse/parse.go b/vendor/github.com/containers/buildah/pkg/parse/parse.go
index 0a09dd75a..5ba2f51d0 100644
--- a/vendor/github.com/containers/buildah/pkg/parse/parse.go
+++ b/vendor/github.com/containers/buildah/pkg/parse/parse.go
@@ -15,6 +15,7 @@ import (
"unicode"
"github.com/containers/buildah/define"
+ "github.com/containers/common/pkg/parse"
"github.com/containers/image/v5/types"
"github.com/containers/storage/pkg/idtools"
"github.com/containers/storage/pkg/unshare"
@@ -205,13 +206,13 @@ func Volume(volume string) (specs.Mount, error) {
if err := validateVolumeMountHostDir(arr[0]); err != nil {
return mount, err
}
- if err := ValidateVolumeCtrDir(arr[1]); err != nil {
+ if err := parse.ValidateVolumeCtrDir(arr[1]); err != nil {
return mount, err
}
mountOptions := ""
if len(arr) > 2 {
mountOptions = arr[2]
- if _, err := ValidateVolumeOpts(strings.Split(arr[2], ",")); err != nil {
+ if _, err := parse.ValidateVolumeOpts(strings.Split(arr[2], ",")); err != nil {
return mount, err
}
}
@@ -360,7 +361,7 @@ func GetBindMount(args []string) (specs.Mount, error) {
if len(kv) == 1 {
return newMount, errors.Wrapf(optionArgError, kv[0])
}
- if err := ValidateVolumeHostDir(kv[1]); err != nil {
+ if err := parse.ValidateVolumeHostDir(kv[1]); err != nil {
return newMount, err
}
newMount.Source = kv[1]
@@ -369,7 +370,7 @@ func GetBindMount(args []string) (specs.Mount, error) {
if len(kv) == 1 {
return newMount, errors.Wrapf(optionArgError, kv[0])
}
- if err := ValidateVolumeCtrDir(kv[1]); err != nil {
+ if err := parse.ValidateVolumeCtrDir(kv[1]); err != nil {
return newMount, err
}
newMount.Destination = kv[1]
@@ -391,7 +392,7 @@ func GetBindMount(args []string) (specs.Mount, error) {
newMount.Source = newMount.Destination
}
- opts, err := ValidateVolumeOpts(newMount.Options)
+ opts, err := parse.ValidateVolumeOpts(newMount.Options)
if err != nil {
return newMount, err
}
@@ -433,7 +434,7 @@ func GetTmpfsMount(args []string) (specs.Mount, error) {
if len(kv) == 1 {
return newMount, errors.Wrapf(optionArgError, kv[0])
}
- if err := ValidateVolumeCtrDir(kv[1]); err != nil {
+ if err := parse.ValidateVolumeCtrDir(kv[1]); err != nil {
return newMount, err
}
newMount.Destination = kv[1]
@@ -452,17 +453,7 @@ func GetTmpfsMount(args []string) (specs.Mount, error) {
// ValidateVolumeHostDir validates a volume mount's source directory
func ValidateVolumeHostDir(hostDir string) error {
- if len(hostDir) == 0 {
- return errors.Errorf("host directory cannot be empty")
- }
- if filepath.IsAbs(hostDir) {
- if _, err := os.Stat(hostDir); err != nil {
- return errors.WithStack(err)
- }
- }
- // If hostDir is not an absolute path, that means the user wants to create a
- // named volume. This will be done later on in the code.
- return nil
+ return parse.ValidateVolumeHostDir(hostDir)
}
// validates the host path of buildah --volume
@@ -478,75 +469,12 @@ func validateVolumeMountHostDir(hostDir string) error {
// ValidateVolumeCtrDir validates a volume mount's destination directory.
func ValidateVolumeCtrDir(ctrDir string) error {
- if len(ctrDir) == 0 {
- return errors.Errorf("container directory cannot be empty")
- }
- if !filepath.IsAbs(ctrDir) {
- return errors.Errorf("invalid container path %q, must be an absolute path", ctrDir)
- }
- return nil
+ return parse.ValidateVolumeCtrDir(ctrDir)
}
// ValidateVolumeOpts validates a volume's options
func ValidateVolumeOpts(options []string) ([]string, error) {
- var foundRootPropagation, foundRWRO, foundLabelChange, bindType, foundExec, foundDev, foundSuid, foundChown int
- finalOpts := make([]string, 0, len(options))
- for _, opt := range options {
- switch opt {
- case "noexec", "exec":
- foundExec++
- if foundExec > 1 {
- return nil, errors.Errorf("invalid options %q, can only specify 1 'noexec' or 'exec' option", strings.Join(options, ", "))
- }
- case "nodev", "dev":
- foundDev++
- if foundDev > 1 {
- return nil, errors.Errorf("invalid options %q, can only specify 1 'nodev' or 'dev' option", strings.Join(options, ", "))
- }
- case "nosuid", "suid":
- foundSuid++
- if foundSuid > 1 {
- return nil, errors.Errorf("invalid options %q, can only specify 1 'nosuid' or 'suid' option", strings.Join(options, ", "))
- }
- case "rw", "ro":
- foundRWRO++
- if foundRWRO > 1 {
- return nil, errors.Errorf("invalid options %q, can only specify 1 'rw' or 'ro' option", strings.Join(options, ", "))
- }
- case "z", "Z", "O":
- foundLabelChange++
- if foundLabelChange > 1 {
- return nil, errors.Errorf("invalid options %q, can only specify 1 'z', 'Z', or 'O' option", strings.Join(options, ", "))
- }
- case "U":
- foundChown++
- if foundChown > 1 {
- return nil, errors.Errorf("invalid options %q, can only specify 1 'U' option", strings.Join(options, ", "))
- }
- case "private", "rprivate", "shared", "rshared", "slave", "rslave", "unbindable", "runbindable":
- foundRootPropagation++
- if foundRootPropagation > 1 {
- return nil, errors.Errorf("invalid options %q, can only specify 1 '[r]shared', '[r]private', '[r]slave' or '[r]unbindable' option", strings.Join(options, ", "))
- }
- case "bind", "rbind":
- bindType++
- if bindType > 1 {
- return nil, errors.Errorf("invalid options %q, can only specify 1 '[r]bind' option", strings.Join(options, ", "))
- }
- case "cached", "delegated":
- // The discarded ops are OS X specific volume options
- // introduced in a recent Docker version.
- // They have no meaning on Linux, so here we silently
- // drop them. This matches Docker's behavior (the options
- // are intended to be always safe to use, even not on OS
- // X).
- continue
- default:
- return nil, errors.Errorf("invalid option type %q", opt)
- }
- finalOpts = append(finalOpts, opt)
- }
- return finalOpts, nil
+ return parse.ValidateVolumeOpts(options)
}
// validateExtraHost validates that the specified string is a valid extrahost and returns it.
@@ -601,7 +529,7 @@ func SystemContextFromOptions(c *cobra.Command) (*types.SystemContext, error) {
creds, err := c.Flags().GetString("creds")
if err == nil && c.Flag("creds").Changed {
var err error
- ctx.DockerAuthConfig, err = getDockerAuth(creds)
+ ctx.DockerAuthConfig, err = AuthConfig(creds)
if err != nil {
return nil, err
}
@@ -734,7 +662,9 @@ func parseCreds(creds string) (string, string) {
return up[0], up[1]
}
-func getDockerAuth(creds string) (*types.DockerAuthConfig, error) {
+// AuthConfig parses the creds in format [username[:password] into an auth
+// config.
+func AuthConfig(creds string) (*types.DockerAuthConfig, error) {
username, password := parseCreds(creds)
if username == "" {
fmt.Print("Username: ")
diff --git a/vendor/github.com/containers/common/libimage/copier.go b/vendor/github.com/containers/common/libimage/copier.go
index 34cc0d45d..a44f098ad 100644
--- a/vendor/github.com/containers/common/libimage/copier.go
+++ b/vendor/github.com/containers/common/libimage/copier.go
@@ -342,7 +342,7 @@ func (c *copier) copy(ctx context.Context, source, destination types.ImageRefere
}
}
- var copiedManifest []byte
+ var returnManifest []byte
f := func() error {
opts := c.imageCopyOptions
if sourceInsecure != nil {
@@ -354,11 +354,13 @@ func (c *copier) copy(ctx context.Context, source, destination types.ImageRefere
opts.DestinationCtx.DockerInsecureSkipTLSVerify = value
}
- var err error
- copiedManifest, err = copy.Image(ctx, c.policyContext, destination, source, &opts)
+ copiedManifest, err := copy.Image(ctx, c.policyContext, destination, source, &opts)
+ if err == nil {
+ returnManifest = copiedManifest
+ }
return err
}
- return copiedManifest, retry.RetryIfNecessary(ctx, f, &c.retryOptions)
+ return returnManifest, retry.RetryIfNecessary(ctx, f, &c.retryOptions)
}
// checkRegistrySourcesAllows checks the $BUILD_REGISTRY_SOURCES environment
@@ -369,7 +371,7 @@ func (c *copier) copy(ctx context.Context, source, destination types.ImageRefere
// If set, the insecure return value indicates whether the registry is set to
// be insecure.
//
-// NOTE: this functionality is required by Buildah.
+// NOTE: this functionality is required by Buildah for OpenShift.
func checkRegistrySourcesAllows(dest types.ImageReference) (insecure *bool, err error) {
registrySources, ok := os.LookupEnv("BUILD_REGISTRY_SOURCES")
if !ok || registrySources == "" {
diff --git a/vendor/github.com/containers/common/libimage/filters.go b/vendor/github.com/containers/common/libimage/filters.go
index eae18fd9c..0cc5cc311 100644
--- a/vendor/github.com/containers/common/libimage/filters.go
+++ b/vendor/github.com/containers/common/libimage/filters.go
@@ -88,7 +88,7 @@ func (r *Runtime) compileImageFilters(ctx context.Context, filters []string) ([]
if err != nil {
return nil, errors.Wrapf(err, "non-boolean value %q for dangling filter", value)
}
- filterFuncs = append(filterFuncs, filterDangling(dangling))
+ filterFuncs = append(filterFuncs, filterDangling(ctx, dangling))
case "id":
filterFuncs = append(filterFuncs, filterID(value))
@@ -201,9 +201,13 @@ func filterContainers(value bool) filterFunc {
}
// filterDangling creates a dangling filter for matching the specified value.
-func filterDangling(value bool) filterFunc {
+func filterDangling(ctx context.Context, value bool) filterFunc {
return func(img *Image) (bool, error) {
- return img.IsDangling() == value, nil
+ isDangling, err := img.IsDangling(ctx)
+ if err != nil {
+ return false, err
+ }
+ return isDangling == value, nil
}
}
diff --git a/vendor/github.com/containers/common/libimage/image.go b/vendor/github.com/containers/common/libimage/image.go
index 19b929dc7..c47e63339 100644
--- a/vendor/github.com/containers/common/libimage/image.go
+++ b/vendor/github.com/containers/common/libimage/image.go
@@ -121,24 +121,29 @@ 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
+// IsDangling returns true if the image is dangling, that is an untagged image
+// without children.
+func (i *Image) IsDangling(ctx context.Context) (bool, error) {
+ if len(i.Names()) > 0 {
+ return false, nil
+ }
+ children, err := i.getChildren(ctx, false)
+ if err != nil {
+ return false, err
+ }
+ return len(children) == 0, nil
}
// IsIntermediate returns true if the image is an intermediate image, that is
-// a dangling image without children.
+// an untagged image with children.
func (i *Image) IsIntermediate(ctx context.Context) (bool, error) {
- // If the image has tags, it's not an intermediate one.
- if !i.IsDangling() {
+ if len(i.Names()) > 0 {
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
}
@@ -271,7 +276,7 @@ type RemoveImageReport struct {
// 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.
+// containers. Returns IDs of removed/untagged images in order.
//
// If the image is used by containers return storage.ErrImageUsedByContainer.
// Use force to remove these containers.
@@ -282,7 +287,12 @@ type RemoveImageReport struct {
//
// 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 {
+func (i *Image) remove(ctx context.Context, rmMap map[string]*RemoveImageReport, referencedBy string, options *RemoveImagesOptions) ([]string, error) {
+ processedIDs := []string{}
+ return i.removeRecursive(ctx, rmMap, processedIDs, referencedBy, options)
+}
+
+func (i *Image) removeRecursive(ctx context.Context, rmMap map[string]*RemoveImageReport, processedIDs []string, referencedBy string, options *RemoveImagesOptions) ([]string, error) {
// If referencedBy is empty, the image is considered to be removed via
// `image remove --all` which alters the logic below.
@@ -294,7 +304,7 @@ func (i *Image) remove(ctx context.Context, rmMap map[string]*RemoveImageReport,
logrus.Debugf("Removing image %s", i.ID())
if i.IsReadOnly() {
- return errors.Errorf("cannot remove read-only image %q", i.ID())
+ return processedIDs, errors.Errorf("cannot remove read-only image %q", i.ID())
}
if i.runtime.eventChannel != nil {
@@ -306,7 +316,7 @@ func (i *Image) remove(ctx context.Context, rmMap map[string]*RemoveImageReport,
if exists {
// If the image has already been removed, we're done.
if report.Removed {
- return nil
+ return processedIDs, nil
}
} else {
report = &RemoveImageReport{ID: i.ID()}
@@ -333,7 +343,7 @@ func (i *Image) remove(ctx context.Context, rmMap map[string]*RemoveImageReport,
if options.WithSize {
size, err := i.Size()
if handleError(err) != nil {
- return err
+ return processedIDs, err
}
report.Size = size
}
@@ -354,18 +364,18 @@ func (i *Image) remove(ctx context.Context, rmMap map[string]*RemoveImageReport,
byDigest := strings.HasPrefix(referencedBy, "sha256:")
if !options.Force {
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())
+ return processedIDs, 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())
+ return processedIDs, 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
+ return processedIDs, err
}
report.Untagged = append(report.Untagged, referencedBy)
@@ -374,14 +384,15 @@ func (i *Image) remove(ctx context.Context, rmMap map[string]*RemoveImageReport,
}
}
+ processedIDs = append(processedIDs, i.ID())
if skipRemove {
- return nil
+ return processedIDs, nil
}
// Perform the actual removal. First, remove containers if needed.
if options.Force {
if err := i.removeContainers(options.RemoveContainerFunc); err != nil {
- return err
+ return processedIDs, err
}
}
@@ -407,7 +418,7 @@ func (i *Image) remove(ctx context.Context, rmMap map[string]*RemoveImageReport,
}
if _, err := i.runtime.store.DeleteImage(i.ID(), true); handleError(err) != nil {
- return err
+ return processedIDs, err
}
report.Untagged = append(report.Untagged, i.Names()...)
@@ -417,27 +428,24 @@ func (i *Image) remove(ctx context.Context, rmMap map[string]*RemoveImageReport,
// Check if can remove the parent image.
if parent == nil {
- return nil
+ return processedIDs, nil
}
- if !parent.IsDangling() {
- return nil
- }
-
- // If the image has siblings, we don't remove the parent.
- hasSiblings, err := parent.HasChildren(ctx)
+ // Only remove the parent if it's dangling, that is being untagged and
+ // without children.
+ danglingParent, err := parent.IsDangling(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
+ danglingParent = false
}
- if hasSiblings {
- return nil
+ if !danglingParent {
+ return processedIDs, nil
}
// Recurse into removing the parent.
- return parent.remove(ctx, rmMap, "", options)
+ return parent.removeRecursive(ctx, rmMap, processedIDs, "", options)
}
// Tag the image with the specified name and store it in the local containers
@@ -828,9 +836,9 @@ func (i *Image) Manifest(ctx context.Context) (rawManifest []byte, mimeType stri
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) {
+// getImageID creates an image object and uses the hex value of the config
+// blob's digest (if it has one) as the image ID for parsing the store reference
+func getImageID(ctx context.Context, src types.ImageReference, sys *types.SystemContext) (string, error) {
newImg, err := src.NewImage(ctx, sys)
if err != nil {
return "", err
@@ -844,5 +852,5 @@ func getImageDigest(ctx context.Context, src types.ImageReference, sys *types.Sy
if err = imageDigest.Validate(); err != nil {
return "", errors.Wrapf(err, "error getting config info")
}
- return "@" + imageDigest.Hex(), nil
+ return "@" + imageDigest.Encoded(), nil
}
diff --git a/vendor/github.com/containers/common/libimage/import.go b/vendor/github.com/containers/common/libimage/import.go
index 9926aaec7..bcfb4e129 100644
--- a/vendor/github.com/containers/common/libimage/import.go
+++ b/vendor/github.com/containers/common/libimage/import.go
@@ -86,7 +86,7 @@ func (r *Runtime) Import(ctx context.Context, path string, options *ImportOption
return "", err
}
- id, err := getImageDigest(ctx, srcRef, r.systemContextCopy())
+ id, err := getImageID(ctx, srcRef, r.systemContextCopy())
if err != nil {
return "", err
}
diff --git a/vendor/github.com/containers/common/libimage/layer_tree.go b/vendor/github.com/containers/common/libimage/layer_tree.go
index 4195b43c0..05f21531b 100644
--- a/vendor/github.com/containers/common/libimage/layer_tree.go
+++ b/vendor/github.com/containers/common/libimage/layer_tree.go
@@ -15,6 +15,9 @@ type layerTree struct {
// ociCache is a cache for Image.ID -> OCI Image. Translations are done
// on-demand.
ociCache map[string]*ociv1.Image
+ // emptyImages do not have any top-layer so we cannot create a
+ // *layerNode for them.
+ emptyImages []*Image
}
// node returns a layerNode for the specified layerID.
@@ -105,6 +108,7 @@ func (r *Runtime) layerTree() (*layerTree, error) {
img := images[i] // do not leak loop variable outside the scope
topLayer := img.TopLayer()
if topLayer == "" {
+ tree.emptyImages = append(tree.emptyImages, img)
continue
}
node, exists := tree.nodes[topLayer]
@@ -126,22 +130,13 @@ func (r *Runtime) layerTree() (*layerTree, error) {
// 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.
+// returned. Otherwise, the first image is returned. Note that manifest lists
+// do not have children.
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
+ if isManifestList, _ := parent.IsManifestList(ctx); isManifestList {
+ return nil, nil
+ }
}
parentID := parent.ID()
@@ -163,6 +158,38 @@ func (t *layerTree) children(ctx context.Context, parent *Image, all bool) ([]*I
return areParentAndChild(parentOCI, childOCI), nil
}
+ var children []*Image
+
+ // Empty images are special in that they do not have any physical layer
+ // but yet can have a parent-child relation. Hence, compare the
+ // "parent" image to all other known empty images.
+ if parent.TopLayer() == "" {
+ for i := range t.emptyImages {
+ empty := t.emptyImages[i]
+ isParent, err := checkParent(empty)
+ if err != nil {
+ return nil, err
+ }
+ if isParent {
+ children = append(children, empty)
+ if !all {
+ break
+ }
+ }
+ }
+ return children, nil
+ }
+
+ 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
+ }
+
// addChildrenFrom adds child images of parent to children. Returns
// true if any image is a child of parent.
addChildrenFromNode := func(node *layerNode) (bool, error) {
@@ -204,8 +231,37 @@ func (t *layerTree) children(ctx context.Context, parent *Image, all bool) ([]*I
}
// parent returns the parent image or nil if no parent image could be found.
+// Note that manifest lists do not have parents.
func (t *layerTree) parent(ctx context.Context, child *Image) (*Image, error) {
if child.TopLayer() == "" {
+ if isManifestList, _ := child.IsManifestList(ctx); isManifestList {
+ return nil, nil
+ }
+ }
+
+ childID := child.ID()
+ childOCI, err := t.toOCI(ctx, child)
+ if err != nil {
+ return nil, err
+ }
+
+ // Empty images are special in that they do not have any physical layer
+ // but yet can have a parent-child relation. Hence, compare the
+ // "child" image to all other known empty images.
+ if child.TopLayer() == "" {
+ for _, empty := range t.emptyImages {
+ if childID == empty.ID() {
+ continue
+ }
+ emptyOCI, err := t.toOCI(ctx, empty)
+ if err != nil {
+ return nil, err
+ }
+ // History check.
+ if areParentAndChild(emptyOCI, childOCI) {
+ return empty, nil
+ }
+ }
return nil, nil
}
@@ -219,14 +275,8 @@ func (t *layerTree) parent(ctx context.Context, child *Image) (*Image, error) {
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...)
diff --git a/vendor/github.com/containers/common/libimage/manifests/manifests.go b/vendor/github.com/containers/common/libimage/manifests/manifests.go
index 875c2948d..81b5343c0 100644
--- a/vendor/github.com/containers/common/libimage/manifests/manifests.go
+++ b/vendor/github.com/containers/common/libimage/manifests/manifests.go
@@ -18,6 +18,7 @@ import (
"github.com/containers/image/v5/transports/alltransports"
"github.com/containers/image/v5/types"
"github.com/containers/storage"
+ "github.com/containers/storage/pkg/lockfile"
digest "github.com/opencontainers/go-digest"
v1 "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
@@ -395,3 +396,20 @@ func (l *list) Remove(instanceDigest digest.Digest) error {
}
return err
}
+
+// LockerForImage returns a Locker for a given image record. It's recommended
+// that processes which use LoadFromImage() to load a list from an image and
+// then use that list's SaveToImage() method to save a modified version of the
+// list to that image record use this lock to avoid accidentally wiping out
+// changes that another process is also attempting to make.
+func LockerForImage(store storage.Store, image string) (lockfile.Locker, error) {
+ img, err := store.Image(image)
+ if err != nil {
+ return nil, errors.Wrapf(err, "locating image %q for locating lock", image)
+ }
+ d := digest.NewDigestFromEncoded(digest.Canonical, img.ID)
+ if err := d.Validate(); err != nil {
+ return nil, errors.Wrapf(err, "coercing image ID for %q into a digest", image)
+ }
+ return store.GetDigestLock(d)
+}
diff --git a/vendor/github.com/containers/common/libimage/pull.go b/vendor/github.com/containers/common/libimage/pull.go
index 71cec021b..97347178a 100644
--- a/vendor/github.com/containers/common/libimage/pull.go
+++ b/vendor/github.com/containers/common/libimage/pull.go
@@ -10,7 +10,9 @@ import (
"github.com/containers/common/pkg/config"
registryTransport "github.com/containers/image/v5/docker"
dockerArchiveTransport "github.com/containers/image/v5/docker/archive"
+ dockerDaemonTransport "github.com/containers/image/v5/docker/daemon"
"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/pkg/shortnames"
@@ -18,6 +20,7 @@ import (
"github.com/containers/image/v5/transports/alltransports"
"github.com/containers/image/v5/types"
"github.com/containers/storage"
+ digest "github.com/opencontainers/go-digest"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
@@ -55,6 +58,13 @@ func (r *Runtime) Pull(ctx context.Context, name string, pullPolicy config.PullP
var possiblyUnqualifiedName string // used for short-name resolution
ref, err := alltransports.ParseImageName(name)
if err != nil {
+ // Check whether `name` points to a transport. If so, we
+ // return the error. Otherwise we assume that `name` refers to
+ // an image on a registry (e.g., "fedora").
+ if alltransports.TransportFromImageName(name) != nil {
+ return nil, err
+ }
+
// 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.ContainsAny(name, "/.:@")) {
@@ -169,25 +179,34 @@ func (r *Runtime) copyFromDefault(ctx context.Context, ref types.ImageReference,
var storageName, imageName string
switch ref.Transport().Name() {
+ case dockerDaemonTransport.Transport.Name():
+ // Normalize to docker.io if needed (see containers/podman/issues/10998).
+ named, err := reference.ParseNormalizedNamed(ref.StringWithinTransport())
+ if err != nil {
+ return nil, err
+ }
+ imageName = named.String()
+ storageName = imageName
+
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)
+ manifestDescriptor, 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 index.json has no reference name, compute the image ID instead
+ if manifestDescriptor.Annotations == nil || manifestDescriptor.Annotations["org.opencontainers.image.ref.name"] == "" {
+ storageName, err = getImageID(ctx, ref, nil)
if err != nil {
return nil, err
}
imageName = "sha256:" + storageName[1:]
} else {
- storageName = manifest.Annotations["org.opencontainers.image.ref.name"]
+ storageName = manifestDescriptor.Annotations["org.opencontainers.image.ref.name"]
named, err := NormalizeName(storageName)
if err != nil {
return nil, err
@@ -231,7 +250,7 @@ func (r *Runtime) storageReferencesReferencesFromArchiveReader(ctx context.Conte
var imageNames []string
if len(destNames) == 0 {
- destName, err := getImageDigest(ctx, readerRef, &r.systemContext)
+ destName, err := getImageID(ctx, readerRef, &r.systemContext)
if err != nil {
return nil, nil, err
}
@@ -299,8 +318,8 @@ func (r *Runtime) copyFromDockerArchiveReaderReference(ctx context.Context, read
}
// 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.
+// registry. On successful pull it returns the ID of the image in local
+// 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) {
@@ -320,7 +339,7 @@ func (r *Runtime) copyFromRegistry(ctx context.Context, ref types.ImageReference
return nil, err
}
- pulledTags := []string{}
+ pulledIDs := []string{}
for _, tag := range tags {
select { // Let's be gentle with Podman remote.
case <-ctx.Done():
@@ -336,15 +355,54 @@ func (r *Runtime) copyFromRegistry(ctx context.Context, ref types.ImageReference
if err != nil {
return nil, err
}
- pulledTags = append(pulledTags, pulled...)
+ pulledIDs = append(pulledIDs, pulled...)
}
- return pulledTags, nil
+ return pulledIDs, nil
+}
+
+// imageIDsForManifest() parses the manifest of the copied image and then looks
+// up the IDs of the matching image. There's a small slice of time, between
+// when we copy the image into local storage and when we go to look for it
+// using the name that we gave it when we copied it, when the name we wanted to
+// assign to the image could have been moved, but the image's ID will remain
+// the same until it is deleted.
+func (r *Runtime) imagesIDsForManifest(manifestBytes []byte, sys *types.SystemContext) ([]string, error) {
+ var imageDigest digest.Digest
+ manifestType := manifest.GuessMIMEType(manifestBytes)
+ if manifest.MIMETypeIsMultiImage(manifestType) {
+ list, err := manifest.ListFromBlob(manifestBytes, manifestType)
+ if err != nil {
+ return nil, errors.Wrapf(err, "parsing manifest list")
+ }
+ d, err := list.ChooseInstance(sys)
+ if err != nil {
+ return nil, errors.Wrapf(err, "choosing instance from manifest list")
+ }
+ imageDigest = d
+ } else {
+ d, err := manifest.Digest(manifestBytes)
+ if err != nil {
+ return nil, errors.Wrapf(err, "digesting manifest")
+ }
+ imageDigest = d
+ }
+ var results []string
+ images, err := r.store.ImagesByDigest(imageDigest)
+ if err != nil {
+ return nil, errors.Wrapf(err, "listing images by manifest digest")
+ }
+ for _, image := range images {
+ results = append(results, image.ID)
+ }
+ if len(results) == 0 {
+ return nil, errors.Wrapf(storage.ErrImageUnknown, "identifying new image by manifest digest")
+ }
+ return results, 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
+// from a registry. On successful pull it returns the ID of the image in local
// storage.
func (r *Runtime) copySingleImageFromRegistry(ctx context.Context, imageName string, pullPolicy config.PullPolicy, options *PullOptions) ([]string, error) { //nolint:gocyclo
// Sanity check.
@@ -358,7 +416,7 @@ func (r *Runtime) copySingleImageFromRegistry(ctx context.Context, imageName str
err error
)
- // Always check if there's a local image. If, we should use it's
+ // Always check if there's a local image. If so, we should use its
// 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.
@@ -437,7 +495,7 @@ func (r *Runtime) copySingleImageFromRegistry(ctx context.Context, imageName str
}
}
- // If we found a local image, we should use it's locally resolved name
+ // If we found a local image, we should use its locally resolved name
// (see containers/buildah/issues/2904). An exception is if a custom
// platform is specified (e.g., `--arch=arm64`). In that case, we need
// to pessimistically pull the image since some images declare wrong
@@ -445,7 +503,8 @@ func (r *Runtime) copySingleImageFromRegistry(ctx context.Context, imageName str
// containers/podman/issues/10682).
//
// In other words: multi-arch support can only be as good as the images
- // in the wild.
+ // in the wild, so we shouldn't break things for our users by trying to
+ // insist that they make sense.
if localImage != nil && !customPlatform {
if imageName != resolvedImageName {
logrus.Debugf("Image %s resolved to local image %s which will be used for pulling", imageName, resolvedImageName)
@@ -524,7 +583,8 @@ func (r *Runtime) copySingleImageFromRegistry(ctx context.Context, imageName str
return nil, err
}
}
- if _, err := c.copy(ctx, srcRef, destRef); err != nil {
+ var manifestBytes []byte
+ if manifestBytes, err = c.copy(ctx, srcRef, destRef); err != nil {
logrus.Debugf("Error pulling candidate %s: %v", candidateString, err)
pullErrors = append(pullErrors, err)
continue
@@ -537,6 +597,9 @@ func (r *Runtime) copySingleImageFromRegistry(ctx context.Context, imageName str
}
logrus.Debugf("Pulled candidate %s successfully", candidateString)
+ if ids, err := r.imagesIDsForManifest(manifestBytes, sys); err == nil {
+ return ids, nil
+ }
return []string{candidate.Value.String()}, nil
}
diff --git a/vendor/github.com/containers/common/libimage/runtime.go b/vendor/github.com/containers/common/libimage/runtime.go
index 1fd2973cb..26a04dad5 100644
--- a/vendor/github.com/containers/common/libimage/runtime.go
+++ b/vendor/github.com/containers/common/libimage/runtime.go
@@ -3,7 +3,6 @@ package libimage
import (
"context"
"os"
- "path/filepath"
"strings"
"github.com/containers/image/v5/docker/reference"
@@ -94,10 +93,6 @@ func RuntimeFromStore(store storage.Store, options *RuntimeOptions) (*Runtime, e
setRegistriesConfPath(&systemContext)
- if systemContext.BlobInfoCacheDir == "" {
- systemContext.BlobInfoCacheDir = filepath.Join(store.GraphRoot(), "cache")
- }
-
return &Runtime{
store: store,
systemContext: systemContext,
@@ -592,11 +587,10 @@ func (r *Runtime) RemoveImages(ctx context.Context, names []string, options *Rem
rmErrors = append(rmErrors, err)
}
- orderedIDs := []string{} // determinism and relative order
deleteMap := make(map[string]*deleteMe) // ID -> deleteMe
-
+ toDelete := []string{}
// Look up images in the local containers storage and fill out
- // orderedIDs and the deleteMap.
+ // toDelete and the deleteMap.
switch {
case len(names) > 0:
// Look up the images one-by-one. That allows for removing
@@ -610,15 +604,12 @@ func (r *Runtime) RemoveImages(ctx context.Context, names []string, options *Rem
}
dm, exists := deleteMap[img.ID()]
if !exists {
- orderedIDs = append(orderedIDs, img.ID())
+ toDelete = append(toDelete, img.ID())
dm = &deleteMe{image: img}
deleteMap[img.ID()] = dm
}
dm.referencedBy = append(dm.referencedBy, resolvedName)
}
- if len(orderedIDs) == 0 {
- return nil, rmErrors
- }
default:
filteredImages, err := r.ListImages(ctx, nil, &ListImagesOptions{Filters: options.Filters})
@@ -627,14 +618,21 @@ func (r *Runtime) RemoveImages(ctx context.Context, names []string, options *Rem
return nil, rmErrors
}
for _, img := range filteredImages {
- orderedIDs = append(orderedIDs, img.ID())
+ toDelete = append(toDelete, img.ID())
deleteMap[img.ID()] = &deleteMe{image: img}
}
}
+ // Return early if there's no image to delete.
+ if len(deleteMap) == 0 {
+ return nil, rmErrors
+ }
+
// Now remove the images in the given order.
rmMap := make(map[string]*RemoveImageReport)
- for _, id := range orderedIDs {
+ orderedIDs := []string{}
+ visitedIDs := make(map[string]bool)
+ for _, id := range toDelete {
del, exists := deleteMap[id]
if !exists {
appendError(errors.Errorf("internal error: ID %s not in found in image-deletion map", id))
@@ -644,9 +642,17 @@ func (r *Runtime) RemoveImages(ctx context.Context, names []string, options *Rem
del.referencedBy = []string{""}
}
for _, ref := range del.referencedBy {
- if err := del.image.remove(ctx, rmMap, ref, options); err != nil {
+ processedIDs, err := del.image.remove(ctx, rmMap, ref, options)
+ if err != nil {
appendError(err)
- continue
+ }
+ // NOTE: make sure to add given ID only once to orderedIDs.
+ for _, id := range processedIDs {
+ if visited := visitedIDs[id]; visited {
+ continue
+ }
+ orderedIDs = append(orderedIDs, id)
+ visitedIDs[id] = true
}
}
}
diff --git a/vendor/github.com/containers/common/libimage/search.go b/vendor/github.com/containers/common/libimage/search.go
index 4d1b842e7..df29bc7da 100644
--- a/vendor/github.com/containers/common/libimage/search.go
+++ b/vendor/github.com/containers/common/libimage/search.go
@@ -185,6 +185,10 @@ func (r *Runtime) searchImageInRegistry(ctx context.Context, term, registry stri
sys.DockerInsecureSkipTLSVerify = options.InsecureSkipTLSVerify
}
+ if options.Authfile != "" {
+ sys.AuthFilePath = options.Authfile
+ }
+
if options.ListTags {
results, err := searchRepositoryTags(ctx, sys, registry, term, options)
if err != nil {
diff --git a/vendor/github.com/containers/common/pkg/auth/auth.go b/vendor/github.com/containers/common/pkg/auth/auth.go
index d2e75c1f7..093da0299 100644
--- a/vendor/github.com/containers/common/pkg/auth/auth.go
+++ b/vendor/github.com/containers/common/pkg/auth/auth.go
@@ -9,6 +9,7 @@ import (
"strings"
"github.com/containers/image/v5/docker"
+ "github.com/containers/image/v5/docker/reference"
"github.com/containers/image/v5/pkg/docker/config"
"github.com/containers/image/v5/pkg/sysregistriesv2"
"github.com/containers/image/v5/types"
@@ -69,30 +70,50 @@ func Login(ctx context.Context, systemContext *types.SystemContext, opts *LoginO
systemContext = systemContextWithOptions(systemContext, opts.AuthFile, opts.CertDir)
var (
- server string
- err error
+ authConfig types.DockerAuthConfig
+ key, registry string
+ ref reference.Named
+ err error
)
- if len(args) > 1 {
- return errors.New("login accepts only one registry to login to")
- }
- if len(args) == 0 {
+ l := len(args)
+ switch l {
+ case 0:
if !opts.AcceptUnspecifiedRegistry {
return errors.New("please provide a registry to login to")
}
- if server, err = defaultRegistryWhenUnspecified(systemContext); err != nil {
+ if key, err = defaultRegistryWhenUnspecified(systemContext); err != nil {
return err
}
- logrus.Debugf("registry not specified, default to the first registry %q from registries.conf", server)
- } else {
- server = getRegistryName(args[0])
+ registry = key
+ logrus.Debugf("registry not specified, default to the first registry %q from registries.conf", key)
+
+ case 1:
+ key, registry, ref, err = parseRegistryArgument(args[0], opts.AcceptRepositories)
+ if err != nil {
+ return err
+ }
+
+ default:
+ return errors.New("login accepts only one registry to login to")
+
}
- authConfig, err := config.GetCredentials(systemContext, server)
- if err != nil {
- return errors.Wrap(err, "reading auth file")
+
+ if ref != nil {
+ authConfig, err = config.GetCredentialsForRef(systemContext, ref)
+ if err != nil {
+ return errors.Wrap(err, "get credentials for repository")
+ }
+ } else {
+ // nolint: staticcheck
+ authConfig, err = config.GetCredentials(systemContext, registry)
+ if err != nil {
+ return errors.Wrap(err, "get credentials")
+ }
}
+
if opts.GetLoginSet {
if authConfig.Username == "" {
- return errors.Errorf("not logged into %s", server)
+ return errors.Errorf("not logged into %s", key)
}
fmt.Fprintf(opts.Stdout, "%s\n", authConfig.Username)
return nil
@@ -119,9 +140,9 @@ func Login(ctx context.Context, systemContext *types.SystemContext, opts *LoginO
// If no username and no password is specified, try to use existing ones.
if opts.Username == "" && password == "" && authConfig.Username != "" && authConfig.Password != "" {
- fmt.Println("Authenticating with existing credentials...")
- if err := docker.CheckAuth(ctx, systemContext, authConfig.Username, authConfig.Password, server); err == nil {
- fmt.Fprintln(opts.Stdout, "Existing credentials are valid. Already logged in to", server)
+ fmt.Fprintf(opts.Stdout, "Authenticating with existing credentials for %s\n", key)
+ if err := docker.CheckAuth(ctx, systemContext, authConfig.Username, authConfig.Password, registry); err == nil {
+ fmt.Fprintf(opts.Stdout, "Existing credentials are valid. Already logged in to %s\n", registry)
return nil
}
fmt.Fprintln(opts.Stdout, "Existing credentials are invalid, please enter valid username and password")
@@ -132,9 +153,9 @@ func Login(ctx context.Context, systemContext *types.SystemContext, opts *LoginO
return errors.Wrap(err, "getting username and password")
}
- if err = docker.CheckAuth(ctx, systemContext, username, password, server); err == nil {
+ if err = docker.CheckAuth(ctx, systemContext, username, password, registry); err == nil {
// Write the new credentials to the authfile
- desc, err := config.SetCredentials(systemContext, server, username, password)
+ desc, err := config.SetCredentials(systemContext, key, username, password)
if err != nil {
return err
}
@@ -147,10 +168,45 @@ func Login(ctx context.Context, systemContext *types.SystemContext, opts *LoginO
return nil
}
if unauthorized, ok := err.(docker.ErrUnauthorizedForCredentials); ok {
- logrus.Debugf("error logging into %q: %v", server, unauthorized)
- return errors.Errorf("error logging into %q: invalid username/password", server)
+ logrus.Debugf("error logging into %q: %v", key, unauthorized)
+ return errors.Errorf("error logging into %q: invalid username/password", key)
+ }
+ return errors.Wrapf(err, "authenticating creds for %q", key)
+}
+
+// parseRegistryArgument verifies the provided arg depending if we accept
+// repositories or not.
+func parseRegistryArgument(arg string, acceptRepositories bool) (key, registry string, maybeRef reference.Named, err error) {
+ if !acceptRepositories {
+ registry = getRegistryName(arg)
+ key = registry
+ return key, registry, maybeRef, nil
+ }
+
+ key = trimScheme(arg)
+ if key != arg {
+ return key, registry, nil, errors.New("credentials key has https[s]:// prefix")
}
- return errors.Wrapf(err, "authenticating creds for %q", server)
+
+ registry = getRegistryName(key)
+ if registry == key {
+ // We cannot parse a reference from a registry, so we stop here
+ return key, registry, nil, nil
+ }
+
+ ref, parseErr := reference.ParseNamed(key)
+ if parseErr != nil {
+ return key, registry, nil, errors.Wrapf(parseErr, "parse reference from %q", key)
+ }
+
+ if !reference.IsNameOnly(ref) {
+ return key, registry, nil, errors.Errorf("reference %q contains tag or digest", ref.String())
+ }
+
+ maybeRef = ref
+ registry = reference.Domain(ref)
+
+ return key, registry, maybeRef, nil
}
// getRegistryName scrubs and parses the input to get the server name
@@ -158,13 +214,21 @@ func getRegistryName(server string) string {
// removes 'http://' or 'https://' from the front of the
// server/registry string if either is there. This will be mostly used
// for user input from 'Buildah login' and 'Buildah logout'.
- server = strings.TrimPrefix(strings.TrimPrefix(server, "https://"), "http://")
+ server = trimScheme(server)
// gets the registry from the input. If the input is of the form
// quay.io/myuser/myimage, it will parse it and just return quay.io
split := strings.Split(server, "/")
return split[0]
}
+// trimScheme removes the HTTP(s) scheme from the provided repository.
+func trimScheme(repository string) string {
+ // removes 'http://' or 'https://' from the front of the
+ // server/registry string if either is there. This will be mostly used
+ // for user input from 'Buildah login' and 'Buildah logout'.
+ return strings.TrimPrefix(strings.TrimPrefix(repository, "https://"), "http://")
+}
+
// getUserAndPass gets the username and password from STDIN if not given
// using the -u and -p flags. If the username prompt is left empty, the
// displayed userFromAuthFile will be used instead.
@@ -209,8 +273,9 @@ func Logout(systemContext *types.SystemContext, opts *LogoutOptions, args []stri
systemContext = systemContextWithOptions(systemContext, opts.AuthFile, "")
var (
- server string
- err error
+ key, registry string
+ ref reference.Named
+ err error
)
if len(args) > 1 {
return errors.New("logout accepts only one registry to logout from")
@@ -219,16 +284,20 @@ func Logout(systemContext *types.SystemContext, opts *LogoutOptions, args []stri
if !opts.AcceptUnspecifiedRegistry {
return errors.New("please provide a registry to logout from")
}
- if server, err = defaultRegistryWhenUnspecified(systemContext); err != nil {
+ if key, err = defaultRegistryWhenUnspecified(systemContext); err != nil {
return err
}
- logrus.Debugf("registry not specified, default to the first registry %q from registries.conf", server)
+ registry = key
+ logrus.Debugf("registry not specified, default to the first registry %q from registries.conf", key)
}
if len(args) != 0 {
if opts.All {
return errors.New("--all takes no arguments")
}
- server = getRegistryName(args[0])
+ key, registry, ref, err = parseRegistryArgument(args[0], opts.AcceptRepositories)
+ if err != nil {
+ return err
+ }
}
if opts.All {
@@ -239,24 +308,34 @@ func Logout(systemContext *types.SystemContext, opts *LogoutOptions, args []stri
return nil
}
- err = config.RemoveAuthentication(systemContext, server)
+ err = config.RemoveAuthentication(systemContext, key)
switch errors.Cause(err) {
case nil:
- fmt.Fprintf(opts.Stdout, "Removed login credentials for %s\n", server)
+ fmt.Fprintf(opts.Stdout, "Removed login credentials for %s\n", key)
return nil
case config.ErrNotLoggedIn:
- authConfig, err := config.GetCredentials(systemContext, server)
- if err != nil {
- return errors.Wrap(err, "reading auth file")
+ var authConfig types.DockerAuthConfig
+ if ref != nil {
+ authConfig, err = config.GetCredentialsForRef(systemContext, ref)
+ if err != nil {
+ return errors.Wrap(err, "get credentials for repository")
+ }
+ } else {
+ // nolint: staticcheck
+ authConfig, err = config.GetCredentials(systemContext, registry)
+ if err != nil {
+ return errors.Wrap(err, "get credentials")
+ }
}
- authInvalid := docker.CheckAuth(context.Background(), systemContext, authConfig.Username, authConfig.Password, server)
+
+ authInvalid := docker.CheckAuth(context.Background(), systemContext, authConfig.Username, authConfig.Password, registry)
if authConfig.Username != "" && authConfig.Password != "" && authInvalid == nil {
- fmt.Printf("Not logged into %s with current tool. Existing credentials were established via docker login. Please use docker logout instead.\n", server)
+ fmt.Printf("Not logged into %s with current tool. Existing credentials were established via docker login. Please use docker logout instead.\n", key)
return nil
}
- return errors.Errorf("Not logged into %s\n", server)
+ return errors.Errorf("Not logged into %s\n", key)
default:
- return errors.Wrapf(err, "logging out of %q", server)
+ return errors.Wrapf(err, "logging out of %q", key)
}
}
diff --git a/vendor/github.com/containers/common/pkg/auth/cli.go b/vendor/github.com/containers/common/pkg/auth/cli.go
index 5a7c1137c..7266bf48b 100644
--- a/vendor/github.com/containers/common/pkg/auth/cli.go
+++ b/vendor/github.com/containers/common/pkg/auth/cli.go
@@ -14,13 +14,14 @@ type LoginOptions struct {
// CLI flags managed by the FlagSet returned by GetLoginFlags
// Callers that use GetLoginFlags should not need to touch these values at all; callers that use
// other CLI frameworks should set them based on user input.
- AuthFile string
- CertDir string
- Password string
- Username string
- StdinPassword bool
- GetLoginSet bool
- Verbose bool // set to true for verbose output
+ AuthFile string
+ CertDir string
+ Password string
+ Username string
+ StdinPassword bool
+ GetLoginSet bool
+ Verbose bool // set to true for verbose output
+ AcceptRepositories bool // set to true to allow namespaces or repositories rather than just registries
// Options caller can set
Stdin io.Reader // set to os.Stdin
Stdout io.Writer // set to os.Stdout
@@ -32,8 +33,9 @@ type LogoutOptions struct {
// CLI flags managed by the FlagSet returned by GetLogoutFlags
// Callers that use GetLogoutFlags should not need to touch these values at all; callers that use
// other CLI frameworks should set them based on user input.
- AuthFile string
- All bool
+ AuthFile string
+ All bool
+ AcceptRepositories bool // set to true to allow namespaces or repositories rather than just registries
// Options caller can set
Stdout io.Writer // set to os.Stdout
AcceptUnspecifiedRegistry bool // set to true if allows logout with unspecified registry
diff --git a/vendor/github.com/containers/common/pkg/config/config.go b/vendor/github.com/containers/common/pkg/config/config.go
index 84876026d..008cfb642 100644
--- a/vendor/github.com/containers/common/pkg/config/config.go
+++ b/vendor/github.com/containers/common/pkg/config/config.go
@@ -637,9 +637,14 @@ func (c *Config) CheckCgroupsAndAdjustConfig() {
session := os.Getenv("DBUS_SESSION_BUS_ADDRESS")
hasSession := session != ""
- if hasSession && strings.HasPrefix(session, "unix:path=") {
- _, err := os.Stat(strings.TrimPrefix(session, "unix:path="))
- hasSession = err == nil
+ if hasSession {
+ for _, part := range strings.Split(session, ",") {
+ if strings.HasPrefix(part, "unix:path=") {
+ _, err := os.Stat(strings.TrimPrefix(part, "unix:path="))
+ hasSession = err == nil
+ break
+ }
+ }
}
if !hasSession && unshare.GetRootlessUID() != 0 {
diff --git a/vendor/github.com/containers/common/pkg/config/pull_policy.go b/vendor/github.com/containers/common/pkg/config/pull_policy.go
index 7c32dd660..8c1f0ec29 100644
--- a/vendor/github.com/containers/common/pkg/config/pull_policy.go
+++ b/vendor/github.com/containers/common/pkg/config/pull_policy.go
@@ -76,13 +76,13 @@ func (p PullPolicy) Validate() error {
// * "never" <-> PullPolicyNever
func ParsePullPolicy(s string) (PullPolicy, error) {
switch s {
- case "always":
+ case "always", "Always":
return PullPolicyAlways, nil
- case "missing", "ifnotpresent", "":
+ case "missing", "Missing", "ifnotpresent", "IfNotPresent", "":
return PullPolicyMissing, nil
- case "newer", "ifnewer":
+ case "newer", "Newer", "ifnewer", "IfNewer":
return PullPolicyNewer, nil
- case "never":
+ case "never", "Never":
return PullPolicyNever, nil
default:
return PullPolicyUnsupported, errors.Errorf("unsupported pull policy %q", s)
diff --git a/vendor/github.com/containers/common/pkg/seccomp/types.go b/vendor/github.com/containers/common/pkg/seccomp/types.go
index 36712458a..07751f729 100644
--- a/vendor/github.com/containers/common/pkg/seccomp/types.go
+++ b/vendor/github.com/containers/common/pkg/seccomp/types.go
@@ -7,7 +7,7 @@ package seccomp
// Seccomp represents the config for a seccomp profile for syscall restriction.
type Seccomp struct {
DefaultAction Action `json:"defaultAction"`
- DefaultErrnoRet *uint `json:"defaultErrnoRet"`
+ DefaultErrnoRet *uint `json:"defaultErrnoRet,omitempty"`
// Architectures is kept to maintain backward compatibility with the old
// seccomp profile.
Architectures []Arch `json:"architectures,omitempty"`
diff --git a/vendor/github.com/containers/image/v5/copy/copy.go b/vendor/github.com/containers/image/v5/copy/copy.go
index 62f47c013..b4ff8aa10 100644
--- a/vendor/github.com/containers/image/v5/copy/copy.go
+++ b/vendor/github.com/containers/image/v5/copy/copy.go
@@ -20,6 +20,7 @@ import (
"github.com/containers/image/v5/manifest"
"github.com/containers/image/v5/pkg/blobinfocache"
"github.com/containers/image/v5/pkg/compression"
+ compressiontypes "github.com/containers/image/v5/pkg/compression/types"
"github.com/containers/image/v5/signature"
"github.com/containers/image/v5/transports"
"github.com/containers/image/v5/types"
@@ -57,7 +58,7 @@ var compressionBufferSize = 1048576
// expectedCompressionFormats is used to check if a blob with a specified media type is compressed
// using the algorithm that the media type says it should be compressed with
-var expectedCompressionFormats = map[string]*compression.Algorithm{
+var expectedCompressionFormats = map[string]*compressiontypes.Algorithm{
imgspecv1.MediaTypeImageLayerGzip: &compression.Gzip,
imgspecv1.MediaTypeImageLayerZstd: &compression.Zstd,
manifest.DockerV2Schema2LayerMediaType: &compression.Gzip,
@@ -92,7 +93,7 @@ func (d *digestingReader) Read(p []byte) (int, error) {
// Coverage: This should not happen, the hash.Hash interface requires
// d.digest.Write to never return an error, and the io.Writer interface
// requires n2 == len(input) if no error is returned.
- return 0, errors.Wrapf(err, "Error updating digest during verification: %d vs. %d", n2, n)
+ return 0, errors.Wrapf(err, "updating digest during verification: %d vs. %d", n2, n)
}
}
if err == io.EOF {
@@ -117,7 +118,7 @@ type copier struct {
progress chan types.ProgressProperties
blobInfoCache internalblobinfocache.BlobInfoCache2
copyInParallel bool
- compressionFormat compression.Algorithm
+ compressionFormat compressiontypes.Algorithm
compressionLevel *int
ociDecryptConfig *encconfig.DecryptConfig
ociEncryptConfig *encconfig.EncryptConfig
@@ -194,12 +195,15 @@ type Options struct {
// 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
+
// MaxParallelDownloads indicates the maximum layers to pull at the same time. A reasonable default is used if this is left as 0.
MaxParallelDownloads uint
+
// When OptimizeDestinationImageAlreadyExists is set, optimize the copy assuming that the destination image already
// exists (and is equivalent). Making the eventual (no-op) copy more performant for this case. Enabling the option
// is slightly pessimistic if the destination image doesn't exist, or is not equivalent.
OptimizeDestinationImageAlreadyExists bool
+
// Download layer contents with "nondistributable" media types ("foreign" layers) and translate the layer media type
// to not indicate "nondistributable".
DownloadForeignLayers bool
@@ -240,7 +244,7 @@ func Image(ctx context.Context, policyContext *signature.PolicyContext, destRef,
dest, err := destRef.NewImageDestination(ctx, options.DestinationCtx)
if err != nil {
- return nil, errors.Wrapf(err, "Error initializing destination %s", transports.ImageName(destRef))
+ return nil, errors.Wrapf(err, "initializing destination %s", transports.ImageName(destRef))
}
defer func() {
if err := dest.Close(); err != nil {
@@ -250,7 +254,7 @@ func Image(ctx context.Context, policyContext *signature.PolicyContext, destRef,
rawSource, err := srcRef.NewImageSource(ctx, options.SourceCtx)
if err != nil {
- return nil, errors.Wrapf(err, "Error initializing source %s", transports.ImageName(srcRef))
+ return nil, errors.Wrapf(err, "initializing source %s", transports.ImageName(srcRef))
}
defer func() {
if err := rawSource.Close(); err != nil {
@@ -286,11 +290,7 @@ func Image(ctx context.Context, policyContext *signature.PolicyContext, destRef,
}
// Default to using gzip compression unless specified otherwise.
if options.DestinationCtx == nil || options.DestinationCtx.CompressionFormat == nil {
- algo, err := compression.AlgorithmByName("gzip")
- if err != nil {
- return nil, err
- }
- c.compressionFormat = algo
+ c.compressionFormat = compression.Gzip
} else {
c.compressionFormat = *options.DestinationCtx.CompressionFormat
}
@@ -302,7 +302,7 @@ func Image(ctx context.Context, policyContext *signature.PolicyContext, destRef,
unparsedToplevel := image.UnparsedInstance(rawSource, nil)
multiImage, err := isMultiImage(ctx, unparsedToplevel)
if err != nil {
- return nil, errors.Wrapf(err, "Error determining manifest MIME type for %s", transports.ImageName(srcRef))
+ return nil, errors.Wrapf(err, "determining manifest MIME type for %s", transports.ImageName(srcRef))
}
if !multiImage {
@@ -315,15 +315,15 @@ func Image(ctx context.Context, policyContext *signature.PolicyContext, destRef,
// matches the current system to copy, and copy it.
mfest, manifestType, err := unparsedToplevel.Manifest(ctx)
if err != nil {
- return nil, errors.Wrapf(err, "Error reading manifest for %s", transports.ImageName(srcRef))
+ return nil, errors.Wrapf(err, "reading manifest for %s", transports.ImageName(srcRef))
}
manifestList, err := manifest.ListFromBlob(mfest, manifestType)
if err != nil {
- return nil, errors.Wrapf(err, "Error parsing primary manifest as list for %s", transports.ImageName(srcRef))
+ return nil, errors.Wrapf(err, "parsing primary manifest as list for %s", transports.ImageName(srcRef))
}
instanceDigest, err := manifestList.ChooseInstance(options.SourceCtx) // try to pick one that matches options.SourceCtx
if err != nil {
- return nil, errors.Wrapf(err, "Error choosing an image from manifest list %s", transports.ImageName(srcRef))
+ return nil, errors.Wrapf(err, "choosing an image from manifest list %s", transports.ImageName(srcRef))
}
logrus.Debugf("Source is a manifest list; copying (only) instance %s for current system", instanceDigest)
unparsedInstance := image.UnparsedInstance(rawSource, &instanceDigest)
@@ -334,7 +334,7 @@ func Image(ctx context.Context, policyContext *signature.PolicyContext, destRef,
} else { /* options.ImageListSelection == CopyAllImages or options.ImageListSelection == CopySpecificImages, */
// If we were asked to copy multiple images and can't, that's an error.
if !supportsMultipleImages(c.dest) {
- return nil, errors.Errorf("Error copying multiple images: destination transport %q does not support copying multiple images as a group", destRef.Transport().Name())
+ return nil, errors.Errorf("copying multiple images: destination transport %q does not support copying multiple images as a group", destRef.Transport().Name())
}
// Copy some or all of the images.
switch options.ImageListSelection {
@@ -343,13 +343,13 @@ func Image(ctx context.Context, policyContext *signature.PolicyContext, destRef,
case CopySpecificImages:
logrus.Debugf("Source is a manifest list; copying some instances")
}
- if copiedManifest, _, err = c.copyMultipleImages(ctx, policyContext, options, unparsedToplevel); err != nil {
+ if copiedManifest, err = c.copyMultipleImages(ctx, policyContext, options, unparsedToplevel); err != nil {
return nil, err
}
}
if err := c.dest.Commit(ctx, unparsedToplevel); err != nil {
- return nil, errors.Wrap(err, "Error committing the finished image")
+ return nil, errors.Wrap(err, "committing the finished image")
}
return copiedManifest, nil
@@ -376,12 +376,12 @@ func supportsMultipleImages(dest types.ImageDestination) bool {
func compareImageDestinationManifestEqual(ctx context.Context, options *Options, src types.Image, targetInstance *digest.Digest, dest types.ImageDestination) (bool, []byte, string, digest.Digest, error) {
srcManifest, _, err := src.Manifest(ctx)
if err != nil {
- return false, nil, "", "", errors.Wrapf(err, "Error reading manifest from image")
+ return false, nil, "", "", errors.Wrapf(err, "reading manifest from image")
}
srcManifestDigest, err := manifest.Digest(srcManifest)
if err != nil {
- return false, nil, "", "", errors.Wrapf(err, "Error calculating manifest digest")
+ return false, nil, "", "", errors.Wrapf(err, "calculating manifest digest")
}
destImageSource, err := dest.Reference().NewImageSource(ctx, options.DestinationCtx)
@@ -398,7 +398,7 @@ func compareImageDestinationManifestEqual(ctx context.Context, options *Options,
destManifestDigest, err := manifest.Digest(destManifest)
if err != nil {
- return false, nil, "", "", errors.Wrapf(err, "Error calculating manifest digest")
+ return false, nil, "", "", errors.Wrapf(err, "calculating manifest digest")
}
logrus.Debugf("Comparing source and destination manifest digests: %v vs. %v", srcManifestDigest, destManifestDigest)
@@ -412,15 +412,15 @@ func compareImageDestinationManifestEqual(ctx context.Context, options *Options,
// copyMultipleImages copies some or all of an image list's instances, using
// policyContext to validate source image admissibility.
-func (c *copier) copyMultipleImages(ctx context.Context, policyContext *signature.PolicyContext, options *Options, unparsedToplevel *image.UnparsedImage) (copiedManifest []byte, copiedManifestType string, retErr error) {
+func (c *copier) copyMultipleImages(ctx context.Context, policyContext *signature.PolicyContext, options *Options, unparsedToplevel *image.UnparsedImage) (copiedManifest []byte, retErr error) {
// Parse the list and get a copy of the original value after it's re-encoded.
manifestList, manifestType, err := unparsedToplevel.Manifest(ctx)
if err != nil {
- return nil, "", errors.Wrapf(err, "Error reading manifest list")
+ return nil, errors.Wrapf(err, "reading manifest list")
}
originalList, err := manifest.ListFromBlob(manifestList, manifestType)
if err != nil {
- return nil, "", errors.Wrapf(err, "Error parsing manifest list %q", string(manifestList))
+ return nil, errors.Wrapf(err, "parsing manifest list %q", string(manifestList))
}
updatedList := originalList.Clone()
@@ -432,14 +432,14 @@ func (c *copier) copyMultipleImages(ctx context.Context, policyContext *signatur
c.Printf("Getting image list signatures\n")
s, err := c.rawSource.GetSignatures(ctx, nil)
if err != nil {
- return nil, "", errors.Wrap(err, "Error reading signatures")
+ return nil, errors.Wrap(err, "reading signatures")
}
sigs = s
}
if len(sigs) != 0 {
c.Printf("Checking if image list destination supports signatures\n")
if err := c.dest.SupportsSignatures(ctx); err != nil {
- return nil, "", errors.Wrapf(err, "Can not copy signatures to %s", transports.ImageName(c.dest.Reference()))
+ return nil, errors.Wrapf(err, "Can not copy signatures to %s", transports.ImageName(c.dest.Reference()))
}
}
canModifyManifestList := (len(sigs) == 0)
@@ -454,11 +454,11 @@ func (c *copier) copyMultipleImages(ctx context.Context, policyContext *signatur
}
selectedListType, otherManifestMIMETypeCandidates, err := c.determineListConversion(manifestType, c.dest.SupportedManifestMIMETypes(), forceListMIMEType)
if err != nil {
- return nil, "", errors.Wrapf(err, "Error determining manifest list type to write to destination")
+ return nil, errors.Wrapf(err, "determining manifest list type to write to destination")
}
if selectedListType != originalList.MIMEType() {
if !canModifyManifestList {
- return nil, "", errors.Errorf("Error: manifest list must be converted to type %q to be written to destination, but that would invalidate signatures", selectedListType)
+ return nil, errors.Errorf("manifest list must be converted to type %q to be written to destination, but that would invalidate signatures", selectedListType)
}
}
@@ -483,7 +483,7 @@ func (c *copier) copyMultipleImages(ctx context.Context, policyContext *signatur
if skip {
update, err := updatedList.Instance(instanceDigest)
if err != nil {
- return nil, "", err
+ return nil, err
}
logrus.Debugf("Skipping instance %s (%d/%d)", instanceDigest, i+1, len(instanceDigests))
// Record the digest/size/type of the manifest that we didn't copy.
@@ -496,7 +496,7 @@ func (c *copier) copyMultipleImages(ctx context.Context, policyContext *signatur
unparsedInstance := image.UnparsedInstance(c.rawSource, &instanceDigest)
updatedManifest, updatedManifestType, updatedManifestDigest, err := c.copyOneImage(ctx, policyContext, options, unparsedToplevel, unparsedInstance, &instanceDigest)
if err != nil {
- return nil, "", err
+ return nil, err
}
instancesCopied++
// Record the result of a possible conversion here.
@@ -510,7 +510,7 @@ func (c *copier) copyMultipleImages(ctx context.Context, policyContext *signatur
// Now reset the digest/size/types of the manifests in the list to account for any conversions that we made.
if err = updatedList.UpdateInstances(updates); err != nil {
- return nil, "", errors.Wrapf(err, "Error updating manifest list")
+ return nil, errors.Wrapf(err, "updating manifest list")
}
// Iterate through supported list types, preferred format first.
@@ -525,7 +525,7 @@ func (c *copier) copyMultipleImages(ctx context.Context, policyContext *signatur
if thisListType != updatedList.MIMEType() {
attemptedList, err = updatedList.ConvertToMIMEType(thisListType)
if err != nil {
- return nil, "", errors.Wrapf(err, "Error converting manifest list to list with MIME type %q", thisListType)
+ return nil, errors.Wrapf(err, "converting manifest list to list with MIME type %q", thisListType)
}
}
@@ -533,17 +533,17 @@ func (c *copier) copyMultipleImages(ctx context.Context, policyContext *signatur
// by serializing them both so that we can compare them.
attemptedManifestList, err := attemptedList.Serialize()
if err != nil {
- return nil, "", errors.Wrapf(err, "Error encoding updated manifest list (%q: %#v)", updatedList.MIMEType(), updatedList.Instances())
+ return nil, errors.Wrapf(err, "encoding updated manifest list (%q: %#v)", updatedList.MIMEType(), updatedList.Instances())
}
originalManifestList, err := originalList.Serialize()
if err != nil {
- return nil, "", errors.Wrapf(err, "Error encoding original manifest list for comparison (%q: %#v)", originalList.MIMEType(), originalList.Instances())
+ return nil, errors.Wrapf(err, "encoding original manifest list for comparison (%q: %#v)", originalList.MIMEType(), originalList.Instances())
}
// If we can't just use the original value, but we have to change it, flag an error.
if !bytes.Equal(attemptedManifestList, originalManifestList) {
if !canModifyManifestList {
- return nil, "", errors.Errorf("Error: manifest list must be converted to type %q to be written to destination, but that would invalidate signatures", thisListType)
+ return nil, errors.Errorf(" manifest list must be converted to type %q to be written to destination, but that would invalidate signatures", thisListType)
}
logrus.Debugf("Manifest list has been updated")
} else {
@@ -563,24 +563,24 @@ func (c *copier) copyMultipleImages(ctx context.Context, policyContext *signatur
break
}
if errs != nil {
- return nil, "", fmt.Errorf("Uploading manifest list failed, attempted the following formats: %s", strings.Join(errs, ", "))
+ return nil, fmt.Errorf("Uploading manifest list failed, attempted the following formats: %s", strings.Join(errs, ", "))
}
// Sign the manifest list.
if options.SignBy != "" {
newSig, err := c.createSignature(manifestList, options.SignBy)
if err != nil {
- return nil, "", err
+ return nil, err
}
sigs = append(sigs, newSig)
}
c.Printf("Storing list signatures\n")
if err := c.dest.PutSignatures(ctx, sigs, nil); err != nil {
- return nil, "", errors.Wrap(err, "Error writing signatures")
+ return nil, errors.Wrap(err, "writing signatures")
}
- return manifestList, selectedListType, nil
+ return manifestList, nil
}
// copyOneImage copies a single (non-manifest-list) image unparsedImage, using policyContext to validate
@@ -591,7 +591,7 @@ func (c *copier) copyOneImage(ctx context.Context, policyContext *signature.Poli
multiImage, err := isMultiImage(ctx, unparsedImage)
if err != nil {
// FIXME FIXME: How to name a reference for the sub-image?
- return nil, "", "", errors.Wrapf(err, "Error determining manifest MIME type for %s", transports.ImageName(unparsedImage.Reference()))
+ return nil, "", "", errors.Wrapf(err, "determining manifest MIME type for %s", transports.ImageName(unparsedImage.Reference()))
}
if multiImage {
return nil, "", "", fmt.Errorf("Unexpectedly received a manifest list instead of a manifest for a single image")
@@ -605,7 +605,7 @@ func (c *copier) copyOneImage(ctx context.Context, policyContext *signature.Poli
}
src, err := image.FromUnparsedImage(ctx, options.SourceCtx, unparsedImage)
if err != nil {
- return nil, "", "", errors.Wrapf(err, "Error initializing image from source %s", transports.ImageName(c.rawSource.Reference()))
+ return nil, "", "", errors.Wrapf(err, "initializing image from source %s", transports.ImageName(c.rawSource.Reference()))
}
// If the destination is a digested reference, make a note of that, determine what digest value we're
@@ -617,20 +617,20 @@ func (c *copier) copyOneImage(ctx context.Context, policyContext *signature.Poli
destIsDigestedReference = true
sourceManifest, _, err := src.Manifest(ctx)
if err != nil {
- return nil, "", "", errors.Wrapf(err, "Error reading manifest from source image")
+ return nil, "", "", errors.Wrapf(err, "reading manifest from source image")
}
matches, err := manifest.MatchesDigest(sourceManifest, digested.Digest())
if err != nil {
- return nil, "", "", errors.Wrapf(err, "Error computing digest of source image's manifest")
+ return nil, "", "", errors.Wrapf(err, "computing digest of source image's manifest")
}
if !matches {
manifestList, _, err := unparsedToplevel.Manifest(ctx)
if err != nil {
- return nil, "", "", errors.Wrapf(err, "Error reading manifest from source image")
+ return nil, "", "", errors.Wrapf(err, "reading manifest from source image")
}
matches, err = manifest.MatchesDigest(manifestList, digested.Digest())
if err != nil {
- return nil, "", "", errors.Wrapf(err, "Error computing digest of source image's manifest")
+ return nil, "", "", errors.Wrapf(err, "computing digest of source image's manifest")
}
if !matches {
return nil, "", "", errors.New("Digest of source image's manifest would not match destination reference")
@@ -650,7 +650,7 @@ func (c *copier) copyOneImage(ctx context.Context, policyContext *signature.Poli
c.Printf("Getting image source signatures\n")
s, err := src.Signatures(ctx)
if err != nil {
- return nil, "", "", errors.Wrap(err, "Error reading signatures")
+ return nil, "", "", errors.Wrap(err, "reading signatures")
}
sigs = s
}
@@ -785,7 +785,7 @@ func (c *copier) copyOneImage(ctx context.Context, policyContext *signature.Poli
c.Printf("Storing signatures\n")
if err := c.dest.PutSignatures(ctx, sigs, targetInstance); err != nil {
- return nil, "", "", errors.Wrap(err, "Error writing signatures")
+ return nil, "", "", errors.Wrap(err, "writing signatures")
}
return manifestBytes, retManifestType, retManifestDigest, nil
@@ -805,11 +805,11 @@ func checkImageDestinationForCurrentRuntime(ctx context.Context, sys *types.Syst
if dest.MustMatchRuntimeOS() {
c, err := src.OCIConfig(ctx)
if err != nil {
- return errors.Wrapf(err, "Error parsing image configuration")
+ return errors.Wrapf(err, "parsing image configuration")
}
wantedPlatforms, err := platform.WantedPlatforms(sys)
if err != nil {
- return errors.Wrapf(err, "error getting current platform information %#v", sys)
+ return errors.Wrapf(err, "getting current platform information %#v", sys)
}
options := newOrderedSet()
@@ -1034,13 +1034,13 @@ func (ic *imageCopier) copyUpdatedConfigAndManifest(ctx context.Context, instanc
}
pi, err := ic.src.UpdatedImage(ctx, *ic.manifestUpdates)
if err != nil {
- return nil, "", errors.Wrap(err, "Error creating an updated image manifest")
+ return nil, "", errors.Wrap(err, "creating an updated image manifest")
}
pendingImage = pi
}
man, _, err := pendingImage.Manifest(ctx)
if err != nil {
- return nil, "", errors.Wrap(err, "Error reading manifest")
+ return nil, "", errors.Wrap(err, "reading manifest")
}
if err := ic.c.copyConfig(ctx, pendingImage); err != nil {
@@ -1056,7 +1056,7 @@ func (ic *imageCopier) copyUpdatedConfigAndManifest(ctx context.Context, instanc
instanceDigest = &manifestDigest
}
if err := ic.c.dest.PutManifest(ctx, man, instanceDigest); err != nil {
- return nil, "", errors.Wrapf(err, "Error writing manifest %q", string(man))
+ return nil, "", errors.Wrapf(err, "writing manifest %q", string(man))
}
return man, manifestDigest, nil
}
@@ -1072,9 +1072,25 @@ func (c *copier) newProgressPool(ctx context.Context) (*mpb.Progress, func()) {
}
}
+// customPartialBlobCounter provides a decorator function for the partial blobs retrieval progress bar
+func customPartialBlobCounter(filler interface{}, wcc ...decor.WC) decor.Decorator {
+ producer := func(filler interface{}) decor.DecorFunc {
+ return func(s decor.Statistics) string {
+ if s.Total == 0 {
+ pairFmt := "%.1f / %.1f (skipped: %.1f)"
+ return fmt.Sprintf(pairFmt, decor.SizeB1024(s.Current), decor.SizeB1024(s.Total), decor.SizeB1024(s.Refill))
+ }
+ pairFmt := "%.1f / %.1f (skipped: %.1f = %.2f%%)"
+ percentage := 100.0 * float64(s.Refill) / float64(s.Total)
+ return fmt.Sprintf(pairFmt, decor.SizeB1024(s.Current), decor.SizeB1024(s.Total), decor.SizeB1024(s.Refill), percentage)
+ }
+ }
+ return decor.Any(producer(filler), wcc...)
+}
+
// createProgressBar creates a mpb.Bar in pool. Note that if the copier's reportWriter
// is ioutil.Discard, the progress bar's output will be discarded
-func (c *copier) createProgressBar(pool *mpb.Progress, info types.BlobInfo, kind string, onComplete string) *mpb.Bar {
+func (c *copier) createProgressBar(pool *mpb.Progress, partial bool, info types.BlobInfo, kind string, onComplete string) *mpb.Bar {
// shortDigestLen is the length of the digest used for blobs.
const shortDigestLen = 12
@@ -1091,18 +1107,30 @@ func (c *copier) createProgressBar(pool *mpb.Progress, info types.BlobInfo, kind
// Use a normal progress bar when we know the size (i.e., size > 0).
// Otherwise, use a spinner to indicate that something's happening.
var bar *mpb.Bar
+ sstyle := mpb.SpinnerStyle(".", "..", "...", "....", "").PositionLeft()
if info.Size > 0 {
- bar = pool.AddBar(info.Size,
- mpb.BarFillerClearOnComplete(),
- mpb.PrependDecorators(
- decor.OnComplete(decor.Name(prefix), onComplete),
- ),
- mpb.AppendDecorators(
- decor.OnComplete(decor.CountersKibiByte("%.1f / %.1f"), ""),
- ),
- )
+ if partial {
+ bar = pool.AddBar(info.Size,
+ mpb.BarFillerClearOnComplete(),
+ mpb.PrependDecorators(
+ decor.OnComplete(decor.Name(prefix), onComplete),
+ ),
+ mpb.AppendDecorators(
+ customPartialBlobCounter(sstyle.Build()),
+ ),
+ )
+ } else {
+ bar = pool.AddBar(info.Size,
+ mpb.BarFillerClearOnComplete(),
+ mpb.PrependDecorators(
+ decor.OnComplete(decor.Name(prefix), onComplete),
+ ),
+ mpb.AppendDecorators(
+ decor.OnComplete(decor.CountersKibiByte("%.1f / %.1f"), ""),
+ ),
+ )
+ }
} else {
- sstyle := mpb.SpinnerStyle(".", "..", "...", "....", "").PositionLeft()
bar = pool.Add(0,
sstyle.Build(),
mpb.BarFillerClearOnComplete(),
@@ -1123,13 +1151,13 @@ func (c *copier) copyConfig(ctx context.Context, src types.Image) error {
if srcInfo.Digest != "" {
configBlob, err := src.ConfigBlob(ctx)
if err != nil {
- return errors.Wrapf(err, "Error reading config blob %s", srcInfo.Digest)
+ return errors.Wrapf(err, "reading config blob %s", srcInfo.Digest)
}
destInfo, err := func() (types.BlobInfo, error) { // A scope for defer
progressPool, progressCleanup := c.newProgressPool(ctx)
defer progressCleanup()
- bar := c.createProgressBar(progressPool, srcInfo, "config", "done")
+ bar := c.createProgressBar(progressPool, false, srcInfo, "config", "done")
destInfo, err := c.copyBlobFromStream(ctx, bytes.NewReader(configBlob), srcInfo, nil, false, true, false, bar, -1, false)
if err != nil {
return types.BlobInfo{}, err
@@ -1213,11 +1241,11 @@ func (ic *imageCopier) copyLayer(ctx context.Context, srcInfo types.BlobInfo, to
}
if err != nil {
- return types.BlobInfo{}, "", errors.Wrapf(err, "Error trying to reuse blob %s at destination", srcInfo.Digest)
+ return types.BlobInfo{}, "", errors.Wrapf(err, "trying to reuse blob %s at destination", srcInfo.Digest)
}
if reused {
logrus.Debugf("Skipping blob %s (already present):", srcInfo.Digest)
- bar := ic.c.createProgressBar(pool, srcInfo, "blob", "skipped: already exists")
+ bar := ic.c.createProgressBar(pool, false, srcInfo, "blob", "skipped: already exists")
bar.SetTotal(0, true)
// Throw an event that the layer has been skipped
@@ -1244,14 +1272,57 @@ func (ic *imageCopier) copyLayer(ctx context.Context, srcInfo types.BlobInfo, to
}
}
+ // A partial pull is managed by the destination storage, that decides what portions
+ // of the source file are not known yet and must be fetched.
+ // Attempt a partial only when the source allows to retrieve a blob partially and
+ // the destination has support for it.
+ imgSource, okSource := ic.c.rawSource.(internalTypes.ImageSourceSeekable)
+ imgDest, okDest := ic.c.dest.(internalTypes.ImageDestinationPartial)
+ if okSource && okDest && !diffIDIsNeeded {
+ bar := ic.c.createProgressBar(pool, true, srcInfo, "blob", "done")
+
+ progress := make(chan int64)
+ terminate := make(chan interface{})
+
+ defer close(terminate)
+ defer close(progress)
+
+ proxy := imageSourceSeekableProxy{
+ source: imgSource,
+ progress: progress,
+ }
+ go func() {
+ for {
+ select {
+ case written := <-progress:
+ bar.IncrInt64(written)
+ case <-terminate:
+ return
+ }
+ }
+ }()
+
+ bar.SetTotal(srcInfo.Size, false)
+ info, err := imgDest.PutBlobPartial(ctx, proxy, srcInfo, ic.c.blobInfoCache)
+ if err == nil {
+ bar.SetRefill(srcInfo.Size - bar.Current())
+ bar.SetCurrent(srcInfo.Size)
+ bar.SetTotal(srcInfo.Size, true)
+ logrus.Debugf("Retrieved partial blob %v", srcInfo.Digest)
+ return info, cachedDiffID, nil
+ }
+ bar.Abort(true)
+ logrus.Debugf("Failed to retrieve partial blob: %v", err)
+ }
+
// Fallback: copy the layer, computing the diffID if we need to do so
srcStream, srcBlobSize, err := ic.c.rawSource.GetBlob(ctx, srcInfo, ic.c.blobInfoCache)
if err != nil {
- return types.BlobInfo{}, "", errors.Wrapf(err, "Error reading blob %s", srcInfo.Digest)
+ return types.BlobInfo{}, "", errors.Wrapf(err, "reading blob %s", srcInfo.Digest)
}
defer srcStream.Close()
- bar := ic.c.createProgressBar(pool, srcInfo, "blob", "done")
+ bar := ic.c.createProgressBar(pool, false, srcInfo, "blob", "done")
blobInfo, diffIDChan, err := ic.copyLayerFromStream(ctx, srcStream, types.BlobInfo{Digest: srcInfo.Digest, Size: srcBlobSize, MediaType: srcInfo.MediaType, Annotations: srcInfo.Annotations}, diffIDIsNeeded, toEncrypt, bar, layerIndex, emptyLayer)
if err != nil {
@@ -1265,7 +1336,7 @@ func (ic *imageCopier) copyLayer(ctx context.Context, srcInfo types.BlobInfo, to
return types.BlobInfo{}, "", ctx.Err()
case diffIDResult := <-diffIDChan:
if diffIDResult.err != nil {
- return types.BlobInfo{}, "", errors.Wrap(diffIDResult.err, "Error computing layer DiffID")
+ return types.BlobInfo{}, "", errors.Wrap(diffIDResult.err, "computing layer DiffID")
}
logrus.Debugf("Computed DiffID %s for layer %s", diffIDResult.digest, srcInfo.Digest)
// This is safe because we have just computed diffIDResult.Digest ourselves, and in the process
@@ -1285,10 +1356,10 @@ func (ic *imageCopier) copyLayer(ctx context.Context, srcInfo types.BlobInfo, to
// and returns a complete blobInfo of the copied blob and perhaps a <-chan diffIDResult if diffIDIsNeeded, to be read by the caller.
func (ic *imageCopier) copyLayerFromStream(ctx context.Context, srcStream io.Reader, srcInfo types.BlobInfo,
diffIDIsNeeded bool, toEncrypt bool, bar *mpb.Bar, layerIndex int, emptyLayer bool) (types.BlobInfo, <-chan diffIDResult, error) {
- var getDiffIDRecorder func(compression.DecompressorFunc) io.Writer // = nil
+ var getDiffIDRecorder func(compressiontypes.DecompressorFunc) io.Writer // = nil
var diffIDChan chan diffIDResult
- err := errors.New("Internal error: unexpected panic in copyLayer") // For pipeWriter.CloseWithError below
+ err := errors.New("Internal error: unexpected panic in copyLayer") // For pipeWriter.CloseWithbelow
if diffIDIsNeeded {
diffIDChan = make(chan diffIDResult, 1) // Buffered, so that sending a value after this or our caller has failed and exited does not block.
pipeReader, pipeWriter := io.Pipe()
@@ -1296,7 +1367,7 @@ func (ic *imageCopier) copyLayerFromStream(ctx context.Context, srcStream io.Rea
_ = pipeWriter.CloseWithError(err) // CloseWithError(nil) is equivalent to Close(), always returns nil
}()
- getDiffIDRecorder = func(decompressor compression.DecompressorFunc) io.Writer {
+ getDiffIDRecorder = func(decompressor compressiontypes.DecompressorFunc) io.Writer {
// If this fails, e.g. because we have exited and due to pipeWriter.CloseWithError() above further
// reading from the pipe has failed, we don’t really care.
// We only read from diffIDChan if the rest of the flow has succeeded, and when we do read from it,
@@ -1315,7 +1386,7 @@ func (ic *imageCopier) copyLayerFromStream(ctx context.Context, srcStream io.Rea
}
// diffIDComputationGoroutine reads all input from layerStream, uncompresses using decompressor if necessary, and sends its digest, and status, if any, to dest.
-func diffIDComputationGoroutine(dest chan<- diffIDResult, layerStream io.ReadCloser, decompressor compression.DecompressorFunc) {
+func diffIDComputationGoroutine(dest chan<- diffIDResult, layerStream io.ReadCloser, decompressor compressiontypes.DecompressorFunc) {
result := diffIDResult{
digest: "",
err: errors.New("Internal error: unexpected panic in diffIDComputationGoroutine"),
@@ -1327,7 +1398,7 @@ func diffIDComputationGoroutine(dest chan<- diffIDResult, layerStream io.ReadClo
}
// computeDiffID reads all input from layerStream, uncompresses it using decompressor if necessary, and returns its digest.
-func computeDiffID(stream io.Reader, decompressor compression.DecompressorFunc) (digest.Digest, error) {
+func computeDiffID(stream io.Reader, decompressor compressiontypes.DecompressorFunc) (digest.Digest, error) {
if decompressor != nil {
s, err := decompressor(stream)
if err != nil {
@@ -1350,7 +1421,7 @@ type errorAnnotationReader struct {
func (r errorAnnotationReader) Read(b []byte) (n int, err error) {
n, err = r.reader.Read(b)
if err != io.EOF {
- return n, errors.Wrapf(err, "error happened during read")
+ return n, errors.Wrapf(err, "happened during read")
}
return n, err
}
@@ -1360,7 +1431,7 @@ func (r errorAnnotationReader) Read(b []byte) (n int, err error) {
// perhaps (de/re/)compressing it if canModifyBlob,
// and returns a complete blobInfo of the copied blob.
func (c *copier) copyBlobFromStream(ctx context.Context, srcStream io.Reader, srcInfo types.BlobInfo,
- getOriginalLayerCopyWriter func(decompressor compression.DecompressorFunc) io.Writer,
+ getOriginalLayerCopyWriter func(decompressor compressiontypes.DecompressorFunc) io.Writer,
canModifyBlob bool, isConfig bool, toEncrypt bool, bar *mpb.Bar, layerIndex int, emptyLayer bool) (types.BlobInfo, error) {
if isConfig { // This is guaranteed by the caller, but set it here to be explicit.
canModifyBlob = false
@@ -1377,7 +1448,7 @@ func (c *copier) copyBlobFromStream(ctx context.Context, srcStream io.Reader, sr
// read stream to the end, and validation does not happen.
digestingReader, err := newDigestingReader(srcStream, srcInfo.Digest)
if err != nil {
- return types.BlobInfo{}, errors.Wrapf(err, "Error preparing to verify blob %s", srcInfo.Digest)
+ return types.BlobInfo{}, errors.Wrapf(err, "preparing to verify blob %s", srcInfo.Digest)
}
var destStream io.Reader = digestingReader
@@ -1391,7 +1462,7 @@ func (c *copier) copyBlobFromStream(ctx context.Context, srcStream io.Reader, sr
var d digest.Digest
destStream, d, err = ocicrypt.DecryptLayer(c.ociDecryptConfig, destStream, newDesc, false)
if err != nil {
- return types.BlobInfo{}, errors.Wrapf(err, "Error decrypting layer %s", srcInfo.Digest)
+ return types.BlobInfo{}, errors.Wrapf(err, "decrypting layer %s", srcInfo.Digest)
}
srcInfo.Digest = d
@@ -1408,7 +1479,7 @@ func (c *copier) copyBlobFromStream(ctx context.Context, srcStream io.Reader, sr
// This requires us to “peek ahead” into the stream to read the initial part, which requires us to chain through another io.Reader returned by DetectCompression.
compressionFormat, decompressor, destStream, err := compression.DetectCompressionFormat(destStream) // We could skip this in some cases, but let's keep the code path uniform
if err != nil {
- return types.BlobInfo{}, errors.Wrapf(err, "Error reading blob %s", srcInfo.Digest)
+ return types.BlobInfo{}, errors.Wrapf(err, "reading blob %s", srcInfo.Digest)
}
isCompressed := decompressor != nil
if expectedCompressionFormat, known := expectedCompressionFormats[srcInfo.MediaType]; known && isCompressed && compressionFormat.Name() != expectedCompressionFormat.Name() {
@@ -1425,6 +1496,7 @@ func (c *copier) copyBlobFromStream(ctx context.Context, srcStream io.Reader, sr
originalLayerReader = destStream
}
+ compressionMetadata := map[string]string{}
// === Deal with layer compression/decompression if necessary
// WARNING: If you are adding new reasons to change the blob, update also the OptimizeDestinationImageAlreadyExists
// short-circuit conditions
@@ -1453,7 +1525,7 @@ func (c *copier) copyBlobFromStream(ctx context.Context, srcStream io.Reader, sr
// If this fails while writing data, it will do pipeWriter.CloseWithError(); if it fails otherwise,
// e.g. because we have exited and due to pipeReader.Close() above further writing to the pipe has failed,
// we don’t care.
- go c.compressGoroutine(pipeWriter, destStream, *uploadCompressionFormat) // Closes pipeWriter
+ go c.compressGoroutine(pipeWriter, destStream, compressionMetadata, *uploadCompressionFormat) // Closes pipeWriter
destStream = pipeReader
inputInfo.Digest = ""
inputInfo.Size = -1
@@ -1473,7 +1545,7 @@ func (c *copier) copyBlobFromStream(ctx context.Context, srcStream io.Reader, sr
pipeReader, pipeWriter := io.Pipe()
defer pipeReader.Close()
- go c.compressGoroutine(pipeWriter, s, *uploadCompressionFormat) // Closes pipeWriter
+ go c.compressGoroutine(pipeWriter, s, compressionMetadata, *uploadCompressionFormat) // Closes pipeWriter
destStream = pipeReader
inputInfo.Digest = ""
@@ -1533,7 +1605,7 @@ func (c *copier) copyBlobFromStream(ctx context.Context, srcStream io.Reader, sr
s, fin, err := ocicrypt.EncryptLayer(c.ociEncryptConfig, destStream, desc)
if err != nil {
- return types.BlobInfo{}, errors.Wrapf(err, "Error encrypting blob %s", srcInfo.Digest)
+ return types.BlobInfo{}, errors.Wrapf(err, "encrypting blob %s", srcInfo.Digest)
}
destStream = s
@@ -1576,7 +1648,7 @@ func (c *copier) copyBlobFromStream(ctx context.Context, srcStream io.Reader, sr
uploadedInfo, err = c.dest.PutBlob(ctx, &errorAnnotationReader{destStream}, inputInfo, c.blobInfoCache, isConfig)
}
if err != nil {
- return types.BlobInfo{}, errors.Wrap(err, "Error writing blob")
+ return types.BlobInfo{}, errors.Wrap(err, "writing blob")
}
uploadedInfo.Annotations = srcInfo.Annotations
@@ -1608,7 +1680,7 @@ func (c *copier) copyBlobFromStream(ctx context.Context, srcStream io.Reader, sr
logrus.Debugf("Consuming rest of the original blob to satisfy getOriginalLayerCopyWriter")
_, err := io.Copy(ioutil.Discard, originalLayerReader)
if err != nil {
- return types.BlobInfo{}, errors.Wrapf(err, "Error reading input blob %s", srcInfo.Digest)
+ return types.BlobInfo{}, errors.Wrapf(err, "reading input blob %s", srcInfo.Digest)
}
}
@@ -1640,23 +1712,42 @@ func (c *copier) copyBlobFromStream(ctx context.Context, srcStream io.Reader, sr
c.blobInfoCache.RecordDigestCompressorName(srcInfo.Digest, srcCompressorName)
}
}
+
+ // Copy all the metadata generated by the compressor into the annotations.
+ if uploadedInfo.Annotations == nil {
+ uploadedInfo.Annotations = map[string]string{}
+ }
+ for k, v := range compressionMetadata {
+ uploadedInfo.Annotations[k] = v
+ }
+
return uploadedInfo, nil
}
-// compressGoroutine reads all input from src and writes its compressed equivalent to dest.
-func (c *copier) compressGoroutine(dest *io.PipeWriter, src io.Reader, compressionFormat compression.Algorithm) {
- err := errors.New("Internal error: unexpected panic in compressGoroutine")
- defer func() { // Note that this is not the same as {defer dest.CloseWithError(err)}; we need err to be evaluated lazily.
- _ = dest.CloseWithError(err) // CloseWithError(nil) is equivalent to Close(), always returns nil
- }()
-
- compressor, err := compression.CompressStream(dest, compressionFormat, c.compressionLevel)
+// doCompression reads all input from src and writes its compressed equivalent to dest.
+func doCompression(dest io.Writer, src io.Reader, metadata map[string]string, compressionFormat compressiontypes.Algorithm, compressionLevel *int) error {
+ compressor, err := compression.CompressStreamWithMetadata(dest, metadata, compressionFormat, compressionLevel)
if err != nil {
- return
+ return err
}
- defer compressor.Close()
buf := make([]byte, compressionBufferSize)
_, err = io.CopyBuffer(compressor, src, buf) // Sets err to nil, i.e. causes dest.Close()
+ if err != nil {
+ compressor.Close()
+ return err
+ }
+
+ return compressor.Close()
+}
+
+// compressGoroutine reads all input from src and writes its compressed equivalent to dest.
+func (c *copier) compressGoroutine(dest *io.PipeWriter, src io.Reader, metadata map[string]string, compressionFormat compressiontypes.Algorithm) {
+ err := errors.New("Internal error: unexpected panic in compressGoroutine")
+ defer func() { // Note that this is not the same as {defer dest.CloseWithError(err)}; we need err to be evaluated lazily.
+ _ = dest.CloseWithError(err) // CloseWithError(nil) is equivalent to Close(), always returns nil
+ }()
+
+ err = doCompression(dest, src, metadata, compressionFormat, c.compressionLevel)
}
diff --git a/vendor/github.com/containers/image/v5/copy/manifest.go b/vendor/github.com/containers/image/v5/copy/manifest.go
index 0c0164cbf..b97edbf08 100644
--- a/vendor/github.com/containers/image/v5/copy/manifest.go
+++ b/vendor/github.com/containers/image/v5/copy/manifest.go
@@ -45,7 +45,7 @@ func (os *orderedSet) append(s string) {
func (ic *imageCopier) determineManifestConversion(ctx context.Context, destSupportedManifestMIMETypes []string, forceManifestMIMEType string, requiresOciEncryption bool) (string, []string, error) {
_, srcType, err := ic.src.Manifest(ctx)
if err != nil { // This should have been cached?!
- return "", nil, errors.Wrap(err, "Error reading manifest")
+ return "", nil, errors.Wrap(err, "reading manifest")
}
normalizedSrcType := manifest.NormalizedMIMEType(srcType)
if srcType != normalizedSrcType {
@@ -137,30 +137,29 @@ func (c *copier) determineListConversion(currentListMIMEType string, destSupport
if forcedListMIMEType != "" {
destSupportedMIMETypes = []string{forcedListMIMEType}
}
- var selectedType string
- var otherSupportedTypes []string
- for i := range destSupportedMIMETypes {
- // The second priority is the first member of the list of acceptable types that is a list,
- // but keep going in case current type occurs later in the list.
- if selectedType == "" && manifest.MIMETypeIsMultiImage(destSupportedMIMETypes[i]) {
- selectedType = destSupportedMIMETypes[i]
- }
- // The first priority is the current type, if it's in the list, since that lets us avoid a
- // conversion that isn't strictly necessary.
- if destSupportedMIMETypes[i] == currentListMIMEType {
- selectedType = destSupportedMIMETypes[i]
+
+ prioritizedTypes := newOrderedSet()
+ // The first priority is the current type, if it's in the list, since that lets us avoid a
+ // conversion that isn't strictly necessary.
+ for _, t := range destSupportedMIMETypes {
+ if t == currentListMIMEType {
+ prioritizedTypes.append(currentListMIMEType)
+ break
}
}
// Pick out the other list types that we support.
- for i := range destSupportedMIMETypes {
- if selectedType != destSupportedMIMETypes[i] && manifest.MIMETypeIsMultiImage(destSupportedMIMETypes[i]) {
- otherSupportedTypes = append(otherSupportedTypes, destSupportedMIMETypes[i])
+ for _, t := range destSupportedMIMETypes {
+ if manifest.MIMETypeIsMultiImage(t) {
+ prioritizedTypes.append(t)
}
}
+
logrus.Debugf("Manifest list has MIME type %s, ordered candidate list [%s]", currentListMIMEType, strings.Join(destSupportedMIMETypes, ", "))
- if selectedType == "" {
+ if len(prioritizedTypes.list) == 0 {
return "", nil, errors.Errorf("destination does not support any supported manifest list types (%v)", manifest.SupportedListMIMETypes)
}
+ selectedType := prioritizedTypes.list[0]
+ otherSupportedTypes := prioritizedTypes.list[1:]
if selectedType != currentListMIMEType {
logrus.Debugf("... will convert to %s first, and then try %v", selectedType, otherSupportedTypes)
} else {
diff --git a/vendor/github.com/containers/image/v5/copy/progress_reader.go b/vendor/github.com/containers/image/v5/copy/progress_reader.go
index 0761065a2..42f490d32 100644
--- a/vendor/github.com/containers/image/v5/copy/progress_reader.go
+++ b/vendor/github.com/containers/image/v5/copy/progress_reader.go
@@ -1,9 +1,11 @@
package copy
import (
+ "context"
"io"
"time"
+ internalTypes "github.com/containers/image/v5/internal/types"
"github.com/containers/image/v5/types"
)
@@ -77,3 +79,26 @@ func (r *progressReader) Read(p []byte) (int, error) {
}
return n, err
}
+
+// imageSourceSeekableProxy wraps ImageSourceSeekable and keeps track of how many bytes
+// are received.
+type imageSourceSeekableProxy struct {
+ // source is the seekable input to read from.
+ source internalTypes.ImageSourceSeekable
+ // progress is the chan where the total number of bytes read so far are reported.
+ progress chan int64
+}
+
+// GetBlobAt reads from the ImageSourceSeekable and report how many bytes were received
+// to the progress chan.
+func (s imageSourceSeekableProxy) GetBlobAt(ctx context.Context, bInfo types.BlobInfo, chunks []internalTypes.ImageSourceChunk) (chan io.ReadCloser, chan error, error) {
+ rc, errs, err := s.source.GetBlobAt(ctx, bInfo, chunks)
+ if err == nil {
+ total := int64(0)
+ for _, c := range chunks {
+ total += int64(c.Length)
+ }
+ s.progress <- total
+ }
+ return rc, errs, err
+}
diff --git a/vendor/github.com/containers/image/v5/copy/sign.go b/vendor/github.com/containers/image/v5/copy/sign.go
index 8f46e9de6..61612a4d3 100644
--- a/vendor/github.com/containers/image/v5/copy/sign.go
+++ b/vendor/github.com/containers/image/v5/copy/sign.go
@@ -10,7 +10,7 @@ import (
func (c *copier) createSignature(manifest []byte, keyIdentity string) ([]byte, error) {
mech, err := signature.NewGPGSigningMechanism()
if err != nil {
- return nil, errors.Wrap(err, "Error initializing GPG")
+ return nil, errors.Wrap(err, "initializing GPG")
}
defer mech.Close()
if err := mech.SupportsSigning(); err != nil {
@@ -25,7 +25,7 @@ func (c *copier) createSignature(manifest []byte, keyIdentity string) ([]byte, e
c.Printf("Signing manifest\n")
newSig, err := signature.SignDockerManifest(manifest, dockerReference.String(), mech, keyIdentity)
if err != nil {
- return nil, errors.Wrap(err, "Error creating signature")
+ return nil, errors.Wrap(err, "creating signature")
}
return newSig, nil
}
diff --git a/vendor/github.com/containers/image/v5/directory/directory_dest.go b/vendor/github.com/containers/image/v5/directory/directory_dest.go
index 5cafd2674..e3280aa2b 100644
--- a/vendor/github.com/containers/image/v5/directory/directory_dest.go
+++ b/vendor/github.com/containers/image/v5/directory/directory_dest.go
@@ -21,20 +21,33 @@ const version = "Directory Transport Version: 1.1\n"
var ErrNotContainerImageDir = errors.New("not a containers image directory, don't want to overwrite important data")
type dirImageDestination struct {
- ref dirReference
- compress bool
+ ref dirReference
+ desiredLayerCompression types.LayerCompression
}
// newImageDestination returns an ImageDestination for writing to a directory.
-func newImageDestination(ref dirReference, compress bool) (types.ImageDestination, error) {
- d := &dirImageDestination{ref: ref, compress: compress}
+func newImageDestination(sys *types.SystemContext, ref dirReference) (types.ImageDestination, error) {
+ desiredLayerCompression := types.PreserveOriginal
+ if sys != nil {
+ if sys.DirForceCompress {
+ desiredLayerCompression = types.Compress
+
+ if sys.DirForceDecompress {
+ return nil, errors.Errorf("Cannot compress and decompress at the same time")
+ }
+ }
+ if sys.DirForceDecompress {
+ desiredLayerCompression = types.Decompress
+ }
+ }
+ d := &dirImageDestination{ref: ref, desiredLayerCompression: desiredLayerCompression}
// If directory exists check if it is empty
// if not empty, check whether the contents match that of a container image directory and overwrite the contents
// if the contents don't match throw an error
dirExists, err := pathExists(d.ref.resolvedPath)
if err != nil {
- return nil, errors.Wrapf(err, "error checking for path %q", d.ref.resolvedPath)
+ return nil, errors.Wrapf(err, "checking for path %q", d.ref.resolvedPath)
}
if dirExists {
isEmpty, err := isDirEmpty(d.ref.resolvedPath)
@@ -45,7 +58,7 @@ func newImageDestination(ref dirReference, compress bool) (types.ImageDestinatio
if !isEmpty {
versionExists, err := pathExists(d.ref.versionPath())
if err != nil {
- return nil, errors.Wrapf(err, "error checking if path exists %q", d.ref.versionPath())
+ return nil, errors.Wrapf(err, "checking if path exists %q", d.ref.versionPath())
}
if versionExists {
contents, err := ioutil.ReadFile(d.ref.versionPath())
@@ -61,7 +74,7 @@ func newImageDestination(ref dirReference, compress bool) (types.ImageDestinatio
}
// delete directory contents so that only one image is in the directory at a time
if err = removeDirContents(d.ref.resolvedPath); err != nil {
- return nil, errors.Wrapf(err, "error erasing contents in %q", d.ref.resolvedPath)
+ return nil, errors.Wrapf(err, "erasing contents in %q", d.ref.resolvedPath)
}
logrus.Debugf("overwriting existing container image directory %q", d.ref.resolvedPath)
}
@@ -74,7 +87,7 @@ func newImageDestination(ref dirReference, compress bool) (types.ImageDestinatio
// create version file
err = ioutil.WriteFile(d.ref.versionPath(), []byte(version), 0644)
if err != nil {
- return nil, errors.Wrapf(err, "error creating version file %q", d.ref.versionPath())
+ return nil, errors.Wrapf(err, "creating version file %q", d.ref.versionPath())
}
return d, nil
}
@@ -101,10 +114,7 @@ func (d *dirImageDestination) SupportsSignatures(ctx context.Context) error {
}
func (d *dirImageDestination) DesiredLayerCompression() types.LayerCompression {
- if d.compress {
- return types.Compress
- }
- return types.PreserveOriginal
+ return d.desiredLayerCompression
}
// AcceptsForeignLayerURLs returns false iff foreign layers in manifest should be actually
@@ -239,6 +249,9 @@ func (d *dirImageDestination) PutSignatures(ctx context.Context, signatures [][]
}
// Commit marks the process of storing the image as successful and asks for the image to be persisted.
+// unparsedToplevel contains data about the top-level manifest of the source (which may be a single-arch image or a manifest list
+// if PutManifest was only called for the single-arch image with instanceDigest == nil), primarily to allow lookups by the
+// original manifest list digest, if desired.
// WARNING: This does not have any transactional semantics:
// - Uploaded data MAY be visible to others before Commit() is called
// - Uploaded data MAY be removed or MAY remain around if Close() is called without Commit() (i.e. rollback is allowed but not guaranteed)
diff --git a/vendor/github.com/containers/image/v5/directory/directory_transport.go b/vendor/github.com/containers/image/v5/directory/directory_transport.go
index adfec6ef3..e542d888c 100644
--- a/vendor/github.com/containers/image/v5/directory/directory_transport.go
+++ b/vendor/github.com/containers/image/v5/directory/directory_transport.go
@@ -153,11 +153,7 @@ func (ref dirReference) NewImageSource(ctx context.Context, sys *types.SystemCon
// NewImageDestination returns a types.ImageDestination for this reference.
// The caller must call .Close() on the returned ImageDestination.
func (ref dirReference) NewImageDestination(ctx context.Context, sys *types.SystemContext) (types.ImageDestination, error) {
- compress := false
- if sys != nil {
- compress = sys.DirForceCompress
- }
- return newImageDestination(ref, compress)
+ return newImageDestination(sys, ref)
}
// DeleteImage deletes the named image from the registry, if supported.
diff --git a/vendor/github.com/containers/image/v5/docker/archive/dest.go b/vendor/github.com/containers/image/v5/docker/archive/dest.go
index e874e02e0..d4248db21 100644
--- a/vendor/github.com/containers/image/v5/docker/archive/dest.go
+++ b/vendor/github.com/containers/image/v5/docker/archive/dest.go
@@ -67,6 +67,9 @@ func (d *archiveImageDestination) Close() error {
}
// Commit marks the process of storing the image as successful and asks for the image to be persisted.
+// unparsedToplevel contains data about the top-level manifest of the source (which may be a single-arch image or a manifest list
+// if PutManifest was only called for the single-arch image with instanceDigest == nil), primarily to allow lookups by the
+// original manifest list digest, if desired.
// WARNING: This does not have any transactional semantics:
// - Uploaded data MAY be visible to others before Commit() is called
// - Uploaded data MAY be removed or MAY remain around if Close() is called without Commit() (i.e. rollback is allowed but not guaranteed)
diff --git a/vendor/github.com/containers/image/v5/docker/archive/reader.go b/vendor/github.com/containers/image/v5/docker/archive/reader.go
index c7bb311bc..4bb519a26 100644
--- a/vendor/github.com/containers/image/v5/docker/archive/reader.go
+++ b/vendor/github.com/containers/image/v5/docker/archive/reader.go
@@ -81,14 +81,14 @@ func (r *Reader) List() ([][]types.ImageReference, error) {
}
ref, err := newReference(r.path, nt, -1, r.archive, nil)
if err != nil {
- return nil, errors.Wrapf(err, "Error creating a reference for tag %#v in manifest item @%d", tag, imageIndex)
+ return nil, errors.Wrapf(err, "creating a reference for tag %#v in manifest item @%d", tag, imageIndex)
}
refs = append(refs, ref)
}
if len(refs) == 0 {
ref, err := newReference(r.path, nil, imageIndex, r.archive, nil)
if err != nil {
- return nil, errors.Wrapf(err, "Error creating a reference for manifest item @%d", imageIndex)
+ return nil, errors.Wrapf(err, "creating a reference for manifest item @%d", imageIndex)
}
refs = append(refs, ref)
}
diff --git a/vendor/github.com/containers/image/v5/docker/archive/writer.go b/vendor/github.com/containers/image/v5/docker/archive/writer.go
index afac2aaee..6a4b8c645 100644
--- a/vendor/github.com/containers/image/v5/docker/archive/writer.go
+++ b/vendor/github.com/containers/image/v5/docker/archive/writer.go
@@ -60,7 +60,7 @@ func openArchiveForWriting(path string) (*os.File, error) {
// only in a different way. Either way, it’s up to the user to not have two writers to the same path.)
fh, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE, 0644)
if err != nil {
- return nil, errors.Wrapf(err, "error opening file %q", path)
+ return nil, errors.Wrapf(err, "opening file %q", path)
}
succeeded := false
defer func() {
@@ -70,7 +70,7 @@ func openArchiveForWriting(path string) (*os.File, error) {
}()
fhStat, err := fh.Stat()
if err != nil {
- return nil, errors.Wrapf(err, "error statting file %q", path)
+ return nil, errors.Wrapf(err, "statting file %q", path)
}
if fhStat.Mode().IsRegular() && fhStat.Size() != 0 {
diff --git a/vendor/github.com/containers/image/v5/docker/daemon/daemon_dest.go b/vendor/github.com/containers/image/v5/docker/daemon/daemon_dest.go
index 88609b3dc..f68981472 100644
--- a/vendor/github.com/containers/image/v5/docker/daemon/daemon_dest.go
+++ b/vendor/github.com/containers/image/v5/docker/daemon/daemon_dest.go
@@ -42,7 +42,7 @@ func newImageDestination(ctx context.Context, sys *types.SystemContext, ref daem
c, err := newDockerClient(sys)
if err != nil {
- return nil, errors.Wrap(err, "Error initializing docker engine client")
+ return nil, errors.Wrap(err, "initializing docker engine client")
}
reader, writer := io.Pipe()
@@ -84,7 +84,7 @@ func imageLoadGoroutine(ctx context.Context, c *client.Client, reader *io.PipeRe
resp, err := c.ImageLoad(ctx, reader, true)
if err != nil {
- err = errors.Wrap(err, "Error saving image to docker engine")
+ err = errors.Wrap(err, "saving image to docker engine")
return
}
defer resp.Body.Close()
@@ -128,6 +128,9 @@ func (d *daemonImageDestination) Reference() types.ImageReference {
}
// Commit marks the process of storing the image as successful and asks for the image to be persisted.
+// unparsedToplevel contains data about the top-level manifest of the source (which may be a single-arch image or a manifest list
+// if PutManifest was only called for the single-arch image with instanceDigest == nil), primarily to allow lookups by the
+// original manifest list digest, if desired.
// WARNING: This does not have any transactional semantics:
// - Uploaded data MAY be visible to others before Commit() is called
// - Uploaded data MAY be removed or MAY remain around if Close() is called without Commit() (i.e. rollback is allowed but not guaranteed)
diff --git a/vendor/github.com/containers/image/v5/docker/daemon/daemon_src.go b/vendor/github.com/containers/image/v5/docker/daemon/daemon_src.go
index 74a678817..a6d8a6cf5 100644
--- a/vendor/github.com/containers/image/v5/docker/daemon/daemon_src.go
+++ b/vendor/github.com/containers/image/v5/docker/daemon/daemon_src.go
@@ -25,13 +25,13 @@ type daemonImageSource struct {
func newImageSource(ctx context.Context, sys *types.SystemContext, ref daemonReference) (types.ImageSource, error) {
c, err := newDockerClient(sys)
if err != nil {
- return nil, errors.Wrap(err, "Error initializing docker engine client")
+ return nil, errors.Wrap(err, "initializing docker engine client")
}
// Per NewReference(), ref.StringWithinTransport() is either an image ID (config digest), or a !reference.NameOnly() reference.
// Either way ImageSave should create a tarball with exactly one image.
inputStream, err := c.ImageSave(ctx, []string{ref.StringWithinTransport()})
if err != nil {
- return nil, errors.Wrap(err, "Error loading image from docker engine")
+ return nil, errors.Wrap(err, "loading image from docker engine")
}
defer inputStream.Close()
diff --git a/vendor/github.com/containers/image/v5/docker/docker_client.go b/vendor/github.com/containers/image/v5/docker/docker_client.go
index a9533ea39..3fe9a11d0 100644
--- a/vendor/github.com/containers/image/v5/docker/docker_client.go
+++ b/vendor/github.com/containers/image/v5/docker/docker_client.go
@@ -92,7 +92,7 @@ type bearerToken struct {
expirationTime time.Time
}
-// dockerClient is configuration for dealing with a single Docker registry.
+// dockerClient is configuration for dealing with a single container registry.
type dockerClient struct {
// The following members are set by newDockerClient and do not change afterwards.
sys *types.SystemContext
@@ -213,10 +213,9 @@ func dockerCertDir(sys *types.SystemContext, hostPort string) (string, error) {
// “write” specifies whether the client will be used for "write" access (in particular passed to lookaside.go:toplevelFromSection)
// signatureBase is always set in the return value
func newDockerClientFromRef(sys *types.SystemContext, ref dockerReference, write bool, actions string) (*dockerClient, error) {
- registry := reference.Domain(ref.ref)
- auth, err := config.GetCredentials(sys, registry)
+ auth, err := config.GetCredentialsForRef(sys, ref.ref)
if err != nil {
- return nil, errors.Wrapf(err, "error getting username and password")
+ return nil, errors.Wrapf(err, "getting username and password")
}
sigBase, err := SignatureStorageBaseURL(sys, ref, write)
@@ -224,6 +223,7 @@ func newDockerClientFromRef(sys *types.SystemContext, ref dockerReference, write
return nil, err
}
+ registry := reference.Domain(ref.ref)
client, err := newDockerClient(sys, registry, ref.ref.Name())
if err != nil {
return nil, err
@@ -269,7 +269,7 @@ func newDockerClient(sys *types.SystemContext, registry, reference string) (*doc
skipVerify := false
reg, err := sysregistriesv2.FindRegistry(sys, reference)
if err != nil {
- return nil, errors.Wrapf(err, "error loading registries")
+ return nil, errors.Wrapf(err, "loading registries")
}
if reg != nil {
if reg.Blocked {
@@ -297,14 +297,14 @@ func newDockerClient(sys *types.SystemContext, registry, reference string) (*doc
func CheckAuth(ctx context.Context, sys *types.SystemContext, username, password, registry string) error {
client, err := newDockerClient(sys, registry, registry)
if err != nil {
- return errors.Wrapf(err, "error creating new docker client")
+ return errors.Wrapf(err, "creating new docker client")
}
client.auth = types.DockerAuthConfig{
Username: username,
Password: password,
}
- resp, err := client.makeRequest(ctx, "GET", "/v2/", nil, nil, v2Auth, nil)
+ resp, err := client.makeRequest(ctx, http.MethodGet, "/v2/", nil, nil, v2Auth, nil)
if err != nil {
return err
}
@@ -343,9 +343,10 @@ func SearchRegistry(ctx context.Context, sys *types.SystemContext, registry, ima
v1Res := &V1Results{}
// Get credentials from authfile for the underlying hostname
+ // We can't use GetCredentialsForRef here because we want to search the whole registry.
auth, err := config.GetCredentials(sys, registry)
if err != nil {
- return nil, errors.Wrapf(err, "error getting username and password")
+ return nil, errors.Wrapf(err, "getting username and password")
}
// The /v2/_catalog endpoint has been disabled for docker.io therefore
@@ -359,7 +360,7 @@ func SearchRegistry(ctx context.Context, sys *types.SystemContext, registry, ima
client, err := newDockerClient(sys, hostname, registry)
if err != nil {
- return nil, errors.Wrapf(err, "error creating new docker client")
+ return nil, errors.Wrapf(err, "creating new docker client")
}
client.auth = auth
if sys != nil {
@@ -379,7 +380,7 @@ func SearchRegistry(ctx context.Context, sys *types.SystemContext, registry, ima
u.RawQuery = q.Encode()
logrus.Debugf("trying to talk to v1 search endpoint")
- resp, err := client.makeRequest(ctx, "GET", u.String(), nil, nil, noAuth, nil)
+ resp, err := client.makeRequest(ctx, http.MethodGet, u.String(), nil, nil, noAuth, nil)
if err != nil {
logrus.Debugf("error getting search results from v1 endpoint %q: %v", registry, err)
} else {
@@ -399,14 +400,15 @@ func SearchRegistry(ctx context.Context, sys *types.SystemContext, registry, ima
searchRes := []SearchResult{}
path := "/v2/_catalog"
for len(searchRes) < limit {
- resp, err := client.makeRequest(ctx, "GET", path, nil, nil, v2Auth, nil)
+ resp, err := client.makeRequest(ctx, http.MethodGet, path, nil, nil, v2Auth, nil)
if err != nil {
logrus.Debugf("error getting search results from v2 endpoint %q: %v", registry, err)
return nil, errors.Wrapf(err, "couldn't search registry %q", registry)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
- logrus.Errorf("error getting search results from v2 endpoint %q: %v", registry, httpResponseToError(resp, ""))
+ err := httpResponseToError(resp, "")
+ logrus.Errorf("error getting search results from v2 endpoint %q: %v", registry, err)
return nil, errors.Wrapf(err, "couldn't search registry %q", registry)
}
v2Res := &V2Results{}
@@ -422,7 +424,14 @@ func SearchRegistry(ctx context.Context, sys *types.SystemContext, registry, ima
res := SearchResult{
Name: repo,
}
- searchRes = append(searchRes, res)
+ // bugzilla.redhat.com/show_bug.cgi?id=1976283
+ // If we have a full match, make sure it's listed as the first result.
+ // (Note there might be a full match we never see if we reach the result limit first.)
+ if repo == image {
+ searchRes = append([]SearchResult{res}, searchRes...)
+ } else {
+ searchRes = append(searchRes, res)
+ }
}
}
@@ -525,11 +534,10 @@ func (c *dockerClient) makeRequestToResolvedURL(ctx context.Context, method, url
// makeRequest should generally be preferred.
// Note that no exponential back off is performed when receiving an http 429 status code.
func (c *dockerClient) makeRequestToResolvedURLOnce(ctx context.Context, method, url string, headers map[string][]string, stream io.Reader, streamLen int64, auth sendAuth, extraScope *authScope) (*http.Response, error) {
- req, err := http.NewRequest(method, url, stream)
+ req, err := http.NewRequestWithContext(ctx, method, url, stream)
if err != nil {
return nil, err
}
- req = req.WithContext(ctx)
if streamLen != -1 { // Do not blindly overwrite if streamLen == -1, http.NewRequest above can figure out the length of bytes.Reader and similar objects without us having to compute it.
req.ContentLength = streamLen
}
@@ -622,13 +630,11 @@ func (c *dockerClient) getBearerTokenOAuth2(ctx context.Context, challenge chall
return nil, errors.Errorf("missing realm in bearer auth challenge")
}
- authReq, err := http.NewRequest(http.MethodPost, realm, nil)
+ authReq, err := http.NewRequestWithContext(ctx, http.MethodPost, realm, nil)
if err != nil {
return nil, err
}
- authReq = authReq.WithContext(ctx)
-
// Make the form data required against the oauth2 authentication
// More details here: https://docs.docker.com/registry/spec/auth/oauth/
params := authReq.URL.Query()
@@ -672,12 +678,11 @@ func (c *dockerClient) getBearerToken(ctx context.Context, challenge challenge,
return nil, errors.Errorf("missing realm in bearer auth challenge")
}
- authReq, err := http.NewRequest(http.MethodGet, realm, nil)
+ authReq, err := http.NewRequestWithContext(ctx, http.MethodGet, realm, nil)
if err != nil {
return nil, err
}
- authReq = authReq.WithContext(ctx)
params := authReq.URL.Query()
if c.auth.Username != "" {
params.Add("account", c.auth.Username)
@@ -731,7 +736,7 @@ func (c *dockerClient) detectPropertiesHelper(ctx context.Context) error {
ping := func(scheme string) error {
url := fmt.Sprintf(resolvedPingV2URL, scheme, c.registry)
- resp, err := c.makeRequestToResolvedURL(ctx, "GET", url, nil, nil, -1, noAuth, nil)
+ resp, err := c.makeRequestToResolvedURL(ctx, http.MethodGet, url, nil, nil, -1, noAuth, nil)
if err != nil {
logrus.Debugf("Ping %s err %s (%#v)", url, err.Error(), err)
return err
@@ -751,14 +756,14 @@ func (c *dockerClient) detectPropertiesHelper(ctx context.Context) error {
err = ping("http")
}
if err != nil {
- err = errors.Wrapf(err, "error pinging docker registry %s", c.registry)
+ err = errors.Wrapf(err, "pinging container registry %s", c.registry)
if c.sys != nil && c.sys.DockerDisableV1Ping {
return err
}
// best effort to understand if we're talking to a V1 registry
pingV1 := func(scheme string) bool {
url := fmt.Sprintf(resolvedPingV1URL, scheme, c.registry)
- resp, err := c.makeRequestToResolvedURL(ctx, "GET", url, nil, nil, -1, noAuth, nil)
+ resp, err := c.makeRequestToResolvedURL(ctx, http.MethodGet, url, nil, nil, -1, noAuth, nil)
if err != nil {
logrus.Debugf("Ping %s err %s (%#v)", url, err.Error(), err)
return false
@@ -792,14 +797,14 @@ func (c *dockerClient) detectProperties(ctx context.Context) error {
// using the original data structures.
func (c *dockerClient) getExtensionsSignatures(ctx context.Context, ref dockerReference, manifestDigest digest.Digest) (*extensionSignatureList, error) {
path := fmt.Sprintf(extensionsSignaturePath, reference.Path(ref.ref), manifestDigest)
- res, err := c.makeRequest(ctx, "GET", path, nil, nil, v2Auth, nil)
+ res, err := c.makeRequest(ctx, http.MethodGet, path, nil, nil, v2Auth, nil)
if err != nil {
return nil, err
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
- return nil, errors.Wrapf(clientLib.HandleErrorResponse(res), "Error downloading signatures for %s in %s", manifestDigest, ref.ref.Name())
+ return nil, errors.Wrapf(clientLib.HandleErrorResponse(res), "downloading signatures for %s in %s", manifestDigest, ref.ref.Name())
}
body, err := iolimits.ReadAtMost(res.Body, iolimits.MaxSignatureListBodySize)
@@ -809,7 +814,7 @@ func (c *dockerClient) getExtensionsSignatures(ctx context.Context, ref dockerRe
var parsedBody extensionSignatureList
if err := json.Unmarshal(body, &parsedBody); err != nil {
- return nil, errors.Wrapf(err, "Error decoding signature list")
+ return nil, errors.Wrapf(err, "decoding signature list")
}
return &parsedBody, nil
}
diff --git a/vendor/github.com/containers/image/v5/docker/docker_image.go b/vendor/github.com/containers/image/v5/docker/docker_image.go
index f9fe4e8a3..c84bb37d2 100644
--- a/vendor/github.com/containers/image/v5/docker/docker_image.go
+++ b/vendor/github.com/containers/image/v5/docker/docker_image.go
@@ -68,12 +68,12 @@ func GetRepositoryTags(ctx context.Context, sys *types.SystemContext, ref types.
tags := make([]string, 0)
for {
- res, err := client.makeRequest(ctx, "GET", path, nil, nil, v2Auth, nil)
+ res, err := client.makeRequest(ctx, http.MethodGet, path, nil, nil, v2Auth, nil)
if err != nil {
return nil, err
}
defer res.Body.Close()
- if err := httpResponseToError(res, "Error fetching tags list"); err != nil {
+ if err := httpResponseToError(res, "fetching tags list"); err != nil {
return nil, err
}
@@ -134,14 +134,14 @@ func GetDigest(ctx context.Context, sys *types.SystemContext, ref types.ImageRef
"Accept": manifest.DefaultRequestedManifestMIMETypes,
}
- res, err := client.makeRequest(ctx, "HEAD", path, headers, nil, v2Auth, nil)
+ res, err := client.makeRequest(ctx, http.MethodHead, path, headers, nil, v2Auth, nil)
if err != nil {
return "", err
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
- return "", errors.Wrapf(registryHTTPResponseToError(res), "Error reading digest %s in %s", tagOrDigest, dr.ref.Name())
+ return "", errors.Wrapf(registryHTTPResponseToError(res), "reading digest %s in %s", tagOrDigest, dr.ref.Name())
}
dig, err := digest.Parse(res.Header.Get("Docker-Content-Digest"))
diff --git a/vendor/github.com/containers/image/v5/docker/docker_image_dest.go b/vendor/github.com/containers/image/v5/docker/docker_image_dest.go
index e11084dc8..360a7122e 100644
--- a/vendor/github.com/containers/image/v5/docker/docker_image_dest.go
+++ b/vendor/github.com/containers/image/v5/docker/docker_image_dest.go
@@ -147,18 +147,18 @@ func (d *dockerImageDestination) PutBlob(ctx context.Context, stream io.Reader,
// FIXME? Chunked upload, progress reporting, etc.
uploadPath := fmt.Sprintf(blobUploadPath, reference.Path(d.ref.ref))
logrus.Debugf("Uploading %s", uploadPath)
- res, err := d.c.makeRequest(ctx, "POST", uploadPath, nil, nil, v2Auth, nil)
+ res, err := d.c.makeRequest(ctx, http.MethodPost, uploadPath, nil, nil, v2Auth, nil)
if err != nil {
return types.BlobInfo{}, err
}
defer res.Body.Close()
if res.StatusCode != http.StatusAccepted {
logrus.Debugf("Error initiating layer upload, response %#v", *res)
- return types.BlobInfo{}, errors.Wrapf(registryHTTPResponseToError(res), "Error initiating layer upload to %s in %s", uploadPath, d.c.registry)
+ return types.BlobInfo{}, errors.Wrapf(registryHTTPResponseToError(res), "initiating layer upload to %s in %s", uploadPath, d.c.registry)
}
uploadLocation, err := res.Location()
if err != nil {
- return types.BlobInfo{}, errors.Wrap(err, "Error determining upload URL")
+ return types.BlobInfo{}, errors.Wrap(err, "determining upload URL")
}
digester := digest.Canonical.Digester()
@@ -168,18 +168,18 @@ func (d *dockerImageDestination) PutBlob(ctx context.Context, stream io.Reader,
// This error text should never be user-visible, we terminate only after makeRequestToResolvedURL
// returns, so there isn’t a way for the error text to be provided to any of our callers.
defer uploadReader.Terminate(errors.New("Reading data from an already terminated upload"))
- res, err = d.c.makeRequestToResolvedURL(ctx, "PATCH", uploadLocation.String(), map[string][]string{"Content-Type": {"application/octet-stream"}}, uploadReader, inputInfo.Size, v2Auth, nil)
+ res, err = d.c.makeRequestToResolvedURL(ctx, http.MethodPatch, uploadLocation.String(), map[string][]string{"Content-Type": {"application/octet-stream"}}, uploadReader, inputInfo.Size, v2Auth, nil)
if err != nil {
logrus.Debugf("Error uploading layer chunked %v", err)
return nil, err
}
defer res.Body.Close()
if !successStatus(res.StatusCode) {
- return nil, errors.Wrapf(registryHTTPResponseToError(res), "Error uploading layer chunked")
+ return nil, errors.Wrapf(registryHTTPResponseToError(res), "uploading layer chunked")
}
uploadLocation, err := res.Location()
if err != nil {
- return nil, errors.Wrap(err, "Error determining upload URL")
+ return nil, errors.Wrap(err, "determining upload URL")
}
return uploadLocation, nil
}()
@@ -194,14 +194,14 @@ func (d *dockerImageDestination) PutBlob(ctx context.Context, stream io.Reader,
// TODO: check inputInfo.Digest == computedDigest https://github.com/containers/image/pull/70#discussion_r77646717
locationQuery.Set("digest", computedDigest.String())
uploadLocation.RawQuery = locationQuery.Encode()
- res, err = d.c.makeRequestToResolvedURL(ctx, "PUT", uploadLocation.String(), map[string][]string{"Content-Type": {"application/octet-stream"}}, nil, -1, v2Auth, nil)
+ res, err = d.c.makeRequestToResolvedURL(ctx, http.MethodPut, uploadLocation.String(), map[string][]string{"Content-Type": {"application/octet-stream"}}, nil, -1, v2Auth, nil)
if err != nil {
return types.BlobInfo{}, err
}
defer res.Body.Close()
if res.StatusCode != http.StatusCreated {
logrus.Debugf("Error uploading layer, response %#v", *res)
- return types.BlobInfo{}, errors.Wrapf(registryHTTPResponseToError(res), "Error uploading layer to %s", uploadLocation)
+ return types.BlobInfo{}, errors.Wrapf(registryHTTPResponseToError(res), "uploading layer to %s", uploadLocation)
}
logrus.Debugf("Upload of layer %s complete", computedDigest)
@@ -215,7 +215,7 @@ func (d *dockerImageDestination) PutBlob(ctx context.Context, stream io.Reader,
func (d *dockerImageDestination) blobExists(ctx context.Context, repo reference.Named, digest digest.Digest, extraScope *authScope) (bool, int64, error) {
checkPath := fmt.Sprintf(blobsPath, reference.Path(repo), digest.String())
logrus.Debugf("Checking %s", checkPath)
- res, err := d.c.makeRequest(ctx, "HEAD", checkPath, nil, nil, v2Auth, extraScope)
+ res, err := d.c.makeRequest(ctx, http.MethodHead, checkPath, nil, nil, v2Auth, extraScope)
if err != nil {
return false, -1, err
}
@@ -226,7 +226,7 @@ func (d *dockerImageDestination) blobExists(ctx context.Context, repo reference.
return true, getBlobSize(res), nil
case http.StatusUnauthorized:
logrus.Debugf("... not authorized")
- return false, -1, errors.Wrapf(registryHTTPResponseToError(res), "Error checking whether a blob %s exists in %s", digest, repo.Name())
+ return false, -1, errors.Wrapf(registryHTTPResponseToError(res), "checking whether a blob %s exists in %s", digest, repo.Name())
case http.StatusNotFound:
logrus.Debugf("... not present")
return false, -1, nil
@@ -246,7 +246,7 @@ func (d *dockerImageDestination) mountBlob(ctx context.Context, srcRepo referenc
}
mountPath := u.String()
logrus.Debugf("Trying to mount %s", mountPath)
- res, err := d.c.makeRequest(ctx, "POST", mountPath, nil, nil, v2Auth, extraScope)
+ res, err := d.c.makeRequest(ctx, http.MethodPost, mountPath, nil, nil, v2Auth, extraScope)
if err != nil {
return err
}
@@ -261,10 +261,10 @@ func (d *dockerImageDestination) mountBlob(ctx context.Context, srcRepo referenc
// NOTE: This does not really work in docker/distribution servers, which incorrectly require the "delete" action in the token's scope, and is thus entirely untested.
uploadLocation, err := res.Location()
if err != nil {
- return errors.Wrap(err, "Error determining upload URL after a mount attempt")
+ return errors.Wrap(err, "determining upload URL after a mount attempt")
}
logrus.Debugf("... started an upload instead of mounting, trying to cancel at %s", uploadLocation.String())
- res2, err := d.c.makeRequestToResolvedURL(ctx, "DELETE", uploadLocation.String(), nil, nil, -1, v2Auth, extraScope)
+ res2, err := d.c.makeRequestToResolvedURL(ctx, http.MethodDelete, uploadLocation.String(), nil, nil, -1, v2Auth, extraScope)
if err != nil {
logrus.Debugf("Error trying to cancel an inadvertent upload: %s", err)
} else {
@@ -277,7 +277,7 @@ func (d *dockerImageDestination) mountBlob(ctx context.Context, srcRepo referenc
return fmt.Errorf("Mounting %s from %s to %s started an upload instead", srcDigest, srcRepo.Name(), d.ref.ref.Name())
default:
logrus.Debugf("Error mounting, response %#v", *res)
- return errors.Wrapf(registryHTTPResponseToError(res), "Error mounting %s from %s to %s", srcDigest, srcRepo.Name(), d.ref.ref.Name())
+ return errors.Wrapf(registryHTTPResponseToError(res), "mounting %s from %s to %s", srcDigest, srcRepo.Name(), d.ref.ref.Name())
}
}
@@ -392,7 +392,7 @@ func (d *dockerImageDestination) PutManifest(ctx context.Context, m []byte, inst
// Double-check that the manifest we've been given matches the digest we've been given.
matches, err := manifest.MatchesDigest(m, *instanceDigest)
if err != nil {
- return errors.Wrapf(err, "error digesting manifest in PutManifest")
+ return errors.Wrapf(err, "digesting manifest in PutManifest")
}
if !matches {
manifestDigest, merr := manifest.Digest(m)
@@ -424,13 +424,13 @@ func (d *dockerImageDestination) PutManifest(ctx context.Context, m []byte, inst
if mimeType != "" {
headers["Content-Type"] = []string{mimeType}
}
- res, err := d.c.makeRequest(ctx, "PUT", path, headers, bytes.NewReader(m), v2Auth, nil)
+ res, err := d.c.makeRequest(ctx, http.MethodPut, path, headers, bytes.NewReader(m), v2Auth, nil)
if err != nil {
return err
}
defer res.Body.Close()
if !successStatus(res.StatusCode) {
- err = errors.Wrapf(registryHTTPResponseToError(res), "Error uploading manifest %s to %s", refTail, d.ref.ref.Name())
+ err = errors.Wrapf(registryHTTPResponseToError(res), "uploading manifest %s to %s", refTail, d.ref.ref.Name())
if isManifestInvalidError(errors.Cause(err)) {
err = types.ManifestTypeRejectedError{Err: err}
}
@@ -621,7 +621,7 @@ sigExists:
randBytes := make([]byte, 16)
n, err := rand.Read(randBytes)
if err != nil || n != 16 {
- return errors.Wrapf(err, "Error generating random signature len %d", n)
+ return errors.Wrapf(err, "generating random signature len %d", n)
}
signatureName = fmt.Sprintf("%s@%032x", manifestDigest.String(), randBytes)
if _, ok := existingSigNames[signatureName]; !ok {
@@ -640,7 +640,7 @@ sigExists:
}
path := fmt.Sprintf(extensionsSignaturePath, reference.Path(d.ref.ref), manifestDigest.String())
- res, err := d.c.makeRequest(ctx, "PUT", path, nil, bytes.NewReader(body), v2Auth, nil)
+ res, err := d.c.makeRequest(ctx, http.MethodPut, path, nil, bytes.NewReader(body), v2Auth, nil)
if err != nil {
return err
}
@@ -651,7 +651,7 @@ sigExists:
logrus.Debugf("Error body %s", string(body))
}
logrus.Debugf("Error uploading signature, status %d, %#v", res.StatusCode, res)
- return errors.Wrapf(registryHTTPResponseToError(res), "Error uploading signature to %s in %s", path, d.c.registry)
+ return errors.Wrapf(registryHTTPResponseToError(res), "uploading signature to %s in %s", path, d.c.registry)
}
}
@@ -659,6 +659,9 @@ sigExists:
}
// Commit marks the process of storing the image as successful and asks for the image to be persisted.
+// unparsedToplevel contains data about the top-level manifest of the source (which may be a single-arch image or a manifest list
+// if PutManifest was only called for the single-arch image with instanceDigest == nil), primarily to allow lookups by the
+// original manifest list digest, if desired.
// WARNING: This does not have any transactional semantics:
// - Uploaded data MAY be visible to others before Commit() is called
// - Uploaded data MAY be removed or MAY remain around if Close() is called without Commit() (i.e. rollback is allowed but not guaranteed)
diff --git a/vendor/github.com/containers/image/v5/docker/docker_image_src.go b/vendor/github.com/containers/image/v5/docker/docker_image_src.go
index 6916b7dad..5dc8e7b1f 100644
--- a/vendor/github.com/containers/image/v5/docker/docker_image_src.go
+++ b/vendor/github.com/containers/image/v5/docker/docker_image_src.go
@@ -6,14 +6,17 @@ import (
"io"
"io/ioutil"
"mime"
+ "mime/multipart"
"net/http"
"net/url"
"os"
"strconv"
"strings"
+ "sync"
"github.com/containers/image/v5/docker/reference"
"github.com/containers/image/v5/internal/iolimits"
+ internalTypes "github.com/containers/image/v5/internal/types"
"github.com/containers/image/v5/manifest"
"github.com/containers/image/v5/pkg/sysregistriesv2"
"github.com/containers/image/v5/types"
@@ -36,7 +39,7 @@ type dockerImageSource struct {
func newImageSource(ctx context.Context, sys *types.SystemContext, ref dockerReference) (*dockerImageSource, error) {
registry, err := sysregistriesv2.FindRegistry(sys, ref.ref.Name())
if err != nil {
- return nil, errors.Wrapf(err, "error loading registries configuration")
+ return nil, errors.Wrapf(err, "loading registries configuration")
}
if registry == nil {
// No configuration was found for the provided reference, so use the
@@ -69,7 +72,6 @@ func newImageSource(ctx context.Context, sys *types.SystemContext, ref dockerRef
} else {
logrus.Debugf("Trying to access %q", pullSource.Reference)
}
- logrus.Debugf("Trying to access %q", pullSource.Reference)
s, err := newImageSourceAttempt(ctx, sys, ref, pullSource)
if err == nil {
return s, nil
@@ -190,14 +192,14 @@ func (s *dockerImageSource) fetchManifest(ctx context.Context, tagOrDigest strin
headers := map[string][]string{
"Accept": manifest.DefaultRequestedManifestMIMETypes,
}
- res, err := s.c.makeRequest(ctx, "GET", path, headers, nil, v2Auth, nil)
+ res, err := s.c.makeRequest(ctx, http.MethodGet, path, headers, nil, v2Auth, nil)
if err != nil {
return nil, "", err
}
logrus.Debugf("Content-Type from manifest GET is %q", res.Header.Get("Content-Type"))
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
- return nil, "", errors.Wrapf(registryHTTPResponseToError(res), "Error reading manifest %s in %s", tagOrDigest, s.physicalRef.ref.Name())
+ return nil, "", errors.Wrapf(registryHTTPResponseToError(res), "reading manifest %s in %s", tagOrDigest, s.physicalRef.ref.Name())
}
manblob, err := iolimits.ReadAtMost(res.Body, iolimits.MaxManifestBodySize)
@@ -246,7 +248,7 @@ func (s *dockerImageSource) getExternalBlob(ctx context.Context, urls []string)
// NOTE: we must not authenticate on additional URLs as those
// can be abused to leak credentials or tokens. Please
// refer to CVE-2020-15157 for more information.
- resp, err = s.c.makeRequestToResolvedURL(ctx, "GET", url, nil, nil, -1, noAuth, nil)
+ resp, err = s.c.makeRequestToResolvedURL(ctx, http.MethodGet, url, nil, nil, -1, noAuth, nil)
if err == nil {
if resp.StatusCode != http.StatusOK {
err = errors.Errorf("error fetching external blob from %q: %d (%s)", url, resp.StatusCode, http.StatusText(resp.StatusCode))
@@ -276,6 +278,82 @@ func (s *dockerImageSource) HasThreadSafeGetBlob() bool {
return true
}
+// GetBlobAt returns a stream for the specified blob.
+func (s *dockerImageSource) GetBlobAt(ctx context.Context, info types.BlobInfo, chunks []internalTypes.ImageSourceChunk) (chan io.ReadCloser, chan error, error) {
+ headers := make(map[string][]string)
+
+ var rangeVals []string
+ for _, c := range chunks {
+ rangeVals = append(rangeVals, fmt.Sprintf("%d-%d", c.Offset, c.Offset+c.Length-1))
+ }
+
+ headers["Range"] = []string{fmt.Sprintf("bytes=%s", strings.Join(rangeVals, ","))}
+
+ if len(info.URLs) != 0 {
+ return nil, nil, fmt.Errorf("external URLs not supported with GetBlobAt")
+ }
+
+ path := fmt.Sprintf(blobsPath, reference.Path(s.physicalRef.ref), info.Digest.String())
+ logrus.Debugf("Downloading %s", path)
+ res, err := s.c.makeRequest(ctx, http.MethodGet, path, headers, nil, v2Auth, nil)
+ if err != nil {
+ return nil, nil, err
+ }
+ if err := httpResponseToError(res, "Error fetching partial blob"); err != nil {
+ if res.Body != nil {
+ res.Body.Close()
+ }
+ return nil, nil, err
+ }
+ if res.StatusCode != http.StatusPartialContent {
+ res.Body.Close()
+ return nil, nil, errors.Errorf("invalid status code returned when fetching blob %d (%s)", res.StatusCode, http.StatusText(res.StatusCode))
+ }
+
+ mediaType, params, err := mime.ParseMediaType(res.Header.Get("Content-Type"))
+ if err != nil {
+ return nil, nil, err
+ }
+
+ streams := make(chan io.ReadCloser)
+ errs := make(chan error)
+
+ go func() {
+ defer close(streams)
+ defer close(errs)
+ if !strings.HasPrefix(mediaType, "multipart/") {
+ streams <- res.Body
+ return
+ }
+ boundary, found := params["boundary"]
+ if !found {
+ errs <- errors.Errorf("could not find boundary")
+ return
+ }
+ buffered := makeBufferedNetworkReader(res.Body, 64, 16384)
+ defer buffered.Close()
+ mr := multipart.NewReader(buffered, boundary)
+ for {
+ p, err := mr.NextPart()
+ if err != nil {
+ if err != io.EOF {
+ errs <- err
+ }
+ return
+ }
+ s := signalCloseReader{
+ Closed: make(chan interface{}),
+ Stream: p,
+ }
+ streams <- s
+ // NextPart() cannot be called while the current part
+ // is being read, so wait until it is closed
+ <-s.Closed
+ }
+ }()
+ return streams, errs, nil
+}
+
// 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.
@@ -286,7 +364,7 @@ func (s *dockerImageSource) GetBlob(ctx context.Context, info types.BlobInfo, ca
path := fmt.Sprintf(blobsPath, reference.Path(s.physicalRef.ref), info.Digest.String())
logrus.Debugf("Downloading %s", path)
- res, err := s.c.makeRequest(ctx, "GET", path, nil, nil, v2Auth, nil)
+ res, err := s.c.makeRequest(ctx, http.MethodGet, path, nil, nil, v2Auth, nil)
if err != nil {
return nil, 0, err
}
@@ -376,11 +454,10 @@ func (s *dockerImageSource) getOneSignature(ctx context.Context, url *url.URL) (
case "http", "https":
logrus.Debugf("GET %s", url)
- req, err := http.NewRequest("GET", url.String(), nil)
+ req, err := http.NewRequestWithContext(ctx, http.MethodGet, url.String(), nil)
if err != nil {
return nil, false, err
}
- req = req.WithContext(ctx)
res, err := s.c.client.Do(req)
if err != nil {
return nil, false, err
@@ -445,7 +522,7 @@ func deleteImage(ctx context.Context, sys *types.SystemContext, ref dockerRefere
return err
}
getPath := fmt.Sprintf(manifestPath, reference.Path(ref.ref), refTail)
- get, err := c.makeRequest(ctx, "GET", getPath, headers, nil, v2Auth, nil)
+ get, err := c.makeRequest(ctx, http.MethodGet, getPath, headers, nil, v2Auth, nil)
if err != nil {
return err
}
@@ -467,7 +544,7 @@ func deleteImage(ctx context.Context, sys *types.SystemContext, ref dockerRefere
// When retrieving the digest from a registry >= 2.3 use the following header:
// "Accept": "application/vnd.docker.distribution.manifest.v2+json"
- delete, err := c.makeRequest(ctx, "DELETE", deletePath, headers, nil, v2Auth, nil)
+ delete, err := c.makeRequest(ctx, http.MethodDelete, deletePath, headers, nil, v2Auth, nil)
if err != nil {
return err
}
@@ -499,3 +576,119 @@ func deleteImage(ctx context.Context, sys *types.SystemContext, ref dockerRefere
return nil
}
+
+type bufferedNetworkReaderBuffer struct {
+ data []byte
+ len int
+ consumed int
+ err error
+}
+
+type bufferedNetworkReader struct {
+ stream io.Reader
+ emptyBuffer chan *bufferedNetworkReaderBuffer
+ readyBuffer chan *bufferedNetworkReaderBuffer
+ terminate chan bool
+ current *bufferedNetworkReaderBuffer
+ mutex sync.Mutex
+ gotEOF bool
+}
+
+// handleBufferedNetworkReader runs in a goroutine
+func handleBufferedNetworkReader(br *bufferedNetworkReader) {
+ defer close(br.readyBuffer)
+ for {
+ select {
+ case b := <-br.emptyBuffer:
+ b.len, b.err = br.stream.Read(b.data)
+ br.readyBuffer <- b
+ if b.err != nil {
+ return
+ }
+ case <-br.terminate:
+ return
+ }
+ }
+}
+
+func (n *bufferedNetworkReader) Close() {
+ close(n.terminate)
+ close(n.emptyBuffer)
+}
+
+func (n *bufferedNetworkReader) read(p []byte) (int, error) {
+ if n.current != nil {
+ copied := copy(p, n.current.data[n.current.consumed:n.current.len])
+ n.current.consumed += copied
+ if n.current.consumed == n.current.len {
+ n.emptyBuffer <- n.current
+ n.current = nil
+ }
+ if copied > 0 {
+ return copied, nil
+ }
+ }
+ if n.gotEOF {
+ return 0, io.EOF
+ }
+
+ var b *bufferedNetworkReaderBuffer
+
+ select {
+ case b = <-n.readyBuffer:
+ if b.err != nil {
+ if b.err != io.EOF {
+ return b.len, b.err
+ }
+ n.gotEOF = true
+ }
+ b.consumed = 0
+ n.current = b
+ return n.read(p)
+ case <-n.terminate:
+ return 0, io.EOF
+ }
+}
+
+func (n *bufferedNetworkReader) Read(p []byte) (int, error) {
+ n.mutex.Lock()
+ defer n.mutex.Unlock()
+
+ return n.read(p)
+}
+
+func makeBufferedNetworkReader(stream io.Reader, nBuffers, bufferSize uint) *bufferedNetworkReader {
+ br := bufferedNetworkReader{
+ stream: stream,
+ emptyBuffer: make(chan *bufferedNetworkReaderBuffer, nBuffers),
+ readyBuffer: make(chan *bufferedNetworkReaderBuffer, nBuffers),
+ terminate: make(chan bool),
+ }
+
+ go func() {
+ handleBufferedNetworkReader(&br)
+ }()
+
+ for i := uint(0); i < nBuffers; i++ {
+ b := bufferedNetworkReaderBuffer{
+ data: make([]byte, bufferSize),
+ }
+ br.emptyBuffer <- &b
+ }
+
+ return &br
+}
+
+type signalCloseReader struct {
+ Closed chan interface{}
+ Stream io.ReadCloser
+}
+
+func (s signalCloseReader) Read(p []byte) (int, error) {
+ return s.Stream.Read(p)
+}
+
+func (s signalCloseReader) Close() error {
+ defer close(s.Closed)
+ return s.Stream.Close()
+}
diff --git a/vendor/github.com/containers/image/v5/docker/docker_transport.go b/vendor/github.com/containers/image/v5/docker/docker_transport.go
index 8b8e57968..541e053f3 100644
--- a/vendor/github.com/containers/image/v5/docker/docker_transport.go
+++ b/vendor/github.com/containers/image/v5/docker/docker_transport.go
@@ -16,7 +16,7 @@ func init() {
transports.Register(Transport)
}
-// Transport is an ImageTransport for Docker registry-hosted images.
+// Transport is an ImageTransport for container registry-hosted images.
var Transport = dockerTransport{}
type dockerTransport struct{}
diff --git a/vendor/github.com/containers/image/v5/docker/errors.go b/vendor/github.com/containers/image/v5/docker/errors.go
index 5b5008af7..6f2c5fde5 100644
--- a/vendor/github.com/containers/image/v5/docker/errors.go
+++ b/vendor/github.com/containers/image/v5/docker/errors.go
@@ -5,6 +5,7 @@ import (
"fmt"
"net/http"
+ internalTypes "github.com/containers/image/v5/internal/types"
"github.com/docker/distribution/registry/client"
perrors "github.com/pkg/errors"
)
@@ -12,7 +13,7 @@ import (
var (
// ErrV1NotSupported is returned when we're trying to talk to a
// docker V1 registry.
- ErrV1NotSupported = errors.New("can't talk to a V1 docker registry")
+ ErrV1NotSupported = errors.New("can't talk to a V1 container registry")
// ErrTooManyRequests is returned when the status code returned is 429
ErrTooManyRequests = errors.New("too many requests to registry")
)
@@ -32,11 +33,15 @@ func httpResponseToError(res *http.Response, context string) error {
switch res.StatusCode {
case http.StatusOK:
return nil
+ case http.StatusPartialContent:
+ return nil
case http.StatusTooManyRequests:
return ErrTooManyRequests
case http.StatusUnauthorized:
err := client.HandleErrorResponse(res)
return ErrUnauthorizedForCredentials{Err: err}
+ case http.StatusBadRequest:
+ return internalTypes.BadPartialRequestError{Status: res.Status}
default:
if context != "" {
context = context + ": "
diff --git a/vendor/github.com/containers/image/v5/docker/internal/tarfile/dest.go b/vendor/github.com/containers/image/v5/docker/internal/tarfile/dest.go
index 9559dfb56..a558657b6 100644
--- a/vendor/github.com/containers/image/v5/docker/internal/tarfile/dest.go
+++ b/vendor/github.com/containers/image/v5/docker/internal/tarfile/dest.go
@@ -140,11 +140,11 @@ func (d *Destination) PutBlob(ctx context.Context, stream io.Reader, inputInfo t
if isConfig {
buf, err := iolimits.ReadAtMost(stream, iolimits.MaxConfigBodySize)
if err != nil {
- return types.BlobInfo{}, errors.Wrap(err, "Error reading Config file stream")
+ return types.BlobInfo{}, errors.Wrap(err, "reading Config file stream")
}
d.config = buf
if err := d.archive.sendFileLocked(d.archive.configPath(inputInfo.Digest), inputInfo.Size, bytes.NewReader(buf)); err != nil {
- return types.BlobInfo{}, errors.Wrap(err, "Error writing Config file")
+ return types.BlobInfo{}, errors.Wrap(err, "writing Config file")
}
} else {
if err := d.archive.sendFileLocked(d.archive.physicalLayerPath(inputInfo.Digest), inputInfo.Size, stream); err != nil {
@@ -187,7 +187,7 @@ func (d *Destination) PutManifest(ctx context.Context, m []byte, instanceDigest
// so the caller trying a different manifest kind would be pointless.
var man manifest.Schema2
if err := json.Unmarshal(m, &man); err != nil {
- return errors.Wrap(err, "Error parsing manifest")
+ return errors.Wrap(err, "parsing manifest")
}
if man.SchemaVersion != 2 || man.MediaType != manifest.DockerV2Schema2MediaType {
return errors.Errorf("Unsupported manifest type, need a Docker schema 2 manifest")
diff --git a/vendor/github.com/containers/image/v5/docker/internal/tarfile/reader.go b/vendor/github.com/containers/image/v5/docker/internal/tarfile/reader.go
index 83de0c520..6164ceb66 100644
--- a/vendor/github.com/containers/image/v5/docker/internal/tarfile/reader.go
+++ b/vendor/github.com/containers/image/v5/docker/internal/tarfile/reader.go
@@ -30,7 +30,7 @@ type Reader struct {
func NewReaderFromFile(sys *types.SystemContext, path string) (*Reader, error) {
file, err := os.Open(path)
if err != nil {
- return nil, errors.Wrapf(err, "error opening file %q", path)
+ return nil, errors.Wrapf(err, "opening file %q", path)
}
defer file.Close()
@@ -38,7 +38,7 @@ func NewReaderFromFile(sys *types.SystemContext, path string) (*Reader, error) {
// as a source. Otherwise we pass the stream to NewReaderFromStream.
stream, isCompressed, err := compression.AutoDecompress(file)
if err != nil {
- return nil, errors.Wrapf(err, "Error detecting compression for file %q", path)
+ return nil, errors.Wrapf(err, "detecting compression for file %q", path)
}
defer stream.Close()
if !isCompressed {
@@ -55,7 +55,7 @@ func NewReaderFromStream(sys *types.SystemContext, inputStream io.Reader) (*Read
// Save inputStream to a temporary file
tarCopyFile, err := ioutil.TempFile(tmpdir.TemporaryDirectoryForBigFiles(sys), "docker-tar")
if err != nil {
- return nil, errors.Wrap(err, "error creating temporary file")
+ return nil, errors.Wrap(err, "creating temporary file")
}
defer tarCopyFile.Close()
@@ -71,7 +71,7 @@ func NewReaderFromStream(sys *types.SystemContext, inputStream io.Reader) (*Read
// giving users really confusing "invalid tar header" errors).
uncompressedStream, _, err := compression.AutoDecompress(inputStream)
if err != nil {
- return nil, errors.Wrap(err, "Error auto-decompressing input")
+ return nil, errors.Wrap(err, "auto-decompressing input")
}
defer uncompressedStream.Close()
@@ -80,7 +80,7 @@ func NewReaderFromStream(sys *types.SystemContext, inputStream io.Reader) (*Read
// TODO: This can take quite some time, and should ideally be cancellable
// using a context.Context.
if _, err := io.Copy(tarCopyFile, uncompressedStream); err != nil {
- return nil, errors.Wrapf(err, "error copying contents to temporary file %q", tarCopyFile.Name())
+ return nil, errors.Wrapf(err, "copying contents to temporary file %q", tarCopyFile.Name())
}
succeeded = true
@@ -113,7 +113,7 @@ func newReader(path string, removeOnClose bool) (*Reader, error) {
return nil, err
}
if err := json.Unmarshal(bytes, &r.Manifest); err != nil {
- return nil, errors.Wrap(err, "Error decoding tar manifest.json")
+ return nil, errors.Wrap(err, "decoding tar manifest.json")
}
succeeded = true
@@ -258,7 +258,7 @@ func findTarComponent(inputFile io.Reader, componentPath string) (*tar.Reader, *
func (r *Reader) readTarComponent(path string, limit int) ([]byte, error) {
file, err := r.openTarComponent(path)
if err != nil {
- return nil, errors.Wrapf(err, "Error loading tar component %s", path)
+ return nil, errors.Wrapf(err, "loading tar component %s", path)
}
defer file.Close()
bytes, err := iolimits.ReadAtMost(file, limit)
diff --git a/vendor/github.com/containers/image/v5/docker/internal/tarfile/src.go b/vendor/github.com/containers/image/v5/docker/internal/tarfile/src.go
index bd65ef844..b8d84d245 100644
--- a/vendor/github.com/containers/image/v5/docker/internal/tarfile/src.go
+++ b/vendor/github.com/containers/image/v5/docker/internal/tarfile/src.go
@@ -80,7 +80,7 @@ func (s *Source) ensureCachedDataIsPresentPrivate() error {
}
var parsedConfig manifest.Schema2Image // There's a lot of info there, but we only really care about layer DiffIDs.
if err := json.Unmarshal(configBytes, &parsedConfig); err != nil {
- return errors.Wrapf(err, "Error decoding tar config %s", tarManifest.Config)
+ return errors.Wrapf(err, "decoding tar config %s", tarManifest.Config)
}
if parsedConfig.RootFS == nil {
return errors.Errorf("Invalid image config (rootFS is not set): %s", tarManifest.Config)
@@ -164,7 +164,7 @@ func (s *Source) prepareLayerData(tarManifest *ManifestItem, parsedConfig *manif
// the slower method of checking if it's compressed.
uncompressedStream, isCompressed, err := compression.AutoDecompress(t)
if err != nil {
- return nil, errors.Wrapf(err, "Error auto-decompressing %s to determine its size", layerPath)
+ return nil, errors.Wrapf(err, "auto-decompressing %s to determine its size", layerPath)
}
defer uncompressedStream.Close()
@@ -172,7 +172,7 @@ func (s *Source) prepareLayerData(tarManifest *ManifestItem, parsedConfig *manif
if isCompressed {
uncompressedSize, err = io.Copy(ioutil.Discard, uncompressedStream)
if err != nil {
- return nil, errors.Wrapf(err, "Error reading %s to find its size", layerPath)
+ return nil, errors.Wrapf(err, "reading %s to find its size", layerPath)
}
}
li.size = uncompressedSize
@@ -292,7 +292,7 @@ func (s *Source) GetBlob(ctx context.Context, info types.BlobInfo, cache types.B
uncompressedStream, _, err := compression.AutoDecompress(underlyingStream)
if err != nil {
- return nil, 0, errors.Wrapf(err, "Error auto-decompressing blob %s", info.Digest)
+ return nil, 0, errors.Wrapf(err, "auto-decompressing blob %s", info.Digest)
}
newStream := uncompressedReadCloser{
diff --git a/vendor/github.com/containers/image/v5/docker/internal/tarfile/writer.go b/vendor/github.com/containers/image/v5/docker/internal/tarfile/writer.go
index e0683b3cd..255f0d354 100644
--- a/vendor/github.com/containers/image/v5/docker/internal/tarfile/writer.go
+++ b/vendor/github.com/containers/image/v5/docker/internal/tarfile/writer.go
@@ -94,16 +94,16 @@ func (w *Writer) ensureSingleLegacyLayerLocked(layerID string, layerDigest diges
// See also the comment in physicalLayerPath.
physicalLayerPath := w.physicalLayerPath(layerDigest)
if err := w.sendSymlinkLocked(filepath.Join(layerID, legacyLayerFileName), filepath.Join("..", physicalLayerPath)); err != nil {
- return errors.Wrap(err, "Error creating layer symbolic link")
+ return errors.Wrap(err, "creating layer symbolic link")
}
b := []byte("1.0")
if err := w.sendBytesLocked(filepath.Join(layerID, legacyVersionFileName), b); err != nil {
- return errors.Wrap(err, "Error writing VERSION file")
+ return errors.Wrap(err, "writing VERSION file")
}
if err := w.sendBytesLocked(filepath.Join(layerID, legacyConfigFileName), configBytes); err != nil {
- return errors.Wrap(err, "Error writing config json file")
+ return errors.Wrap(err, "writing config json file")
}
w.legacyLayers[layerID] = struct{}{}
@@ -128,7 +128,7 @@ func (w *Writer) writeLegacyMetadataLocked(layerDescriptors []manifest.Schema2De
var config map[string]*json.RawMessage
err := json.Unmarshal(configBytes, &config)
if err != nil {
- return errors.Wrap(err, "Error unmarshaling config")
+ return errors.Wrap(err, "unmarshaling config")
}
for _, attr := range [7]string{"architecture", "config", "container", "container_config", "created", "docker_version", "os"} {
layerConfig[attr] = config[attr]
@@ -152,7 +152,7 @@ func (w *Writer) writeLegacyMetadataLocked(layerDescriptors []manifest.Schema2De
layerConfig["layer_id"] = chainID
b, err := json.Marshal(layerConfig) // Note that layerConfig["id"] is not set yet at this point.
if err != nil {
- return errors.Wrap(err, "Error marshaling layer config")
+ return errors.Wrap(err, "marshaling layer config")
}
delete(layerConfig, "layer_id")
layerID := digest.Canonical.FromBytes(b).Hex()
@@ -160,7 +160,7 @@ func (w *Writer) writeLegacyMetadataLocked(layerDescriptors []manifest.Schema2De
configBytes, err := json.Marshal(layerConfig)
if err != nil {
- return errors.Wrap(err, "Error marshaling layer config")
+ return errors.Wrap(err, "marshaling layer config")
}
if err := w.ensureSingleLegacyLayerLocked(layerID, l.Digest, configBytes); err != nil {
@@ -280,10 +280,10 @@ func (w *Writer) Close() error {
b, err = json.Marshal(w.repositories)
if err != nil {
- return errors.Wrap(err, "Error marshaling repositories")
+ return errors.Wrap(err, "marshaling repositories")
}
if err := w.sendBytesLocked(legacyRepositoriesFileName, b); err != nil {
- return errors.Wrap(err, "Error writing config json file")
+ return errors.Wrap(err, "writing config json file")
}
if err := w.tar.Close(); err != nil {
diff --git a/vendor/github.com/containers/image/v5/docker/lookaside.go b/vendor/github.com/containers/image/v5/docker/lookaside.go
index 0d5d8d82a..515e59327 100644
--- a/vendor/github.com/containers/image/v5/docker/lookaside.go
+++ b/vendor/github.com/containers/image/v5/docker/lookaside.go
@@ -154,7 +154,7 @@ func loadAndMergeConfig(dirPath string) (*registryConfiguration, error) {
var config registryConfiguration
err = yaml.Unmarshal(configBytes, &config)
if err != nil {
- return nil, errors.Wrapf(err, "Error parsing %s", configPath)
+ return nil, errors.Wrapf(err, "parsing %s", configPath)
}
if config.DefaultDocker != nil {
diff --git a/vendor/github.com/containers/image/v5/image/docker_list.go b/vendor/github.com/containers/image/v5/image/docker_list.go
index 651c301aa..4fe84413c 100644
--- a/vendor/github.com/containers/image/v5/image/docker_list.go
+++ b/vendor/github.com/containers/image/v5/image/docker_list.go
@@ -11,20 +11,20 @@ import (
func manifestSchema2FromManifestList(ctx context.Context, sys *types.SystemContext, src types.ImageSource, manblob []byte) (genericManifest, error) {
list, err := manifest.Schema2ListFromManifest(manblob)
if err != nil {
- return nil, errors.Wrapf(err, "Error parsing schema2 manifest list")
+ return nil, errors.Wrapf(err, "parsing schema2 manifest list")
}
targetManifestDigest, err := list.ChooseInstance(sys)
if err != nil {
- return nil, errors.Wrapf(err, "Error choosing image instance")
+ return nil, errors.Wrapf(err, "choosing image instance")
}
manblob, mt, err := src.GetManifest(ctx, &targetManifestDigest)
if err != nil {
- return nil, errors.Wrapf(err, "Error loading manifest for target platform")
+ return nil, errors.Wrapf(err, "loading manifest for target platform")
}
matches, err := manifest.MatchesDigest(manblob, targetManifestDigest)
if err != nil {
- return nil, errors.Wrap(err, "Error computing manifest digest")
+ return nil, errors.Wrap(err, "computing manifest digest")
}
if !matches {
return nil, errors.Errorf("Image manifest does not match selected manifest digest %s", targetManifestDigest)
diff --git a/vendor/github.com/containers/image/v5/image/docker_schema2.go b/vendor/github.com/containers/image/v5/image/docker_schema2.go
index 61ca83364..b250a6b1d 100644
--- a/vendor/github.com/containers/image/v5/image/docker_schema2.go
+++ b/vendor/github.com/containers/image/v5/image/docker_schema2.go
@@ -289,7 +289,7 @@ func (m *manifestSchema2) convertToManifestSchema1(ctx context.Context, options
// and anyway this blob is so small that it’s easier to just copy it than to worry about figuring out another location where to get it.
info, err := dest.PutBlob(ctx, bytes.NewReader(GzippedEmptyLayer), emptyLayerBlobInfo, none.NoCache, false)
if err != nil {
- return nil, errors.Wrap(err, "Error uploading empty layer")
+ return nil, errors.Wrap(err, "uploading empty layer")
}
if info.Digest != emptyLayerBlobInfo.Digest {
return nil, errors.Errorf("Internal error: Uploaded empty layer has digest %#v instead of %s", info.Digest, emptyLayerBlobInfo.Digest)
diff --git a/vendor/github.com/containers/image/v5/image/oci_index.go b/vendor/github.com/containers/image/v5/image/oci_index.go
index 022e03aca..4e6ca879a 100644
--- a/vendor/github.com/containers/image/v5/image/oci_index.go
+++ b/vendor/github.com/containers/image/v5/image/oci_index.go
@@ -11,20 +11,20 @@ import (
func manifestOCI1FromImageIndex(ctx context.Context, sys *types.SystemContext, src types.ImageSource, manblob []byte) (genericManifest, error) {
index, err := manifest.OCI1IndexFromManifest(manblob)
if err != nil {
- return nil, errors.Wrapf(err, "Error parsing OCI1 index")
+ return nil, errors.Wrapf(err, "parsing OCI1 index")
}
targetManifestDigest, err := index.ChooseInstance(sys)
if err != nil {
- return nil, errors.Wrapf(err, "Error choosing image instance")
+ return nil, errors.Wrapf(err, "choosing image instance")
}
manblob, mt, err := src.GetManifest(ctx, &targetManifestDigest)
if err != nil {
- return nil, errors.Wrapf(err, "Error loading manifest for target platform")
+ return nil, errors.Wrapf(err, "loading manifest for target platform")
}
matches, err := manifest.MatchesDigest(manblob, targetManifestDigest)
if err != nil {
- return nil, errors.Wrap(err, "Error computing manifest digest")
+ return nil, errors.Wrap(err, "computing manifest digest")
}
if !matches {
return nil, errors.Errorf("Image manifest does not match selected manifest digest %s", targetManifestDigest)
diff --git a/vendor/github.com/containers/image/v5/image/unparsed.go b/vendor/github.com/containers/image/v5/image/unparsed.go
index 4e3028d85..c64852f72 100644
--- a/vendor/github.com/containers/image/v5/image/unparsed.go
+++ b/vendor/github.com/containers/image/v5/image/unparsed.go
@@ -53,7 +53,7 @@ func (i *UnparsedImage) Manifest(ctx context.Context) ([]byte, string, error) {
if digest, haveDigest := i.expectedManifestDigest(); haveDigest {
matches, err := manifest.MatchesDigest(m, digest)
if err != nil {
- return nil, "", errors.Wrap(err, "Error computing manifest digest")
+ return nil, "", errors.Wrap(err, "computing manifest digest")
}
if !matches {
return nil, "", errors.Errorf("Manifest does not match provided manifest digest %s", digest)
diff --git a/vendor/github.com/containers/image/v5/internal/blobinfocache/blobinfocache.go b/vendor/github.com/containers/image/v5/internal/blobinfocache/blobinfocache.go
index 1dceaa669..b86e8b1ac 100644
--- a/vendor/github.com/containers/image/v5/internal/blobinfocache/blobinfocache.go
+++ b/vendor/github.com/containers/image/v5/internal/blobinfocache/blobinfocache.go
@@ -2,6 +2,7 @@ package blobinfocache
import (
"github.com/containers/image/v5/pkg/compression"
+ compressiontypes "github.com/containers/image/v5/pkg/compression/types"
"github.com/containers/image/v5/types"
digest "github.com/opencontainers/go-digest"
)
@@ -47,7 +48,7 @@ func CandidateLocationsFromV2(v2candidates []BICReplacementCandidate2) []types.B
// compression algorithm, or Uncompressed, or UnknownCompression. This is typically used by
// TryReusingBlob() implementations to set values in the BlobInfo structure that they return
// upon success.
-func OperationAndAlgorithmForCompressor(compressorName string) (types.LayerCompression, *compression.Algorithm, error) {
+func OperationAndAlgorithmForCompressor(compressorName string) (types.LayerCompression, *compressiontypes.Algorithm, error) {
switch compressorName {
case Uncompressed:
return types.Decompress, nil, nil
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 4a863ba34..e0355a477 100644
--- a/vendor/github.com/containers/image/v5/internal/types/types.go
+++ b/vendor/github.com/containers/image/v5/internal/types/types.go
@@ -58,3 +58,33 @@ type TryReusingBlobOptions struct {
// The reference of the image that contains the target blob.
SrcRef reference.Named
}
+
+// ImageSourceChunk is a portion of a blob.
+// This API is experimental and can be changed without bumping the major version number.
+type ImageSourceChunk struct {
+ Offset uint64
+ Length uint64
+}
+
+// ImageSourceSeekable is an image source that permits to fetch chunks of the entire blob.
+// This API is experimental and can be changed without bumping the major version number.
+type ImageSourceSeekable interface {
+ // GetBlobAt returns a stream for the specified blob.
+ GetBlobAt(context.Context, publicTypes.BlobInfo, []ImageSourceChunk) (chan io.ReadCloser, chan error, error)
+}
+
+// ImageDestinationPartial is a service to store a blob by requesting the missing chunks to a ImageSourceSeekable.
+// This API is experimental and can be changed without bumping the major version number.
+type ImageDestinationPartial interface {
+ // PutBlobPartial writes contents of stream and returns data representing the result.
+ PutBlobPartial(ctx context.Context, stream ImageSourceSeekable, srcInfo publicTypes.BlobInfo, cache publicTypes.BlobInfoCache) (publicTypes.BlobInfo, error)
+}
+
+// BadPartialRequestError is returned by ImageSourceSeekable.GetBlobAt on an invalid request.
+type BadPartialRequestError struct {
+ Status string
+}
+
+func (e BadPartialRequestError) Error() string {
+ return e.Status
+}
diff --git a/vendor/github.com/containers/image/v5/manifest/common.go b/vendor/github.com/containers/image/v5/manifest/common.go
index 3ece948a0..4692211c0 100644
--- a/vendor/github.com/containers/image/v5/manifest/common.go
+++ b/vendor/github.com/containers/image/v5/manifest/common.go
@@ -3,7 +3,7 @@ package manifest
import (
"fmt"
- "github.com/containers/image/v5/pkg/compression"
+ compressiontypes "github.com/containers/image/v5/pkg/compression/types"
"github.com/containers/image/v5/types"
"github.com/sirupsen/logrus"
)
@@ -44,7 +44,7 @@ func layerInfosToStrings(infos []LayerInfo) []string {
// compressionMIMETypeSet describes a set of MIME type “variants” that represent differently-compressed
// versions of “the same kind of content”.
-// The map key is the return value of compression.Algorithm.Name(), or mtsUncompressed;
+// The map key is the return value of compressiontypes.Algorithm.Name(), or mtsUncompressed;
// the map value is a MIME type, or mtsUnsupportedMIMEType to mean "recognized but unsupported".
type compressionMIMETypeSet map[string]string
@@ -59,7 +59,7 @@ const mtsUnsupportedMIMEType = "" // A value in compressionMIMETypeSet that mean
// If the compression algorithm is unrecognized, or mimeType is not known to have variants that
// differ from it only in what type of compression has been applied, the returned error will not be
// a ManifestLayerCompressionIncompatibilityError.
-func compressionVariantMIMEType(variantTable []compressionMIMETypeSet, mimeType string, algorithm *compression.Algorithm) (string, error) {
+func compressionVariantMIMEType(variantTable []compressionMIMETypeSet, mimeType string, algorithm *compressiontypes.Algorithm) (string, error) {
if mimeType == mtsUnsupportedMIMEType { // Prevent matching against the {algo:mtsUnsupportedMIMEType} entries
return "", fmt.Errorf("cannot update unknown MIME type")
}
@@ -68,7 +68,7 @@ func compressionVariantMIMEType(variantTable []compressionMIMETypeSet, mimeType
if mt == mimeType { // Found the variant
name := mtsUncompressed
if algorithm != nil {
- name = algorithm.Name()
+ name = algorithm.InternalUnstableUndocumentedMIMEQuestionMark()
}
if res, ok := variants[name]; ok {
if res != mtsUnsupportedMIMEType {
diff --git a/vendor/github.com/containers/image/v5/manifest/docker_schema1.go b/vendor/github.com/containers/image/v5/manifest/docker_schema1.go
index 58527d713..8679cad11 100644
--- a/vendor/github.com/containers/image/v5/manifest/docker_schema1.go
+++ b/vendor/github.com/containers/image/v5/manifest/docker_schema1.go
@@ -109,7 +109,7 @@ func (m *Schema1) initialize() error {
m.ExtractedV1Compatibility = make([]Schema1V1Compatibility, len(m.History))
for i, h := range m.History {
if err := json.Unmarshal([]byte(h.V1Compatibility), &m.ExtractedV1Compatibility[i]); err != nil {
- return errors.Wrapf(err, "Error parsing v2s1 history entry %d", i)
+ return errors.Wrapf(err, "parsing v2s1 history entry %d", i)
}
}
return nil
@@ -242,14 +242,14 @@ func (m *Schema1) ToSchema2Config(diffIDs []digest.Digest) ([]byte, error) {
config := []byte(m.History[0].V1Compatibility)
err := json.Unmarshal(config, &s1)
if err != nil {
- return nil, errors.Wrapf(err, "error decoding configuration")
+ return nil, errors.Wrapf(err, "decoding configuration")
}
// Images created with versions prior to 1.8.3 require us to re-encode the encoded object,
// adding some fields that aren't "omitempty".
if s1.DockerVersion != "" && versions.LessThan(s1.DockerVersion, "1.8.3") {
config, err = json.Marshal(&s1)
if err != nil {
- return nil, errors.Wrapf(err, "error re-encoding compat image config %#v", s1)
+ return nil, errors.Wrapf(err, "re-encoding compat image config %#v", s1)
}
}
// Build the history.
@@ -276,7 +276,7 @@ func (m *Schema1) ToSchema2Config(diffIDs []digest.Digest) ([]byte, error) {
raw := make(map[string]*json.RawMessage)
err = json.Unmarshal(config, &raw)
if err != nil {
- return nil, errors.Wrapf(err, "error re-decoding compat image config %#v", s1)
+ return nil, errors.Wrapf(err, "re-decoding compat image config %#v", s1)
}
// Drop some fields.
delete(raw, "id")
diff --git a/vendor/github.com/containers/image/v5/manifest/docker_schema2.go b/vendor/github.com/containers/image/v5/manifest/docker_schema2.go
index 6cb605263..2711ca5eb 100644
--- a/vendor/github.com/containers/image/v5/manifest/docker_schema2.go
+++ b/vendor/github.com/containers/image/v5/manifest/docker_schema2.go
@@ -5,7 +5,7 @@ import (
"fmt"
"time"
- "github.com/containers/image/v5/pkg/compression"
+ compressiontypes "github.com/containers/image/v5/pkg/compression/types"
"github.com/containers/image/v5/pkg/strslice"
"github.com/containers/image/v5/types"
"github.com/opencontainers/go-digest"
@@ -214,14 +214,14 @@ func (m *Schema2) LayerInfos() []LayerInfo {
var schema2CompressionMIMETypeSets = []compressionMIMETypeSet{
{
- mtsUncompressed: DockerV2Schema2ForeignLayerMediaType,
- compression.Gzip.Name(): DockerV2Schema2ForeignLayerMediaTypeGzip,
- compression.Zstd.Name(): mtsUnsupportedMIMEType,
+ mtsUncompressed: DockerV2Schema2ForeignLayerMediaType,
+ compressiontypes.GzipAlgorithmName: DockerV2Schema2ForeignLayerMediaTypeGzip,
+ compressiontypes.ZstdAlgorithmName: mtsUnsupportedMIMEType,
},
{
- mtsUncompressed: DockerV2SchemaLayerMediaTypeUncompressed,
- compression.Gzip.Name(): DockerV2Schema2LayerMediaType,
- compression.Zstd.Name(): mtsUnsupportedMIMEType,
+ mtsUncompressed: DockerV2SchemaLayerMediaTypeUncompressed,
+ compressiontypes.GzipAlgorithmName: DockerV2Schema2LayerMediaType,
+ compressiontypes.ZstdAlgorithmName: mtsUnsupportedMIMEType,
},
}
@@ -242,7 +242,7 @@ func (m *Schema2) UpdateLayerInfos(layerInfos []types.BlobInfo) error {
}
mimeType, err := updatedMIMEType(schema2CompressionMIMETypeSets, mimeType, info)
if err != nil {
- return errors.Wrapf(err, "Error preparing updated manifest, layer %q", info.Digest)
+ return errors.Wrapf(err, "preparing updated manifest, layer %q", info.Digest)
}
m.LayersDescriptors[i].MediaType = mimeType
m.LayersDescriptors[i].Digest = info.Digest
diff --git a/vendor/github.com/containers/image/v5/manifest/docker_schema2_list.go b/vendor/github.com/containers/image/v5/manifest/docker_schema2_list.go
index bfedff69c..9ebb8d6b9 100644
--- a/vendor/github.com/containers/image/v5/manifest/docker_schema2_list.go
+++ b/vendor/github.com/containers/image/v5/manifest/docker_schema2_list.go
@@ -91,7 +91,7 @@ func (list *Schema2List) UpdateInstances(updates []ListUpdate) error {
func (list *Schema2List) ChooseInstance(ctx *types.SystemContext) (digest.Digest, error) {
wantedPlatforms, err := platform.WantedPlatforms(ctx)
if err != nil {
- return "", errors.Wrapf(err, "error getting platform information %#v", ctx)
+ return "", errors.Wrapf(err, "getting platform information %#v", ctx)
}
for _, wantedPlatform := range wantedPlatforms {
for _, d := range list.Manifests {
@@ -115,7 +115,7 @@ func (list *Schema2List) ChooseInstance(ctx *types.SystemContext) (digest.Digest
func (list *Schema2List) Serialize() ([]byte, error) {
buf, err := json.Marshal(list)
if err != nil {
- return nil, errors.Wrapf(err, "error marshaling Schema2List %#v", list)
+ return nil, errors.Wrapf(err, "marshaling Schema2List %#v", list)
}
return buf, nil
}
@@ -190,7 +190,7 @@ func Schema2ListFromManifest(manifest []byte) (*Schema2List, error) {
Manifests: []Schema2ManifestDescriptor{},
}
if err := json.Unmarshal(manifest, &list); err != nil {
- return nil, errors.Wrapf(err, "error unmarshaling Schema2List %q", string(manifest))
+ return nil, errors.Wrapf(err, "unmarshaling Schema2List %q", string(manifest))
}
return &list, nil
}
diff --git a/vendor/github.com/containers/image/v5/manifest/manifest.go b/vendor/github.com/containers/image/v5/manifest/manifest.go
index 32680e09d..4b644f253 100644
--- a/vendor/github.com/containers/image/v5/manifest/manifest.go
+++ b/vendor/github.com/containers/image/v5/manifest/manifest.go
@@ -195,7 +195,7 @@ func MatchesDigest(manifest []byte, expectedDigest digest.Digest) (bool, error)
}
// AddDummyV2S1Signature adds an JWS signature with a temporary key (i.e. useless) to a v2s1 manifest.
-// This is useful to make the manifest acceptable to a Docker Registry (even though nothing needs or wants the JWS signature).
+// This is useful to make the manifest acceptable to a docker/distribution registry (even though nothing needs or wants the JWS signature).
func AddDummyV2S1Signature(manifest []byte) ([]byte, error) {
key, err := libtrust.GenerateECP256PrivateKey()
if err != nil {
diff --git a/vendor/github.com/containers/image/v5/manifest/oci.go b/vendor/github.com/containers/image/v5/manifest/oci.go
index c6299d8e6..29a479c94 100644
--- a/vendor/github.com/containers/image/v5/manifest/oci.go
+++ b/vendor/github.com/containers/image/v5/manifest/oci.go
@@ -5,7 +5,7 @@ import (
"fmt"
"strings"
- "github.com/containers/image/v5/pkg/compression"
+ compressiontypes "github.com/containers/image/v5/pkg/compression/types"
"github.com/containers/image/v5/types"
ociencspec "github.com/containers/ocicrypt/spec"
"github.com/opencontainers/go-digest"
@@ -96,14 +96,14 @@ func (m *OCI1) LayerInfos() []LayerInfo {
var oci1CompressionMIMETypeSets = []compressionMIMETypeSet{
{
- mtsUncompressed: imgspecv1.MediaTypeImageLayerNonDistributable,
- compression.Gzip.Name(): imgspecv1.MediaTypeImageLayerNonDistributableGzip,
- compression.Zstd.Name(): imgspecv1.MediaTypeImageLayerNonDistributableZstd,
+ mtsUncompressed: imgspecv1.MediaTypeImageLayerNonDistributable,
+ compressiontypes.GzipAlgorithmName: imgspecv1.MediaTypeImageLayerNonDistributableGzip,
+ compressiontypes.ZstdAlgorithmName: imgspecv1.MediaTypeImageLayerNonDistributableZstd,
},
{
- mtsUncompressed: imgspecv1.MediaTypeImageLayer,
- compression.Gzip.Name(): imgspecv1.MediaTypeImageLayerGzip,
- compression.Zstd.Name(): imgspecv1.MediaTypeImageLayerZstd,
+ mtsUncompressed: imgspecv1.MediaTypeImageLayer,
+ compressiontypes.GzipAlgorithmName: imgspecv1.MediaTypeImageLayerGzip,
+ compressiontypes.ZstdAlgorithmName: imgspecv1.MediaTypeImageLayerZstd,
},
}
@@ -127,7 +127,7 @@ func (m *OCI1) UpdateLayerInfos(layerInfos []types.BlobInfo) error {
}
mimeType, err := updatedMIMEType(oci1CompressionMIMETypeSets, mimeType, info)
if err != nil {
- return errors.Wrapf(err, "Error preparing updated manifest, layer %q", info.Digest)
+ return errors.Wrapf(err, "preparing updated manifest, layer %q", info.Digest)
}
if info.CryptoOperation == types.Encrypt {
encMediaType, err := getEncryptedMediaType(mimeType)
diff --git a/vendor/github.com/containers/image/v5/manifest/oci_index.go b/vendor/github.com/containers/image/v5/manifest/oci_index.go
index 7bdea8fb2..5b4111e4e 100644
--- a/vendor/github.com/containers/image/v5/manifest/oci_index.go
+++ b/vendor/github.com/containers/image/v5/manifest/oci_index.go
@@ -75,7 +75,7 @@ func (index *OCI1Index) UpdateInstances(updates []ListUpdate) error {
func (index *OCI1Index) ChooseInstance(ctx *types.SystemContext) (digest.Digest, error) {
wantedPlatforms, err := platform.WantedPlatforms(ctx)
if err != nil {
- return "", errors.Wrapf(err, "error getting platform information %#v", ctx)
+ return "", errors.Wrapf(err, "getting platform information %#v", ctx)
}
for _, wantedPlatform := range wantedPlatforms {
for _, d := range index.Manifests {
@@ -108,7 +108,7 @@ func (index *OCI1Index) ChooseInstance(ctx *types.SystemContext) (digest.Digest,
func (index *OCI1Index) Serialize() ([]byte, error) {
buf, err := json.Marshal(index)
if err != nil {
- return nil, errors.Wrapf(err, "error marshaling OCI1Index %#v", index)
+ return nil, errors.Wrapf(err, "marshaling OCI1Index %#v", index)
}
return buf, nil
}
@@ -200,7 +200,7 @@ func OCI1IndexFromManifest(manifest []byte) (*OCI1Index, error) {
},
}
if err := json.Unmarshal(manifest, &index); err != nil {
- return nil, errors.Wrapf(err, "error unmarshaling OCI1Index %q", string(manifest))
+ return nil, errors.Wrapf(err, "unmarshaling OCI1Index %q", string(manifest))
}
return &index, nil
}
diff --git a/vendor/github.com/containers/image/v5/oci/archive/oci_dest.go b/vendor/github.com/containers/image/v5/oci/archive/oci_dest.go
index c874eb775..065a0b055 100644
--- a/vendor/github.com/containers/image/v5/oci/archive/oci_dest.go
+++ b/vendor/github.com/containers/image/v5/oci/archive/oci_dest.go
@@ -22,12 +22,12 @@ type ociArchiveImageDestination struct {
func newImageDestination(ctx context.Context, sys *types.SystemContext, ref ociArchiveReference) (types.ImageDestination, error) {
tempDirRef, err := createOCIRef(sys, ref.image)
if err != nil {
- return nil, errors.Wrapf(err, "error creating oci reference")
+ return nil, errors.Wrapf(err, "creating oci reference")
}
unpackedDest, err := tempDirRef.ociRefExtracted.NewImageDestination(ctx, sys)
if err != nil {
if err := tempDirRef.deleteTempDir(); err != nil {
- return nil, errors.Wrapf(err, "error deleting temp directory %q", tempDirRef.tempDirectory)
+ return nil, errors.Wrapf(err, "deleting temp directory %q", tempDirRef.tempDirectory)
}
return nil, err
}
@@ -129,10 +129,13 @@ func (d *ociArchiveImageDestination) PutSignatures(ctx context.Context, signatur
}
// Commit marks the process of storing the image as successful and asks for the image to be persisted
+// unparsedToplevel contains data about the top-level manifest of the source (which may be a single-arch image or a manifest list
+// if PutManifest was only called for the single-arch image with instanceDigest == nil), primarily to allow lookups by the
+// original manifest list digest, if desired.
// after the directory is made, it is tarred up into a file and the directory is deleted
func (d *ociArchiveImageDestination) Commit(ctx context.Context, unparsedToplevel types.UnparsedImage) error {
if err := d.unpackedDest.Commit(ctx, unparsedToplevel); err != nil {
- return errors.Wrapf(err, "error storing image %q", d.ref.image)
+ return errors.Wrapf(err, "storing image %q", d.ref.image)
}
// path of directory to tar up
@@ -147,13 +150,13 @@ func tarDirectory(src, dst string) error {
// input is a stream of bytes from the archive of the directory at path
input, err := archive.Tar(src, archive.Uncompressed)
if err != nil {
- return errors.Wrapf(err, "error retrieving stream of bytes from %q", src)
+ return errors.Wrapf(err, "retrieving stream of bytes from %q", src)
}
// creates the tar file
outFile, err := os.Create(dst)
if err != nil {
- return errors.Wrapf(err, "error creating tar file %q", dst)
+ return errors.Wrapf(err, "creating tar file %q", dst)
}
defer outFile.Close()
diff --git a/vendor/github.com/containers/image/v5/oci/archive/oci_src.go b/vendor/github.com/containers/image/v5/oci/archive/oci_src.go
index 8f07b3307..20b392dc0 100644
--- a/vendor/github.com/containers/image/v5/oci/archive/oci_src.go
+++ b/vendor/github.com/containers/image/v5/oci/archive/oci_src.go
@@ -23,13 +23,13 @@ type ociArchiveImageSource struct {
func newImageSource(ctx context.Context, sys *types.SystemContext, ref ociArchiveReference) (types.ImageSource, error) {
tempDirRef, err := createUntarTempDir(sys, ref)
if err != nil {
- return nil, errors.Wrap(err, "error creating temp directory")
+ return nil, errors.Wrap(err, "creating temp directory")
}
unpackedSrc, err := tempDirRef.ociRefExtracted.NewImageSource(ctx, sys)
if err != nil {
if err := tempDirRef.deleteTempDir(); err != nil {
- return nil, errors.Wrapf(err, "error deleting temp directory %q", tempDirRef.tempDirectory)
+ return nil, errors.Wrapf(err, "deleting temp directory %q", tempDirRef.tempDirectory)
}
return nil, err
}
@@ -52,7 +52,7 @@ func LoadManifestDescriptorWithContext(sys *types.SystemContext, imgRef types.Im
}
tempDirRef, err := createUntarTempDir(sys, ociArchRef)
if err != nil {
- return imgspecv1.Descriptor{}, errors.Wrap(err, "error creating temp directory")
+ return imgspecv1.Descriptor{}, errors.Wrap(err, "creating temp directory")
}
defer func() {
err := tempDirRef.deleteTempDir()
@@ -61,7 +61,7 @@ func LoadManifestDescriptorWithContext(sys *types.SystemContext, imgRef types.Im
descriptor, err := ocilayout.LoadManifestDescriptor(tempDirRef.ociRefExtracted)
if err != nil {
- return imgspecv1.Descriptor{}, errors.Wrap(err, "error loading index")
+ return imgspecv1.Descriptor{}, errors.Wrap(err, "loading index")
}
return descriptor, nil
}
diff --git a/vendor/github.com/containers/image/v5/oci/archive/oci_transport.go b/vendor/github.com/containers/image/v5/oci/archive/oci_transport.go
index c808539d2..54d325d34 100644
--- a/vendor/github.com/containers/image/v5/oci/archive/oci_transport.go
+++ b/vendor/github.com/containers/image/v5/oci/archive/oci_transport.go
@@ -163,7 +163,7 @@ func (t *tempDirOCIRef) deleteTempDir() error {
func createOCIRef(sys *types.SystemContext, image string) (tempDirOCIRef, error) {
dir, err := ioutil.TempDir(tmpdir.TemporaryDirectoryForBigFiles(sys), "oci")
if err != nil {
- return tempDirOCIRef{}, errors.Wrapf(err, "error creating temp directory")
+ return tempDirOCIRef{}, errors.Wrapf(err, "creating temp directory")
}
ociRef, err := ocilayout.NewReference(dir, image)
if err != nil {
@@ -178,7 +178,7 @@ func createOCIRef(sys *types.SystemContext, image string) (tempDirOCIRef, error)
func createUntarTempDir(sys *types.SystemContext, ref ociArchiveReference) (tempDirOCIRef, error) {
tempDirRef, err := createOCIRef(sys, ref.image)
if err != nil {
- return tempDirOCIRef{}, errors.Wrap(err, "error creating oci reference")
+ return tempDirOCIRef{}, errors.Wrap(err, "creating oci reference")
}
src := ref.resolvedFile
dst := tempDirRef.tempDirectory
@@ -190,9 +190,9 @@ func createUntarTempDir(sys *types.SystemContext, ref ociArchiveReference) (temp
defer arch.Close()
if err := archive.NewDefaultArchiver().Untar(arch, dst, &archive.TarOptions{NoLchown: true}); err != nil {
if err := tempDirRef.deleteTempDir(); err != nil {
- return tempDirOCIRef{}, errors.Wrapf(err, "error deleting temp directory %q", tempDirRef.tempDirectory)
+ return tempDirOCIRef{}, errors.Wrapf(err, "deleting temp directory %q", tempDirRef.tempDirectory)
}
- return tempDirOCIRef{}, errors.Wrapf(err, "error untarring file %q", tempDirRef.tempDirectory)
+ return tempDirOCIRef{}, errors.Wrapf(err, "untarring file %q", tempDirRef.tempDirectory)
}
return tempDirRef, nil
}
diff --git a/vendor/github.com/containers/image/v5/oci/layout/oci_dest.go b/vendor/github.com/containers/image/v5/oci/layout/oci_dest.go
index 1230e8ca3..d1d06d64d 100644
--- a/vendor/github.com/containers/image/v5/oci/layout/oci_dest.go
+++ b/vendor/github.com/containers/image/v5/oci/layout/oci_dest.go
@@ -303,6 +303,9 @@ func (d *ociImageDestination) PutSignatures(ctx context.Context, signatures [][]
}
// Commit marks the process of storing the image as successful and asks for the image to be persisted.
+// unparsedToplevel contains data about the top-level manifest of the source (which may be a single-arch image or a manifest list
+// if PutManifest was only called for the single-arch image with instanceDigest == nil), primarily to allow lookups by the
+// original manifest list digest, if desired.
// WARNING: This does not have any transactional semantics:
// - Uploaded data MAY be visible to others before Commit() is called
// - Uploaded data MAY be removed or MAY remain around if Close() is called without Commit() (i.e. rollback is allowed but not guaranteed)
diff --git a/vendor/github.com/containers/image/v5/oci/layout/oci_src.go b/vendor/github.com/containers/image/v5/oci/layout/oci_src.go
index 9925aeda7..55d3f637a 100644
--- a/vendor/github.com/containers/image/v5/oci/layout/oci_src.go
+++ b/vendor/github.com/containers/image/v5/oci/layout/oci_src.go
@@ -148,13 +148,13 @@ func (s *ociImageSource) getExternalBlob(ctx context.Context, urls []string) (io
errWrap := errors.New("failed fetching external blob from all urls")
for _, url := range urls {
- req, err := http.NewRequest("GET", url, nil)
+ req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
if err != nil {
errWrap = errors.Wrapf(errWrap, "fetching %s failed %s", url, err.Error())
continue
}
- resp, err := s.client.Do(req.WithContext(ctx))
+ resp, err := s.client.Do(req)
if err != nil {
errWrap = errors.Wrapf(errWrap, "fetching %s failed %s", url, err.Error())
continue
diff --git a/vendor/github.com/containers/image/v5/openshift/openshift-copies.go b/vendor/github.com/containers/image/v5/openshift/openshift-copies.go
index ec88b4ebf..f9f811784 100644
--- a/vendor/github.com/containers/image/v5/openshift/openshift-copies.go
+++ b/vendor/github.com/containers/image/v5/openshift/openshift-copies.go
@@ -579,7 +579,7 @@ func (rules *clientConfigLoadingRules) Load() (*clientcmdConfig, error) {
continue
}
if err != nil {
- errlist = append(errlist, errors.Wrapf(err, "Error loading config file \"%s\"", filename))
+ errlist = append(errlist, errors.Wrapf(err, "loading config file \"%s\"", filename))
continue
}
diff --git a/vendor/github.com/containers/image/v5/openshift/openshift.go b/vendor/github.com/containers/image/v5/openshift/openshift.go
index 426046e66..6ea65bcf3 100644
--- a/vendor/github.com/containers/image/v5/openshift/openshift.go
+++ b/vendor/github.com/containers/image/v5/openshift/openshift.go
@@ -79,11 +79,10 @@ func (c *openshiftClient) doRequest(ctx context.Context, method, path string, re
logrus.Debugf("Will send body: %s", requestBody)
requestBodyReader = bytes.NewReader(requestBody)
}
- req, err := http.NewRequest(method, url.String(), requestBodyReader)
+ req, err := http.NewRequestWithContext(ctx, method, url.String(), requestBodyReader)
if err != nil {
return nil, err
}
- req = req.WithContext(ctx)
if len(c.bearerToken) != 0 {
req.Header.Set("Authorization", "Bearer "+c.bearerToken)
@@ -137,7 +136,7 @@ func (c *openshiftClient) doRequest(ctx context.Context, method, path string, re
func (c *openshiftClient) getImage(ctx context.Context, imageStreamImageName string) (*image, error) {
// FIXME: validate components per validation.IsValidPathSegmentName?
path := fmt.Sprintf("/oapi/v1/namespaces/%s/imagestreamimages/%s@%s", c.ref.namespace, c.ref.stream, imageStreamImageName)
- body, err := c.doRequest(ctx, "GET", path, nil)
+ body, err := c.doRequest(ctx, http.MethodGet, path, nil)
if err != nil {
return nil, err
}
@@ -164,7 +163,7 @@ type openshiftImageSource struct {
// Values specific to this image
sys *types.SystemContext
// State
- docker types.ImageSource // The Docker Registry endpoint, or nil if not resolved yet
+ docker types.ImageSource // The docker/distribution API endpoint, or nil if not resolved yet
imageStreamImageName string // Resolved image identifier, or "" if not known yet
}
@@ -273,7 +272,7 @@ func (s *openshiftImageSource) ensureImageIsResolved(ctx context.Context) error
// FIXME: validate components per validation.IsValidPathSegmentName?
path := fmt.Sprintf("/oapi/v1/namespaces/%s/imagestreams/%s", s.client.ref.namespace, s.client.ref.stream)
- body, err := s.client.doRequest(ctx, "GET", path, nil)
+ body, err := s.client.doRequest(ctx, http.MethodGet, path, nil)
if err != nil {
return err
}
@@ -316,7 +315,7 @@ func (s *openshiftImageSource) ensureImageIsResolved(ctx context.Context) error
type openshiftImageDestination struct {
client *openshiftClient
- docker types.ImageDestination // The Docker Registry endpoint
+ docker types.ImageDestination // The docker/distribution API endpoint
// State
imageStreamImageName string // "" if not yet known
}
@@ -435,14 +434,14 @@ func (d *openshiftImageDestination) PutManifest(ctx context.Context, m []byte, i
}
func (d *openshiftImageDestination) PutSignatures(ctx context.Context, signatures [][]byte, instanceDigest *digest.Digest) error {
- var imageStreamName string
+ var imageStreamImageName string
if instanceDigest == nil {
if d.imageStreamImageName == "" {
return errors.Errorf("Internal error: Unknown manifest digest, can't add signatures")
}
- imageStreamName = d.imageStreamImageName
+ imageStreamImageName = d.imageStreamImageName
} else {
- imageStreamName = instanceDigest.String()
+ imageStreamImageName = instanceDigest.String()
}
// Because image signatures are a shared resource in Atomic Registry, the default upload
@@ -452,7 +451,7 @@ func (d *openshiftImageDestination) PutSignatures(ctx context.Context, signature
return nil // No need to even read the old state.
}
- image, err := d.client.getImage(ctx, imageStreamName)
+ image, err := d.client.getImage(ctx, imageStreamImageName)
if err != nil {
return err
}
@@ -475,9 +474,9 @@ sigExists:
randBytes := make([]byte, 16)
n, err := rand.Read(randBytes)
if err != nil || n != 16 {
- return errors.Wrapf(err, "Error generating random signature len %d", n)
+ return errors.Wrapf(err, "generating random signature len %d", n)
}
- signatureName = fmt.Sprintf("%s@%032x", imageStreamName, randBytes)
+ signatureName = fmt.Sprintf("%s@%032x", imageStreamImageName, randBytes)
if _, ok := existingSigNames[signatureName]; !ok {
break
}
@@ -496,7 +495,7 @@ sigExists:
if err != nil {
return err
}
- _, err = d.client.doRequest(ctx, "POST", "/oapi/v1/imagesignatures", body)
+ _, err = d.client.doRequest(ctx, http.MethodPost, "/oapi/v1/imagesignatures", body)
if err != nil {
return err
}
@@ -506,6 +505,9 @@ sigExists:
}
// Commit marks the process of storing the image as successful and asks for the image to be persisted.
+// unparsedToplevel contains data about the top-level manifest of the source (which may be a single-arch image or a manifest list
+// if PutManifest was only called for the single-arch image with instanceDigest == nil), primarily to allow lookups by the
+// original manifest list digest, if desired.
// WARNING: This does not have any transactional semantics:
// - Uploaded data MAY be visible to others before Commit() is called
// - Uploaded data MAY be removed or MAY remain around if Close() is called without Commit() (i.e. rollback is allowed but not guaranteed)
diff --git a/vendor/github.com/containers/image/v5/pkg/compression/compression.go b/vendor/github.com/containers/image/v5/pkg/compression/compression.go
index d5cfd8d31..c28e81792 100644
--- a/vendor/github.com/containers/image/v5/pkg/compression/compression.go
+++ b/vendor/github.com/containers/image/v5/pkg/compression/compression.go
@@ -9,6 +9,7 @@ import (
"github.com/containers/image/v5/pkg/compression/internal"
"github.com/containers/image/v5/pkg/compression/types"
+ "github.com/containers/storage/pkg/chunked/compressor"
"github.com/klauspost/pgzip"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@@ -20,19 +21,27 @@ type Algorithm = types.Algorithm
var (
// Gzip compression.
- Gzip = internal.NewAlgorithm("gzip", []byte{0x1F, 0x8B, 0x08}, GzipDecompressor, gzipCompressor)
+ Gzip = internal.NewAlgorithm(types.GzipAlgorithmName, types.GzipAlgorithmName,
+ []byte{0x1F, 0x8B, 0x08}, GzipDecompressor, gzipCompressor)
// Bzip2 compression.
- Bzip2 = internal.NewAlgorithm("bzip2", []byte{0x42, 0x5A, 0x68}, Bzip2Decompressor, bzip2Compressor)
+ Bzip2 = internal.NewAlgorithm(types.Bzip2AlgorithmName, types.Bzip2AlgorithmName,
+ []byte{0x42, 0x5A, 0x68}, Bzip2Decompressor, bzip2Compressor)
// Xz compression.
- Xz = internal.NewAlgorithm("Xz", []byte{0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00}, XzDecompressor, xzCompressor)
+ Xz = internal.NewAlgorithm(types.XzAlgorithmName, types.XzAlgorithmName,
+ []byte{0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00}, XzDecompressor, xzCompressor)
// Zstd compression.
- Zstd = internal.NewAlgorithm("zstd", []byte{0x28, 0xb5, 0x2f, 0xfd}, ZstdDecompressor, zstdCompressor)
+ Zstd = internal.NewAlgorithm(types.ZstdAlgorithmName, types.ZstdAlgorithmName,
+ []byte{0x28, 0xb5, 0x2f, 0xfd}, ZstdDecompressor, zstdCompressor)
+ // Zstd:chunked compression.
+ ZstdChunked = internal.NewAlgorithm(types.ZstdChunkedAlgorithmName, types.ZstdAlgorithmName, /* Note: InternalUnstableUndocumentedMIMEQuestionMark is not ZstdChunkedAlgorithmName */
+ nil, ZstdDecompressor, compressor.ZstdCompressor)
compressionAlgorithms = map[string]Algorithm{
- Gzip.Name(): Gzip,
- Bzip2.Name(): Bzip2,
- Xz.Name(): Xz,
- Zstd.Name(): Zstd,
+ Gzip.Name(): Gzip,
+ Bzip2.Name(): Bzip2,
+ Xz.Name(): Xz,
+ Zstd.Name(): Zstd,
+ ZstdChunked.Name(): ZstdChunked,
}
)
@@ -69,7 +78,7 @@ func XzDecompressor(r io.Reader) (io.ReadCloser, error) {
}
// gzipCompressor is a CompressorFunc for the gzip compression algorithm.
-func gzipCompressor(r io.Writer, level *int) (io.WriteCloser, error) {
+func gzipCompressor(r io.Writer, metadata map[string]string, level *int) (io.WriteCloser, error) {
if level != nil {
return pgzip.NewWriterLevel(r, *level)
}
@@ -77,18 +86,25 @@ func gzipCompressor(r io.Writer, level *int) (io.WriteCloser, error) {
}
// bzip2Compressor is a CompressorFunc for the bzip2 compression algorithm.
-func bzip2Compressor(r io.Writer, level *int) (io.WriteCloser, error) {
+func bzip2Compressor(r io.Writer, metadata map[string]string, level *int) (io.WriteCloser, error) {
return nil, fmt.Errorf("bzip2 compression not supported")
}
// xzCompressor is a CompressorFunc for the xz compression algorithm.
-func xzCompressor(r io.Writer, level *int) (io.WriteCloser, error) {
+func xzCompressor(r io.Writer, metadata map[string]string, level *int) (io.WriteCloser, error) {
return xz.NewWriter(r)
}
// CompressStream returns the compressor by its name
func CompressStream(dest io.Writer, algo Algorithm, level *int) (io.WriteCloser, error) {
- return internal.AlgorithmCompressor(algo)(dest, level)
+ m := map[string]string{}
+ return internal.AlgorithmCompressor(algo)(dest, m, level)
+}
+
+// CompressStreamWithMetadata returns the compressor by its name. If the compression
+// generates any metadata, it is written to the provided metadata map.
+func CompressStreamWithMetadata(dest io.Writer, metadata map[string]string, algo Algorithm, level *int) (io.WriteCloser, error) {
+ return internal.AlgorithmCompressor(algo)(dest, metadata, level)
}
// DetectCompressionFormat returns an Algorithm and DecompressorFunc if the input is recognized as a compressed format, an invalid
@@ -107,7 +123,8 @@ func DetectCompressionFormat(input io.Reader) (Algorithm, DecompressorFunc, io.R
var retAlgo Algorithm
var decompressor DecompressorFunc
for _, algo := range compressionAlgorithms {
- if bytes.HasPrefix(buffer[:n], internal.AlgorithmPrefix(algo)) {
+ prefix := internal.AlgorithmPrefix(algo)
+ if len(prefix) > 0 && bytes.HasPrefix(buffer[:n], prefix) {
logrus.Debugf("Detected compression format %s", algo.Name())
retAlgo = algo
decompressor = internal.AlgorithmDecompressor(algo)
@@ -135,13 +152,13 @@ func DetectCompression(input io.Reader) (DecompressorFunc, io.Reader, error) {
func AutoDecompress(stream io.Reader) (io.ReadCloser, bool, error) {
decompressor, stream, err := DetectCompression(stream)
if err != nil {
- return nil, false, errors.Wrapf(err, "Error detecting compression")
+ return nil, false, errors.Wrapf(err, "detecting compression")
}
var res io.ReadCloser
if decompressor != nil {
res, err = decompressor(stream)
if err != nil {
- return nil, false, errors.Wrapf(err, "Error initializing decompression")
+ return nil, false, errors.Wrapf(err, "initializing decompression")
}
} else {
res = ioutil.NopCloser(stream)
diff --git a/vendor/github.com/containers/image/v5/pkg/compression/internal/types.go b/vendor/github.com/containers/image/v5/pkg/compression/internal/types.go
index 6092a9517..fb37ca317 100644
--- a/vendor/github.com/containers/image/v5/pkg/compression/internal/types.go
+++ b/vendor/github.com/containers/image/v5/pkg/compression/internal/types.go
@@ -4,7 +4,7 @@ import "io"
// CompressorFunc writes the compressed stream to the given writer using the specified compression level.
// The caller must call Close() on the stream (even if the input stream does not need closing!).
-type CompressorFunc func(io.Writer, *int) (io.WriteCloser, error)
+type CompressorFunc func(io.Writer, map[string]string, *int) (io.WriteCloser, error)
// DecompressorFunc returns the decompressed stream, given a compressed stream.
// The caller must call Close() on the decompressed stream (even if the compressed input stream does not need closing!).
@@ -13,7 +13,8 @@ type DecompressorFunc func(io.Reader) (io.ReadCloser, error)
// Algorithm is a compression algorithm that can be used for CompressStream.
type Algorithm struct {
name string
- prefix []byte
+ mime string
+ prefix []byte // Initial bytes of a stream compressed using this algorithm, or empty to disable detection.
decompressor DecompressorFunc
compressor CompressorFunc
}
@@ -21,9 +22,10 @@ type Algorithm struct {
// NewAlgorithm creates an Algorithm instance.
// This function exists so that Algorithm instances can only be created by code that
// is allowed to import this internal subpackage.
-func NewAlgorithm(name string, prefix []byte, decompressor DecompressorFunc, compressor CompressorFunc) Algorithm {
+func NewAlgorithm(name, mime string, prefix []byte, decompressor DecompressorFunc, compressor CompressorFunc) Algorithm {
return Algorithm{
name: name,
+ mime: mime,
prefix: prefix,
decompressor: decompressor,
compressor: compressor,
@@ -35,6 +37,12 @@ func (c Algorithm) Name() string {
return c.name
}
+// InternalUnstableUndocumentedMIMEQuestionMark ???
+// DO NOT USE THIS anywhere outside of c/image until it is properly documented.
+func (c Algorithm) InternalUnstableUndocumentedMIMEQuestionMark() string {
+ return c.mime
+}
+
// AlgorithmCompressor returns the compressor field of algo.
// This is a function instead of a public method so that it is only callable from by code
// that is allowed to import this internal subpackage.
diff --git a/vendor/github.com/containers/image/v5/pkg/compression/types/types.go b/vendor/github.com/containers/image/v5/pkg/compression/types/types.go
index f96eff2e3..43d03b601 100644
--- a/vendor/github.com/containers/image/v5/pkg/compression/types/types.go
+++ b/vendor/github.com/containers/image/v5/pkg/compression/types/types.go
@@ -11,3 +11,31 @@ type DecompressorFunc = internal.DecompressorFunc
// Algorithm is a compression algorithm provided and supported by pkg/compression.
// It can’t be supplied from the outside.
type Algorithm = internal.Algorithm
+
+const (
+ // GzipAlgorithmName is the name used by pkg/compression.Gzip.
+ // NOTE: Importing only this /types package does not inherently guarantee a Gzip algorithm
+ // will actually be available. (In fact it is intended for this types package not to depend
+ // on any of the implementations.)
+ GzipAlgorithmName = "gzip"
+ // Bzip2AlgorithmName is the name used by pkg/compression.Bzip2.
+ // NOTE: Importing only this /types package does not inherently guarantee a Bzip2 algorithm
+ // will actually be available. (In fact it is intended for this types package not to depend
+ // on any of the implementations.)
+ Bzip2AlgorithmName = "bzip2"
+ // XzAlgorithmName is the name used by pkg/compression.Xz.
+ // NOTE: Importing only this /types package does not inherently guarantee a Xz algorithm
+ // will actually be available. (In fact it is intended for this types package not to depend
+ // on any of the implementations.)
+ XzAlgorithmName = "Xz"
+ // ZstdAlgorithmName is the name used by pkg/compression.Zstd.
+ // NOTE: Importing only this /types package does not inherently guarantee a Zstd algorithm
+ // will actually be available. (In fact it is intended for this types package not to depend
+ // on any of the implementations.)
+ ZstdAlgorithmName = "zstd"
+ // ZstdChunkedAlgorithmName is the name used by pkg/compression.ZstdChunked.
+ // NOTE: Importing only this /types package does not inherently guarantee a ZstdChunked algorithm
+ // will actually be available. (In fact it is intended for this types package not to depend
+ // on any of the implementations.)
+ ZstdChunkedAlgorithmName = "zstd:chunked"
+)
diff --git a/vendor/github.com/containers/image/v5/pkg/compression/zstd.go b/vendor/github.com/containers/image/v5/pkg/compression/zstd.go
index 962fe9676..39ae014d2 100644
--- a/vendor/github.com/containers/image/v5/pkg/compression/zstd.go
+++ b/vendor/github.com/containers/image/v5/pkg/compression/zstd.go
@@ -40,13 +40,13 @@ func zstdWriter(dest io.Writer) (io.WriteCloser, error) {
return zstd.NewWriter(dest)
}
-func zstdWriterWithLevel(dest io.Writer, level int) (io.WriteCloser, error) {
+func zstdWriterWithLevel(dest io.Writer, level int) (*zstd.Encoder, error) {
el := zstd.EncoderLevelFromZstd(level)
return zstd.NewWriter(dest, zstd.WithEncoderLevel(el))
}
// zstdCompressor is a CompressorFunc for the zstd compression algorithm.
-func zstdCompressor(r io.Writer, level *int) (io.WriteCloser, error) {
+func zstdCompressor(r io.Writer, metadata map[string]string, level *int) (io.WriteCloser, error) {
if level == nil {
return zstdWriter(r)
}
diff --git a/vendor/github.com/containers/image/v5/pkg/docker/config/config.go b/vendor/github.com/containers/image/v5/pkg/docker/config/config.go
index ec7c2fcc3..c82a9e1a0 100644
--- a/vendor/github.com/containers/image/v5/pkg/docker/config/config.go
+++ b/vendor/github.com/containers/image/v5/pkg/docker/config/config.go
@@ -11,6 +11,7 @@ import (
"runtime"
"strings"
+ "github.com/containers/image/v5/docker/reference"
"github.com/containers/image/v5/pkg/sysregistriesv2"
"github.com/containers/image/v5/types"
"github.com/containers/storage/pkg/homedir"
@@ -51,12 +52,19 @@ var (
ErrNotSupported = errors.New("not supported")
)
-// SetCredentials stores the username and password in the credential helper or file
-// and returns path to file or helper name in format (helper:%s).
+// SetCredentials stores the username and password in a location
+// appropriate for sys and the users’ configuration.
+// A valid key can be either a registry hostname or additionally a namespace if
+// the AuthenticationFileHelper is being unsed.
// Returns a human-redable description of the location that was updated.
// NOTE: The return value is only intended to be read by humans; its form is not an API,
// it may change (or new forms can be added) any time.
-func SetCredentials(sys *types.SystemContext, registry, username, password string) (string, error) {
+func SetCredentials(sys *types.SystemContext, key, username, password string) (string, error) {
+ isNamespaced, err := validateKey(key)
+ if err != nil {
+ return "", err
+ }
+
helpers, err := sysregistriesv2.CredentialHelpers(sys)
if err != nil {
return "", err
@@ -71,33 +79,45 @@ func SetCredentials(sys *types.SystemContext, registry, username, password strin
// Special-case the built-in helpers for auth files.
case sysregistriesv2.AuthenticationFileHelper:
desc, err = modifyJSON(sys, func(auths *dockerConfigFile) (bool, error) {
- if ch, exists := auths.CredHelpers[registry]; exists {
- return false, setAuthToCredHelper(ch, registry, username, password)
+ if ch, exists := auths.CredHelpers[key]; exists {
+ if isNamespaced {
+ return false, unsupportedNamespaceErr(ch)
+ }
+ return false, setAuthToCredHelper(ch, key, username, password)
}
creds := base64.StdEncoding.EncodeToString([]byte(username + ":" + password))
newCreds := dockerAuthConfig{Auth: creds}
- auths.AuthConfigs[registry] = newCreds
+ auths.AuthConfigs[key] = newCreds
return true, nil
})
// External helpers.
default:
- desc = fmt.Sprintf("credential helper: %s", helper)
- err = setAuthToCredHelper(helper, registry, username, password)
+ if isNamespaced {
+ err = unsupportedNamespaceErr(helper)
+ } else {
+ desc = fmt.Sprintf("credential helper: %s", helper)
+ err = setAuthToCredHelper(helper, key, username, password)
+ }
}
if err != nil {
multiErr = multierror.Append(multiErr, err)
- logrus.Debugf("Error storing credentials for %s in credential helper %s: %v", registry, helper, err)
+ logrus.Debugf("Error storing credentials for %s in credential helper %s: %v", key, helper, err)
continue
}
- logrus.Debugf("Stored credentials for %s in credential helper %s", registry, helper)
+ logrus.Debugf("Stored credentials for %s in credential helper %s", key, helper)
return desc, nil
}
return "", multiErr
}
+func unsupportedNamespaceErr(helper string) error {
+ return errors.Errorf("namespaced key is not supported for credential helper %s", helper)
+}
+
// SetAuthentication stores the username and password in the credential helper or file
-func SetAuthentication(sys *types.SystemContext, registry, username, password string) error {
- _, err := SetCredentials(sys, registry, username, password)
+// See the documentation of SetCredentials for format of "key"
+func SetAuthentication(sys *types.SystemContext, key, username, password string) error {
+ _, err := SetCredentials(sys, key, username, password)
return err
}
@@ -125,7 +145,7 @@ func GetAllCredentials(sys *types.SystemContext) (map[string]types.DockerAuthCon
// readJSONFile returns an empty map in case the path doesn't exist.
auths, err := readJSONFile(path.path, path.legacyFormat)
if err != nil {
- return nil, errors.Wrapf(err, "error reading JSON file %q", path.path)
+ return nil, errors.Wrapf(err, "reading JSON file %q", path.path)
}
// Credential helpers in the auth file have a
// direct mapping to a registry, so we can just
@@ -215,13 +235,33 @@ func getAuthFilePaths(sys *types.SystemContext, homeDir string) []authPath {
// helpers with falling back to using either auth.json
// file or .docker/config.json, including support for OAuth2 and IdentityToken.
// If an entry is not found, an empty struct is returned.
+//
+// GetCredentialsForRef should almost always be used in favor of this API to
+// allow different credentials for different repositories on the same registry.
func GetCredentials(sys *types.SystemContext, registry string) (types.DockerAuthConfig, error) {
- return getCredentialsWithHomeDir(sys, registry, homedir.Get())
+ return getCredentialsWithHomeDir(sys, nil, registry, homedir.Get())
}
-// getCredentialsWithHomeDir is an internal implementation detail of GetCredentials,
-// it exists only to allow testing it with an artificial home directory.
-func getCredentialsWithHomeDir(sys *types.SystemContext, registry, homeDir string) (types.DockerAuthConfig, error) {
+// GetCredentialsForRef returns the registry credentials necessary for
+// accessing ref on the registry ref points to,
+// appropriate for sys and the users’ configuration.
+// If an entry is not found, an empty struct is returned.
+func GetCredentialsForRef(sys *types.SystemContext, ref reference.Named) (types.DockerAuthConfig, error) {
+ return getCredentialsWithHomeDir(sys, ref, reference.Domain(ref), homedir.Get())
+}
+
+// getCredentialsWithHomeDir is an internal implementation detail of
+// GetCredentialsForRef and GetCredentials. It exists only to allow testing it
+// with an artificial home directory.
+func getCredentialsWithHomeDir(sys *types.SystemContext, ref reference.Named, registry, homeDir string) (types.DockerAuthConfig, error) {
+ // consistency check of the ref and registry arguments
+ if ref != nil && reference.Domain(ref) != registry {
+ return types.DockerAuthConfig{}, errors.Errorf(
+ "internal error: provided reference domain %q name does not match registry %q",
+ reference.Domain(ref), registry,
+ )
+ }
+
if sys != nil && sys.DockerAuthConfig != nil {
logrus.Debugf("Returning credentials for %s from DockerAuthConfig", registry)
return *sys.DockerAuthConfig, nil
@@ -230,7 +270,7 @@ func getCredentialsWithHomeDir(sys *types.SystemContext, registry, homeDir strin
// Anonymous function to query credentials from auth files.
getCredentialsFromAuthFiles := func() (types.DockerAuthConfig, error) {
for _, path := range getAuthFilePaths(sys, homeDir) {
- authConfig, err := findAuthentication(registry, path.path, path.legacyFormat)
+ authConfig, err := findAuthentication(ref, registry, path.path, path.legacyFormat)
if err != nil {
return types.DockerAuthConfig{}, err
}
@@ -284,7 +324,7 @@ func getCredentialsWithHomeDir(sys *types.SystemContext, registry, homeDir strin
// .docker/config.json
//
// Deprecated: This API only has support for username and password. To get the
-// support for oauth2 in docker registry authentication, we added the new
+// support for oauth2 in container registry authentication, we added the new
// GetCredentials API. The new API should be used and this API is kept to
// maintain backward compatibility.
func GetAuthentication(sys *types.SystemContext, registry string) (string, string, error) {
@@ -294,7 +334,7 @@ func GetAuthentication(sys *types.SystemContext, registry string) (string, strin
// getAuthenticationWithHomeDir is an internal implementation detail of GetAuthentication,
// it exists only to allow testing it with an artificial home directory.
func getAuthenticationWithHomeDir(sys *types.SystemContext, registry, homeDir string) (string, string, error) {
- auth, err := getCredentialsWithHomeDir(sys, registry, homeDir)
+ auth, err := getCredentialsWithHomeDir(sys, nil, registry, homeDir)
if err != nil {
return "", "", err
}
@@ -304,9 +344,16 @@ func getAuthenticationWithHomeDir(sys *types.SystemContext, registry, homeDir st
return auth.Username, auth.Password, nil
}
-// RemoveAuthentication removes credentials for `registry` from all possible
+// RemoveAuthentication removes credentials for `key` from all possible
// sources such as credential helpers and auth files.
-func RemoveAuthentication(sys *types.SystemContext, registry string) error {
+// A valid key can be either a registry hostname or additionally a namespace if
+// the AuthenticationFileHelper is being unsed.
+func RemoveAuthentication(sys *types.SystemContext, key string) error {
+ isNamespaced, err := validateKey(key)
+ if err != nil {
+ return err
+ }
+
helpers, err := sysregistriesv2.CredentialHelpers(sys)
if err != nil {
return err
@@ -316,17 +363,22 @@ func RemoveAuthentication(sys *types.SystemContext, registry string) error {
isLoggedIn := false
removeFromCredHelper := func(helper string) {
- err := deleteAuthFromCredHelper(helper, registry)
- if err == nil {
- logrus.Debugf("Credentials for %q were deleted from credential helper %s", registry, helper)
- isLoggedIn = true
- return
- }
- if credentials.IsErrCredentialsNotFoundMessage(err.Error()) {
- logrus.Debugf("Not logged in to %s with credential helper %s", registry, helper)
+ if isNamespaced {
+ logrus.Debugf("Not removing credentials because namespaced keys are not supported for the credential helper: %s", helper)
return
+ } else {
+ err := deleteAuthFromCredHelper(helper, key)
+ if err == nil {
+ logrus.Debugf("Credentials for %q were deleted from credential helper %s", key, helper)
+ isLoggedIn = true
+ return
+ }
+ if credentials.IsErrCredentialsNotFoundMessage(err.Error()) {
+ logrus.Debugf("Not logged in to %s with credential helper %s", key, helper)
+ return
+ }
}
- multiErr = multierror.Append(multiErr, errors.Wrapf(err, "error removing credentials for %s from credential helper %s", registry, helper))
+ multiErr = multierror.Append(multiErr, errors.Wrapf(err, "removing credentials for %s from credential helper %s", key, helper))
}
for _, helper := range helpers {
@@ -335,15 +387,12 @@ func RemoveAuthentication(sys *types.SystemContext, registry string) error {
// Special-case the built-in helper for auth files.
case sysregistriesv2.AuthenticationFileHelper:
_, err = modifyJSON(sys, func(auths *dockerConfigFile) (bool, error) {
- if innerHelper, exists := auths.CredHelpers[registry]; exists {
+ if innerHelper, exists := auths.CredHelpers[key]; exists {
removeFromCredHelper(innerHelper)
}
- if _, ok := auths.AuthConfigs[registry]; ok {
- isLoggedIn = true
- delete(auths.AuthConfigs, registry)
- } else if _, ok := auths.AuthConfigs[normalizeRegistry(registry)]; ok {
+ if _, ok := auths.AuthConfigs[key]; ok {
isLoggedIn = true
- delete(auths.AuthConfigs, normalizeRegistry(registry))
+ delete(auths.AuthConfigs, key)
}
return true, multiErr
})
@@ -486,13 +535,13 @@ func readJSONFile(path string, legacyFormat bool) (dockerConfigFile, error) {
if legacyFormat {
if err = json.Unmarshal(raw, &auths.AuthConfigs); err != nil {
- return dockerConfigFile{}, errors.Wrapf(err, "error unmarshaling JSON at %q", path)
+ return dockerConfigFile{}, errors.Wrapf(err, "unmarshaling JSON at %q", path)
}
return auths, nil
}
if err = json.Unmarshal(raw, &auths); err != nil {
- return dockerConfigFile{}, errors.Wrapf(err, "error unmarshaling JSON at %q", path)
+ return dockerConfigFile{}, errors.Wrapf(err, "unmarshaling JSON at %q", path)
}
if auths.AuthConfigs == nil {
@@ -524,21 +573,21 @@ func modifyJSON(sys *types.SystemContext, editor func(auths *dockerConfigFile) (
auths, err := readJSONFile(path, false)
if err != nil {
- return "", errors.Wrapf(err, "error reading JSON file %q", path)
+ return "", errors.Wrapf(err, "reading JSON file %q", path)
}
updated, err := editor(&auths)
if err != nil {
- return "", errors.Wrapf(err, "error updating %q", path)
+ return "", errors.Wrapf(err, "updating %q", path)
}
if updated {
newData, err := json.MarshalIndent(auths, "", "\t")
if err != nil {
- return "", errors.Wrapf(err, "error marshaling JSON %q", path)
+ return "", errors.Wrapf(err, "marshaling JSON %q", path)
}
if err = ioutil.WriteFile(path, newData, 0600); err != nil {
- return "", errors.Wrapf(err, "error writing to file %q", path)
+ return "", errors.Wrapf(err, "writing to file %q", path)
}
}
@@ -575,11 +624,13 @@ func deleteAuthFromCredHelper(credHelper, registry string) error {
return helperclient.Erase(p, registry)
}
-// findAuthentication looks for auth of registry in path
-func findAuthentication(registry, path string, legacyFormat bool) (types.DockerAuthConfig, error) {
+// findAuthentication looks for auth of registry in path. If ref is
+// not nil, then it will be taken into account when looking up the
+// authentication credentials.
+func findAuthentication(ref reference.Named, registry, path string, legacyFormat bool) (types.DockerAuthConfig, error) {
auths, err := readJSONFile(path, legacyFormat)
if err != nil {
- return types.DockerAuthConfig{}, errors.Wrapf(err, "error reading JSON file %q", path)
+ return types.DockerAuthConfig{}, errors.Wrapf(err, "reading JSON file %q", path)
}
// First try cred helpers. They should always be normalized.
@@ -587,23 +638,62 @@ func findAuthentication(registry, path string, legacyFormat bool) (types.DockerA
return getAuthFromCredHelper(ch, registry)
}
- // I'm feeling lucky
- if val, exists := auths.AuthConfigs[registry]; exists {
- return decodeDockerAuth(val)
+ // Support for different paths in auth.
+ // (This is not a feature of ~/.docker/config.json; we support it even for
+ // those files as an extension.)
+ var keys []string
+ if !legacyFormat && ref != nil {
+ keys = authKeysForRef(ref)
+ } else {
+ keys = []string{registry}
+ }
+
+ // Repo or namespace keys are only supported as exact matches. For registry
+ // keys we prefer exact matches as well.
+ for _, key := range keys {
+ if val, exists := auths.AuthConfigs[key]; exists {
+ return decodeDockerAuth(val)
+ }
}
// bad luck; let's normalize the entries first
+ // This primarily happens for legacyFormat, which for a time used API URLs
+ // (http[s:]//…/v1/) as keys.
+ // Secondarily, (docker login) accepted URLs with no normalization for
+ // several years, and matched registry hostnames against that, so support
+ // those entries even in non-legacyFormat ~/.docker/config.json.
+ // The docker.io registry still uses the /v1/ key with a special host name,
+ // so account for that as well.
registry = normalizeRegistry(registry)
- normalizedAuths := map[string]dockerAuthConfig{}
for k, v := range auths.AuthConfigs {
- normalizedAuths[normalizeRegistry(k)] = v
+ if normalizeAuthFileKey(k, legacyFormat) == registry {
+ return decodeDockerAuth(v)
+ }
}
- if val, exists := normalizedAuths[registry]; exists {
- return decodeDockerAuth(val)
+ return types.DockerAuthConfig{}, nil
+}
+
+// authKeysForRef returns the valid paths for a provided reference. For example,
+// when given a reference "quay.io/repo/ns/image:tag", then it would return
+// - quay.io/repo/ns/image
+// - quay.io/repo/ns
+// - quay.io/repo
+// - quay.io
+func authKeysForRef(ref reference.Named) (res []string) {
+ name := ref.Name()
+
+ for {
+ res = append(res, name)
+
+ lastSlash := strings.LastIndex(name, "/")
+ if lastSlash == -1 {
+ break
+ }
+ name = name[:lastSlash]
}
- return types.DockerAuthConfig{}, nil
+ return res
}
// decodeDockerAuth decodes the username and password, which is
@@ -629,27 +719,36 @@ func decodeDockerAuth(conf dockerAuthConfig) (types.DockerAuthConfig, error) {
}, nil
}
-// convertToHostname converts a registry url which has http|https prepended
-// to just an hostname.
-// Copied from github.com/docker/docker/registry/auth.go
-func convertToHostname(url string) string {
- stripped := url
- if strings.HasPrefix(url, "http://") {
- stripped = strings.TrimPrefix(url, "http://")
- } else if strings.HasPrefix(url, "https://") {
- stripped = strings.TrimPrefix(url, "https://")
- }
+// normalizeAuthFileKey takes a key, converts it to a host name and normalizes
+// the resulting registry.
+func normalizeAuthFileKey(key string, legacyFormat bool) string {
+ stripped := strings.TrimPrefix(key, "http://")
+ stripped = strings.TrimPrefix(stripped, "https://")
- nameParts := strings.SplitN(stripped, "/", 2)
+ if legacyFormat || stripped != key {
+ stripped = strings.SplitN(stripped, "/", 2)[0]
+ }
- return nameParts[0]
+ return normalizeRegistry(stripped)
}
+// normalizeRegistry converts the provided registry if a known docker.io host
+// is provided.
func normalizeRegistry(registry string) string {
- normalized := convertToHostname(registry)
- switch normalized {
+ switch registry {
case "registry-1.docker.io", "docker.io":
return "index.docker.io"
}
- return normalized
+ return registry
+}
+
+// validateKey verifies that the input key does not have a prefix that is not
+// allowed and returns an indicator if the key is namespaced.
+func validateKey(key string) (isNamespaced bool, err error) {
+ if strings.HasPrefix(key, "http://") || strings.HasPrefix(key, "https://") {
+ return isNamespaced, errors.Errorf("key %s contains http[s]:// prefix", key)
+ }
+
+ // check if the provided key contains one or more subpaths.
+ return strings.ContainsRune(key, '/'), nil
}
diff --git a/vendor/github.com/containers/image/v5/pkg/docker/config/config_linux.go b/vendor/github.com/containers/image/v5/pkg/docker/config/config_linux.go
index 93c75b944..1354ee46d 100644
--- a/vendor/github.com/containers/image/v5/pkg/docker/config/config_linux.go
+++ b/vendor/github.com/containers/image/v5/pkg/docker/config/config_linux.go
@@ -73,7 +73,7 @@ func removeAllAuthFromKernelKeyring() error { //nolint:deadcode,unused
if strings.HasPrefix(keyDescribe, keyDescribePrefix) {
err := keyctl.Unlink(userkeyring, k)
if err != nil {
- return errors.Wrapf(err, "error unlinking key %d", k.ID())
+ return errors.Wrapf(err, "unlinking key %d", k.ID())
}
logrus.Debugf("unlinked key %d:%s", k.ID(), keyAttr)
}
@@ -100,16 +100,16 @@ func setAuthToKernelKeyring(registry, username, password string) error { //nolin
// link the key to userKeyring
userKeyring, err := keyctl.UserKeyring()
if err != nil {
- return errors.Wrapf(err, "error getting user keyring")
+ return errors.Wrapf(err, "getting user keyring")
}
err = keyctl.Link(userKeyring, id)
if err != nil {
- return errors.Wrapf(err, "error linking the key to user keyring")
+ return errors.Wrapf(err, "linking the key to user keyring")
}
// unlink the key from session keyring
err = keyctl.Unlink(keyring, id)
if err != nil {
- return errors.Wrapf(err, "error unlinking the key from session keyring")
+ return errors.Wrapf(err, "unlinking the key from session keyring")
}
return nil
}
diff --git a/vendor/github.com/containers/image/v5/pkg/shortnames/shortnames.go b/vendor/github.com/containers/image/v5/pkg/shortnames/shortnames.go
index ab1eee8f3..fb0a15b99 100644
--- a/vendor/github.com/containers/image/v5/pkg/shortnames/shortnames.go
+++ b/vendor/github.com/containers/image/v5/pkg/shortnames/shortnames.go
@@ -211,7 +211,7 @@ func (c *PullCandidate) Record() error {
value := reference.TrimNamed(c.Value)
if err := Add(c.resolved.systemContext, name.String(), value); err != nil {
- return errors.Wrapf(err, "error recording short-name alias (%q=%q)", c.resolved.userInput, c.Value)
+ return errors.Wrapf(err, "recording short-name alias (%q=%q)", c.resolved.userInput, c.Value)
}
return nil
}
@@ -323,7 +323,7 @@ func Resolve(ctx *types.SystemContext, name string) (*Resolved, error) {
for _, reg := range unqualifiedSearchRegistries {
named, err := reference.ParseNormalizedNamed(fmt.Sprintf("%s/%s", reg, name))
if err != nil {
- return nil, errors.Wrapf(err, "error creating reference with unqualified-search registry %q", reg)
+ return nil, errors.Wrapf(err, "creating reference with unqualified-search registry %q", reg)
}
// Make sure to add ":latest" if needed
named = reference.TagNameOnly(named)
@@ -450,7 +450,7 @@ func ResolveLocally(ctx *types.SystemContext, name string) ([]reference.Named, e
for _, reg := range append([]string{"localhost"}, unqualifiedSearchRegistries...) {
named, err := reference.ParseNormalizedNamed(fmt.Sprintf("%s/%s", reg, name))
if err != nil {
- return nil, errors.Wrapf(err, "error creating reference with unqualified-search registry %q", reg)
+ return nil, errors.Wrapf(err, "creating reference with unqualified-search registry %q", reg)
}
// Make sure to add ":latest" if needed
named = reference.TagNameOnly(named)
diff --git a/vendor/github.com/containers/image/v5/pkg/sysregistriesv2/shortnames.go b/vendor/github.com/containers/image/v5/pkg/sysregistriesv2/shortnames.go
index 784a616dc..7122e869f 100644
--- a/vendor/github.com/containers/image/v5/pkg/sysregistriesv2/shortnames.go
+++ b/vendor/github.com/containers/image/v5/pkg/sysregistriesv2/shortnames.go
@@ -3,6 +3,7 @@ package sysregistriesv2
import (
"os"
"path/filepath"
+ "reflect"
"strings"
"github.com/BurntSushi/toml"
@@ -49,6 +50,17 @@ type shortNameAliasConf struct {
// reference counter parts.
// Note that Aliases is niled after being loaded from a file.
Aliases map[string]string `toml:"aliases"`
+
+ // If you add any field, make sure to update nonempty() below.
+}
+
+// nonempty returns true if config contains at least one configuration entry.
+func (c *shortNameAliasConf) nonempty() bool {
+ copy := *c // A shallow copy
+ if copy.Aliases != nil && len(copy.Aliases) == 0 {
+ copy.Aliases = nil
+ }
+ return !reflect.DeepEqual(copy, shortNameAliasConf{})
}
// alias combines the parsed value of an alias with the config file it has been
@@ -197,7 +209,7 @@ func RemoveShortNameAlias(ctx *types.SystemContext, name string) error {
func parseShortNameValue(alias string) (reference.Named, error) {
ref, err := reference.Parse(alias)
if err != nil {
- return nil, errors.Wrapf(err, "error parsing alias %q", alias)
+ return nil, errors.Wrapf(err, "parsing alias %q", alias)
}
if _, ok := ref.(reference.Digested); ok {
@@ -306,14 +318,14 @@ func loadShortNameAliasConf(confPath string) (*shortNameAliasConf, *shortNameAli
_, err := toml.DecodeFile(confPath, &conf)
if err != nil && !os.IsNotExist(err) {
// It's okay if the config doesn't exist. Other errors are not.
- return nil, nil, errors.Wrapf(err, "error loading short-name aliases config file %q", confPath)
+ return nil, nil, errors.Wrapf(err, "loading short-name aliases config file %q", confPath)
}
// Even if we don’t always need the cache, doing so validates the machine-generated config. The
// file could still be corrupted by another process or user.
cache, err := newShortNameAliasCache(confPath, &conf)
if err != nil {
- return nil, nil, errors.Wrapf(err, "error loading short-name aliases config file %q", confPath)
+ return nil, nil, errors.Wrapf(err, "loading short-name aliases config file %q", confPath)
}
return &conf, cache, nil
diff --git a/vendor/github.com/containers/image/v5/pkg/sysregistriesv2/system_registries_v2.go b/vendor/github.com/containers/image/v5/pkg/sysregistriesv2/system_registries_v2.go
index 880f8c871..4c1629f56 100644
--- a/vendor/github.com/containers/image/v5/pkg/sysregistriesv2/system_registries_v2.go
+++ b/vendor/github.com/containers/image/v5/pkg/sysregistriesv2/system_registries_v2.go
@@ -4,6 +4,7 @@ import (
"fmt"
"os"
"path/filepath"
+ "reflect"
"regexp"
"sort"
"strings"
@@ -87,7 +88,7 @@ func (e *Endpoint) rewriteReference(ref reference.Named, prefix string) (referen
newNamedRef = e.Location + refString[prefixLen:]
newParsedRef, err := reference.ParseNamed(newNamedRef)
if err != nil {
- return nil, errors.Wrapf(err, "error rewriting reference")
+ return nil, errors.Wrapf(err, "rewriting reference")
}
return newParsedRef, nil
@@ -172,9 +173,17 @@ type V1RegistriesConf struct {
// Nonempty returns true if config contains at least one configuration entry.
func (config *V1RegistriesConf) Nonempty() bool {
- return (len(config.V1TOMLConfig.Search.Registries) != 0 ||
- len(config.V1TOMLConfig.Insecure.Registries) != 0 ||
- len(config.V1TOMLConfig.Block.Registries) != 0)
+ copy := *config // A shallow copy
+ if copy.V1TOMLConfig.Search.Registries != nil && len(copy.V1TOMLConfig.Search.Registries) == 0 {
+ copy.V1TOMLConfig.Search.Registries = nil
+ }
+ if copy.V1TOMLConfig.Insecure.Registries != nil && len(copy.V1TOMLConfig.Insecure.Registries) == 0 {
+ copy.V1TOMLConfig.Insecure.Registries = nil
+ }
+ if copy.V1TOMLConfig.Block.Registries != nil && len(copy.V1TOMLConfig.Block.Registries) == 0 {
+ copy.V1TOMLConfig.Block.Registries = nil
+ }
+ return !reflect.DeepEqual(copy, V1RegistriesConf{})
}
// V2RegistriesConf is the sysregistries v2 configuration format.
@@ -203,12 +212,26 @@ type V2RegistriesConf struct {
ShortNameMode string `toml:"short-name-mode"`
shortNameAliasConf
+
+ // If you add any field, make sure to update Nonempty() below.
}
// Nonempty returns true if config contains at least one configuration entry.
func (config *V2RegistriesConf) Nonempty() bool {
- return (len(config.Registries) != 0 ||
- len(config.UnqualifiedSearchRegistries) != 0)
+ copy := *config // A shallow copy
+ if copy.Registries != nil && len(copy.Registries) == 0 {
+ copy.Registries = nil
+ }
+ if copy.UnqualifiedSearchRegistries != nil && len(copy.UnqualifiedSearchRegistries) == 0 {
+ copy.UnqualifiedSearchRegistries = nil
+ }
+ if copy.CredentialHelpers != nil && len(copy.CredentialHelpers) == 0 {
+ copy.CredentialHelpers = nil
+ }
+ if !copy.shortNameAliasConf.nonempty() {
+ copy.shortNameAliasConf = shortNameAliasConf{}
+ }
+ return !reflect.DeepEqual(copy, V2RegistriesConf{})
}
// parsedConfig is the result of parsing, and possibly merging, configuration files;
@@ -604,7 +627,7 @@ func dropInConfigs(wrapper configWrapper) ([]string, error) {
if err != nil && !os.IsNotExist(err) {
// Ignore IsNotExist errors: most systems won't have a registries.conf.d
// directory.
- return nil, errors.Wrapf(err, "error reading registries.conf.d")
+ return nil, errors.Wrapf(err, "reading registries.conf.d")
}
}
@@ -646,7 +669,7 @@ func tryUpdatingCache(ctx *types.SystemContext, wrapper configWrapper) (*parsedC
return nil, err // Should never happen
}
} else {
- return nil, errors.Wrapf(err, "error loading registries configuration %q", wrapper.configPath)
+ return nil, errors.Wrapf(err, "loading registries configuration %q", wrapper.configPath)
}
}
@@ -659,7 +682,7 @@ func tryUpdatingCache(ctx *types.SystemContext, wrapper configWrapper) (*parsedC
// Enforce v2 format for drop-in-configs.
dropIn, err := loadConfigFile(path, true)
if err != nil {
- return nil, errors.Wrapf(err, "error loading drop-in registries configuration %q", path)
+ return nil, errors.Wrapf(err, "loading drop-in registries configuration %q", path)
}
config.updateWithConfigurationFrom(dropIn)
}
@@ -910,7 +933,7 @@ func loadConfigFile(path string, forceV2 bool) (*parsedConfig, error) {
// Parse and validate short-name aliases.
cache, err := newShortNameAliasCache(path, &res.partialV2.shortNameAliasConf)
if err != nil {
- return nil, errors.Wrap(err, "error validating short-name aliases")
+ return nil, errors.Wrap(err, "validating short-name aliases")
}
res.aliasCache = cache
// Clear conf.partialV2.shortNameAliasConf to make it available for garbage collection and
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 7072d6860..6b0fea61a 100644
--- a/vendor/github.com/containers/image/v5/storage/storage_image.go
+++ b/vendor/github.com/containers/image/v5/storage/storage_image.go
@@ -23,7 +23,9 @@ import (
"github.com/containers/image/v5/pkg/blobinfocache/none"
"github.com/containers/image/v5/types"
"github.com/containers/storage"
+ "github.com/containers/storage/drivers"
"github.com/containers/storage/pkg/archive"
+ "github.com/containers/storage/pkg/chunked"
"github.com/containers/storage/pkg/ioutils"
digest "github.com/opencontainers/go-digest"
imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
@@ -59,6 +61,7 @@ type storageImageDestination struct {
directory string // Temporary directory where we store blobs until Commit() time
nextTempFileID int32 // A counter that we use for computing filenames to assign to blobs
manifest []byte // Manifest contents, temporary
+ manifestDigest digest.Digest // Valid if len(manifest) != 0
signatures []byte // Signature contents, temporary
signatureses map[digest.Digest][]byte // Instance signature contents, temporary
SignatureSizes []int `json:"signature-sizes,omitempty"` // List of sizes of each signature slice
@@ -76,12 +79,13 @@ 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)
- indexToPulledLayerInfo map[int]*manifest.LayerInfo // Mapping from layer (by index) to pulled down blob
- blobAdditionalLayer map[digest.Digest]storage.AdditionalLayer // Mapping from layer blobsums to their corresponding additional layer
+ 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)
+ indexToPulledLayerInfo map[int]*manifest.LayerInfo // Mapping from layer (by index) to pulled down blob
+ blobAdditionalLayer map[digest.Digest]storage.AdditionalLayer // Mapping from layer blobsums to their corresponding additional layer
+ diffOutputs map[digest.Digest]*graphdriver.DriverWithDifferOutput // Mapping from digest to differ output
}
type storageImageCloser struct {
@@ -121,7 +125,7 @@ func newImageSource(ctx context.Context, sys *types.SystemContext, imageRef stor
}
if img.Metadata != "" {
if err := json.Unmarshal([]byte(img.Metadata), image); err != nil {
- return nil, errors.Wrap(err, "error decoding metadata for source image")
+ return nil, errors.Wrap(err, "decoding metadata for source image")
}
}
return image, nil
@@ -239,7 +243,7 @@ func (s *storageImageSource) GetManifest(ctx context.Context, instanceDigest *di
key := manifestBigDataKey(*instanceDigest)
blob, err := s.imageRef.transport.store.ImageBigData(s.image.ID, key)
if err != nil {
- return nil, "", errors.Wrapf(err, "error reading manifest for image instance %q", *instanceDigest)
+ return nil, "", errors.Wrapf(err, "reading manifest for image instance %q", *instanceDigest)
}
return blob, manifest.GuessMIMEType(blob), err
}
@@ -276,14 +280,14 @@ func (s *storageImageSource) GetManifest(ctx context.Context, instanceDigest *di
func (s *storageImageSource) LayerInfosForCopy(ctx context.Context, instanceDigest *digest.Digest) ([]types.BlobInfo, error) {
manifestBlob, manifestType, err := s.GetManifest(ctx, instanceDigest)
if err != nil {
- return nil, errors.Wrapf(err, "error reading image manifest for %q", s.image.ID)
+ return nil, errors.Wrapf(err, "reading image manifest for %q", s.image.ID)
}
if manifest.MIMETypeIsMultiImage(manifestType) {
return nil, errors.Errorf("can't copy layers for a manifest list (shouldn't be attempted)")
}
man, err := manifest.FromBlob(manifestBlob, manifestType)
if err != nil {
- return nil, errors.Wrapf(err, "error parsing image manifest for %q", s.image.ID)
+ return nil, errors.Wrapf(err, "parsing image manifest for %q", s.image.ID)
}
uncompressedLayerType := ""
@@ -299,7 +303,7 @@ func (s *storageImageSource) LayerInfosForCopy(ctx context.Context, instanceDige
for layerID != "" {
layer, err := s.imageRef.transport.store.Layer(layerID)
if err != nil {
- return nil, errors.Wrapf(err, "error reading layer %q in image %q", layerID, s.image.ID)
+ return nil, errors.Wrapf(err, "reading layer %q in image %q", layerID, s.image.ID)
}
if layer.UncompressedDigest == "" {
return nil, errors.Errorf("uncompressed digest for layer %q is unknown", layerID)
@@ -318,7 +322,7 @@ func (s *storageImageSource) LayerInfosForCopy(ctx context.Context, instanceDige
res, err := buildLayerInfosForCopy(man.LayerInfos(), physicalBlobInfos)
if err != nil {
- return nil, errors.Wrapf(err, "error creating LayerInfosForCopy of image %q", s.image.ID)
+ return nil, errors.Wrapf(err, "creating LayerInfosForCopy of image %q", s.image.ID)
}
return res, nil
}
@@ -367,13 +371,13 @@ func (s *storageImageSource) GetSignatures(ctx context.Context, instanceDigest *
if len(signatureSizes) > 0 {
signatureBlob, err := s.imageRef.transport.store.ImageBigData(s.image.ID, key)
if err != nil {
- return nil, errors.Wrapf(err, "error looking up signatures data for image %q (%s)", s.image.ID, instance)
+ return nil, errors.Wrapf(err, "looking up signatures data for image %q (%s)", s.image.ID, instance)
}
signature = signatureBlob
}
for _, length := range signatureSizes {
if offset+length > len(signature) {
- return nil, errors.Wrapf(err, "error looking up signatures data for image %q (%s): expected at least %d bytes, only found %d", s.image.ID, instance, len(signature), offset+length)
+ return nil, errors.Wrapf(err, "looking up signatures data for image %q (%s): expected at least %d bytes, only found %d", s.image.ID, instance, len(signature), offset+length)
}
sigslice = append(sigslice, signature[offset:offset+length])
offset += length
@@ -389,7 +393,7 @@ func (s *storageImageSource) GetSignatures(ctx context.Context, instanceDigest *
func newImageDestination(sys *types.SystemContext, imageRef storageReference) (*storageImageDestination, error) {
directory, err := ioutil.TempDir(tmpdir.TemporaryDirectoryForBigFiles(sys), "storage")
if err != nil {
- return nil, errors.Wrapf(err, "error creating a temporary directory")
+ return nil, errors.Wrapf(err, "creating a temporary directory")
}
image := &storageImageDestination{
imageRef: imageRef,
@@ -403,6 +407,7 @@ func newImageDestination(sys *types.SystemContext, imageRef storageReference) (*
SignaturesSizes: make(map[digest.Digest][]int),
indexToStorageID: make(map[int]*string),
indexToPulledLayerInfo: make(map[int]*manifest.LayerInfo),
+ diffOutputs: make(map[digest.Digest]*graphdriver.DriverWithDifferOutput),
}
return image, nil
}
@@ -418,6 +423,11 @@ func (s *storageImageDestination) Close() error {
for _, al := range s.blobAdditionalLayer {
al.Release()
}
+ for _, v := range s.diffOutputs {
+ if v.Target != "" {
+ _ = s.imageRef.transport.store.CleanupStagingDirectory(v.Target)
+ }
+ }
return os.RemoveAll(s.directory)
}
@@ -483,21 +493,21 @@ func (s *storageImageDestination) PutBlob(ctx context.Context, stream io.Reader,
filename := s.computeNextBlobCacheFile()
file, err := os.OpenFile(filename, os.O_CREATE|os.O_TRUNC|os.O_WRONLY|os.O_EXCL, 0600)
if err != nil {
- return errorBlobInfo, errors.Wrapf(err, "error creating temporary file %q", filename)
+ return errorBlobInfo, errors.Wrapf(err, "creating temporary file %q", filename)
}
defer file.Close()
counter := ioutils.NewWriteCounter(hasher.Hash())
reader := io.TeeReader(io.TeeReader(stream, counter), file)
decompressed, err := archive.DecompressStream(reader)
if err != nil {
- return errorBlobInfo, errors.Wrap(err, "error setting up to decompress blob")
+ return errorBlobInfo, errors.Wrap(err, "setting up to decompress blob")
}
// Copy the data to the file.
// TODO: This can take quite some time, and should ideally be cancellable using ctx.Done().
_, err = io.Copy(diffID.Hash(), decompressed)
decompressed.Close()
if err != nil {
- return errorBlobInfo, errors.Wrapf(err, "error storing blob to file %q", filename)
+ return errorBlobInfo, errors.Wrapf(err, "storing blob to file %q", filename)
}
// Ensure that any information that we were given about the blob is correct.
if blobinfo.Digest.Validate() == nil && blobinfo.Digest != hasher.Digest() {
@@ -556,7 +566,7 @@ func (s *storageImageDestination) tryReusingBlobWithSrcRef(ctx context.Context,
// 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)
+ return false, types.BlobInfo{}, errors.Wrapf(err, `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()
@@ -572,6 +582,61 @@ func (s *storageImageDestination) tryReusingBlobWithSrcRef(ctx context.Context,
return s.tryReusingBlobLocked(ctx, blobinfo, cache, canSubstitute)
}
+type zstdFetcher struct {
+ stream internalTypes.ImageSourceSeekable
+ ctx context.Context
+ blobInfo types.BlobInfo
+}
+
+// GetBlobAt converts from chunked.GetBlobAt to ImageSourceSeekable.GetBlobAt.
+func (f *zstdFetcher) GetBlobAt(chunks []chunked.ImageSourceChunk) (chan io.ReadCloser, chan error, error) {
+ var newChunks []internalTypes.ImageSourceChunk
+ for _, v := range chunks {
+ i := internalTypes.ImageSourceChunk{
+ Offset: v.Offset,
+ Length: v.Length,
+ }
+ newChunks = append(newChunks, i)
+ }
+ rc, errs, err := f.stream.GetBlobAt(f.ctx, f.blobInfo, newChunks)
+ if _, ok := err.(internalTypes.BadPartialRequestError); ok {
+ err = chunked.ErrBadRequest{}
+ }
+ return rc, errs, err
+
+}
+
+// PutBlobPartial attempts to create a blob using the data that is already present at the destination storage. stream is accessed
+// in a non-sequential way to retrieve the missing chunks.
+func (s *storageImageDestination) PutBlobPartial(ctx context.Context, stream internalTypes.ImageSourceSeekable, srcInfo types.BlobInfo, cache types.BlobInfoCache) (types.BlobInfo, error) {
+ fetcher := zstdFetcher{
+ stream: stream,
+ ctx: ctx,
+ blobInfo: srcInfo,
+ }
+
+ differ, err := chunked.GetDiffer(ctx, s.imageRef.transport.store, srcInfo.Size, srcInfo.Annotations, &fetcher)
+ if err != nil {
+ return srcInfo, err
+ }
+
+ out, err := s.imageRef.transport.store.ApplyDiffWithDiffer("", nil, differ)
+ if err != nil {
+ return srcInfo, err
+ }
+
+ blobDigest := srcInfo.Digest
+
+ s.lock.Lock()
+ s.blobDiffIDs[blobDigest] = blobDigest
+ s.fileSizes[blobDigest] = 0
+ s.filenames[blobDigest] = ""
+ s.diffOutputs[blobDigest] = out
+ s.lock.Unlock()
+
+ return srcInfo, nil
+}
+
// 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.
@@ -611,7 +676,7 @@ func (s *storageImageDestination) tryReusingBlobLocked(ctx context.Context, blob
// Check if we have a wasn't-compressed layer in storage that's based on that blob.
layers, err := s.imageRef.transport.store.LayersByUncompressedDigest(blobinfo.Digest)
if err != nil && errors.Cause(err) != storage.ErrLayerUnknown {
- return false, types.BlobInfo{}, errors.Wrapf(err, `Error looking for layers with digest %q`, blobinfo.Digest)
+ return false, types.BlobInfo{}, errors.Wrapf(err, `looking for layers with digest %q`, blobinfo.Digest)
}
if len(layers) > 0 {
// Save this for completeness.
@@ -626,7 +691,7 @@ func (s *storageImageDestination) tryReusingBlobLocked(ctx context.Context, blob
// Check if we have a was-compressed layer in storage that's based on that blob.
layers, err = s.imageRef.transport.store.LayersByCompressedDigest(blobinfo.Digest)
if err != nil && errors.Cause(err) != storage.ErrLayerUnknown {
- return false, types.BlobInfo{}, errors.Wrapf(err, `Error looking for compressed layers with digest %q`, blobinfo.Digest)
+ return false, types.BlobInfo{}, errors.Wrapf(err, `looking for compressed layers with digest %q`, blobinfo.Digest)
}
if len(layers) > 0 {
// Record the uncompressed value so that we can use it to calculate layer IDs.
@@ -645,7 +710,7 @@ func (s *storageImageDestination) tryReusingBlobLocked(ctx context.Context, blob
if uncompressedDigest := cache.UncompressedDigest(blobinfo.Digest); uncompressedDigest != "" && uncompressedDigest != blobinfo.Digest {
layers, err := s.imageRef.transport.store.LayersByUncompressedDigest(uncompressedDigest)
if err != nil && errors.Cause(err) != storage.ErrLayerUnknown {
- return false, types.BlobInfo{}, errors.Wrapf(err, `Error looking for layers with digest %q`, uncompressedDigest)
+ return false, types.BlobInfo{}, errors.Wrapf(err, `looking for layers with digest %q`, uncompressedDigest)
}
if len(layers) > 0 {
if blobinfo.Size != -1 {
@@ -720,7 +785,7 @@ func (s *storageImageDestination) getConfigBlob(info types.BlobInfo) ([]byte, er
if filename, ok := s.filenames[info.Digest]; ok {
contents, err2 := ioutil.ReadFile(filename)
if err2 != nil {
- return nil, errors.Wrapf(err2, `error reading blob from file %q`, filename)
+ return nil, errors.Wrapf(err2, `reading blob from file %q`, filename)
}
return contents, nil
}
@@ -822,7 +887,7 @@ func (s *storageImageDestination) commitLayer(ctx context.Context, blob manifest
// NOTE: use `TryReusingBlob` to prevent recursion.
has, _, err := s.TryReusingBlob(ctx, blob.BlobInfo, none.NoCache, false)
if err != nil {
- return errors.Wrapf(err, "error checking for a layer based on blob %q", blob.Digest.String())
+ return errors.Wrapf(err, "checking for a layer based on blob %q", blob.Digest.String())
}
if !has {
return errors.Errorf("error determining uncompressed digest for blob %q", blob.Digest.String())
@@ -844,6 +909,27 @@ func (s *storageImageDestination) commitLayer(ctx context.Context, blob manifest
}
s.lock.Lock()
+ diffOutput, ok := s.diffOutputs[blob.Digest]
+ s.lock.Unlock()
+ if ok {
+ layer, err := s.imageRef.transport.store.CreateLayer(id, lastLayer, nil, "", false, nil)
+ if err != nil {
+ return err
+ }
+
+ // FIXME: what to do with the uncompressed digest?
+ diffOutput.UncompressedDigest = blob.Digest
+
+ if err := s.imageRef.transport.store.ApplyDiffFromStagingDirectory(layer.ID, diffOutput.Target, diffOutput, nil); err != nil {
+ _ = s.imageRef.transport.store.Delete(layer.ID)
+ return err
+ }
+
+ s.indexToStorageID[index] = &layer.ID
+ return nil
+ }
+
+ s.lock.Lock()
al, ok := s.blobAdditionalLayer[blob.Digest]
s.lock.Unlock()
if ok {
@@ -874,7 +960,7 @@ func (s *storageImageDestination) commitLayer(ctx context.Context, blob manifest
}
}
if layer == "" {
- return errors.Wrapf(err2, "error locating layer for blob %q", blob.Digest)
+ return errors.Wrapf(err2, "locating layer for blob %q", blob.Digest)
}
// Read the layer's contents.
noCompression := archive.Uncompressed
@@ -883,7 +969,7 @@ func (s *storageImageDestination) commitLayer(ctx context.Context, blob manifest
}
diff, err2 := s.imageRef.transport.store.Diff("", layer, diffOptions)
if err2 != nil {
- return errors.Wrapf(err2, "error reading layer %q for blob %q", layer, blob.Digest)
+ return errors.Wrapf(err2, "reading layer %q for blob %q", layer, blob.Digest)
}
// Copy the layer diff to a file. Diff() takes a lock that it holds
// until the ReadCloser that it returns is closed, and PutLayer() wants
@@ -893,7 +979,7 @@ func (s *storageImageDestination) commitLayer(ctx context.Context, blob manifest
file, err := os.OpenFile(filename, os.O_CREATE|os.O_TRUNC|os.O_WRONLY|os.O_EXCL, 0600)
if err != nil {
diff.Close()
- return errors.Wrapf(err, "error creating temporary file %q", filename)
+ return errors.Wrapf(err, "creating temporary file %q", filename)
}
// Copy the data to the file.
// TODO: This can take quite some time, and should ideally be cancellable using
@@ -902,7 +988,7 @@ func (s *storageImageDestination) commitLayer(ctx context.Context, blob manifest
diff.Close()
file.Close()
if err != nil {
- return errors.Wrapf(err, "error storing blob to file %q", filename)
+ return errors.Wrapf(err, "storing blob to file %q", filename)
}
// Make sure that we can find this file later, should we need the layer's
// contents again.
@@ -913,27 +999,34 @@ func (s *storageImageDestination) commitLayer(ctx context.Context, blob manifest
// Read the cached blob and use it as a diff.
file, err := os.Open(filename)
if err != nil {
- return errors.Wrapf(err, "error opening file %q", filename)
+ return errors.Wrapf(err, "opening file %q", filename)
}
defer file.Close()
// Build the new layer using the diff, regardless of where it came from.
// TODO: This can take quite some time, and should ideally be cancellable using ctx.Done().
layer, _, err := s.imageRef.transport.store.PutLayer(id, lastLayer, nil, "", false, nil, file)
if err != nil && errors.Cause(err) != storage.ErrDuplicateID {
- return errors.Wrapf(err, "error adding layer with blob %q", blob.Digest)
+ return errors.Wrapf(err, "adding layer with blob %q", blob.Digest)
}
s.indexToStorageID[index] = &layer.ID
return nil
}
+// Commit marks the process of storing the image as successful and asks for the image to be persisted.
+// unparsedToplevel contains data about the top-level manifest of the source (which may be a single-arch image or a manifest list
+// if PutManifest was only called for the single-arch image with instanceDigest == nil), primarily to allow lookups by the
+// original manifest list digest, if desired.
+// WARNING: This does not have any transactional semantics:
+// - Uploaded data MAY be visible to others before Commit() is called
+// - Uploaded data MAY be removed or MAY remain around if Close() is called without Commit() (i.e. rollback is allowed but not guaranteed)
func (s *storageImageDestination) Commit(ctx context.Context, unparsedToplevel types.UnparsedImage) error {
if len(s.manifest) == 0 {
return errors.New("Internal error: storageImageDestination.Commit() called without PutManifest()")
}
toplevelManifest, _, err := unparsedToplevel.Manifest(ctx)
if err != nil {
- return errors.Wrapf(err, "error retrieving top-level manifest")
+ return errors.Wrapf(err, "retrieving top-level manifest")
}
// If the name we're saving to includes a digest, then check that the
// manifests that we're about to save all either match the one from the
@@ -956,14 +1049,12 @@ func (s *storageImageDestination) Commit(ctx context.Context, unparsedToplevel t
}
}
// Find the list of layer blobs.
- if len(s.manifest) == 0 {
- return errors.New("Internal error: storageImageDestination.Commit() called without PutManifest()")
- }
man, err := manifest.FromBlob(s.manifest, manifest.GuessMIMEType(s.manifest))
if err != nil {
- return errors.Wrapf(err, "error parsing manifest")
+ return errors.Wrapf(err, "parsing manifest")
}
layerBlobs := man.LayerInfos()
+
// Extract, commit, or find the layers.
for i, blob := range layerBlobs {
if err := s.commitLayer(ctx, blob, i); err != nil {
@@ -996,11 +1087,11 @@ func (s *storageImageDestination) Commit(ctx context.Context, unparsedToplevel t
if err != nil {
if errors.Cause(err) != storage.ErrDuplicateID {
logrus.Debugf("error creating image: %q", err)
- return errors.Wrapf(err, "error creating image %q", intendedID)
+ return errors.Wrapf(err, "creating image %q", intendedID)
}
img, err = s.imageRef.transport.store.Image(intendedID)
if err != nil {
- return errors.Wrapf(err, "error reading image %q", intendedID)
+ return errors.Wrapf(err, "reading image %q", intendedID)
}
if img.TopLayer != lastLayer {
logrus.Debugf("error creating image: image with ID %q exists, but uses different layers", intendedID)
@@ -1011,6 +1102,19 @@ func (s *storageImageDestination) Commit(ctx context.Context, unparsedToplevel t
} else {
logrus.Debugf("created new image ID %q", img.ID)
}
+
+ // Clean up the unfinished image on any error.
+ // (Is this the right thing to do if the image has existed before?)
+ commitSucceeded := false
+ defer func() {
+ if !commitSucceeded {
+ logrus.Errorf("Updating image %q (old names %v) failed, deleting it", img.ID, oldNames)
+ if _, err := s.imageRef.transport.store.DeleteImage(img.ID, true); err != nil {
+ logrus.Errorf("Error deleting incomplete image %q: %v", img.ID, err)
+ }
+ }
+ }()
+
// Add the non-layer blobs as data items. Since we only share layers, they should all be in files, so
// we just need to screen out the ones that are actually layers to get the list of non-layers.
dataBlobs := make(map[digest.Digest]struct{})
@@ -1023,90 +1127,62 @@ func (s *storageImageDestination) Commit(ctx context.Context, unparsedToplevel t
for blob := range dataBlobs {
v, err := ioutil.ReadFile(s.filenames[blob])
if err != nil {
- return errors.Wrapf(err, "error copying non-layer blob %q to image", blob)
+ return errors.Wrapf(err, "copying non-layer blob %q to image", blob)
}
if err := s.imageRef.transport.store.SetImageBigData(img.ID, blob.String(), v, manifest.Digest); err != nil {
- if _, err2 := s.imageRef.transport.store.DeleteImage(img.ID, true); err2 != nil {
- logrus.Debugf("error deleting incomplete image %q: %v", img.ID, err2)
- }
logrus.Debugf("error saving big data %q for image %q: %v", blob.String(), img.ID, err)
- return errors.Wrapf(err, "error saving big data %q for image %q", blob.String(), img.ID)
+ return errors.Wrapf(err, "saving big data %q for image %q", blob.String(), img.ID)
}
}
- // Save the unparsedToplevel's manifest.
- if len(toplevelManifest) != 0 {
+ // Save the unparsedToplevel's manifest if it differs from the per-platform one, which is saved below.
+ if len(toplevelManifest) != 0 && !bytes.Equal(toplevelManifest, s.manifest) {
manifestDigest, err := manifest.Digest(toplevelManifest)
if err != nil {
- return errors.Wrapf(err, "error digesting top-level manifest")
+ return errors.Wrapf(err, "digesting top-level manifest")
}
key := manifestBigDataKey(manifestDigest)
if err := s.imageRef.transport.store.SetImageBigData(img.ID, key, toplevelManifest, manifest.Digest); err != nil {
- if _, err2 := s.imageRef.transport.store.DeleteImage(img.ID, true); err2 != nil {
- logrus.Debugf("error deleting incomplete image %q: %v", img.ID, err2)
- }
logrus.Debugf("error saving top-level manifest for image %q: %v", img.ID, err)
- return errors.Wrapf(err, "error saving top-level manifest for image %q", img.ID)
+ return errors.Wrapf(err, "saving top-level manifest for image %q", img.ID)
}
}
// Save the image's manifest. Allow looking it up by digest by using the key convention defined by the Store.
// Record the manifest twice: using a digest-specific key to allow references to that specific digest instance,
// and using storage.ImageDigestBigDataKey for future users that don’t specify any digest and for compatibility with older readers.
- manifestDigest, err := manifest.Digest(s.manifest)
- if err != nil {
- return errors.Wrapf(err, "error computing manifest digest")
- }
- key := manifestBigDataKey(manifestDigest)
+ key := manifestBigDataKey(s.manifestDigest)
if err := s.imageRef.transport.store.SetImageBigData(img.ID, key, s.manifest, manifest.Digest); err != nil {
- if _, err2 := s.imageRef.transport.store.DeleteImage(img.ID, true); err2 != nil {
- logrus.Debugf("error deleting incomplete image %q: %v", img.ID, err2)
- }
logrus.Debugf("error saving manifest for image %q: %v", img.ID, err)
- return errors.Wrapf(err, "error saving manifest for image %q", img.ID)
+ return errors.Wrapf(err, "saving manifest for image %q", img.ID)
}
key = storage.ImageDigestBigDataKey
if err := s.imageRef.transport.store.SetImageBigData(img.ID, key, s.manifest, manifest.Digest); err != nil {
- if _, err2 := s.imageRef.transport.store.DeleteImage(img.ID, true); err2 != nil {
- logrus.Debugf("error deleting incomplete image %q: %v", img.ID, err2)
- }
logrus.Debugf("error saving manifest for image %q: %v", img.ID, err)
- return errors.Wrapf(err, "error saving manifest for image %q", img.ID)
+ return errors.Wrapf(err, "saving manifest for image %q", img.ID)
}
// Save the signatures, if we have any.
if len(s.signatures) > 0 {
if err := s.imageRef.transport.store.SetImageBigData(img.ID, "signatures", s.signatures, manifest.Digest); err != nil {
- if _, err2 := s.imageRef.transport.store.DeleteImage(img.ID, true); err2 != nil {
- logrus.Debugf("error deleting incomplete image %q: %v", img.ID, err2)
- }
logrus.Debugf("error saving signatures for image %q: %v", img.ID, err)
- return errors.Wrapf(err, "error saving signatures for image %q", img.ID)
+ return errors.Wrapf(err, "saving signatures for image %q", img.ID)
}
}
for instanceDigest, signatures := range s.signatureses {
key := signatureBigDataKey(instanceDigest)
if err := s.imageRef.transport.store.SetImageBigData(img.ID, key, signatures, manifest.Digest); err != nil {
- if _, err2 := s.imageRef.transport.store.DeleteImage(img.ID, true); err2 != nil {
- logrus.Debugf("error deleting incomplete image %q: %v", img.ID, err2)
- }
logrus.Debugf("error saving signatures for image %q: %v", img.ID, err)
- return errors.Wrapf(err, "error saving signatures for image %q", img.ID)
+ return errors.Wrapf(err, "saving signatures for image %q", img.ID)
}
}
// Save our metadata.
metadata, err := json.Marshal(s)
if err != nil {
- if _, err2 := s.imageRef.transport.store.DeleteImage(img.ID, true); err2 != nil {
- logrus.Debugf("error deleting incomplete image %q: %v", img.ID, err2)
- }
logrus.Debugf("error encoding metadata for image %q: %v", img.ID, err)
- return errors.Wrapf(err, "error encoding metadata for image %q", img.ID)
+ return errors.Wrapf(err, "encoding metadata for image %q", img.ID)
}
if len(metadata) != 0 {
if err = s.imageRef.transport.store.SetMetadata(img.ID, string(metadata)); err != nil {
- if _, err2 := s.imageRef.transport.store.DeleteImage(img.ID, true); err2 != nil {
- logrus.Debugf("error deleting incomplete image %q: %v", img.ID, err2)
- }
logrus.Debugf("error saving metadata for image %q: %v", img.ID, err)
- return errors.Wrapf(err, "error saving metadata for image %q", img.ID)
+ return errors.Wrapf(err, "saving metadata for image %q", img.ID)
}
logrus.Debugf("saved image metadata %q", string(metadata))
}
@@ -1121,14 +1197,13 @@ func (s *storageImageDestination) Commit(ctx context.Context, unparsedToplevel t
names = append(names, oldNames...)
}
if err := s.imageRef.transport.store.SetNames(img.ID, names); err != nil {
- if _, err2 := s.imageRef.transport.store.DeleteImage(img.ID, true); err2 != nil {
- logrus.Debugf("error deleting incomplete image %q: %v", img.ID, err2)
- }
logrus.Debugf("error setting names %v on image %q: %v", names, img.ID, err)
- return errors.Wrapf(err, "error setting names %v on image %q", names, img.ID)
+ return errors.Wrapf(err, "setting names %v on image %q", names, img.ID)
}
logrus.Debugf("set names of image %q to %v", img.ID, names)
}
+
+ commitSucceeded = true
return nil
}
@@ -1145,9 +1220,14 @@ func (s *storageImageDestination) SupportedManifestMIMETypes() []string {
// PutManifest writes the manifest to the destination.
func (s *storageImageDestination) PutManifest(ctx context.Context, manifestBlob []byte, instanceDigest *digest.Digest) error {
+ digest, err := manifest.Digest(manifestBlob)
+ if err != nil {
+ return err
+ }
newBlob := make([]byte, len(manifestBlob))
copy(newBlob, manifestBlob)
s.manifest = newBlob
+ s.manifestDigest = digest
return nil
}
@@ -1189,13 +1269,10 @@ func (s *storageImageDestination) PutSignatures(ctx context.Context, signatures
if instanceDigest == nil {
s.signatures = sigblob
s.SignatureSizes = sizes
- }
- if instanceDigest == nil && len(s.manifest) > 0 {
- manifestDigest, err := manifest.Digest(s.manifest)
- if err != nil {
- return err
+ if len(s.manifest) > 0 {
+ manifestDigest := s.manifestDigest
+ instanceDigest = &manifestDigest
}
- instanceDigest = &manifestDigest
}
if instanceDigest != nil {
s.signatureses[*instanceDigest] = sigblob
@@ -1211,12 +1288,12 @@ func (s *storageImageSource) getSize() (int64, error) {
// Size up the data blobs.
dataNames, err := s.imageRef.transport.store.ListImageBigData(s.image.ID)
if err != nil {
- return -1, errors.Wrapf(err, "error reading image %q", s.image.ID)
+ return -1, errors.Wrapf(err, "reading image %q", s.image.ID)
}
for _, dataName := range dataNames {
bigSize, err := s.imageRef.transport.store.ImageBigDataSize(s.image.ID, dataName)
if err != nil {
- return -1, errors.Wrapf(err, "error reading data blob size %q for %q", dataName, s.image.ID)
+ return -1, errors.Wrapf(err, "reading data blob size %q for %q", dataName, s.image.ID)
}
sum += bigSize
}
diff --git a/vendor/github.com/containers/image/v5/storage/storage_reference.go b/vendor/github.com/containers/image/v5/storage/storage_reference.go
index 394557f39..1aafe9068 100644
--- a/vendor/github.com/containers/image/v5/storage/storage_reference.go
+++ b/vendor/github.com/containers/image/v5/storage/storage_reference.go
@@ -11,7 +11,6 @@ import (
"github.com/containers/image/v5/types"
"github.com/containers/storage"
digest "github.com/opencontainers/go-digest"
- imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
@@ -62,18 +61,17 @@ func imageMatchesRepo(image *storage.Image, ref reference.Named) bool {
return false
}
-// imageMatchesSystemContext checks if the passed-in image both contains a
-// manifest that matches the passed-in digest, and identifies itself as being
-// appropriate for running on the system that matches sys.
-// If we somehow ended up sharing the same storage among multiple types of
-// systems, and managed to download multiple images from the same manifest
-// list, their image records will all contain copies of the manifest list, and
-// this check will help us decide which of them we want to return when we've
-// been asked to resolve an image reference that uses the list's digest to a
-// specific image ID.
-func imageMatchesSystemContext(store storage.Store, img *storage.Image, manifestDigest digest.Digest, sys *types.SystemContext) bool {
- // First, check if the image record has a manifest that matches the
- // specified digest.
+// multiArchImageMatchesSystemContext returns true if if the passed-in image both contains a
+// multi-arch manifest that matches the passed-in digest, and the image is the per-platform
+// image instance that matches sys.
+//
+// See the comment in storageReference.ResolveImage explaining why
+// this check is necessary.
+func multiArchImageMatchesSystemContext(store storage.Store, img *storage.Image, manifestDigest digest.Digest, sys *types.SystemContext) bool {
+ // Load the manifest that matches the specified digest.
+ // We don't need to care about storage.ImageDigestBigDataKey because
+ // manifests lists are only stored into storage by c/image versions
+ // that know about manifestBigDataKey, and only using that key.
key := manifestBigDataKey(manifestDigest)
manifestBytes, err := store.ImageBigData(img.ID, key)
if err != nil {
@@ -83,56 +81,22 @@ func imageMatchesSystemContext(store storage.Store, img *storage.Image, manifest
// the digest of the instance that matches the current system, and try
// to load that manifest from the image record, and use it.
manifestType := manifest.GuessMIMEType(manifestBytes)
- if manifest.MIMETypeIsMultiImage(manifestType) {
- list, err := manifest.ListFromBlob(manifestBytes, manifestType)
- if err != nil {
- return false
- }
- manifestDigest, err = list.ChooseInstance(sys)
- if err != nil {
- return false
- }
- key = manifestBigDataKey(manifestDigest)
- manifestBytes, err = store.ImageBigData(img.ID, key)
- if err != nil {
- return false
- }
- manifestType = manifest.GuessMIMEType(manifestBytes)
- }
- // Load the image's configuration blob.
- m, err := manifest.FromBlob(manifestBytes, manifestType)
- if err != nil {
+ if !manifest.MIMETypeIsMultiImage(manifestType) {
+ // manifestDigest directly specifies a per-platform image, so we aren't
+ // choosing among different variants.
return false
}
- getConfig := func(blobInfo types.BlobInfo) ([]byte, error) {
- return store.ImageBigData(img.ID, blobInfo.Digest.String())
- }
- ii, err := m.Inspect(getConfig)
+ list, err := manifest.ListFromBlob(manifestBytes, manifestType)
if err != nil {
return false
}
- // Build a dummy index containing one instance and information about
- // the image's target system from the image's configuration.
- index := manifest.OCI1IndexFromComponents([]imgspecv1.Descriptor{{
- MediaType: imgspecv1.MediaTypeImageManifest,
- Digest: manifestDigest,
- Size: int64(len(manifestBytes)),
- Platform: &imgspecv1.Platform{
- OS: ii.Os,
- Architecture: ii.Architecture,
- },
- }}, nil)
- // Check that ChooseInstance() would select this image for this system,
- // from a list of images.
- instanceDigest, err := index.ChooseInstance(sys)
+ chosenInstance, err := list.ChooseInstance(sys)
if err != nil {
return false
}
- // Double-check that we can read the runnable image's manifest from the
- // image record.
- key = manifestBigDataKey(instanceDigest)
+ key = manifestBigDataKey(chosenInstance)
_, err = store.ImageBigData(img.ID, key)
- return err == nil
+ return err == nil // true if img.ID is based on chosenInstance.
}
// Resolve the reference's name to an image ID in the store, if there's already
@@ -152,11 +116,24 @@ func (s *storageReference) resolveImage(sys *types.SystemContext) (*storage.Imag
// Look for an image with the specified digest that has the same name,
// though possibly with a different tag or digest, as a Name value, so
// that the canonical reference can be implicitly resolved to the image.
+ //
+ // Typically there should be at most one such image, because the same
+ // manifest digest implies the same config, and we choose the storage ID
+ // based on the config (deduplicating images), except:
+ // - the user can explicitly specify an ID when creating the image.
+ // In this case we don't have a preference among the alternatives.
+ // - when pulling an image from a multi-platform manifest list, we also
+ // store the manifest list in the image; this allows referencing a
+ // per-platform image using the manifest list digest, but that also
+ // means that we can have multiple genuinely different images in the
+ // storage matching the same manifest list digest (if pulled using different
+ // SystemContext.{OS,Architecture,Variant}Choice to the same storage).
+ // In this case we prefer the image matching the current SystemContext.
images, err := s.transport.store.ImagesByDigest(digested.Digest())
if err == nil && len(images) > 0 {
for _, image := range images {
if imageMatchesRepo(image, s.named) {
- if loadedImage == nil || imageMatchesSystemContext(s.transport.store, image, digested.Digest(), sys) {
+ if loadedImage == nil || multiArchImageMatchesSystemContext(s.transport.store, image, digested.Digest(), sys) {
loadedImage = image
s.id = image.ID
}
@@ -172,7 +149,7 @@ func (s *storageReference) resolveImage(sys *types.SystemContext) (*storage.Imag
if loadedImage == nil {
img, err := s.transport.store.Image(s.id)
if err != nil {
- return nil, errors.Wrapf(err, "error reading image %q", s.id)
+ return nil, errors.Wrapf(err, "reading image %q", s.id)
}
loadedImage = img
}
diff --git a/vendor/github.com/containers/image/v5/storage/storage_transport.go b/vendor/github.com/containers/image/v5/storage/storage_transport.go
index c024bee9b..d4c85b725 100644
--- a/vendor/github.com/containers/image/v5/storage/storage_transport.go
+++ b/vendor/github.com/containers/image/v5/storage/storage_transport.go
@@ -172,7 +172,7 @@ func (s storageTransport) ParseStoreReference(store storage.Store, ref string) (
var err error
named, err = reference.ParseNormalizedNamed(ref)
if err != nil {
- return nil, errors.Wrapf(err, "error parsing named reference %q", ref)
+ return nil, errors.Wrapf(err, "parsing named reference %q", ref)
}
named = reference.TagNameOnly(named)
}
@@ -303,7 +303,7 @@ func (s storageTransport) GetStoreImage(store storage.Store, ref types.ImageRefe
}
if sref, ok := ref.(*storageReference); ok {
tmpRef := *sref
- if img, err := tmpRef.resolveImage(&types.SystemContext{}); err == nil {
+ if img, err := tmpRef.resolveImage(nil); err == nil {
return img, nil
}
}
diff --git a/vendor/github.com/containers/image/v5/types/types.go b/vendor/github.com/containers/image/v5/types/types.go
index 3e7abd34d..1c4a1419f 100644
--- a/vendor/github.com/containers/image/v5/types/types.go
+++ b/vendor/github.com/containers/image/v5/types/types.go
@@ -334,6 +334,9 @@ type ImageDestination interface {
// MUST be called after PutManifest (signatures may reference manifest contents).
PutSignatures(ctx context.Context, signatures [][]byte, instanceDigest *digest.Digest) error
// Commit marks the process of storing the image as successful and asks for the image to be persisted.
+ // unparsedToplevel contains data about the top-level manifest of the source (which may be a single-arch image or a manifest list
+ // if PutManifest was only called for the single-arch image with instanceDigest == nil), primarily to allow lookups by the
+ // original manifest list digest, if desired.
// WARNING: This does not have any transactional semantics:
// - Uploaded data MAY be visible to others before Commit() is called
// - Uploaded data MAY be removed or MAY remain around if Close() is called without Commit() (i.e. rollback is allowed but not guaranteed)
@@ -595,12 +598,12 @@ type SystemContext struct {
// === docker.Transport overrides ===
// If not "", a directory containing a CA certificate (ending with ".crt"),
// a client certificate (ending with ".cert") and a client certificate key
- // (ending with ".key") used when talking to a Docker Registry.
+ // (ending with ".key") used when talking to a container registry.
DockerCertPath string
// If not "", overrides the system’s default path for a directory containing host[:port] subdirectories with the same structure as DockerCertPath above.
// Ignored if DockerCertPath is non-empty.
DockerPerHostCertDirPath string
- // Allow contacting docker registries over HTTP, or HTTPS with failed TLS verification. Note that this does not affect other TLS connections.
+ // Allow contacting container registries over HTTP, or HTTPS with failed TLS verification. Note that this does not affect other TLS connections.
DockerInsecureSkipTLSVerify OptionalBool
// if nil, the library tries to parse ~/.docker/config.json to retrieve credentials
// Ignored if DockerBearerRegistryToken is non-empty.
@@ -633,6 +636,8 @@ type SystemContext struct {
// === dir.Transport overrides ===
// DirForceCompress compresses the image layers if set to true
DirForceCompress bool
+ // DirForceDecompress decompresses the image layers if set to true
+ DirForceDecompress bool
// CompressionFormat is the format to use for the compression of the blobs
CompressionFormat *compression.Algorithm
diff --git a/vendor/github.com/containers/image/v5/version/version.go b/vendor/github.com/containers/image/v5/version/version.go
index edf4681de..8936ec087 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 = 13
+ VersionMinor = 15
// VersionPatch is for backwards-compatible bug fixes
- VersionPatch = 2
+ VersionPatch = 0
// VersionDev indicates development branch. Releases will be empty string.
VersionDev = ""
diff --git a/vendor/github.com/containers/storage/VERSION b/vendor/github.com/containers/storage/VERSION
index 5d245052c..02261bead 100644
--- a/vendor/github.com/containers/storage/VERSION
+++ b/vendor/github.com/containers/storage/VERSION
@@ -1 +1 @@
-1.32.6
+1.33.1
diff --git a/vendor/github.com/containers/storage/drivers/overlay/overlay.go b/vendor/github.com/containers/storage/drivers/overlay/overlay.go
index 2fa54a207..ecfbae916 100644
--- a/vendor/github.com/containers/storage/drivers/overlay/overlay.go
+++ b/vendor/github.com/containers/storage/drivers/overlay/overlay.go
@@ -364,12 +364,12 @@ func Init(home string, options graphdriver.Options) (graphdriver.Driver, error)
// Try to enable project quota support over xfs.
if d.quotaCtl, err = quota.NewControl(home); err == nil {
projectQuotaSupported = true
- } else if opts.quota.Size > 0 {
- return nil, fmt.Errorf("Storage option overlay.size not supported. Filesystem does not support Project Quota: %v", err)
+ } else if opts.quota.Size > 0 || opts.quota.Inodes > 0 {
+ return nil, fmt.Errorf("Storage options overlay.size and overlay.inodes not supported. Filesystem does not support Project Quota: %v", err)
}
- } else if opts.quota.Size > 0 {
+ } else if opts.quota.Size > 0 || opts.quota.Inodes > 0 {
// if xfs is not the backing fs then error out if the storage-opt overlay.size is used.
- return nil, fmt.Errorf("Storage option overlay.size only supported for backingFS XFS. Found %v", backingFs)
+ return nil, fmt.Errorf("Storage option overlay.size and overlay.inodes only supported for backingFS XFS. Found %v", backingFs)
}
logrus.Debugf("backingFs=%s, projectQuotaSupported=%v, useNativeDiff=%v, usingMetacopy=%v", backingFs, projectQuotaSupported, !d.useNaiveDiff(), d.usingMetacopy)
@@ -400,6 +400,13 @@ func parseOptions(options []string) (*overlayOptions, error) {
return nil, err
}
o.quota.Size = uint64(size)
+ case "inodes":
+ logrus.Debugf("overlay: inodes=%s", val)
+ inodes, err := strconv.ParseUint(val, 10, 64)
+ if err != nil {
+ return nil, err
+ }
+ o.quota.Inodes = uint64(inodes)
case "imagestore", "additionalimagestore":
logrus.Debugf("overlay: imagestore=%s", val)
// Additional read only image stores to use for lower paths
@@ -613,6 +620,10 @@ func supportsOverlay(home string, homeMagic graphdriver.FsMagic, rootUID, rootGI
if unshare.IsRootless() {
flags = fmt.Sprintf("%s,userxattr", flags)
}
+ if err := syscall.Mknod(filepath.Join(upperDir, "whiteout"), syscall.S_IFCHR|0600, int(unix.Mkdev(0, 0))); err != nil {
+ logrus.Debugf("unable to create kernel-style whiteout: %v", err)
+ return supportsDType, errors.Wrapf(err, "unable to create kernel-style whiteout")
+ }
if len(flags) < unix.Getpagesize() {
err := unix.Mount("overlay", mergedDir, "overlay", 0, flags)
@@ -784,6 +795,13 @@ func (d *Driver) CreateReadWrite(id, parent string, opts *graphdriver.CreateOpts
opts.StorageOpt["size"] = strconv.FormatUint(d.options.quota.Size, 10)
}
+ if _, ok := opts.StorageOpt["inodes"]; !ok {
+ if opts.StorageOpt == nil {
+ opts.StorageOpt = map[string]string{}
+ }
+ opts.StorageOpt["inodes"] = strconv.FormatUint(d.options.quota.Inodes, 10)
+ }
+
return d.create(id, parent, opts)
}
@@ -794,6 +812,9 @@ func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) (retErr
if _, ok := opts.StorageOpt["size"]; ok {
return fmt.Errorf("--storage-opt size is only supported for ReadWrite Layers")
}
+ if _, ok := opts.StorageOpt["inodes"]; ok {
+ return fmt.Errorf("--storage-opt inodes is only supported for ReadWrite Layers")
+ }
}
return d.create(id, parent, opts)
@@ -850,7 +871,9 @@ func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts) (retErr
if driver.options.quota.Size > 0 {
quota.Size = driver.options.quota.Size
}
-
+ if driver.options.quota.Inodes > 0 {
+ quota.Inodes = driver.options.quota.Inodes
+ }
}
// Set container disk quota limit
// If it is set to 0, we will track the disk usage, but not enforce a limit
@@ -922,6 +945,12 @@ func (d *Driver) parseStorageOpt(storageOpt map[string]string, driver *Driver) e
return err
}
driver.options.quota.Size = uint64(size)
+ case "inodes":
+ inodes, err := strconv.ParseUint(val, 10, 64)
+ if err != nil {
+ return err
+ }
+ driver.options.quota.Inodes = uint64(inodes)
default:
return fmt.Errorf("Unknown option %s", key)
}
diff --git a/vendor/github.com/containers/storage/drivers/quota/projectquota.go b/vendor/github.com/containers/storage/drivers/quota/projectquota.go
index d805623b5..0609f970c 100644
--- a/vendor/github.com/containers/storage/drivers/quota/projectquota.go
+++ b/vendor/github.com/containers/storage/drivers/quota/projectquota.go
@@ -38,8 +38,8 @@ struct fsxattr {
#ifndef PRJQUOTA
#define PRJQUOTA 2
#endif
-#ifndef XFS_PROJ_QUOTA
-#define XFS_PROJ_QUOTA 2
+#ifndef FS_PROJ_QUOTA
+#define FS_PROJ_QUOTA 2
#endif
#ifndef Q_XSETPQLIM
#define Q_XSETPQLIM QCMD(Q_XSETQLIM, PRJQUOTA)
@@ -52,8 +52,11 @@ import "C"
import (
"fmt"
"io/ioutil"
+ "math"
+ "os"
"path"
"path/filepath"
+ "syscall"
"unsafe"
"github.com/containers/storage/pkg/directory"
@@ -61,9 +64,12 @@ import (
"golang.org/x/sys/unix"
)
-// Quota limit params - currently we only control blocks hard limit
+const projectIDsAllocatedPerQuotaHome = 10000
+
+// Quota limit params - currently we only control blocks hard limit and inodes
type Quota struct {
- Size uint64
+ Size uint64
+ Inodes uint64
}
// Control - Context to be used by storage driver (e.g. overlay)
@@ -74,23 +80,48 @@ type Control struct {
quotas map[string]uint32
}
+// Attempt to generate a unigue projectid. Multiple directories
+// per file system can have quota and they need a group of unique
+// ids. This function attempts to allocate at least projectIDsAllocatedPerQuotaHome(10000)
+// unique projectids, based on the inode of the basepath.
+func generateUniqueProjectID(path string) (uint32, error) {
+ fileinfo, err := os.Stat(path)
+ if err != nil {
+ return 0, err
+ }
+ stat, ok := fileinfo.Sys().(*syscall.Stat_t)
+ if !ok {
+ return 0, fmt.Errorf("Not a syscall.Stat_t %s", path)
+
+ }
+ projectID := projectIDsAllocatedPerQuotaHome + (stat.Ino*projectIDsAllocatedPerQuotaHome)%(math.MaxUint32-projectIDsAllocatedPerQuotaHome)
+ return uint32(projectID), nil
+}
+
// NewControl - initialize project quota support.
// Test to make sure that quota can be set on a test dir and find
// the first project id to be used for the next container create.
//
// Returns nil (and error) if project quota is not supported.
//
-// First get the project id of the home directory.
+// First get the project id of the basePath directory.
// This test will fail if the backing fs is not xfs.
//
// xfs_quota tool can be used to assign a project id to the driver home directory, e.g.:
-// echo 999:/var/lib/containers/storage/overlay >> /etc/projects
-// echo storage:999 >> /etc/projid
-// xfs_quota -x -c 'project -s storage' /<xfs mount point>
+// echo 100000:/var/lib/containers/storage/overlay >> /etc/projects
+// echo 200000:/var/lib/containers/storage/volumes >> /etc/projects
+// echo storage:100000 >> /etc/projid
+// echo volumes:200000 >> /etc/projid
+// xfs_quota -x -c 'project -s storage volumes' /<xfs mount point>
//
-// In that case, the home directory project id will be used as a "start offset"
-// and all containers will be assigned larger project ids (e.g. >= 1000).
-// This is a way to prevent xfs_quota management from conflicting with containers/storage.
+// In the example above, the storage directory project id will be used as a
+// "start offset" and all containers will be assigned larger project ids
+// (e.g. >= 100000). Then the volumes directory project id will be used as a
+// "start offset" and all volumes will be assigned larger project ids
+// (e.g. >= 200000).
+// This is a way to prevent xfs_quota management from conflicting with
+// containers/storage.
+
//
// Then try to create a test directory with the next project id and set a quota
// on it. If that works, continue to scan existing containers to map allocated
@@ -104,8 +135,15 @@ func NewControl(basePath string) (*Control, error) {
if err != nil {
return nil, err
}
- minProjectID++
+ if minProjectID == 0 {
+ // Indicates the storage was never initialized
+ // Generate a unique range of Projectids for this basepath
+ minProjectID, err = generateUniqueProjectID(basePath)
+ if err != nil {
+ return nil, err
+ }
+ }
//
// create backing filesystem device node
//
@@ -119,7 +157,8 @@ func NewControl(basePath string) (*Control, error) {
// a quota on the first available project id
//
quota := Quota{
- Size: 0,
+ Size: 0,
+ Inodes: 0,
}
if err := setProjectQuota(backingFsBlockDev, minProjectID, quota); err != nil {
return nil, err
@@ -166,7 +205,7 @@ func (q *Control) SetQuota(targetPath string, quota Quota) error {
//
// set the quota limit for the container's project id
//
- logrus.Debugf("SetQuota(%s, %d): projectID=%d", targetPath, quota.Size, projectID)
+ logrus.Debugf("SetQuota path=%s, size=%d, inodes=%d, projectID=%d", targetPath, quota.Size, quota.Inodes, projectID)
return setProjectQuota(q.backingFsBlockDev, projectID, quota)
}
@@ -175,11 +214,18 @@ func setProjectQuota(backingFsBlockDev string, projectID uint32, quota Quota) er
var d C.fs_disk_quota_t
d.d_version = C.FS_DQUOT_VERSION
d.d_id = C.__u32(projectID)
- d.d_flags = C.XFS_PROJ_QUOTA
+ d.d_flags = C.FS_PROJ_QUOTA
- d.d_fieldmask = C.FS_DQ_BHARD | C.FS_DQ_BSOFT
- d.d_blk_hardlimit = C.__u64(quota.Size / 512)
- d.d_blk_softlimit = d.d_blk_hardlimit
+ if quota.Size > 0 {
+ d.d_fieldmask = d.d_fieldmask | C.FS_DQ_BHARD | C.FS_DQ_BSOFT
+ d.d_blk_hardlimit = C.__u64(quota.Size / 512)
+ d.d_blk_softlimit = d.d_blk_hardlimit
+ }
+ if quota.Inodes > 0 {
+ d.d_fieldmask = d.d_fieldmask | C.FS_DQ_IHARD | C.FS_DQ_ISOFT
+ d.d_ino_hardlimit = C.__u64(quota.Inodes)
+ d.d_ino_softlimit = d.d_ino_hardlimit
+ }
var cs = C.CString(backingFsBlockDev)
defer C.free(unsafe.Pointer(cs))
@@ -202,6 +248,7 @@ func (q *Control) GetQuota(targetPath string, quota *Quota) error {
return err
}
quota.Size = uint64(d.d_blk_hardlimit) * 512
+ quota.Inodes = uint64(d.d_ino_hardlimit)
return nil
}
diff --git a/vendor/github.com/containers/storage/drivers/quota/projectquota_unsupported.go b/vendor/github.com/containers/storage/drivers/quota/projectquota_unsupported.go
index be6c75a58..7469138db 100644
--- a/vendor/github.com/containers/storage/drivers/quota/projectquota_unsupported.go
+++ b/vendor/github.com/containers/storage/drivers/quota/projectquota_unsupported.go
@@ -8,7 +8,8 @@ import (
// Quota limit params - currently we only control blocks hard limit
type Quota struct {
- Size uint64
+ Size uint64
+ Inodes uint64
}
// Control - Context to be used by storage driver (e.g. overlay)
diff --git a/vendor/github.com/containers/storage/go.mod b/vendor/github.com/containers/storage/go.mod
index d46000ace..e4f484d6b 100644
--- a/vendor/github.com/containers/storage/go.mod
+++ b/vendor/github.com/containers/storage/go.mod
@@ -16,7 +16,7 @@ require (
github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible
github.com/moby/sys/mountinfo v0.4.1
github.com/opencontainers/go-digest v1.0.0
- github.com/opencontainers/runc v1.0.0
+ github.com/opencontainers/runc v1.0.1
github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417
github.com/opencontainers/selinux v1.8.2
github.com/pkg/errors v0.9.1
diff --git a/vendor/github.com/containers/storage/go.sum b/vendor/github.com/containers/storage/go.sum
index 081da00e4..2607dbc9b 100644
--- a/vendor/github.com/containers/storage/go.sum
+++ b/vendor/github.com/containers/storage/go.sum
@@ -99,7 +99,7 @@ github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3/go.mod h1:MA5e5Lr8slmE
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/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs=
-github.com/cilium/ebpf v0.6.1/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs=
+github.com/cilium/ebpf v0.6.2/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs=
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=
@@ -468,8 +468,8 @@ github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59P
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-rc93/go.mod h1:3NOsor4w32B2tC0Zbl8Knk4Wg84SM2ImC1fxBuqJ/H0=
-github.com/opencontainers/runc v1.0.0 h1:QOhAQAYUlKeofuyeKdR6ITvOnXLPbEAjPMjz9wCUXcU=
-github.com/opencontainers/runc v1.0.0/go.mod h1:MU2S3KEB2ZExnhnAQYbwjdYV6HwKtDlNbA2Z2OeNDeA=
+github.com/opencontainers/runc v1.0.1 h1:G18PGckGdAm3yVQRWDVQ1rLSLntiniKJ0cNRT2Tm5gs=
+github.com/opencontainers/runc v1.0.1/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0=
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=
diff --git a/vendor/github.com/containers/storage/pkg/archive/archive.go b/vendor/github.com/containers/storage/pkg/archive/archive.go
index 50e3e3555..48e846f7c 100644
--- a/vendor/github.com/containers/storage/pkg/archive/archive.go
+++ b/vendor/github.com/containers/storage/pkg/archive/archive.go
@@ -645,10 +645,13 @@ func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, L
}
file.Close()
- case tar.TypeBlock, tar.TypeChar, tar.TypeFifo:
+ case tar.TypeBlock, tar.TypeChar:
if inUserns { // cannot create devices in a userns
+ logrus.Debugf("Tar: Can't create device %v while running in user namespace", path)
return nil
}
+ fallthrough
+ case tar.TypeFifo:
// Handle this is an OS-specific way
if err := handleTarTypeBlockCharFifo(hdr, path); err != nil {
return err
diff --git a/vendor/github.com/containers/storage/pkg/archive/archive_unix.go b/vendor/github.com/containers/storage/pkg/archive/archive_unix.go
index e257737e7..7c3e442da 100644
--- a/vendor/github.com/containers/storage/pkg/archive/archive_unix.go
+++ b/vendor/github.com/containers/storage/pkg/archive/archive_unix.go
@@ -11,7 +11,6 @@ import (
"github.com/containers/storage/pkg/idtools"
"github.com/containers/storage/pkg/system"
- "github.com/opencontainers/runc/libcontainer/userns"
"golang.org/x/sys/unix"
)
@@ -88,11 +87,6 @@ func minor(device uint64) uint64 {
// handleTarTypeBlockCharFifo is an OS-specific helper function used by
// createTarFile to handle the following types of header: Block; Char; Fifo
func handleTarTypeBlockCharFifo(hdr *tar.Header, path string) error {
- if userns.RunningInUserNS() {
- // cannot create a device if running in user namespace
- return nil
- }
-
mode := uint32(hdr.Mode & 07777)
switch hdr.Typeflag {
case tar.TypeBlock:
diff --git a/vendor/github.com/containers/storage/pkg/chunked/compression.go b/vendor/github.com/containers/storage/pkg/chunked/compression.go
new file mode 100644
index 000000000..f2811fb9a
--- /dev/null
+++ b/vendor/github.com/containers/storage/pkg/chunked/compression.go
@@ -0,0 +1,169 @@
+package chunked
+
+import (
+ "bytes"
+ "encoding/binary"
+ "fmt"
+ "io"
+
+ "github.com/containers/storage/pkg/chunked/compressor"
+ "github.com/containers/storage/pkg/chunked/internal"
+ "github.com/klauspost/compress/zstd"
+ digest "github.com/opencontainers/go-digest"
+ "github.com/pkg/errors"
+ "github.com/vbatts/tar-split/archive/tar"
+)
+
+const (
+ TypeReg = internal.TypeReg
+ TypeChunk = internal.TypeChunk
+ TypeLink = internal.TypeLink
+ TypeChar = internal.TypeChar
+ TypeBlock = internal.TypeBlock
+ TypeDir = internal.TypeDir
+ TypeFifo = internal.TypeFifo
+ TypeSymlink = internal.TypeSymlink
+)
+
+var typesToTar = map[string]byte{
+ TypeReg: tar.TypeReg,
+ TypeLink: tar.TypeLink,
+ TypeChar: tar.TypeChar,
+ TypeBlock: tar.TypeBlock,
+ TypeDir: tar.TypeDir,
+ TypeFifo: tar.TypeFifo,
+ TypeSymlink: tar.TypeSymlink,
+}
+
+func typeToTarType(t string) (byte, error) {
+ r, found := typesToTar[t]
+ if !found {
+ return 0, fmt.Errorf("unknown type: %v", t)
+ }
+ return r, nil
+}
+
+func isZstdChunkedFrameMagic(data []byte) bool {
+ if len(data) < 8 {
+ return false
+ }
+ return bytes.Equal(internal.ZstdChunkedFrameMagic, data[:8])
+}
+
+// readZstdChunkedManifest reads the zstd:chunked manifest from the seekable stream blobStream. The blob total size must
+// be specified.
+// This function uses the io.containers.zstd-chunked. annotations when specified.
+func readZstdChunkedManifest(blobStream ImageSourceSeekable, blobSize int64, annotations map[string]string) ([]byte, error) {
+ footerSize := int64(internal.FooterSizeSupported)
+ if blobSize <= footerSize {
+ return nil, errors.New("blob too small")
+ }
+
+ manifestChecksumAnnotation := annotations[internal.ManifestChecksumKey]
+ if manifestChecksumAnnotation == "" {
+ return nil, fmt.Errorf("manifest checksum annotation %q not found", internal.ManifestChecksumKey)
+ }
+
+ var offset, length, lengthUncompressed, manifestType uint64
+
+ if offsetMetadata := annotations[internal.ManifestInfoKey]; offsetMetadata != "" {
+ if _, err := fmt.Sscanf(offsetMetadata, "%d:%d:%d:%d", &offset, &length, &lengthUncompressed, &manifestType); err != nil {
+ return nil, err
+ }
+ } else {
+ chunk := ImageSourceChunk{
+ Offset: uint64(blobSize - footerSize),
+ Length: uint64(footerSize),
+ }
+ parts, errs, err := blobStream.GetBlobAt([]ImageSourceChunk{chunk})
+ if err != nil {
+ return nil, err
+ }
+ var reader io.ReadCloser
+ select {
+ case r := <-parts:
+ reader = r
+ case err := <-errs:
+ return nil, err
+ }
+ footer := make([]byte, footerSize)
+ if _, err := io.ReadFull(reader, footer); err != nil {
+ return nil, err
+ }
+
+ offset = binary.LittleEndian.Uint64(footer[0:8])
+ length = binary.LittleEndian.Uint64(footer[8:16])
+ lengthUncompressed = binary.LittleEndian.Uint64(footer[16:24])
+ manifestType = binary.LittleEndian.Uint64(footer[24:32])
+ if !isZstdChunkedFrameMagic(footer[32:40]) {
+ return nil, errors.New("invalid magic number")
+ }
+ }
+
+ if manifestType != internal.ManifestTypeCRFS {
+ return nil, errors.New("invalid manifest type")
+ }
+
+ // set a reasonable limit
+ if length > (1<<20)*50 {
+ return nil, errors.New("manifest too big")
+ }
+ if lengthUncompressed > (1<<20)*50 {
+ return nil, errors.New("manifest too big")
+ }
+
+ chunk := ImageSourceChunk{
+ Offset: offset,
+ Length: length,
+ }
+
+ parts, errs, err := blobStream.GetBlobAt([]ImageSourceChunk{chunk})
+ if err != nil {
+ return nil, err
+ }
+ var reader io.ReadCloser
+ select {
+ case r := <-parts:
+ reader = r
+ case err := <-errs:
+ return nil, err
+ }
+
+ manifest := make([]byte, length)
+ if _, err := io.ReadFull(reader, manifest); err != nil {
+ return nil, err
+ }
+
+ manifestDigester := digest.Canonical.Digester()
+ manifestChecksum := manifestDigester.Hash()
+ if _, err := manifestChecksum.Write(manifest); err != nil {
+ return nil, err
+ }
+
+ d, err := digest.Parse(manifestChecksumAnnotation)
+ if err != nil {
+ return nil, err
+ }
+ if manifestDigester.Digest() != d {
+ return nil, errors.New("invalid manifest checksum")
+ }
+
+ decoder, err := zstd.NewReader(nil)
+ if err != nil {
+ return nil, err
+ }
+ defer decoder.Close()
+
+ b := make([]byte, 0, lengthUncompressed)
+ if decoded, err := decoder.DecodeAll(manifest, b); err == nil {
+ return decoded, nil
+ }
+
+ return manifest, nil
+}
+
+// ZstdCompressor is a CompressorFunc for the zstd compression algorithm.
+// Deprecated: Use pkg/chunked/compressor.ZstdCompressor.
+func ZstdCompressor(r io.Writer, metadata map[string]string, level *int) (io.WriteCloser, error) {
+ return compressor.ZstdCompressor(r, metadata, level)
+}
diff --git a/vendor/github.com/containers/storage/pkg/chunked/compressor/compressor.go b/vendor/github.com/containers/storage/pkg/chunked/compressor/compressor.go
new file mode 100644
index 000000000..a205b73fd
--- /dev/null
+++ b/vendor/github.com/containers/storage/pkg/chunked/compressor/compressor.go
@@ -0,0 +1,220 @@
+package compressor
+
+// NOTE: This is used from github.com/containers/image by callers that
+// don't otherwise use containers/storage, so don't make this depend on any
+// larger software like the graph drivers.
+
+import (
+ "encoding/base64"
+ "io"
+ "io/ioutil"
+
+ "github.com/containers/storage/pkg/chunked/internal"
+ "github.com/containers/storage/pkg/ioutils"
+ "github.com/opencontainers/go-digest"
+ "github.com/vbatts/tar-split/archive/tar"
+)
+
+func writeZstdChunkedStream(destFile io.Writer, outMetadata map[string]string, reader io.Reader, level int) error {
+ // total written so far. Used to retrieve partial offsets in the file
+ dest := ioutils.NewWriteCounter(destFile)
+
+ tr := tar.NewReader(reader)
+ tr.RawAccounting = true
+
+ buf := make([]byte, 4096)
+
+ zstdWriter, err := internal.ZstdWriterWithLevel(dest, level)
+ if err != nil {
+ return err
+ }
+ defer func() {
+ if zstdWriter != nil {
+ zstdWriter.Close()
+ zstdWriter.Flush()
+ }
+ }()
+
+ restartCompression := func() (int64, error) {
+ var offset int64
+ if zstdWriter != nil {
+ if err := zstdWriter.Close(); err != nil {
+ return 0, err
+ }
+ if err := zstdWriter.Flush(); err != nil {
+ return 0, err
+ }
+ offset = dest.Count
+ zstdWriter.Reset(dest)
+ }
+ return offset, nil
+ }
+
+ var metadata []internal.ZstdFileMetadata
+ for {
+ hdr, err := tr.Next()
+ if err != nil {
+ if err == io.EOF {
+ break
+ }
+ return err
+ }
+
+ rawBytes := tr.RawBytes()
+ if _, err := zstdWriter.Write(rawBytes); err != nil {
+ return err
+ }
+ payloadDigester := digest.Canonical.Digester()
+ payloadChecksum := payloadDigester.Hash()
+
+ payloadDest := io.MultiWriter(payloadChecksum, zstdWriter)
+
+ // Now handle the payload, if any
+ var startOffset, endOffset int64
+ checksum := ""
+ for {
+ read, errRead := tr.Read(buf)
+ if errRead != nil && errRead != io.EOF {
+ return err
+ }
+
+ // restart the compression only if there is
+ // a payload.
+ if read > 0 {
+ if startOffset == 0 {
+ startOffset, err = restartCompression()
+ if err != nil {
+ return err
+ }
+ }
+ _, err := payloadDest.Write(buf[:read])
+ if err != nil {
+ return err
+ }
+ }
+ if errRead == io.EOF {
+ if startOffset > 0 {
+ endOffset, err = restartCompression()
+ if err != nil {
+ return err
+ }
+ checksum = payloadDigester.Digest().String()
+ }
+ break
+ }
+ }
+
+ typ, err := internal.GetType(hdr.Typeflag)
+ if err != nil {
+ return err
+ }
+ xattrs := make(map[string]string)
+ for k, v := range hdr.Xattrs {
+ xattrs[k] = base64.StdEncoding.EncodeToString([]byte(v))
+ }
+ m := internal.ZstdFileMetadata{
+ Type: typ,
+ Name: hdr.Name,
+ Linkname: hdr.Linkname,
+ Mode: hdr.Mode,
+ Size: hdr.Size,
+ UID: hdr.Uid,
+ GID: hdr.Gid,
+ ModTime: hdr.ModTime,
+ AccessTime: hdr.AccessTime,
+ ChangeTime: hdr.ChangeTime,
+ Devmajor: hdr.Devmajor,
+ Devminor: hdr.Devminor,
+ Xattrs: xattrs,
+ Digest: checksum,
+ Offset: startOffset,
+ EndOffset: endOffset,
+
+ // ChunkSize is 0 for the last chunk
+ ChunkSize: 0,
+ ChunkOffset: 0,
+ ChunkDigest: checksum,
+ }
+ metadata = append(metadata, m)
+ }
+
+ rawBytes := tr.RawBytes()
+ if _, err := zstdWriter.Write(rawBytes); err != nil {
+ return err
+ }
+ if err := zstdWriter.Flush(); err != nil {
+ return err
+ }
+ if err := zstdWriter.Close(); err != nil {
+ return err
+ }
+ zstdWriter = nil
+
+ return internal.WriteZstdChunkedManifest(dest, outMetadata, uint64(dest.Count), metadata, level)
+}
+
+type zstdChunkedWriter struct {
+ tarSplitOut *io.PipeWriter
+ tarSplitErr chan error
+}
+
+func (w zstdChunkedWriter) Close() error {
+ err := <-w.tarSplitErr
+ if err != nil {
+ w.tarSplitOut.Close()
+ return err
+ }
+ return w.tarSplitOut.Close()
+}
+
+func (w zstdChunkedWriter) Write(p []byte) (int, error) {
+ select {
+ case err := <-w.tarSplitErr:
+ w.tarSplitOut.Close()
+ return 0, err
+ default:
+ return w.tarSplitOut.Write(p)
+ }
+}
+
+// zstdChunkedWriterWithLevel writes a zstd compressed tarball where each file is
+// compressed separately so it can be addressed separately. Idea based on CRFS:
+// https://github.com/google/crfs
+// The difference with CRFS is that the zstd compression is used instead of gzip.
+// The reason for it is that zstd supports embedding metadata ignored by the decoder
+// as part of the compressed stream.
+// A manifest json file with all the metadata is appended at the end of the tarball
+// stream, using zstd skippable frames.
+// The final file will look like:
+// [FILE_1][FILE_2]..[FILE_N][SKIPPABLE FRAME 1][SKIPPABLE FRAME 2]
+// Where:
+// [FILE_N]: [ZSTD HEADER][TAR HEADER][PAYLOAD FILE_N][ZSTD FOOTER]
+// [SKIPPABLE FRAME 1]: [ZSTD SKIPPABLE FRAME, SIZE=MANIFEST LENGTH][MANIFEST]
+// [SKIPPABLE FRAME 2]: [ZSTD SKIPPABLE FRAME, SIZE=16][MANIFEST_OFFSET][MANIFEST_LENGTH][MANIFEST_LENGTH_UNCOMPRESSED][MANIFEST_TYPE][CHUNKED_ZSTD_MAGIC_NUMBER]
+// MANIFEST_OFFSET, MANIFEST_LENGTH, MANIFEST_LENGTH_UNCOMPRESSED and CHUNKED_ZSTD_MAGIC_NUMBER are 64 bits unsigned in little endian format.
+func zstdChunkedWriterWithLevel(out io.Writer, metadata map[string]string, level int) (io.WriteCloser, error) {
+ ch := make(chan error, 1)
+ r, w := io.Pipe()
+
+ go func() {
+ ch <- writeZstdChunkedStream(out, metadata, r, level)
+ io.Copy(ioutil.Discard, r)
+ r.Close()
+ close(ch)
+ }()
+
+ return zstdChunkedWriter{
+ tarSplitOut: w,
+ tarSplitErr: ch,
+ }, nil
+}
+
+// ZstdCompressor is a CompressorFunc for the zstd compression algorithm.
+func ZstdCompressor(r io.Writer, metadata map[string]string, level *int) (io.WriteCloser, error) {
+ if level == nil {
+ l := 3
+ level = &l
+ }
+
+ return zstdChunkedWriterWithLevel(r, metadata, *level)
+}
diff --git a/vendor/github.com/containers/storage/pkg/chunked/internal/compression.go b/vendor/github.com/containers/storage/pkg/chunked/internal/compression.go
new file mode 100644
index 000000000..af0025c20
--- /dev/null
+++ b/vendor/github.com/containers/storage/pkg/chunked/internal/compression.go
@@ -0,0 +1,172 @@
+package internal
+
+// NOTE: This is used from github.com/containers/image by callers that
+// don't otherwise use containers/storage, so don't make this depend on any
+// larger software like the graph drivers.
+
+import (
+ "archive/tar"
+ "bytes"
+ "encoding/binary"
+ "encoding/json"
+ "fmt"
+ "io"
+ "time"
+
+ "github.com/klauspost/compress/zstd"
+ "github.com/opencontainers/go-digest"
+)
+
+type ZstdTOC struct {
+ Version int `json:"version"`
+ Entries []ZstdFileMetadata `json:"entries"`
+}
+
+type ZstdFileMetadata struct {
+ Type string `json:"type"`
+ Name string `json:"name"`
+ Linkname string `json:"linkName,omitempty"`
+ Mode int64 `json:"mode,omitempty"`
+ Size int64 `json:"size"`
+ UID int `json:"uid"`
+ GID int `json:"gid"`
+ ModTime time.Time `json:"modtime"`
+ AccessTime time.Time `json:"accesstime"`
+ ChangeTime time.Time `json:"changetime"`
+ Devmajor int64 `json:"devMajor"`
+ Devminor int64 `json:"devMinor"`
+ Xattrs map[string]string `json:"xattrs,omitempty"`
+ Digest string `json:"digest,omitempty"`
+ Offset int64 `json:"offset,omitempty"`
+ EndOffset int64 `json:"endOffset,omitempty"`
+
+ // Currently chunking is not supported.
+ ChunkSize int64 `json:"chunkSize,omitempty"`
+ ChunkOffset int64 `json:"chunkOffset,omitempty"`
+ ChunkDigest string `json:"chunkDigest,omitempty"`
+}
+
+const (
+ TypeReg = "reg"
+ TypeChunk = "chunk"
+ TypeLink = "hardlink"
+ TypeChar = "char"
+ TypeBlock = "block"
+ TypeDir = "dir"
+ TypeFifo = "fifo"
+ TypeSymlink = "symlink"
+)
+
+var TarTypes = map[byte]string{
+ tar.TypeReg: TypeReg,
+ tar.TypeRegA: TypeReg,
+ tar.TypeLink: TypeLink,
+ tar.TypeChar: TypeChar,
+ tar.TypeBlock: TypeBlock,
+ tar.TypeDir: TypeDir,
+ tar.TypeFifo: TypeFifo,
+ tar.TypeSymlink: TypeSymlink,
+}
+
+func GetType(t byte) (string, error) {
+ r, found := TarTypes[t]
+ if !found {
+ return "", fmt.Errorf("unknown tarball type: %v", t)
+ }
+ return r, nil
+}
+
+const (
+ ManifestChecksumKey = "io.containers.zstd-chunked.manifest-checksum"
+ ManifestInfoKey = "io.containers.zstd-chunked.manifest-position"
+
+ // ManifestTypeCRFS is a manifest file compatible with the CRFS TOC file.
+ ManifestTypeCRFS = 1
+
+ // FooterSizeSupported is the footer size supported by this implementation.
+ // Newer versions of the image format might increase this value, so reject
+ // any version that is not supported.
+ FooterSizeSupported = 40
+)
+
+var (
+ // when the zstd decoder encounters a skippable frame + 1 byte for the size, it
+ // will ignore it.
+ // https://tools.ietf.org/html/rfc8478#section-3.1.2
+ skippableFrameMagic = []byte{0x50, 0x2a, 0x4d, 0x18}
+
+ ZstdChunkedFrameMagic = []byte{0x47, 0x6e, 0x55, 0x6c, 0x49, 0x6e, 0x55, 0x78}
+)
+
+func appendZstdSkippableFrame(dest io.Writer, data []byte) error {
+ if _, err := dest.Write(skippableFrameMagic); err != nil {
+ return err
+ }
+
+ var size []byte = make([]byte, 4)
+ binary.LittleEndian.PutUint32(size, uint32(len(data)))
+ if _, err := dest.Write(size); err != nil {
+ return err
+ }
+ if _, err := dest.Write(data); err != nil {
+ return err
+ }
+ return nil
+}
+
+func WriteZstdChunkedManifest(dest io.Writer, outMetadata map[string]string, offset uint64, metadata []ZstdFileMetadata, level int) error {
+ // 8 is the size of the zstd skippable frame header + the frame size
+ manifestOffset := offset + 8
+
+ toc := ZstdTOC{
+ Version: 1,
+ Entries: metadata,
+ }
+
+ // Generate the manifest
+ manifest, err := json.Marshal(toc)
+ if err != nil {
+ return err
+ }
+
+ var compressedBuffer bytes.Buffer
+ zstdWriter, err := ZstdWriterWithLevel(&compressedBuffer, level)
+ if err != nil {
+ return err
+ }
+ if _, err := zstdWriter.Write(manifest); err != nil {
+ zstdWriter.Close()
+ return err
+ }
+ if err := zstdWriter.Close(); err != nil {
+ return err
+ }
+ compressedManifest := compressedBuffer.Bytes()
+
+ manifestDigester := digest.Canonical.Digester()
+ manifestChecksum := manifestDigester.Hash()
+ if _, err := manifestChecksum.Write(compressedManifest); err != nil {
+ return err
+ }
+
+ outMetadata[ManifestChecksumKey] = manifestDigester.Digest().String()
+ outMetadata[ManifestInfoKey] = fmt.Sprintf("%d:%d:%d:%d", manifestOffset, len(compressedManifest), len(manifest), ManifestTypeCRFS)
+ if err := appendZstdSkippableFrame(dest, compressedManifest); err != nil {
+ return err
+ }
+
+ // Store the offset to the manifest and its size in LE order
+ var manifestDataLE []byte = make([]byte, FooterSizeSupported)
+ binary.LittleEndian.PutUint64(manifestDataLE, manifestOffset)
+ binary.LittleEndian.PutUint64(manifestDataLE[8:], uint64(len(compressedManifest)))
+ binary.LittleEndian.PutUint64(manifestDataLE[16:], uint64(len(manifest)))
+ binary.LittleEndian.PutUint64(manifestDataLE[24:], uint64(ManifestTypeCRFS))
+ copy(manifestDataLE[32:], ZstdChunkedFrameMagic)
+
+ return appendZstdSkippableFrame(dest, manifestDataLE)
+}
+
+func ZstdWriterWithLevel(dest io.Writer, level int) (*zstd.Encoder, error) {
+ el := zstd.EncoderLevelFromZstd(level)
+ return zstd.NewWriter(dest, zstd.WithEncoderLevel(el))
+}
diff --git a/vendor/github.com/containers/storage/pkg/chunked/storage.go b/vendor/github.com/containers/storage/pkg/chunked/storage.go
new file mode 100644
index 000000000..9212cbbcf
--- /dev/null
+++ b/vendor/github.com/containers/storage/pkg/chunked/storage.go
@@ -0,0 +1,26 @@
+package chunked
+
+import (
+ "fmt"
+ "io"
+)
+
+// ImageSourceChunk is a portion of a blob.
+type ImageSourceChunk struct {
+ Offset uint64
+ Length uint64
+}
+
+// ImageSourceSeekable is an image source that permits to fetch chunks of the entire blob.
+type ImageSourceSeekable interface {
+ // GetBlobAt returns a stream for the specified blob.
+ GetBlobAt([]ImageSourceChunk) (chan io.ReadCloser, chan error, error)
+}
+
+// ErrBadRequest is returned when the request is not valid
+type ErrBadRequest struct {
+}
+
+func (e ErrBadRequest) Error() string {
+ return fmt.Sprintf("bad request")
+}
diff --git a/vendor/github.com/containers/storage/pkg/chunked/storage_linux.go b/vendor/github.com/containers/storage/pkg/chunked/storage_linux.go
new file mode 100644
index 000000000..0f14d8af9
--- /dev/null
+++ b/vendor/github.com/containers/storage/pkg/chunked/storage_linux.go
@@ -0,0 +1,875 @@
+package chunked
+
+import (
+ archivetar "archive/tar"
+ "context"
+ "encoding/base64"
+ "encoding/json"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "sort"
+ "strings"
+ "syscall"
+ "time"
+
+ storage "github.com/containers/storage"
+ graphdriver "github.com/containers/storage/drivers"
+ driversCopy "github.com/containers/storage/drivers/copy"
+ "github.com/containers/storage/pkg/archive"
+ "github.com/containers/storage/pkg/chunked/internal"
+ "github.com/containers/storage/pkg/idtools"
+ "github.com/containers/storage/types"
+ "github.com/klauspost/compress/zstd"
+ digest "github.com/opencontainers/go-digest"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+ "github.com/vbatts/tar-split/archive/tar"
+ "golang.org/x/sys/unix"
+)
+
+const (
+ maxNumberMissingChunks = 1024
+ newFileFlags = (unix.O_CREAT | unix.O_TRUNC | unix.O_WRONLY | unix.O_EXCL)
+ containersOverrideXattr = "user.containers.override_stat"
+ bigDataKey = "zstd-chunked-manifest"
+)
+
+type chunkedZstdDiffer struct {
+ stream ImageSourceSeekable
+ manifest []byte
+ layersMetadata map[string][]internal.ZstdFileMetadata
+ layersTarget map[string]string
+}
+
+func timeToTimespec(time time.Time) (ts unix.Timespec) {
+ if time.IsZero() {
+ // Return UTIME_OMIT special value
+ ts.Sec = 0
+ ts.Nsec = ((1 << 30) - 2)
+ return
+ }
+ return unix.NsecToTimespec(time.UnixNano())
+}
+
+func copyFileContent(src, destFile, root string, dirfd int, missingDirsMode, mode os.FileMode) (*os.File, int64, error) {
+ st, err := os.Stat(src)
+ if err != nil {
+ return nil, -1, err
+ }
+
+ copyWithFileRange, copyWithFileClone := true, true
+
+ // If the destination file already exists, we shouldn't blow it away
+ dstFile, err := openFileUnderRoot(destFile, root, dirfd, newFileFlags, mode)
+ if err != nil {
+ return nil, -1, err
+ }
+
+ err = driversCopy.CopyRegularToFile(src, dstFile, st, &copyWithFileRange, &copyWithFileClone)
+ if err != nil {
+ dstFile.Close()
+ return nil, -1, err
+ }
+ return dstFile, st.Size(), err
+}
+
+func prepareOtherLayersCache(layersMetadata map[string][]internal.ZstdFileMetadata) map[string]map[string]*internal.ZstdFileMetadata {
+ maps := make(map[string]map[string]*internal.ZstdFileMetadata)
+
+ for layerID, v := range layersMetadata {
+ r := make(map[string]*internal.ZstdFileMetadata)
+ for i := range v {
+ r[v[i].Digest] = &v[i]
+ }
+ maps[layerID] = r
+ }
+ return maps
+}
+
+func getLayersCache(store storage.Store) (map[string][]internal.ZstdFileMetadata, map[string]string, error) {
+ allLayers, err := store.Layers()
+ if err != nil {
+ return nil, nil, err
+ }
+
+ layersMetadata := make(map[string][]internal.ZstdFileMetadata)
+ layersTarget := make(map[string]string)
+ for _, r := range allLayers {
+ manifestReader, err := store.LayerBigData(r.ID, bigDataKey)
+ if err != nil {
+ continue
+ }
+ defer manifestReader.Close()
+ manifest, err := ioutil.ReadAll(manifestReader)
+ if err != nil {
+ return nil, nil, err
+ }
+ var toc internal.ZstdTOC
+ if err := json.Unmarshal(manifest, &toc); err != nil {
+ continue
+ }
+ layersMetadata[r.ID] = toc.Entries
+ target, err := store.DifferTarget(r.ID)
+ if err != nil {
+ return nil, nil, err
+ }
+ layersTarget[r.ID] = target
+ }
+
+ return layersMetadata, layersTarget, nil
+}
+
+// GetDiffer returns a differ than can be used with ApplyDiffWithDiffer.
+func GetDiffer(ctx context.Context, store storage.Store, blobSize int64, annotations map[string]string, iss ImageSourceSeekable) (graphdriver.Differ, error) {
+ if _, ok := annotations[internal.ManifestChecksumKey]; ok {
+ return makeZstdChunkedDiffer(ctx, store, blobSize, annotations, iss)
+ }
+ return nil, errors.New("blob type not supported for partial retrieval")
+}
+
+func makeZstdChunkedDiffer(ctx context.Context, store storage.Store, blobSize int64, annotations map[string]string, iss ImageSourceSeekable) (*chunkedZstdDiffer, error) {
+ manifest, err := readZstdChunkedManifest(iss, blobSize, annotations)
+ if err != nil {
+ return nil, err
+ }
+ layersMetadata, layersTarget, err := getLayersCache(store)
+ if err != nil {
+ return nil, err
+ }
+
+ return &chunkedZstdDiffer{
+ stream: iss,
+ manifest: manifest,
+ layersMetadata: layersMetadata,
+ layersTarget: layersTarget,
+ }, nil
+}
+
+func findFileInOtherLayers(file internal.ZstdFileMetadata, root string, dirfd int, layersMetadata map[string]map[string]*internal.ZstdFileMetadata, layersTarget map[string]string, missingDirsMode os.FileMode) (*os.File, int64, error) {
+ // this is ugly, needs to be indexed
+ for layerID, checksums := range layersMetadata {
+ m, found := checksums[file.Digest]
+ if !found {
+ continue
+ }
+
+ source, ok := layersTarget[layerID]
+ if !ok {
+ continue
+ }
+
+ srcDirfd, err := unix.Open(source, unix.O_RDONLY, 0)
+ if err != nil {
+ continue
+ }
+ defer unix.Close(srcDirfd)
+
+ srcFile, err := openFileUnderRoot(m.Name, source, srcDirfd, unix.O_RDONLY, 0)
+ if err != nil {
+ continue
+ }
+ defer srcFile.Close()
+
+ srcPath := fmt.Sprintf("/proc/self/fd/%d", srcFile.Fd())
+
+ dstFile, written, err := copyFileContent(srcPath, file.Name, root, dirfd, missingDirsMode, 0)
+ if err != nil {
+ continue
+ }
+ return dstFile, written, nil
+ }
+ return nil, 0, nil
+}
+
+func getFileDigest(f *os.File) (digest.Digest, error) {
+ digester := digest.Canonical.Digester()
+ if _, err := io.Copy(digester.Hash(), f); err != nil {
+ return "", err
+ }
+ return digester.Digest(), nil
+}
+
+// findFileOnTheHost checks whether the requested file already exist on the host and copies the file content from there if possible.
+// It is currently implemented to look only at the file with the same path. Ideally it can detect the same content also at different
+// paths.
+func findFileOnTheHost(file internal.ZstdFileMetadata, root string, dirfd int, missingDirsMode os.FileMode) (*os.File, int64, error) {
+ sourceFile := filepath.Clean(filepath.Join("/", file.Name))
+ if !strings.HasPrefix(sourceFile, "/usr/") {
+ // limit host deduplication to files under /usr.
+ return nil, 0, nil
+ }
+
+ st, err := os.Stat(sourceFile)
+ if err != nil || !st.Mode().IsRegular() {
+ return nil, 0, nil
+ }
+
+ if st.Size() != file.Size {
+ return nil, 0, nil
+ }
+
+ fd, err := unix.Open(sourceFile, unix.O_RDONLY|unix.O_NONBLOCK, 0)
+ if err != nil {
+ return nil, 0, nil
+ }
+
+ f := os.NewFile(uintptr(fd), "fd")
+ defer f.Close()
+
+ manifestChecksum, err := digest.Parse(file.Digest)
+ if err != nil {
+ return nil, 0, err
+ }
+
+ checksum, err := getFileDigest(f)
+ if err != nil {
+ return nil, 0, err
+ }
+
+ if checksum != manifestChecksum {
+ return nil, 0, nil
+ }
+
+ dstFile, written, err := copyFileContent(fmt.Sprintf("/proc/self/fd/%d", fd), file.Name, root, dirfd, missingDirsMode, 0)
+ if err != nil {
+ return nil, 0, nil
+ }
+
+ // calculate the checksum again to make sure the file wasn't modified while it was copied
+ if _, err := f.Seek(0, 0); err != nil {
+ return nil, 0, err
+ }
+ checksum, err = getFileDigest(f)
+ if err != nil {
+ return nil, 0, err
+ }
+ if checksum != manifestChecksum {
+ return nil, 0, nil
+ }
+ return dstFile, written, nil
+}
+
+func maybeDoIDRemap(manifest []internal.ZstdFileMetadata, options *archive.TarOptions) error {
+ if options.ChownOpts == nil && len(options.UIDMaps) == 0 || len(options.GIDMaps) == 0 {
+ return nil
+ }
+
+ idMappings := idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps)
+
+ for i := range manifest {
+ if options.ChownOpts != nil {
+ manifest[i].UID = options.ChownOpts.UID
+ manifest[i].GID = options.ChownOpts.GID
+ } else {
+ pair := idtools.IDPair{
+ UID: manifest[i].UID,
+ GID: manifest[i].GID,
+ }
+ var err error
+ manifest[i].UID, manifest[i].GID, err = idMappings.ToContainer(pair)
+ if err != nil {
+ return err
+ }
+ }
+ }
+ return nil
+}
+
+type missingFile struct {
+ File *internal.ZstdFileMetadata
+ Gap int64
+}
+
+func (m missingFile) Length() int64 {
+ return m.File.EndOffset - m.File.Offset
+}
+
+type missingChunk struct {
+ RawChunk ImageSourceChunk
+ Files []missingFile
+}
+
+func setFileAttrs(file *os.File, mode os.FileMode, metadata *internal.ZstdFileMetadata, options *archive.TarOptions) error {
+ if file == nil || file.Fd() < 0 {
+ return errors.Errorf("invalid file")
+ }
+ fd := int(file.Fd())
+
+ t, err := typeToTarType(metadata.Type)
+ if err != nil {
+ return err
+ }
+ if t == tar.TypeSymlink {
+ return nil
+ }
+
+ if err := unix.Fchown(fd, metadata.UID, metadata.GID); err != nil {
+ if !options.IgnoreChownErrors {
+ return err
+ }
+ }
+
+ for k, v := range metadata.Xattrs {
+ data, err := base64.StdEncoding.DecodeString(v)
+ if err != nil {
+ return err
+ }
+ if err := unix.Fsetxattr(fd, k, data, 0); err != nil {
+ return err
+ }
+ }
+
+ ts := []unix.Timespec{timeToTimespec(metadata.AccessTime), timeToTimespec(metadata.ModTime)}
+ if err := unix.UtimesNanoAt(fd, "", ts, 0); err != nil && errors.Is(err, unix.ENOSYS) {
+ return err
+ }
+
+ if err := unix.Fchmod(fd, uint32(mode)); err != nil {
+ return err
+ }
+ return nil
+}
+
+func openFileUnderRoot(name, root string, dirfd int, flags uint64, mode os.FileMode) (*os.File, error) {
+ how := unix.OpenHow{
+ Flags: flags,
+ Mode: uint64(mode & 07777),
+ Resolve: unix.RESOLVE_IN_ROOT,
+ }
+
+ fd, err := unix.Openat2(dirfd, name, &how)
+ if err != nil {
+ return nil, err
+ }
+ return os.NewFile(uintptr(fd), name), nil
+}
+
+func createFileFromZstdStream(dest string, dirfd int, reader io.Reader, missingDirsMode, mode os.FileMode, metadata *internal.ZstdFileMetadata, options *archive.TarOptions) (err error) {
+ file, err := openFileUnderRoot(metadata.Name, dest, dirfd, newFileFlags, 0)
+ if err != nil {
+ return err
+ }
+ defer func() {
+ err2 := file.Close()
+ if err == nil {
+ err = err2
+ }
+ }()
+
+ z, err := zstd.NewReader(reader)
+ if err != nil {
+ return err
+ }
+ defer z.Close()
+
+ digester := digest.Canonical.Digester()
+ checksum := digester.Hash()
+ _, err = z.WriteTo(io.MultiWriter(file, checksum))
+ if err != nil {
+ return err
+ }
+ manifestChecksum, err := digest.Parse(metadata.Digest)
+ if err != nil {
+ return err
+ }
+ if digester.Digest() != manifestChecksum {
+ return fmt.Errorf("checksum mismatch for %q", dest)
+ }
+ return setFileAttrs(file, mode, metadata, options)
+}
+
+func storeMissingFiles(streams chan io.ReadCloser, errs chan error, dest string, dirfd int, missingChunks []missingChunk, missingDirsMode os.FileMode, options *archive.TarOptions) error {
+ for mc := 0; ; mc++ {
+ var part io.ReadCloser
+ select {
+ case p := <-streams:
+ part = p
+ case err := <-errs:
+ return err
+ }
+ if part == nil {
+ if mc == len(missingChunks) {
+ break
+ }
+ return errors.Errorf("invalid stream returned %d %d", mc, len(missingChunks))
+ }
+ if mc == len(missingChunks) {
+ return errors.Errorf("too many chunks returned")
+ }
+
+ for _, mf := range missingChunks[mc].Files {
+ if mf.Gap > 0 {
+ limitReader := io.LimitReader(part, mf.Gap)
+ _, err := io.Copy(ioutil.Discard, limitReader)
+ if err != nil {
+ return err
+ }
+ continue
+ }
+
+ limitReader := io.LimitReader(part, mf.Length())
+
+ if err := createFileFromZstdStream(dest, dirfd, limitReader, missingDirsMode, os.FileMode(mf.File.Mode), mf.File, options); err != nil {
+ part.Close()
+ return err
+ }
+ }
+ part.Close()
+ }
+ return nil
+}
+
+func mergeMissingChunks(missingChunks []missingChunk, target int) []missingChunk {
+ if len(missingChunks) <= target {
+ return missingChunks
+ }
+
+ getGap := func(missingChunks []missingChunk, i int) int {
+ prev := missingChunks[i-1].RawChunk.Offset + missingChunks[i-1].RawChunk.Length
+ return int(missingChunks[i].RawChunk.Offset - prev)
+ }
+
+ // this implementation doesn't account for duplicates, so it could merge
+ // more than necessary to reach the specified target. Since target itself
+ // is a heuristic value, it doesn't matter.
+ var gaps []int
+ for i := 1; i < len(missingChunks); i++ {
+ gaps = append(gaps, getGap(missingChunks, i))
+ }
+ sort.Ints(gaps)
+
+ toShrink := len(missingChunks) - target
+ targetValue := gaps[toShrink-1]
+
+ newMissingChunks := missingChunks[0:1]
+ for i := 1; i < len(missingChunks); i++ {
+ gap := getGap(missingChunks, i)
+ if gap > targetValue {
+ newMissingChunks = append(newMissingChunks, missingChunks[i])
+ } else {
+ prev := &newMissingChunks[len(newMissingChunks)-1]
+ gapFile := missingFile{
+ Gap: int64(gap),
+ }
+ prev.RawChunk.Length += uint64(gap) + missingChunks[i].RawChunk.Length
+ prev.Files = append(append(prev.Files, gapFile), missingChunks[i].Files...)
+ }
+ }
+
+ return newMissingChunks
+}
+
+func retrieveMissingFiles(input *chunkedZstdDiffer, dest string, dirfd int, missingChunks []missingChunk, missingDirsMode os.FileMode, options *archive.TarOptions) error {
+ var chunksToRequest []ImageSourceChunk
+ for _, c := range missingChunks {
+ chunksToRequest = append(chunksToRequest, c.RawChunk)
+ }
+
+ // There are some missing files. Prepare a multirange request for the missing chunks.
+ var streams chan io.ReadCloser
+ var err error
+ var errs chan error
+ for {
+ streams, errs, err = input.stream.GetBlobAt(chunksToRequest)
+ if err == nil {
+ break
+ }
+
+ if _, ok := err.(ErrBadRequest); ok {
+ requested := len(missingChunks)
+ // If the server cannot handle at least 64 chunks in a single request, just give up.
+ if requested < 64 {
+ return err
+ }
+
+ // Merge more chunks to request
+ missingChunks = mergeMissingChunks(missingChunks, requested/2)
+ continue
+ }
+ return err
+ }
+
+ if err := storeMissingFiles(streams, errs, dest, dirfd, missingChunks, missingDirsMode, options); err != nil {
+ return err
+ }
+ return nil
+}
+
+func safeMkdir(target string, dirfd int, mode os.FileMode, metadata *internal.ZstdFileMetadata, options *archive.TarOptions) error {
+ parent := filepath.Dir(metadata.Name)
+ base := filepath.Base(metadata.Name)
+
+ parentFd := dirfd
+ if parent != "." {
+ parentFile, err := openFileUnderRoot(parent, target, dirfd, unix.O_DIRECTORY|unix.O_PATH|unix.O_RDONLY, 0)
+ if err != nil {
+ return err
+ }
+ defer parentFile.Close()
+ parentFd = int(parentFile.Fd())
+ }
+
+ if err := unix.Mkdirat(parentFd, base, uint32(mode)); err != nil {
+ if !os.IsExist(err) {
+ return err
+ }
+ }
+
+ file, err := openFileUnderRoot(metadata.Name, target, dirfd, unix.O_RDONLY, 0)
+ if err != nil {
+ return err
+ }
+ defer file.Close()
+
+ return setFileAttrs(file, mode, metadata, options)
+}
+
+func safeLink(target string, dirfd int, mode os.FileMode, metadata *internal.ZstdFileMetadata, options *archive.TarOptions) error {
+ sourceFile, err := openFileUnderRoot(metadata.Linkname, target, dirfd, unix.O_RDONLY, 0)
+ if err != nil {
+ return err
+ }
+ defer sourceFile.Close()
+
+ destDir, destBase := filepath.Dir(metadata.Name), filepath.Base(metadata.Name)
+ destDirFd := dirfd
+ if destDir != "." {
+ f, err := openFileUnderRoot(destDir, target, dirfd, unix.O_RDONLY, 0)
+ if err != nil {
+ return err
+ }
+ defer f.Close()
+ destDirFd = int(f.Fd())
+ }
+
+ err = unix.Linkat(int(sourceFile.Fd()), "", destDirFd, destBase, unix.AT_EMPTY_PATH)
+ if err != nil {
+ return err
+ }
+
+ newFile, err := openFileUnderRoot(metadata.Name, target, dirfd, unix.O_WRONLY, 0)
+ if err != nil {
+ return err
+ }
+ defer newFile.Close()
+
+ return setFileAttrs(newFile, mode, metadata, options)
+}
+
+func safeSymlink(target string, dirfd int, mode os.FileMode, metadata *internal.ZstdFileMetadata, options *archive.TarOptions) error {
+ destDir, destBase := filepath.Dir(metadata.Name), filepath.Base(metadata.Name)
+ destDirFd := dirfd
+ if destDir != "." {
+ f, err := openFileUnderRoot(destDir, target, dirfd, unix.O_RDONLY, 0)
+ if err != nil {
+ return err
+ }
+ defer f.Close()
+ destDirFd = int(f.Fd())
+ }
+
+ return unix.Symlinkat(metadata.Linkname, destDirFd, destBase)
+}
+
+type whiteoutHandler struct {
+ Dirfd int
+ Root string
+}
+
+func (d whiteoutHandler) Setxattr(path, name string, value []byte) error {
+ file, err := openFileUnderRoot(path, d.Root, d.Dirfd, unix.O_RDONLY, 0)
+ if err != nil {
+ return err
+ }
+ defer file.Close()
+
+ return unix.Fsetxattr(int(file.Fd()), name, value, 0)
+}
+
+func (d whiteoutHandler) Mknod(path string, mode uint32, dev int) error {
+ dir := filepath.Dir(path)
+ base := filepath.Base(path)
+
+ dirfd := d.Dirfd
+ if dir != "" {
+ dir, err := openFileUnderRoot(dir, d.Root, d.Dirfd, unix.O_RDONLY, 0)
+ if err != nil {
+ return err
+ }
+ defer dir.Close()
+
+ dirfd = int(dir.Fd())
+ }
+
+ return unix.Mknodat(dirfd, base, mode, dev)
+}
+
+func checkChownErr(err error, name string, uid, gid int) error {
+ if errors.Is(err, syscall.EINVAL) {
+ return errors.Wrapf(err, "potentially insufficient UIDs or GIDs available in user namespace (requested %d:%d for %s): Check /etc/subuid and /etc/subgid", uid, gid, name)
+ }
+ return err
+}
+
+func (d whiteoutHandler) Chown(path string, uid, gid int) error {
+ file, err := openFileUnderRoot(path, d.Root, d.Dirfd, unix.O_PATH, 0)
+ if err != nil {
+ return err
+ }
+ defer file.Close()
+
+ if err := unix.Fchownat(int(file.Fd()), "", uid, gid, unix.AT_EMPTY_PATH); err != nil {
+ var stat unix.Stat_t
+ if unix.Fstat(int(file.Fd()), &stat) == nil {
+ if stat.Uid == uint32(uid) && stat.Gid == uint32(gid) {
+ return nil
+ }
+ }
+ return checkChownErr(err, path, uid, gid)
+ }
+ return nil
+}
+
+type hardLinkToCreate struct {
+ dest string
+ dirfd int
+ mode os.FileMode
+ metadata *internal.ZstdFileMetadata
+}
+
+func (d *chunkedZstdDiffer) ApplyDiff(dest string, options *archive.TarOptions) (graphdriver.DriverWithDifferOutput, error) {
+ bigData := map[string][]byte{
+ bigDataKey: d.manifest,
+ }
+ output := graphdriver.DriverWithDifferOutput{
+ Differ: d,
+ BigData: bigData,
+ }
+
+ storeOpts, err := types.DefaultStoreOptionsAutoDetectUID()
+ if err != nil {
+ return output, err
+ }
+
+ enableHostDedup := false
+ if value := storeOpts.PullOptions["enable_host_deduplication"]; strings.ToLower(value) == "true" {
+ enableHostDedup = true
+ }
+
+ // Generate the manifest
+ var toc internal.ZstdTOC
+ if err := json.Unmarshal(d.manifest, &toc); err != nil {
+ return output, err
+ }
+
+ whiteoutConverter := archive.GetWhiteoutConverter(options.WhiteoutFormat, options.WhiteoutData)
+
+ var missingChunks []missingChunk
+ var mergedEntries []internal.ZstdFileMetadata
+
+ if err := maybeDoIDRemap(toc.Entries, options); err != nil {
+ return output, err
+ }
+
+ for _, e := range toc.Entries {
+ if e.Type == TypeChunk {
+ l := len(mergedEntries)
+ if l == 0 || mergedEntries[l-1].Type != TypeReg {
+ return output, errors.New("chunk type without a regular file")
+ }
+ mergedEntries[l-1].EndOffset = e.EndOffset
+ continue
+ }
+ mergedEntries = append(mergedEntries, e)
+ }
+
+ if options.ForceMask != nil {
+ uid, gid, mode, err := archive.GetFileOwner(dest)
+ if err == nil {
+ value := fmt.Sprintf("%d:%d:0%o", uid, gid, mode)
+ if err := unix.Setxattr(dest, containersOverrideXattr, []byte(value), 0); err != nil {
+ return output, err
+ }
+ }
+ }
+
+ dirfd, err := unix.Open(dest, unix.O_RDONLY|unix.O_PATH, 0)
+ if err != nil {
+ return output, err
+ }
+ defer unix.Close(dirfd)
+
+ otherLayersCache := prepareOtherLayersCache(d.layersMetadata)
+
+ missingDirsMode := os.FileMode(0700)
+ if options.ForceMask != nil {
+ missingDirsMode = *options.ForceMask
+ }
+
+ // hardlinks can point to missing files. So create them after all files
+ // are retrieved
+ var hardLinks []hardLinkToCreate
+
+ missingChunksSize, totalChunksSize := int64(0), int64(0)
+ for i, r := range mergedEntries {
+ if options.ForceMask != nil {
+ value := fmt.Sprintf("%d:%d:0%o", r.UID, r.GID, r.Mode&07777)
+ r.Xattrs[containersOverrideXattr] = base64.StdEncoding.EncodeToString([]byte(value))
+ r.Mode = int64(*options.ForceMask)
+ }
+
+ mode := os.FileMode(r.Mode)
+
+ r.Name = filepath.Clean(r.Name)
+ r.Linkname = filepath.Clean(r.Linkname)
+
+ t, err := typeToTarType(r.Type)
+ if err != nil {
+ return output, err
+ }
+ if whiteoutConverter != nil {
+ hdr := archivetar.Header{
+ Typeflag: t,
+ Name: r.Name,
+ Linkname: r.Linkname,
+ Size: r.Size,
+ Mode: r.Mode,
+ Uid: r.UID,
+ Gid: r.GID,
+ }
+ handler := whiteoutHandler{
+ Dirfd: dirfd,
+ Root: dest,
+ }
+ writeFile, err := whiteoutConverter.ConvertReadWithHandler(&hdr, r.Name, &handler)
+ if err != nil {
+ return output, err
+ }
+ if !writeFile {
+ continue
+ }
+ }
+ switch t {
+ case tar.TypeReg:
+ // Create directly empty files.
+ if r.Size == 0 {
+ // Used to have a scope for cleanup.
+ createEmptyFile := func() error {
+ file, err := openFileUnderRoot(r.Name, dest, dirfd, newFileFlags, 0)
+ if err != nil {
+ return err
+ }
+ defer file.Close()
+ if err := setFileAttrs(file, mode, &r, options); err != nil {
+ return err
+ }
+ return nil
+ }
+ if err := createEmptyFile(); err != nil {
+ return output, err
+ }
+ continue
+ }
+
+ case tar.TypeDir:
+ if err := safeMkdir(dest, dirfd, mode, &r, options); err != nil {
+ return output, err
+ }
+ continue
+
+ case tar.TypeLink:
+ dest := dest
+ dirfd := dirfd
+ mode := mode
+ r := r
+ hardLinks = append(hardLinks, hardLinkToCreate{
+ dest: dest,
+ dirfd: dirfd,
+ mode: mode,
+ metadata: &r,
+ })
+ continue
+
+ case tar.TypeSymlink:
+ if err := safeSymlink(dest, dirfd, mode, &r, options); err != nil {
+ return output, err
+ }
+ continue
+
+ case tar.TypeChar:
+ case tar.TypeBlock:
+ case tar.TypeFifo:
+ /* Ignore. */
+ default:
+ return output, fmt.Errorf("invalid type %q", t)
+ }
+
+ totalChunksSize += r.Size
+
+ dstFile, _, err := findFileInOtherLayers(r, dest, dirfd, otherLayersCache, d.layersTarget, missingDirsMode)
+ if err != nil {
+ return output, err
+ }
+ if dstFile != nil {
+ if err := setFileAttrs(dstFile, mode, &r, options); err != nil {
+ dstFile.Close()
+ return output, err
+ }
+ dstFile.Close()
+ continue
+ }
+
+ if enableHostDedup {
+ dstFile, _, err = findFileOnTheHost(r, dest, dirfd, missingDirsMode)
+ if err != nil {
+ return output, err
+ }
+ if dstFile != nil {
+ if err := setFileAttrs(dstFile, mode, &r, options); err != nil {
+ dstFile.Close()
+ return output, err
+ }
+ dstFile.Close()
+ continue
+ }
+ }
+
+ missingChunksSize += r.Size
+ if t == tar.TypeReg {
+ rawChunk := ImageSourceChunk{
+ Offset: uint64(r.Offset),
+ Length: uint64(r.EndOffset - r.Offset),
+ }
+ file := missingFile{
+ File: &toc.Entries[i],
+ }
+ missingChunks = append(missingChunks, missingChunk{
+ RawChunk: rawChunk,
+ Files: []missingFile{
+ file,
+ },
+ })
+ }
+ }
+ // There are some missing files. Prepare a multirange request for the missing chunks.
+ if len(missingChunks) > 0 {
+ missingChunks = mergeMissingChunks(missingChunks, maxNumberMissingChunks)
+ if err := retrieveMissingFiles(d, dest, dirfd, missingChunks, missingDirsMode, options); err != nil {
+ return output, err
+ }
+ }
+
+ for _, m := range hardLinks {
+ if err := safeLink(m.dest, m.dirfd, m.mode, m.metadata, options); err != nil {
+ return output, err
+ }
+ }
+
+ if totalChunksSize > 0 {
+ logrus.Debugf("Missing %d bytes out of %d (%.2f %%)", missingChunksSize, totalChunksSize, float32(missingChunksSize*100.0)/float32(totalChunksSize))
+ }
+ return output, nil
+}
diff --git a/vendor/github.com/containers/storage/pkg/chunked/storage_unsupported.go b/vendor/github.com/containers/storage/pkg/chunked/storage_unsupported.go
new file mode 100644
index 000000000..3a406ba78
--- /dev/null
+++ b/vendor/github.com/containers/storage/pkg/chunked/storage_unsupported.go
@@ -0,0 +1,16 @@
+// +build !linux
+
+package chunked
+
+import (
+ "context"
+
+ storage "github.com/containers/storage"
+ graphdriver "github.com/containers/storage/drivers"
+ "github.com/pkg/errors"
+)
+
+// GetDiffer returns a differ than can be used with ApplyDiffWithDiffer.
+func GetDiffer(ctx context.Context, store storage.Store, blobSize int64, annotations map[string]string, iss ImageSourceSeekable) (graphdriver.Differ, error) {
+ return nil, errors.New("format not supported on this architecture")
+}
diff --git a/vendor/github.com/containers/storage/storage.conf b/vendor/github.com/containers/storage/storage.conf
index e70f4f018..722750c0c 100644
--- a/vendor/github.com/containers/storage/storage.conf
+++ b/vendor/github.com/containers/storage/storage.conf
@@ -69,6 +69,9 @@ additionalimagestores = [
# and vfs drivers.
#ignore_chown_errors = "false"
+# Inodes is used to set a maximum inodes of the container image.
+# inodes = ""
+
# Path to an helper program to use for mounting the file system instead of mounting it
# directly.
#mount_program = "/usr/bin/fuse-overlayfs"
diff --git a/vendor/github.com/containers/storage/types/utils.go b/vendor/github.com/containers/storage/types/utils.go
index 03ddd5ad9..4d62b151a 100644
--- a/vendor/github.com/containers/storage/types/utils.go
+++ b/vendor/github.com/containers/storage/types/utils.go
@@ -2,6 +2,7 @@ package types
import (
"fmt"
+ "io/ioutil"
"os"
"path/filepath"
"strconv"
@@ -74,9 +75,12 @@ func getRootlessRuntimeDirIsolated(env rootlessRuntimeDirEnvironment) (string, e
return runtimeDir, nil
}
- runUserDir := env.getRunUserDir()
- if isRootlessRuntimeDirOwner(runUserDir, env) {
- return runUserDir, nil
+ initCommand, err := ioutil.ReadFile(env.getProcCommandFile())
+ if err != nil || string(initCommand) == "systemd" {
+ runUserDir := env.getRunUserDir()
+ if isRootlessRuntimeDirOwner(runUserDir, env) {
+ return runUserDir, nil
+ }
}
tmpPerUserDir := env.getTmpPerUserDir()
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/user/user.go b/vendor/github.com/opencontainers/runc/libcontainer/user/user.go
index d2c16f7fd..cc7a106be 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/user/user.go
+++ b/vendor/github.com/opencontainers/runc/libcontainer/user/user.go
@@ -2,6 +2,7 @@ package user
import (
"bufio"
+ "bytes"
"errors"
"fmt"
"io"
@@ -55,11 +56,11 @@ type IDMap struct {
Count int64
}
-func parseLine(line string, v ...interface{}) {
- parseParts(strings.Split(line, ":"), v...)
+func parseLine(line []byte, v ...interface{}) {
+ parseParts(bytes.Split(line, []byte(":")), v...)
}
-func parseParts(parts []string, v ...interface{}) {
+func parseParts(parts [][]byte, v ...interface{}) {
if len(parts) == 0 {
return
}
@@ -75,16 +76,16 @@ func parseParts(parts []string, v ...interface{}) {
// This is legit.
switch e := v[i].(type) {
case *string:
- *e = p
+ *e = string(p)
case *int:
// "numbers", with conversion errors ignored because of some misbehaving configuration files.
- *e, _ = strconv.Atoi(p)
+ *e, _ = strconv.Atoi(string(p))
case *int64:
- *e, _ = strconv.ParseInt(p, 10, 64)
+ *e, _ = strconv.ParseInt(string(p), 10, 64)
case *[]string:
// Comma-separated lists.
- if p != "" {
- *e = strings.Split(p, ",")
+ if len(p) != 0 {
+ *e = strings.Split(string(p), ",")
} else {
*e = []string{}
}
@@ -128,8 +129,8 @@ func ParsePasswdFilter(r io.Reader, filter func(User) bool) ([]User, error) {
)
for s.Scan() {
- line := strings.TrimSpace(s.Text())
- if line == "" {
+ line := bytes.TrimSpace(s.Bytes())
+ if len(line) == 0 {
continue
}
@@ -179,15 +180,53 @@ func ParseGroupFilter(r io.Reader, filter func(Group) bool) ([]Group, error) {
if r == nil {
return nil, fmt.Errorf("nil source for group-formatted data")
}
+ rd := bufio.NewReader(r)
+ out := []Group{}
- var (
- s = bufio.NewScanner(r)
- out = []Group{}
- )
+ // Read the file line-by-line.
+ for {
+ var (
+ isPrefix bool
+ wholeLine []byte
+ err error
+ )
- for s.Scan() {
- text := s.Text()
- if text == "" {
+ // Read the next line. We do so in chunks (as much as reader's
+ // buffer is able to keep), check if we read enough columns
+ // already on each step and store final result in wholeLine.
+ for {
+ var line []byte
+ line, isPrefix, err = rd.ReadLine()
+
+ if err != nil {
+ // We should return no error if EOF is reached
+ // without a match.
+ if err == io.EOF { //nolint:errorlint // comparison with io.EOF is legit, https://github.com/polyfloyd/go-errorlint/pull/12
+ err = nil
+ }
+ return out, err
+ }
+
+ // Simple common case: line is short enough to fit in a
+ // single reader's buffer.
+ if !isPrefix && len(wholeLine) == 0 {
+ wholeLine = line
+ break
+ }
+
+ wholeLine = append(wholeLine, line...)
+
+ // Check if we read the whole line already.
+ if !isPrefix {
+ break
+ }
+ }
+
+ // There's no spec for /etc/passwd or /etc/group, but we try to follow
+ // the same rules as the glibc parser, which allows comments and blank
+ // space at the beginning of a line.
+ wholeLine = bytes.TrimSpace(wholeLine)
+ if len(wholeLine) == 0 || wholeLine[0] == '#' {
continue
}
@@ -197,17 +236,12 @@ func ParseGroupFilter(r io.Reader, filter func(Group) bool) ([]Group, error) {
// root:x:0:root
// adm:x:4:root,adm,daemon
p := Group{}
- parseLine(text, &p.Name, &p.Pass, &p.Gid, &p.List)
+ parseLine(wholeLine, &p.Name, &p.Pass, &p.Gid, &p.List)
if filter == nil || filter(p) {
out = append(out, p)
}
}
- if err := s.Err(); err != nil {
- return nil, err
- }
-
- return out, nil
}
type ExecUser struct {
@@ -278,7 +312,7 @@ func GetExecUser(userSpec string, defaults *ExecUser, passwd, group io.Reader) (
// Allow for userArg to have either "user" syntax, or optionally "user:group" syntax
var userArg, groupArg string
- parseLine(userSpec, &userArg, &groupArg)
+ parseLine([]byte(userSpec), &userArg, &groupArg)
// Convert userArg and groupArg to be numeric, so we don't have to execute
// Atoi *twice* for each iteration over lines.
@@ -496,8 +530,8 @@ func ParseSubIDFilter(r io.Reader, filter func(SubID) bool) ([]SubID, error) {
)
for s.Scan() {
- line := strings.TrimSpace(s.Text())
- if line == "" {
+ line := bytes.TrimSpace(s.Bytes())
+ if len(line) == 0 {
continue
}
@@ -549,14 +583,14 @@ func ParseIDMapFilter(r io.Reader, filter func(IDMap) bool) ([]IDMap, error) {
)
for s.Scan() {
- line := strings.TrimSpace(s.Text())
- if line == "" {
+ line := bytes.TrimSpace(s.Bytes())
+ if len(line) == 0 {
continue
}
// see: man 7 user_namespaces
p := IDMap{}
- parseParts(strings.Fields(line), &p.ID, &p.ParentID, &p.Count)
+ parseParts(bytes.Fields(line), &p.ID, &p.ParentID, &p.Count)
if filter == nil || filter(p) {
out = append(out, p)
diff --git a/vendor/github.com/vbauerster/mpb/v7/cwriter/util_zos.go b/vendor/github.com/vbauerster/mpb/v7/cwriter/util_zos.go
new file mode 100644
index 000000000..b7d67fc43
--- /dev/null
+++ b/vendor/github.com/vbauerster/mpb/v7/cwriter/util_zos.go
@@ -0,0 +1,7 @@
+// +build zos
+
+package cwriter
+
+import "golang.org/x/sys/unix"
+
+const ioctlReadTermios = unix.TCGETS
diff --git a/vendor/github.com/vbauerster/mpb/v7/go.mod b/vendor/github.com/vbauerster/mpb/v7/go.mod
index ea22e1eda..22a2c651c 100644
--- a/vendor/github.com/vbauerster/mpb/v7/go.mod
+++ b/vendor/github.com/vbauerster/mpb/v7/go.mod
@@ -4,7 +4,7 @@ require (
github.com/VividCortex/ewma v1.2.0
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d
github.com/mattn/go-runewidth v0.0.13
- golang.org/x/sys v0.0.0-20210603125802-9665404d3644
+ golang.org/x/sys v0.0.0-20210616094352-59db8d763f22
)
go 1.14
diff --git a/vendor/github.com/vbauerster/mpb/v7/go.sum b/vendor/github.com/vbauerster/mpb/v7/go.sum
index 0b609b223..59051bd7b 100644
--- a/vendor/github.com/vbauerster/mpb/v7/go.sum
+++ b/vendor/github.com/vbauerster/mpb/v7/go.sum
@@ -6,5 +6,5 @@ github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
-golang.org/x/sys v0.0.0-20210603125802-9665404d3644 h1:CA1DEQ4NdKphKeL70tvsWNdT5oFh1lOjihRcEDROi0I=
-golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 h1:RqytpXGR1iVNX7psjB3ff8y7sNFinVFvkx1c8SjBkio=
+golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
diff --git a/vendor/golang.org/x/sys/unix/mkerrors.sh b/vendor/golang.org/x/sys/unix/mkerrors.sh
index 3f670faba..6e6afcaa1 100644
--- a/vendor/golang.org/x/sys/unix/mkerrors.sh
+++ b/vendor/golang.org/x/sys/unix/mkerrors.sh
@@ -563,6 +563,7 @@ ccflags="$@"
$2 ~ /^KEYCTL_/ ||
$2 ~ /^PERF_/ ||
$2 ~ /^SECCOMP_MODE_/ ||
+ $2 ~ /^SEEK_/ ||
$2 ~ /^SPLICE_/ ||
$2 ~ /^SYNC_FILE_RANGE_/ ||
$2 !~ /^AUDIT_RECORD_MAGIC/ &&
diff --git a/vendor/golang.org/x/sys/unix/syscall_darwin.go b/vendor/golang.org/x/sys/unix/syscall_darwin.go
index 9945e5f96..23f6b5760 100644
--- a/vendor/golang.org/x/sys/unix/syscall_darwin.go
+++ b/vendor/golang.org/x/sys/unix/syscall_darwin.go
@@ -13,6 +13,7 @@
package unix
import (
+ "fmt"
"runtime"
"syscall"
"unsafe"
@@ -398,6 +399,38 @@ func GetsockoptXucred(fd, level, opt int) (*Xucred, error) {
return x, err
}
+func SysctlKinfoProcSlice(name string) ([]KinfoProc, error) {
+ mib, err := sysctlmib(name)
+ if err != nil {
+ return nil, err
+ }
+
+ // Find size.
+ n := uintptr(0)
+ if err := sysctl(mib, nil, &n, nil, 0); err != nil {
+ return nil, err
+ }
+ if n == 0 {
+ return nil, nil
+ }
+ if n%SizeofKinfoProc != 0 {
+ return nil, fmt.Errorf("sysctl() returned a size of %d, which is not a multiple of %d", n, SizeofKinfoProc)
+ }
+
+ // Read into buffer of that size.
+ buf := make([]KinfoProc, n/SizeofKinfoProc)
+ if err := sysctl(mib, (*byte)(unsafe.Pointer(&buf[0])), &n, nil, 0); err != nil {
+ return nil, err
+ }
+ if n%SizeofKinfoProc != 0 {
+ return nil, fmt.Errorf("sysctl() returned a size of %d, which is not a multiple of %d", n, SizeofKinfoProc)
+ }
+
+ // The actual call may return less than the original reported required
+ // size so ensure we deal with that.
+ return buf[:n/SizeofKinfoProc], nil
+}
+
//sys sendfile(infd int, outfd int, offset int64, len *int64, hdtr unsafe.Pointer, flags int) (err error)
/*
diff --git a/vendor/golang.org/x/sys/unix/zerrors_darwin_amd64.go b/vendor/golang.org/x/sys/unix/zerrors_darwin_amd64.go
index 991996b60..5bb48ef54 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_darwin_amd64.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_darwin_amd64.go
@@ -1262,6 +1262,11 @@ const (
SCM_RIGHTS = 0x1
SCM_TIMESTAMP = 0x2
SCM_TIMESTAMP_MONOTONIC = 0x4
+ SEEK_CUR = 0x1
+ SEEK_DATA = 0x4
+ SEEK_END = 0x2
+ SEEK_HOLE = 0x3
+ SEEK_SET = 0x0
SHUT_RD = 0x0
SHUT_RDWR = 0x2
SHUT_WR = 0x1
diff --git a/vendor/golang.org/x/sys/unix/zerrors_darwin_arm64.go b/vendor/golang.org/x/sys/unix/zerrors_darwin_arm64.go
index e644eaf5e..11e570979 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_darwin_arm64.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_darwin_arm64.go
@@ -1262,6 +1262,11 @@ const (
SCM_RIGHTS = 0x1
SCM_TIMESTAMP = 0x2
SCM_TIMESTAMP_MONOTONIC = 0x4
+ SEEK_CUR = 0x1
+ SEEK_DATA = 0x4
+ SEEK_END = 0x2
+ SEEK_HOLE = 0x3
+ SEEK_SET = 0x0
SHUT_RD = 0x0
SHUT_RDWR = 0x2
SHUT_WR = 0x1
diff --git a/vendor/golang.org/x/sys/unix/zerrors_freebsd_386.go b/vendor/golang.org/x/sys/unix/zerrors_freebsd_386.go
index 9c7c5e165..440900112 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_freebsd_386.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_freebsd_386.go
@@ -1297,6 +1297,11 @@ const (
SCM_RIGHTS = 0x1
SCM_TIMESTAMP = 0x2
SCM_TIME_INFO = 0x7
+ SEEK_CUR = 0x1
+ SEEK_DATA = 0x3
+ SEEK_END = 0x2
+ SEEK_HOLE = 0x4
+ SEEK_SET = 0x0
SHUT_RD = 0x0
SHUT_RDWR = 0x2
SHUT_WR = 0x1
diff --git a/vendor/golang.org/x/sys/unix/zerrors_freebsd_amd64.go b/vendor/golang.org/x/sys/unix/zerrors_freebsd_amd64.go
index b265abb25..64520d312 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_freebsd_amd64.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_freebsd_amd64.go
@@ -1298,6 +1298,11 @@ const (
SCM_RIGHTS = 0x1
SCM_TIMESTAMP = 0x2
SCM_TIME_INFO = 0x7
+ SEEK_CUR = 0x1
+ SEEK_DATA = 0x3
+ SEEK_END = 0x2
+ SEEK_HOLE = 0x4
+ SEEK_SET = 0x0
SHUT_RD = 0x0
SHUT_RDWR = 0x2
SHUT_WR = 0x1
diff --git a/vendor/golang.org/x/sys/unix/zerrors_freebsd_arm.go b/vendor/golang.org/x/sys/unix/zerrors_freebsd_arm.go
index 3df99f285..99e9a0e06 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_freebsd_arm.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_freebsd_arm.go
@@ -1276,6 +1276,11 @@ const (
SCM_CREDS = 0x3
SCM_RIGHTS = 0x1
SCM_TIMESTAMP = 0x2
+ SEEK_CUR = 0x1
+ SEEK_DATA = 0x3
+ SEEK_END = 0x2
+ SEEK_HOLE = 0x4
+ SEEK_SET = 0x0
SHUT_RD = 0x0
SHUT_RDWR = 0x2
SHUT_WR = 0x1
diff --git a/vendor/golang.org/x/sys/unix/zerrors_freebsd_arm64.go b/vendor/golang.org/x/sys/unix/zerrors_freebsd_arm64.go
index 218d39906..4c8377114 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_freebsd_arm64.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_freebsd_arm64.go
@@ -1298,6 +1298,11 @@ const (
SCM_RIGHTS = 0x1
SCM_TIMESTAMP = 0x2
SCM_TIME_INFO = 0x7
+ SEEK_CUR = 0x1
+ SEEK_DATA = 0x3
+ SEEK_END = 0x2
+ SEEK_HOLE = 0x4
+ SEEK_SET = 0x0
SHUT_RD = 0x0
SHUT_RDWR = 0x2
SHUT_WR = 0x1
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux.go b/vendor/golang.org/x/sys/unix/zerrors_linux.go
index c3fa22486..52f5bbc14 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux.go
@@ -2284,6 +2284,12 @@ const (
SECCOMP_MODE_FILTER = 0x2
SECCOMP_MODE_STRICT = 0x1
SECURITYFS_MAGIC = 0x73636673
+ SEEK_CUR = 0x1
+ SEEK_DATA = 0x3
+ SEEK_END = 0x2
+ SEEK_HOLE = 0x4
+ SEEK_MAX = 0x4
+ SEEK_SET = 0x0
SELINUX_MAGIC = 0xf97cff8c
SHUT_RD = 0x0
SHUT_RDWR = 0x2
diff --git a/vendor/golang.org/x/sys/unix/ztypes_darwin_amd64.go b/vendor/golang.org/x/sys/unix/ztypes_darwin_amd64.go
index 2673e6c59..4c8dc0ba2 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_darwin_amd64.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_darwin_amd64.go
@@ -535,3 +535,107 @@ type CtlInfo struct {
Id uint32
Name [96]byte
}
+
+const SizeofKinfoProc = 0x288
+
+type Eproc struct {
+ Paddr uintptr
+ Sess uintptr
+ Pcred Pcred
+ Ucred Ucred
+ Vm Vmspace
+ Ppid int32
+ Pgid int32
+ Jobc int16
+ Tdev int32
+ Tpgid int32
+ Tsess uintptr
+ Wmesg [8]int8
+ Xsize int32
+ Xrssize int16
+ Xccount int16
+ Xswrss int16
+ Flag int32
+ Login [12]int8
+ Spare [4]int32
+ _ [4]byte
+}
+
+type ExternProc struct {
+ P_starttime Timeval
+ P_vmspace *Vmspace
+ P_sigacts uintptr
+ P_flag int32
+ P_stat int8
+ P_pid int32
+ P_oppid int32
+ P_dupfd int32
+ User_stack *int8
+ Exit_thread *byte
+ P_debugger int32
+ Sigwait int32
+ P_estcpu uint32
+ P_cpticks int32
+ P_pctcpu uint32
+ P_wchan *byte
+ P_wmesg *int8
+ P_swtime uint32
+ P_slptime uint32
+ P_realtimer Itimerval
+ P_rtime Timeval
+ P_uticks uint64
+ P_sticks uint64
+ P_iticks uint64
+ P_traceflag int32
+ P_tracep uintptr
+ P_siglist int32
+ P_textvp uintptr
+ P_holdcnt int32
+ P_sigmask uint32
+ P_sigignore uint32
+ P_sigcatch uint32
+ P_priority uint8
+ P_usrpri uint8
+ P_nice int8
+ P_comm [17]int8
+ P_pgrp uintptr
+ P_addr uintptr
+ P_xstat uint16
+ P_acflag uint16
+ P_ru *Rusage
+}
+
+type Itimerval struct {
+ Interval Timeval
+ Value Timeval
+}
+
+type KinfoProc struct {
+ Proc ExternProc
+ Eproc Eproc
+}
+
+type Vmspace struct {
+ Dummy int32
+ Dummy2 *int8
+ Dummy3 [5]int32
+ Dummy4 [3]*int8
+}
+
+type Pcred struct {
+ Pc_lock [72]int8
+ Pc_ucred uintptr
+ P_ruid uint32
+ P_svuid uint32
+ P_rgid uint32
+ P_svgid uint32
+ P_refcnt int32
+ _ [4]byte
+}
+
+type Ucred struct {
+ Ref int32
+ Uid uint32
+ Ngroups int16
+ Groups [16]uint32
+}
diff --git a/vendor/golang.org/x/sys/unix/ztypes_darwin_arm64.go b/vendor/golang.org/x/sys/unix/ztypes_darwin_arm64.go
index 1465cbcff..96f0e6ae2 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_darwin_arm64.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_darwin_arm64.go
@@ -535,3 +535,107 @@ type CtlInfo struct {
Id uint32
Name [96]byte
}
+
+const SizeofKinfoProc = 0x288
+
+type Eproc struct {
+ Paddr uintptr
+ Sess uintptr
+ Pcred Pcred
+ Ucred Ucred
+ Vm Vmspace
+ Ppid int32
+ Pgid int32
+ Jobc int16
+ Tdev int32
+ Tpgid int32
+ Tsess uintptr
+ Wmesg [8]int8
+ Xsize int32
+ Xrssize int16
+ Xccount int16
+ Xswrss int16
+ Flag int32
+ Login [12]int8
+ Spare [4]int32
+ _ [4]byte
+}
+
+type ExternProc struct {
+ P_starttime Timeval
+ P_vmspace *Vmspace
+ P_sigacts uintptr
+ P_flag int32
+ P_stat int8
+ P_pid int32
+ P_oppid int32
+ P_dupfd int32
+ User_stack *int8
+ Exit_thread *byte
+ P_debugger int32
+ Sigwait int32
+ P_estcpu uint32
+ P_cpticks int32
+ P_pctcpu uint32
+ P_wchan *byte
+ P_wmesg *int8
+ P_swtime uint32
+ P_slptime uint32
+ P_realtimer Itimerval
+ P_rtime Timeval
+ P_uticks uint64
+ P_sticks uint64
+ P_iticks uint64
+ P_traceflag int32
+ P_tracep uintptr
+ P_siglist int32
+ P_textvp uintptr
+ P_holdcnt int32
+ P_sigmask uint32
+ P_sigignore uint32
+ P_sigcatch uint32
+ P_priority uint8
+ P_usrpri uint8
+ P_nice int8
+ P_comm [17]int8
+ P_pgrp uintptr
+ P_addr uintptr
+ P_xstat uint16
+ P_acflag uint16
+ P_ru *Rusage
+}
+
+type Itimerval struct {
+ Interval Timeval
+ Value Timeval
+}
+
+type KinfoProc struct {
+ Proc ExternProc
+ Eproc Eproc
+}
+
+type Vmspace struct {
+ Dummy int32
+ Dummy2 *int8
+ Dummy3 [5]int32
+ Dummy4 [3]*int8
+}
+
+type Pcred struct {
+ Pc_lock [72]int8
+ Pc_ucred uintptr
+ P_ruid uint32
+ P_svuid uint32
+ P_rgid uint32
+ P_svgid uint32
+ P_refcnt int32
+ _ [4]byte
+}
+
+type Ucred struct {
+ Ref int32
+ Uid uint32
+ Ngroups int16
+ Groups [16]uint32
+}
diff --git a/vendor/golang.org/x/sys/unix/ztypes_dragonfly_amd64.go b/vendor/golang.org/x/sys/unix/ztypes_dragonfly_amd64.go
index 1d049d7a1..d0ba8e9b8 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_dragonfly_amd64.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_dragonfly_amd64.go
@@ -431,6 +431,9 @@ type Winsize struct {
const (
AT_FDCWD = 0xfffafdcd
AT_SYMLINK_NOFOLLOW = 0x1
+ AT_REMOVEDIR = 0x2
+ AT_EACCESS = 0x4
+ AT_SYMLINK_FOLLOW = 0x8
)
type PollFd struct {
diff --git a/vendor/golang.org/x/sys/unix/ztypes_freebsd_386.go b/vendor/golang.org/x/sys/unix/ztypes_freebsd_386.go
index c51bc88ff..1f99c024a 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_freebsd_386.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_freebsd_386.go
@@ -672,9 +672,10 @@ type Winsize struct {
const (
AT_FDCWD = -0x64
- AT_REMOVEDIR = 0x800
- AT_SYMLINK_FOLLOW = 0x400
+ AT_EACCESS = 0x100
AT_SYMLINK_NOFOLLOW = 0x200
+ AT_SYMLINK_FOLLOW = 0x400
+ AT_REMOVEDIR = 0x800
)
type PollFd struct {
diff --git a/vendor/golang.org/x/sys/unix/ztypes_freebsd_amd64.go b/vendor/golang.org/x/sys/unix/ztypes_freebsd_amd64.go
index 395b69187..ddf0305a5 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_freebsd_amd64.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_freebsd_amd64.go
@@ -675,9 +675,10 @@ type Winsize struct {
const (
AT_FDCWD = -0x64
- AT_REMOVEDIR = 0x800
- AT_SYMLINK_FOLLOW = 0x400
+ AT_EACCESS = 0x100
AT_SYMLINK_NOFOLLOW = 0x200
+ AT_SYMLINK_FOLLOW = 0x400
+ AT_REMOVEDIR = 0x800
)
type PollFd struct {
diff --git a/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm.go b/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm.go
index d3f9d2541..dce0a5c80 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm.go
@@ -656,9 +656,10 @@ type Winsize struct {
const (
AT_FDCWD = -0x64
- AT_REMOVEDIR = 0x800
- AT_SYMLINK_FOLLOW = 0x400
+ AT_EACCESS = 0x100
AT_SYMLINK_NOFOLLOW = 0x200
+ AT_SYMLINK_FOLLOW = 0x400
+ AT_REMOVEDIR = 0x800
)
type PollFd struct {
diff --git a/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm64.go b/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm64.go
index 434d6e8e8..e23244702 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm64.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm64.go
@@ -653,9 +653,10 @@ type Winsize struct {
const (
AT_FDCWD = -0x64
- AT_REMOVEDIR = 0x800
- AT_SYMLINK_FOLLOW = 0x400
+ AT_EACCESS = 0x100
AT_SYMLINK_NOFOLLOW = 0x200
+ AT_SYMLINK_FOLLOW = 0x400
+ AT_REMOVEDIR = 0x800
)
type PollFd struct {
diff --git a/vendor/golang.org/x/sys/unix/ztypes_netbsd_386.go b/vendor/golang.org/x/sys/unix/ztypes_netbsd_386.go
index b10e73abf..2fd2060e6 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_netbsd_386.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_netbsd_386.go
@@ -445,8 +445,10 @@ type Ptmget struct {
const (
AT_FDCWD = -0x64
- AT_SYMLINK_FOLLOW = 0x400
+ AT_EACCESS = 0x100
AT_SYMLINK_NOFOLLOW = 0x200
+ AT_SYMLINK_FOLLOW = 0x400
+ AT_REMOVEDIR = 0x800
)
type PollFd struct {
diff --git a/vendor/golang.org/x/sys/unix/ztypes_netbsd_amd64.go b/vendor/golang.org/x/sys/unix/ztypes_netbsd_amd64.go
index 28ed6d55a..6a5a1a8ae 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_netbsd_amd64.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_netbsd_amd64.go
@@ -453,8 +453,10 @@ type Ptmget struct {
const (
AT_FDCWD = -0x64
- AT_SYMLINK_FOLLOW = 0x400
+ AT_EACCESS = 0x100
AT_SYMLINK_NOFOLLOW = 0x200
+ AT_SYMLINK_FOLLOW = 0x400
+ AT_REMOVEDIR = 0x800
)
type PollFd struct {
diff --git a/vendor/golang.org/x/sys/unix/ztypes_netbsd_arm.go b/vendor/golang.org/x/sys/unix/ztypes_netbsd_arm.go
index 4ba196ebe..84cc8d01e 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_netbsd_arm.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_netbsd_arm.go
@@ -450,8 +450,10 @@ type Ptmget struct {
const (
AT_FDCWD = -0x64
- AT_SYMLINK_FOLLOW = 0x400
+ AT_EACCESS = 0x100
AT_SYMLINK_NOFOLLOW = 0x200
+ AT_SYMLINK_FOLLOW = 0x400
+ AT_REMOVEDIR = 0x800
)
type PollFd struct {
diff --git a/vendor/golang.org/x/sys/unix/ztypes_netbsd_arm64.go b/vendor/golang.org/x/sys/unix/ztypes_netbsd_arm64.go
index dd642bd9c..c844e7096 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_netbsd_arm64.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_netbsd_arm64.go
@@ -453,8 +453,10 @@ type Ptmget struct {
const (
AT_FDCWD = -0x64
- AT_SYMLINK_FOLLOW = 0x400
+ AT_EACCESS = 0x100
AT_SYMLINK_NOFOLLOW = 0x200
+ AT_SYMLINK_FOLLOW = 0x400
+ AT_REMOVEDIR = 0x800
)
type PollFd struct {
diff --git a/vendor/golang.org/x/sys/unix/ztypes_openbsd_386.go b/vendor/golang.org/x/sys/unix/ztypes_openbsd_386.go
index 1fdb0e5fa..2a8b1e6f7 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_openbsd_386.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_openbsd_386.go
@@ -438,8 +438,10 @@ type Winsize struct {
const (
AT_FDCWD = -0x64
- AT_SYMLINK_FOLLOW = 0x4
+ AT_EACCESS = 0x1
AT_SYMLINK_NOFOLLOW = 0x2
+ AT_SYMLINK_FOLLOW = 0x4
+ AT_REMOVEDIR = 0x8
)
type PollFd struct {
diff --git a/vendor/golang.org/x/sys/unix/ztypes_openbsd_amd64.go b/vendor/golang.org/x/sys/unix/ztypes_openbsd_amd64.go
index e2fc93c7c..b1759cf70 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_openbsd_amd64.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_openbsd_amd64.go
@@ -438,8 +438,10 @@ type Winsize struct {
const (
AT_FDCWD = -0x64
- AT_SYMLINK_FOLLOW = 0x4
+ AT_EACCESS = 0x1
AT_SYMLINK_NOFOLLOW = 0x2
+ AT_SYMLINK_FOLLOW = 0x4
+ AT_REMOVEDIR = 0x8
)
type PollFd struct {
diff --git a/vendor/golang.org/x/sys/unix/ztypes_openbsd_arm.go b/vendor/golang.org/x/sys/unix/ztypes_openbsd_arm.go
index 8d34b5a2f..e807de206 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_openbsd_arm.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_openbsd_arm.go
@@ -439,8 +439,10 @@ type Winsize struct {
const (
AT_FDCWD = -0x64
- AT_SYMLINK_FOLLOW = 0x4
+ AT_EACCESS = 0x1
AT_SYMLINK_NOFOLLOW = 0x2
+ AT_SYMLINK_FOLLOW = 0x4
+ AT_REMOVEDIR = 0x8
)
type PollFd struct {
diff --git a/vendor/golang.org/x/sys/unix/ztypes_openbsd_arm64.go b/vendor/golang.org/x/sys/unix/ztypes_openbsd_arm64.go
index ea8f1a0d9..ff3aecaee 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_openbsd_arm64.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_openbsd_arm64.go
@@ -432,8 +432,10 @@ type Winsize struct {
const (
AT_FDCWD = -0x64
- AT_SYMLINK_FOLLOW = 0x4
+ AT_EACCESS = 0x1
AT_SYMLINK_NOFOLLOW = 0x2
+ AT_SYMLINK_FOLLOW = 0x4
+ AT_REMOVEDIR = 0x8
)
type PollFd struct {
diff --git a/vendor/golang.org/x/sys/unix/ztypes_openbsd_mips64.go b/vendor/golang.org/x/sys/unix/ztypes_openbsd_mips64.go
index ec6e8bc3f..9ecda6917 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_openbsd_mips64.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_openbsd_mips64.go
@@ -432,8 +432,10 @@ type Winsize struct {
const (
AT_FDCWD = -0x64
- AT_SYMLINK_FOLLOW = 0x4
+ AT_EACCESS = 0x1
AT_SYMLINK_NOFOLLOW = 0x2
+ AT_SYMLINK_FOLLOW = 0x4
+ AT_REMOVEDIR = 0x8
)
type PollFd struct {
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 2a858bced..c89582328 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -46,9 +46,9 @@ github.com/buger/goterm
github.com/cespare/xxhash/v2
# github.com/checkpoint-restore/checkpointctl v0.0.0-20210301084134-a2024f5584e7
github.com/checkpoint-restore/checkpointctl/lib
-# github.com/checkpoint-restore/go-criu v0.0.0-20190109184317-bdb7599cd87b
-github.com/checkpoint-restore/go-criu
-github.com/checkpoint-restore/go-criu/rpc
+# github.com/checkpoint-restore/go-criu/v5 v5.1.0
+github.com/checkpoint-restore/go-criu/v5
+github.com/checkpoint-restore/go-criu/v5/rpc
# github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e
github.com/chzyer/readline
# github.com/container-orchestrated-devices/container-device-interface v0.0.0-20210325223243-f99e8b6c10b9
@@ -77,7 +77,7 @@ github.com/containernetworking/plugins/pkg/utils/hwaddr
github.com/containernetworking/plugins/pkg/utils/sysctl
github.com/containernetworking/plugins/plugins/ipam/host-local/backend
github.com/containernetworking/plugins/plugins/ipam/host-local/backend/allocator
-# github.com/containers/buildah v1.21.1-0.20210707133512-2eb97b499d74
+# github.com/containers/buildah v1.21.1-0.20210721171232-54cafea4c933
github.com/containers/buildah
github.com/containers/buildah/bind
github.com/containers/buildah/chroot
@@ -93,7 +93,7 @@ github.com/containers/buildah/pkg/overlay
github.com/containers/buildah/pkg/parse
github.com/containers/buildah/pkg/rusage
github.com/containers/buildah/util
-# github.com/containers/common v0.41.1-0.20210716140645-ffcfe1ff6e70
+# github.com/containers/common v0.41.1-0.20210730122913-cd6c45fd20e3
github.com/containers/common/libimage
github.com/containers/common/libimage/manifests
github.com/containers/common/pkg/apparmor
@@ -125,7 +125,7 @@ github.com/containers/common/pkg/umask
github.com/containers/common/version
# github.com/containers/conmon v2.0.20+incompatible
github.com/containers/conmon/runner/config
-# github.com/containers/image/v5 v5.13.2
+# github.com/containers/image/v5 v5.15.0
github.com/containers/image/v5/copy
github.com/containers/image/v5/directory
github.com/containers/image/v5/directory/explicitfilepath
@@ -197,7 +197,7 @@ github.com/containers/psgo/internal/dev
github.com/containers/psgo/internal/host
github.com/containers/psgo/internal/proc
github.com/containers/psgo/internal/process
-# github.com/containers/storage v1.32.6
+# github.com/containers/storage v1.33.1
github.com/containers/storage
github.com/containers/storage/drivers
github.com/containers/storage/drivers/aufs
@@ -213,6 +213,9 @@ github.com/containers/storage/drivers/windows
github.com/containers/storage/drivers/zfs
github.com/containers/storage/pkg/archive
github.com/containers/storage/pkg/chrootarchive
+github.com/containers/storage/pkg/chunked
+github.com/containers/storage/pkg/chunked/compressor
+github.com/containers/storage/pkg/chunked/internal
github.com/containers/storage/pkg/config
github.com/containers/storage/pkg/devicemapper
github.com/containers/storage/pkg/directory
@@ -505,7 +508,7 @@ github.com/opencontainers/go-digest
# github.com/opencontainers/image-spec v1.0.2-0.20190823105129-775207bd45b6
github.com/opencontainers/image-spec/specs-go
github.com/opencontainers/image-spec/specs-go/v1
-# github.com/opencontainers/runc v1.0.0
+# github.com/opencontainers/runc v1.0.1
github.com/opencontainers/runc/libcontainer/apparmor
github.com/opencontainers/runc/libcontainer/cgroups
github.com/opencontainers/runc/libcontainer/configs
@@ -609,7 +612,7 @@ github.com/vbauerster/mpb/v6
github.com/vbauerster/mpb/v6/cwriter
github.com/vbauerster/mpb/v6/decor
github.com/vbauerster/mpb/v6/internal
-# github.com/vbauerster/mpb/v7 v7.0.2
+# github.com/vbauerster/mpb/v7 v7.0.3
github.com/vbauerster/mpb/v7
github.com/vbauerster/mpb/v7/cwriter
github.com/vbauerster/mpb/v7/decor
@@ -672,7 +675,7 @@ golang.org/x/net/proxy
golang.org/x/net/trace
# golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
golang.org/x/sync/semaphore
-# golang.org/x/sys v0.0.0-20210603125802-9665404d3644
+# golang.org/x/sys v0.0.0-20210616094352-59db8d763f22
golang.org/x/sys/cpu
golang.org/x/sys/execabs
golang.org/x/sys/internal/unsafeheader