summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cirrus.yml62
-rw-r--r--.golangci.yml2
-rw-r--r--Makefile34
-rw-r--r--changelog.txt81
-rw-r--r--cmd/podman/common/create.go12
-rw-r--r--cmd/podman/common/create_opts.go2
-rw-r--r--cmd/podman/common/default.go2
-rw-r--r--cmd/podman/common/specgen.go36
-rw-r--r--cmd/podman/common/util.go32
-rw-r--r--cmd/podman/containers/attach.go4
-rw-r--r--cmd/podman/containers/container.go2
-rw-r--r--cmd/podman/containers/create.go29
-rw-r--r--cmd/podman/containers/diff.go2
-rw-r--r--cmd/podman/containers/exec.go8
-rw-r--r--cmd/podman/containers/inspect.go8
-rw-r--r--cmd/podman/containers/ps.go2
-rw-r--r--cmd/podman/containers/stats.go10
-rw-r--r--cmd/podman/containers/stop.go3
-rw-r--r--cmd/podman/containers/wait.go16
-rw-r--r--cmd/podman/diff.go2
-rw-r--r--cmd/podman/images/image.go2
-rw-r--r--cmd/podman/images/inspect.go5
-rw-r--r--cmd/podman/images/list.go4
-rw-r--r--cmd/podman/networks/list.go14
-rw-r--r--cmd/podman/pods/create.go10
-rw-r--r--cmd/podman/pods/pod.go2
-rw-r--r--cmd/podman/pods/ps.go10
-rw-r--r--cmd/podman/pods/stats.go4
-rw-r--r--cmd/podman/registry/config_abi.go2
-rw-r--r--cmd/podman/registry/config_tunnel.go2
-rw-r--r--cmd/podman/registry/json.go4
-rw-r--r--cmd/podman/report/report.go2
-rw-r--r--cmd/podman/root.go34
-rw-r--r--cmd/podman/system/df.go6
-rw-r--r--cmd/podman/system/events.go6
-rw-r--r--cmd/podman/system/service.go4
-rw-r--r--cmd/podman/system/service_abi.go2
-rw-r--r--cmd/podman/system/service_unsupported.go14
-rw-r--r--cmd/podman/system/system.go2
-rw-r--r--cmd/podman/validate/args.go4
-rw-r--r--cmd/podman/validate/choice.go16
-rw-r--r--cmd/podman/volumes/create.go2
-rw-r--r--cmd/podman/volumes/volume.go2
-rw-r--r--contrib/cirrus/README.md62
-rwxr-xr-xcontrib/cirrus/check_image.sh42
-rwxr-xr-xcontrib/cirrus/integration_test.sh17
-rw-r--r--contrib/cirrus/lib.sh13
-rw-r--r--contrib/cirrus/packer/fedora_packaging.sh85
-rw-r--r--contrib/cirrus/packer/fedora_setup.sh8
-rw-r--r--contrib/cirrus/packer/ubuntu_packaging.sh31
-rwxr-xr-xcontrib/cirrus/rootless_test.sh22
-rwxr-xr-xcontrib/cirrus/setup_environment.sh19
-rw-r--r--contrib/cirrus/swagger_stack_trace.pngbin0 -> 42799 bytes
-rw-r--r--contrib/gate/Dockerfile2
-rw-r--r--contrib/spec/podman.spec.in4
-rw-r--r--docs/Readme.md30
-rw-r--r--docs/source/markdown/podman-events.1.md2
-rw-r--r--docs/source/markdown/podman-info.1.md7
-rw-r--r--docs/source/markdown/podman.1.md14
-rw-r--r--go.mod12
-rw-r--r--go.sum23
-rwxr-xr-xhack/golangci-lint.sh6
-rwxr-xr-xhack/install_bats.sh16
-rw-r--r--libpod/container_internal.go24
-rw-r--r--libpod/container_internal_linux.go14
-rw-r--r--libpod/container_log.go4
-rw-r--r--libpod/define/errors.go3
-rw-r--r--libpod/define/info.go7
-rw-r--r--libpod/filters/pods.go8
-rw-r--r--libpod/image/filters.go6
-rw-r--r--libpod/networking_linux.go2
-rw-r--r--libpod/oci.go7
-rw-r--r--libpod/oci_conmon_linux.go25
-rw-r--r--libpod/oci_missing.go5
-rw-r--r--libpod/oci_util.go36
-rw-r--r--libpod/pod.go5
-rw-r--r--libpod/pod_api.go2
-rw-r--r--libpod/runtime_ctr.go6
-rw-r--r--pkg/api/handlers/compat/containers.go4
-rw-r--r--pkg/api/handlers/compat/images.go4
-rw-r--r--pkg/api/handlers/compat/images_build.go8
-rw-r--r--pkg/api/handlers/compat/info.go2
-rw-r--r--pkg/api/handlers/compat/networks.go4
-rw-r--r--pkg/api/handlers/compat/ping.go4
-rw-r--r--pkg/api/handlers/compat/version.go4
-rw-r--r--pkg/api/handlers/decoder.go6
-rw-r--r--pkg/api/handlers/libpod/pods.go9
-rw-r--r--pkg/api/handlers/libpod/volumes.go2
-rw-r--r--pkg/api/handlers/types.go27
-rw-r--r--pkg/api/handlers/utils/containers.go2
-rw-r--r--pkg/api/handlers/utils/handler.go24
-rw-r--r--pkg/api/handlers/utils/handler_test.go4
-rw-r--r--pkg/api/handlers/utils/pods.go4
-rw-r--r--pkg/api/server/handler_api.go6
-rw-r--r--pkg/api/server/server.go2
-rw-r--r--pkg/bindings/bindings.go46
-rw-r--r--pkg/bindings/connection.go88
-rw-r--r--pkg/bindings/containers/attach.go16
-rw-r--r--pkg/bindings/containers/checkpoint.go12
-rw-r--r--pkg/bindings/containers/commit.go6
-rw-r--r--pkg/bindings/containers/diff.go4
-rw-r--r--pkg/bindings/generate/generate.go2
-rw-r--r--pkg/bindings/images/diff.go4
-rw-r--r--pkg/bindings/images/images.go4
-rw-r--r--pkg/bindings/play/play.go2
-rw-r--r--pkg/domain/entities/container_ps.go6
-rw-r--r--pkg/domain/entities/containers.go36
-rw-r--r--pkg/domain/entities/engine.go8
-rw-r--r--pkg/domain/entities/engine_container.go24
-rw-r--r--pkg/domain/entities/engine_image.go14
-rw-r--r--pkg/domain/entities/filters.go24
-rw-r--r--pkg/domain/entities/images.go10
-rw-r--r--pkg/domain/entities/pods.go24
-rw-r--r--pkg/domain/entities/set.go16
-rw-r--r--pkg/domain/entities/types.go4
-rw-r--r--pkg/domain/entities/volumes.go8
-rw-r--r--pkg/domain/infra/abi/containers.go110
-rw-r--r--pkg/domain/infra/abi/healthcheck.go4
-rw-r--r--pkg/domain/infra/abi/images.go34
-rw-r--r--pkg/domain/infra/abi/manifest.go2
-rw-r--r--pkg/domain/infra/abi/parse/parse.go2
-rw-r--r--pkg/domain/infra/abi/play.go2
-rw-r--r--pkg/domain/infra/abi/pods.go8
-rw-r--r--pkg/domain/infra/abi/system.go41
-rw-r--r--pkg/domain/infra/abi/trust.go8
-rw-r--r--pkg/domain/infra/abi/volumes.go6
-rw-r--r--pkg/domain/infra/runtime_abi.go6
-rw-r--r--pkg/domain/infra/runtime_abi_unsupported.go2
-rw-r--r--pkg/domain/infra/runtime_libpod.go2
-rw-r--r--pkg/domain/infra/runtime_proxy.go2
-rw-r--r--pkg/domain/infra/runtime_tunnel.go6
-rw-r--r--pkg/domain/infra/tunnel/containers.go67
-rw-r--r--pkg/domain/infra/tunnel/generate.go2
-rw-r--r--pkg/domain/infra/tunnel/healthcheck.go4
-rw-r--r--pkg/domain/infra/tunnel/helpers.go16
-rw-r--r--pkg/domain/infra/tunnel/images.go34
-rw-r--r--pkg/domain/infra/tunnel/play.go2
-rw-r--r--pkg/domain/infra/tunnel/pods.go18
-rw-r--r--pkg/domain/infra/tunnel/volumes.go4
-rw-r--r--pkg/domain/utils/utils.go2
-rw-r--r--pkg/network/network.go2
-rw-r--r--pkg/parallel/parallel.go44
-rw-r--r--pkg/parallel/parallel_linux.go57
-rw-r--r--pkg/spec/createconfig.go2
-rw-r--r--pkg/specgen/config_linux.go93
-rw-r--r--pkg/specgen/container_validate.go4
-rw-r--r--pkg/specgen/generate/container.go2
-rw-r--r--pkg/specgen/generate/container_create.go42
-rw-r--r--pkg/specgen/generate/namespaces.go8
-rw-r--r--pkg/specgen/generate/oci.go4
-rw-r--r--pkg/specgen/pod_validate.go2
-rw-r--r--pkg/systemd/generate/systemdgen_test.go4
-rw-r--r--pkg/trust/config.go4
-rw-r--r--pkg/varlinkapi/create.go4
-rw-r--r--pkg/varlinkapi/volumes.go2
-rw-r--r--test/apiv2/20-containers.at54
-rw-r--r--test/dockerpy/README.md30
-rw-r--r--test/dockerpy/__init__.py0
-rw-r--r--test/dockerpy/common.py68
-rw-r--r--test/dockerpy/constant.py13
-rw-r--r--test/dockerpy/containers.py46
-rw-r--r--test/dockerpy/images.py151
-rw-r--r--test/e2e/checkpoint_test.go2
-rw-r--r--test/e2e/cp_test.go2
-rw-r--r--test/e2e/create_test.go1
-rw-r--r--test/e2e/diff_test.go6
-rw-r--r--test/e2e/exists_test.go1
-rw-r--r--test/e2e/generate_kube_test.go2
-rw-r--r--test/e2e/healthcheck_run_test.go2
-rw-r--r--test/e2e/inspect_test.go64
-rw-r--r--test/e2e/libpod_suite_remote_test.go6
-rw-r--r--test/e2e/pod_create_test.go1
-rw-r--r--test/e2e/pod_rm_test.go1
-rw-r--r--test/e2e/pod_stats_test.go17
-rw-r--r--test/e2e/pod_stop_test.go2
-rw-r--r--test/e2e/ps_test.go2
-rw-r--r--test/e2e/pull_test.go1
-rw-r--r--test/e2e/rm_test.go3
-rw-r--r--test/e2e/run_networking_test.go26
-rw-r--r--test/e2e/stop_test.go2
-rw-r--r--test/e2e/systemd_test.go8
-rw-r--r--test/e2e/volume_rm_test.go1
-rw-r--r--test/system/080-pause.bats58
-rw-r--r--test/system/200-pod.bats6
-rw-r--r--test/system/220-healthcheck.bats116
-rw-r--r--test/utils/utils.go2
-rw-r--r--vendor/github.com/containers/common/pkg/config/config.go3
-rw-r--r--vendor/github.com/containers/storage/VERSION2
-rw-r--r--vendor/github.com/containers/storage/drivers/devmapper/deviceset.go4
-rw-r--r--vendor/github.com/containers/storage/drivers/overlay/overlay.go3
-rw-r--r--vendor/github.com/containers/storage/go.mod10
-rw-r--r--vendor/github.com/containers/storage/go.sum28
-rw-r--r--vendor/github.com/containers/storage/pkg/config/config.go10
-rw-r--r--vendor/github.com/containers/storage/storage.conf3
-rw-r--r--vendor/github.com/containers/storage/store.go3
-rw-r--r--vendor/github.com/json-iterator/go/README.md36
-rw-r--r--vendor/github.com/json-iterator/go/any_str.go4
-rw-r--r--vendor/github.com/json-iterator/go/config.go4
-rw-r--r--vendor/github.com/json-iterator/go/iter_object.go4
-rw-r--r--vendor/github.com/json-iterator/go/reflect_extension.go2
-rw-r--r--vendor/github.com/json-iterator/go/reflect_map.go80
-rw-r--r--vendor/github.com/json-iterator/go/reflect_optional.go4
-rw-r--r--vendor/github.com/json-iterator/go/reflect_struct_decoder.go22
-rw-r--r--vendor/github.com/json-iterator/go/stream.go5
-rw-r--r--vendor/github.com/klauspost/compress/huff0/decompress.go166
-rw-r--r--vendor/github.com/klauspost/compress/zstd/README.md14
-rw-r--r--vendor/github.com/klauspost/compress/zstd/blockdec.go34
-rw-r--r--vendor/github.com/klauspost/compress/zstd/bytereader.go9
-rw-r--r--vendor/github.com/klauspost/compress/zstd/decoder.go34
-rw-r--r--vendor/github.com/klauspost/compress/zstd/dict.go104
-rw-r--r--vendor/github.com/klauspost/compress/zstd/enc_dfast.go4
-rw-r--r--vendor/github.com/klauspost/compress/zstd/enc_fast.go15
-rw-r--r--vendor/github.com/klauspost/compress/zstd/encoder.go21
-rw-r--r--vendor/github.com/klauspost/compress/zstd/framedec.go23
-rw-r--r--vendor/github.com/klauspost/compress/zstd/fse_decoder.go2
-rw-r--r--vendor/github.com/klauspost/compress/zstd/history.go18
-rw-r--r--vendor/github.com/klauspost/compress/zstd/seqdec.go144
-rw-r--r--vendor/github.com/seccomp/containers-golang/seccomp.json106
-rw-r--r--vendor/github.com/seccomp/containers-golang/seccomp_default_linux.go84
-rw-r--r--vendor/github.com/stretchr/testify/assert/assertion_format.go9
-rw-r--r--vendor/github.com/stretchr/testify/assert/assertion_forward.go17
-rw-r--r--vendor/github.com/stretchr/testify/assert/http_assertions.go21
-rw-r--r--vendor/github.com/stretchr/testify/require/require.go17
-rw-r--r--vendor/github.com/stretchr/testify/require/require_forward.go17
-rw-r--r--vendor/golang.org/x/crypto/ssh/agent/client.go813
-rw-r--r--vendor/golang.org/x/crypto/ssh/agent/forward.go103
-rw-r--r--vendor/golang.org/x/crypto/ssh/agent/keyring.go241
-rw-r--r--vendor/golang.org/x/crypto/ssh/agent/server.go570
-rw-r--r--vendor/modules.txt15
229 files changed, 4558 insertions, 1167 deletions
diff --git a/.cirrus.yml b/.cirrus.yml
index 292f83951..6d9ccfc78 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -39,7 +39,7 @@ env:
UBUNTU_NAME: "ubuntu-20"
PRIOR_UBUNTU_NAME: "ubuntu-19"
- _BUILT_IMAGE_SUFFIX: "libpod-6268069335007232" # From the packer output of 'build_vm_images_script'
+ _BUILT_IMAGE_SUFFIX: "libpod-6508632441356288"
FEDORA_CACHE_IMAGE_NAME: "${FEDORA_NAME}-${_BUILT_IMAGE_SUFFIX}"
PRIOR_FEDORA_CACHE_IMAGE_NAME: "${PRIOR_FEDORA_NAME}-${_BUILT_IMAGE_SUFFIX}"
UBUNTU_CACHE_IMAGE_NAME: "${UBUNTU_NAME}-${_BUILT_IMAGE_SUFFIX}"
@@ -72,10 +72,6 @@ env:
GCE_SSH_USERNAME: cirrus-ci
# Name where this repositories cloud resources are located
GCP_PROJECT_ID: ENCRYPTED[7c80e728e046b1c76147afd156a32c1c57d4a1ac1eab93b7e68e718c61ca8564fc61fef815952b8ae0a64e7034b8fe4f]
- RELEASE_GCPJSON: ENCRYPTED[789d8f7e9a5972ce350fd8e60f1032ccbf4a35c3938b604774b711aad280e12c21faf10e25af1e0ba33597ffb9e39e46]
- RELEASE_GCPNAME: ENCRYPTED[417d50488a4bd197bcc925ba6574de5823b97e68db1a17e3a5fde4bcf26576987345e75f8d9ea1c15a156b4612c072a1]
- RELEASE_GCPROJECT: ENCRYPTED[7c80e728e046b1c76147afd156a32c1c57d4a1ac1eab93b7e68e718c61ca8564fc61fef815952b8ae0a64e7034b8fe4f]
-
# Default VM to use unless set or modified by task
@@ -134,8 +130,7 @@ gating_task:
# not break. It also verifies all sub-commands have man pages.
build_script:
- '/usr/local/bin/entrypoint.sh podman |& ${TIMESTAMP}'
- # FIXME
- #- 'cd $GOSRC && ./hack/podman-commands.sh |& ${TIMESTAMP}'
+ - 'cd $GOSRC && ./hack/podman-commands.sh |& ${TIMESTAMP}'
# N/B: need 'clean' so some committed files are re-generated.
- '/usr/local/bin/entrypoint.sh clean podman-remote |& ${TIMESTAMP}'
- '/usr/local/bin/entrypoint.sh clean podman xref_helpmsgs_manpages BUILDTAGS="exclude_graphdriver_devicemapper selinux seccomp" |& ${TIMESTAMP}'
@@ -423,25 +418,20 @@ testing_task:
- name: "test ${PRIOR_FEDORA_NAME}"
gce_instance:
image_name: "${PRIOR_FEDORA_CACHE_IMAGE_NAME}"
- # TODO:
- # - name: "test ${UBUNTU_NAME}"
- # gce_instance:
- # image_name: "${UBUNTU_CACHE_IMAGE_NAME}"
- # - name: "test ${PRIOR_UBUNTU_NAME}"
- # gce_instance:
- # image_name: "${PRIOR_UBUNTU_CACHE_IMAGE_NAME}"
+ - name: "test ${UBUNTU_NAME}"
+ gce_instance:
+ image_name: "${UBUNTU_CACHE_IMAGE_NAME}"
+ - name: "test ${PRIOR_UBUNTU_NAME}"
+ gce_instance:
+ image_name: "${PRIOR_UBUNTU_CACHE_IMAGE_NAME}"
timeout_in: 120m
env:
ADD_SECOND_PARTITION: 'true'
matrix:
- - name: remote
- env:
- TEST_REMOTE_CLIENT: 'true'
- - name: local
- env:
- TEST_REMOTE_CLIENT: 'false'
+ - TEST_REMOTE_CLIENT: 'true'
+ - TEST_REMOTE_CLIENT: 'false'
networking_script: '${CIRRUS_WORKING_DIR}/${SCRIPT_BASE}/networking.sh'
setup_environment_script: '$SCRIPT_BASE/setup_environment.sh |& ${TIMESTAMP}'
@@ -488,12 +478,8 @@ special_testing_rootless_task:
ADD_SECOND_PARTITION: 'true'
SPECIALMODE: 'rootless' # See docs
matrix:
- - name: remote
- env:
- TEST_REMOTE_CLIENT: 'true'
- - name: local
- env:
- TEST_REMOTE_CLIENT: 'false'
+ - TEST_REMOTE_CLIENT: 'true'
+ - TEST_REMOTE_CLIENT: 'false'
timeout_in: 60m
@@ -512,7 +498,6 @@ special_testing_rootless_task:
special_testing_in_podman_task:
- skip: $CI == 'true'
alias: "special_testing_in_podman"
depends_on:
- "gating"
@@ -603,6 +588,7 @@ special_testing_bindings_task:
env:
SPECIALMODE: 'bindings' # See docs
+ ADD_SECOND_PARTITION: 'true' # More root fs space is required
timeout_in: 40m
@@ -696,27 +682,19 @@ verify_test_built_images_task:
env:
ADD_SECOND_PARTITION: 'true'
matrix:
- - name: remote
- env:
- TEST_REMOTE_CLIENT: 'true'
- - name: local
- env:
- TEST_REMOTE_CLIENT: 'false'
+ - TEST_REMOTE_CLIENT: 'true'
+ - TEST_REMOTE_CLIENT: 'false'
matrix:
- # Required env. var. by check_image_script
PACKER_BUILDER_NAME: "${FEDORA_NAME}"
PACKER_BUILDER_NAME: "${PRIOR_FEDORA_NAME}"
+ PACKER_BUILDER_NAME: "${UBUNTU_NAME}"
PACKER_BUILDER_NAME: "${PRIOR_UBUNTU_NAME}"
- # Multiple test failures on ${UBUNTU_CACHE_IMAGE_NAME}
- # PACKER_BUILDER_NAME: "${UBUNTU_NAME}"
networking_script: '${CIRRUS_WORKING_DIR}/${SCRIPT_BASE}/networking.sh'
installed_packages_script: '$SCRIPT_BASE/logcollector.sh packages'
environment_script: '$SCRIPT_BASE/setup_environment.sh |& ${TIMESTAMP}'
- # Verify expectations once per image
- check_image_script: >-
- [[ "$TEST_REMOTE_CLIENT" == "false" ]] || \
- $SCRIPT_BASE/check_image.sh |& ${TIMESTAMP}
+ # Verify expectations of built images
+ check_image_script: '$SCRIPT_BASE/check_image.sh |& ${TIMESTAMP}'
# Note: A truncated form of normal testing. It only needs to confirm new images
# "probably" work. A full round of testing will happen again after $*_CACHE_IMAGE_NAME
# are updated in this or another PR (w/o '***CIRRUS: TEST IMAGES***').
@@ -734,6 +712,10 @@ docs_task:
depends_on:
- "gating"
+ env:
+ RELEASE_GCPJSON: ENCRYPTED[789d8f7e9a5972ce350fd8e60f1032ccbf4a35c3938b604774b711aad280e12c21faf10e25af1e0ba33597ffb9e39e46]
+ RELEASE_GCPNAME: ENCRYPTED[417d50488a4bd197bcc925ba6574de5823b97e68db1a17e3a5fde4bcf26576987345e75f8d9ea1c15a156b4612c072a1]
+ RELEASE_GCPROJECT: ENCRYPTED[7c80e728e046b1c76147afd156a32c1c57d4a1ac1eab93b7e68e718c61ca8564fc61fef815952b8ae0a64e7034b8fe4f]
script:
- "$SCRIPT_BASE/build_swagger.sh |& ${TIMESTAMP}"
diff --git a/.golangci.yml b/.golangci.yml
index 5480b02bb..33a8b4f59 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -7,6 +7,7 @@ run:
- contrib
- dependencies
- test
+ - pkg/spec
- pkg/varlink
- pkg/varlinkapi
skip-files:
@@ -21,7 +22,6 @@ linters:
- gochecknoinits
- goconst
- gocyclo
- - golint
- gosec
- lll
- maligned
diff --git a/Makefile b/Makefile
index b7bad33af..2ac6f426f 100644
--- a/Makefile
+++ b/Makefile
@@ -22,7 +22,7 @@ ETCDIR ?= /etc
TMPFILESDIR ?= ${PREFIX}/lib/tmpfiles.d
SYSTEMDDIR ?= ${PREFIX}/lib/systemd/system
USERSYSTEMDDIR ?= ${PREFIX}/lib/systemd/user
-REMOTETAGS ?= !ABISupport remote exclude_graphdriver_btrfs btrfs_noversion exclude_graphdriver_devicemapper containers_image_openpgp
+REMOTETAGS ?= remote exclude_graphdriver_btrfs btrfs_noversion exclude_graphdriver_devicemapper containers_image_openpgp
BUILDTAGS ?= \
$(shell hack/apparmor_tag.sh) \
$(shell hack/btrfs_installed_tag.sh) \
@@ -44,7 +44,7 @@ ifeq ($(shell go help mod >/dev/null 2>&1 && echo true), true)
GO_BUILD=GO111MODULE=on $(GO) build -mod=vendor
endif
-BUILDTAGS_CROSS ?= ABISupport containers_image_openpgp exclude_graphdriver_btrfs exclude_graphdriver_devicemapper exclude_graphdriver_overlay
+BUILDTAGS_CROSS ?= containers_image_openpgp exclude_graphdriver_btrfs exclude_graphdriver_devicemapper exclude_graphdriver_overlay
ifneq (,$(findstring varlink,$(BUILDTAGS)))
PODMAN_VARLINK_DEPENDENCIES = pkg/varlink/iopodman.go
endif
@@ -88,8 +88,8 @@ RELEASE_DIST_VER ?= $(shell hack/get_release_info.sh DIST_VER)
RELEASE_ARCH ?= $(shell hack/get_release_info.sh ARCH)
RELEASE_BASENAME := $(shell hack/get_release_info.sh BASENAME)
-# If non-empty, logs all output from varlink during remote system testing
-VARLINK_LOG ?=
+# If non-empty, logs all output from server during remote system testing
+PODMAN_SERVER_LOG ?=
# If GOPATH not specified, use one in the local directory
ifeq ($(GOPATH),)
@@ -185,7 +185,7 @@ ifeq (,$(findstring systemd,$(BUILDTAGS)))
@echo "Podman is being compiled without the systemd build tag. Install libsystemd on \
Ubuntu or systemd-devel on rpm based distro for journald support."
endif
- $(GO_BUILD) $(BUILDFLAGS) -gcflags '$(GCFLAGS)' -asmflags '$(ASMFLAGS)' -ldflags '$(LDFLAGS_PODMAN)' -tags "ABISupport $(BUILDTAGS)" -o $@ $(PROJECT)/cmd/podman
+ $(GO_BUILD) $(BUILDFLAGS) -gcflags '$(GCFLAGS)' -asmflags '$(ASMFLAGS)' -ldflags '$(LDFLAGS_PODMAN)' -tags "$(BUILDTAGS)" -o $@ $(PROJECT)/cmd/podman
.PHONY: podman
podman: bin/podman
@@ -357,22 +357,28 @@ localsystem:
remotesystem:
# Wipe existing config, database, and cache: start with clean slate.
$(RM) -rf ${HOME}/.local/share/containers ${HOME}/.config/containers
- # Start varlink server using tmp socket; loop-wait for it;
+ # Start podman server using tmp socket; loop-wait for it;
# test podman-remote; kill server, clean up tmp socket file.
- # varlink server spews copious unhelpful output; ignore it.
+ # podman server spews copious unhelpful output; ignore it.
+ # FIXME FIXME FIXME: remove 'exit 0' after #6538 and #6539 are fixed
+ exit 0;\
rc=0;\
if timeout -v 1 true; then \
SOCK_FILE=$(shell mktemp --dry-run --tmpdir podman.XXXXXX);\
- export PODMAN_SOCKEY=unix:$$SOCK_FILE; \
- ./bin/podman system service --timeout=0 $$PODMAN_VARLINK_ADDRESS &> $(if $(VARLINK_LOG),$(VARLINK_LOG),/dev/null) & \
+ export PODMAN_SOCKET=unix:$$SOCK_FILE; \
+ ./bin/podman system service --timeout=0 $$PODMAN_SOCKET &> $(if $(PODMAN_SERVER_LOG),$(PODMAN_SERVER_LOG),/dev/null) & \
retry=5;\
while [[ $$retry -ge 0 ]]; do\
echo Waiting for server...;\
sleep 1;\
- ./bin/podman-remote --remote $(SOCK_FILE) info &>/dev/null && break;\
+ ./bin/podman-remote --url $$PODMAN_SOCKET info &>/dev/null && break;\
retry=$$(expr $$retry - 1);\
done;\
- env PODMAN=./bin/podman-remote bats test/system/ ;\
+ if [[ $$retry -lt 0 ]]; then\
+ echo "Error: ./bin/podman system service did not come up on $$SOCK_FILE" >&2;\
+ exit 1;\
+ fi;\
+ env PODMAN="./bin/podman-remote --url $$PODMAN_SOCKET" bats test/system/ ;\
rc=$$?;\
kill %1;\
rm -f $$SOCK_FILE;\
@@ -612,7 +618,7 @@ uninstall:
GIT_CHECK_EXCLUDE="./vendor:docs/make.bat" $(GOBIN)/git-validation -run DCO,short-subject,dangling-whitespace -range $(EPOCH_TEST_COMMIT)..$(HEAD)
.PHONY: install.tools
-install.tools: .install.gitvalidation .install.md2man .install.ginkgo .install.golangci-lint ## Install needed tools
+install.tools: .install.gitvalidation .install.md2man .install.ginkgo .install.golangci-lint .install.bats ## Install needed tools
define go-get
env GO111MODULE=off \
@@ -635,6 +641,10 @@ endef
.install.golangci-lint: .gopathok
VERSION=1.18.0 GOBIN=$(GOBIN) sh ./hack/install_golangci.sh
+.PHONY: .install.bats
+.install.bats: .gopathok
+ VERSION=v1.1.0 ./hack/install_bats.sh
+
.PHONY: .install.pre-commit
.install.pre-commit:
if [ -z "$(PRE_COMMIT)" ]; then \
diff --git a/changelog.txt b/changelog.txt
index 47a99ba64..f17e0ee75 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -1,3 +1,78 @@
+- Changelog for v2.0.0-rc5 (2020-06-10)
+ * Fix Id->ID where possible for lint
+ * Fixup issues found by golint
+ * podman-events: clarify streaming behaviour
+ * Cirrus: Include packages for containers/conmon CI
+ * Ensure signal validation happens first in pod kill
+ * Bump github.com/json-iterator/go from 1.1.9 to 1.1.10
+ * Bump github.com/containers/common from 0.12.0 to 0.13.0
+ * Improve swagger+CORS metadata docs
+ * Ensure Conmon is alive before waiting for exit file
+ * Bump github.com/stretchr/testify from 1.6.0 to 1.6.1
+ * e2e: disable checkpoint test on Ubuntu
+ * force bats version to v1.1.0
+ * Enable Ubuntu tests in CI
+ * Modify py test to start stop system service for each test
+ * Add parallel operation to `podman stop`
+ * Fix handling of systemd.
+ * Add parallel execution code for container operations
+ * Fix handling of ThrottleWriteIOPSDevice
+ * Bump github.com/seccomp/containers-golang from 0.4.1 to 0.5.0
+ * Strip defaults from namespace flags
+ * Ensure that containers in pods properly set hostname
+ * Adds docker py regression test.
+ * Turn on the podman-commands script to verify man pages
+ * Attempt to turn on special_testing_in_podman tests
+ * Bump to v2.0.0-dev
+
+- Changelog for v2.0.0-rc4 (2020-06-04)
+ * /images/.../json: fix port parsing
+ * BATS and APIv2: more tests and tweaks
+ * Vendor in container/storage v1.20.2
+ * add socket information to podman info
+ * Namespace fields were set with bogus values
+ * When stopping containers locally, ensure cleanup runs
+ * Remove use of ABISupport buildtag
+ * fix remote test --ignore & turn on more tests
+ * Ensure that image/container inspect are specialized
+ * turn on remote stop_test
+ * V2 Add support for ssh authentication methods
+ * Add a few CVE entries to changelog.txt
+ * Add more Remote tests
+ * RHEL8 and Centos8 don't have oci-runtime yet
+ * test.apiv2: add test cases for committing an image from a container
+ * Turn on remote rm_test --cidfile
+ * Properly follow linked namespace container for stats
+ * Fix a segfault in `podman inspect -l` w/ no containers
+ * Remove reference to "upcoming" RHEL 7.7
+ * Bump Conmon in COPR spec
+ * Enable detached exec for remote
+ * check --user range for rootless containers
+ * images --no-trunc: fix ID formatting
+ * make env handling os dependent
+ * Bump github.com/containers/conmon
+ * Bump github.com/onsi/ginkgo from 1.12.2 to 1.12.3
+ * Update vendor containers/psgo
+ * Bump github.com/opencontainers/runc from 1.0.0-rc9 to 1.0.0-rc90
+ * Bump github.com/coreos/go-systemd/v22 from 22.0.0 to 22.1.0
+ * Combine the code of dealing with 'readonly' and 'ro'.
+ * Add bindings for exec and enable attached remote
+ * Add information on detach-keys
+ * system tests : more tests
+ * Add support for format {{.Label}}
+ * turn on remote testing for images. podman-remote build now works.
+ * Add invalid value to error message
+ * Fix leak of empty tarball
+ * Update man pages for --ip with CNI networks
+ * [CI:DOCS] update httpd location in tutorial
+ * default build without `varlink` tag
+ * Bump to v2.0.0-dev
+ * compat handlers: add X-Registry-Auth header support
+ * Don't build code on remoteclient
+ * v2 copy endpoints
+ * Bump github.com/rootless-containers/rootlesskit from 0.9.4 to 0.9.5
+ * system tests: enable skopeo REGISTRY_AUTH_FILE
+
- Changelog for v2.0.0-rc3 (2020-05-29)
* Bump github.com/stretchr/testify from 1.5.1 to 1.6.0
* V2 verify JSON output is consistent and doesn't drift
@@ -555,7 +630,7 @@
* podmanv2: implement pod top
* v2 api: implement pods top endpoint
* podmanv2 commit
- * Bump to buildah v1.14.5
+ * Bump to buildah v1.14.5 (Edit 2020-06-03: Addresses CVE-2020-10696)
* Add support for containers.conf
* API v2 tests: usability improvements
* Sanitize port parsing for pods in play kube
@@ -878,7 +953,7 @@
* rootlessport: drop Pdeathsig in favor of Kill
* rootlessport: fix potential hang
* add pkg/seccomp
- * Do not copy up when volume is not empty
+ * Do not copy up when volume is not empty (Edit 2020-06-03: Addresses CVE-2020-1726)
* api: pull: fix reference parsing
* cmd/podman/pull: refactor code
* stats: add SystemUsage
@@ -1573,7 +1648,7 @@
* get runtime for podman-remote push earlier
* rootless: report the correct error
* Report errors when trying to pause rootless containers
- * Do not support wildcards on cp
+ * Do not support wildcards on cp (Edit 2020-06-03: Addresses CVE-2019-18466)
* Podman-remote run should wait for exit code
* Use exit code constants
* exec: Register resize func a bit later
diff --git a/cmd/podman/common/create.go b/cmd/podman/common/create.go
index 7086dc839..86cd51643 100644
--- a/cmd/podman/common/create.go
+++ b/cmd/podman/common/create.go
@@ -50,7 +50,7 @@ func GetCreateFlags(cf *ContainerCLIOpts) *pflag.FlagSet {
"Drop capabilities from the container",
)
createFlags.String(
- "cgroupns", containerConfig.CgroupNS(),
+ "cgroupns", "",
"cgroup namespace to use",
)
createFlags.StringVar(
@@ -244,7 +244,7 @@ func GetCreateFlags(cf *ContainerCLIOpts) *pflag.FlagSet {
"Keep STDIN open even if not attached",
)
createFlags.String(
- "ipc", containerConfig.IPCNS(),
+ "ipc", "",
"IPC namespace to use",
)
createFlags.StringVar(
@@ -325,7 +325,7 @@ func GetCreateFlags(cf *ContainerCLIOpts) *pflag.FlagSet {
)
// markFlagHidden(createFlags, "override-os")
createFlags.String(
- "pid", containerConfig.PidNS(),
+ "pid", "",
"PID namespace to use",
)
createFlags.Int64Var(
@@ -424,7 +424,7 @@ func GetCreateFlags(cf *ContainerCLIOpts) *pflag.FlagSet {
"Sysctl options",
)
createFlags.StringVar(
- &cf.SystemdD,
+ &cf.Systemd,
"systemd", "true",
`Run container in systemd mode ("true"|"false"|"always")`,
)
@@ -454,11 +454,11 @@ func GetCreateFlags(cf *ContainerCLIOpts) *pflag.FlagSet {
"Username or UID (format: <name|uid>[:<group|gid>])",
)
createFlags.String(
- "userns", containerConfig.Containers.UserNS,
+ "userns", "",
"User namespace to use",
)
createFlags.String(
- "uts", containerConfig.Containers.UTSNS,
+ "uts", "",
"UTS namespace to use",
)
createFlags.StringArrayVar(
diff --git a/cmd/podman/common/create_opts.go b/cmd/podman/common/create_opts.go
index 8b38e3b47..4cba5daf7 100644
--- a/cmd/podman/common/create_opts.go
+++ b/cmd/podman/common/create_opts.go
@@ -85,7 +85,7 @@ type ContainerCLIOpts struct {
SubUIDName string
SubGIDName string
Sysctl []string
- SystemdD string
+ Systemd string
TmpFS []string
TTY bool
UIDMap []string
diff --git a/cmd/podman/common/default.go b/cmd/podman/common/default.go
index 7233b2091..6e5994b18 100644
--- a/cmd/podman/common/default.go
+++ b/cmd/podman/common/default.go
@@ -16,5 +16,5 @@ var (
// DefaultImageVolume default value
DefaultImageVolume = "bind"
// Pull in configured json library
- json = registry.JsonLibrary()
+ json = registry.JSONLibrary()
)
diff --git a/cmd/podman/common/specgen.go b/cmd/podman/common/specgen.go
index 1fabff378..2286e67de 100644
--- a/cmd/podman/common/specgen.go
+++ b/cmd/podman/common/specgen.go
@@ -3,7 +3,6 @@ package common
import (
"fmt"
"os"
- "path/filepath"
"strconv"
"strings"
"time"
@@ -285,16 +284,13 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string
s.NetNS = c.Net.Network
}
- // STOP SIGNAL
- signalString := "TERM"
if sig := c.StopSignal; len(sig) > 0 {
- signalString = sig
- }
- stopSignal, err := util.ParseSignal(signalString)
- if err != nil {
- return err
+ stopSignal, err := util.ParseSignal(sig)
+ if err != nil {
+ return err
+ }
+ s.StopSignal = &stopSignal
}
- s.StopSignal = &stopSignal
// ENVIRONMENT VARIABLES
//
@@ -439,25 +435,7 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string
s.ImageVolumeMode = "anonymous"
}
- systemd := c.SystemdD == "always"
- if !systemd && command != nil {
- x, err := strconv.ParseBool(c.SystemdD)
- if err != nil {
- return errors.Wrapf(err, "cannot parse bool %s", c.SystemdD)
- }
- if x && (command[0] == "/usr/sbin/init" || command[0] == "/sbin/init" || (filepath.Base(command[0]) == "systemd")) {
- systemd = true
- }
- }
- if systemd {
- if s.StopSignal == nil {
- stopSignal, err = util.ParseSignal("RTMIN+3")
- if err != nil {
- return errors.Wrapf(err, "error parsing systemd signal")
- }
- s.StopSignal = &stopSignal
- }
- }
+ s.Systemd = c.Systemd
if s.ResourceLimits == nil {
s.ResourceLimits = &specs.LinuxResources{}
}
@@ -691,7 +669,7 @@ func makeHealthCheckFromCli(inCmd, interval string, retries uint, timeout, start
hc.Interval = intervalDuration
if retries < 1 {
- return nil, errors.New("healthcheck-retries must be greater than 0.")
+ return nil, errors.New("healthcheck-retries must be greater than 0")
}
hc.Retries = int(retries)
timeoutDuration, err := time.ParseDuration(timeout)
diff --git a/cmd/podman/common/util.go b/cmd/podman/common/util.go
index a3626b4e4..0d9f3ba26 100644
--- a/cmd/podman/common/util.go
+++ b/cmd/podman/common/util.go
@@ -71,14 +71,44 @@ func createPortBindings(ports []string) ([]specgen.PortMapping, error) {
return nil, errors.Errorf("invalid port format - protocol can only be specified once")
}
- splitPort := strings.Split(splitProto[0], ":")
+ remainder := splitProto[0]
+ haveV6 := false
+
+ // Check for an IPv6 address in brackets
+ splitV6 := strings.Split(remainder, "]")
+ switch len(splitV6) {
+ case 1:
+ // Do nothing, proceed as before
+ case 2:
+ // We potentially have an IPv6 address
+ haveV6 = true
+ if !strings.HasPrefix(splitV6[0], "[") {
+ return nil, errors.Errorf("invalid port format - IPv6 addresses must be enclosed by []")
+ }
+ if !strings.HasPrefix(splitV6[1], ":") {
+ return nil, errors.Errorf("invalid port format - IPv6 address must be followed by a colon (':')")
+ }
+ ipNoPrefix := strings.TrimPrefix(splitV6[0], "[")
+ hostIP = &ipNoPrefix
+ remainder = strings.TrimPrefix(splitV6[1], ":")
+ default:
+ return nil, errors.Errorf("invalid port format - at most one IPv6 address can be specified in a --publish")
+ }
+
+ splitPort := strings.Split(remainder, ":")
switch len(splitPort) {
case 1:
+ if haveV6 {
+ return nil, errors.Errorf("invalid port format - must provide host and destination port if specifying an IP")
+ }
ctrPort = splitPort[0]
case 2:
hostPort = &(splitPort[0])
ctrPort = splitPort[1]
case 3:
+ if haveV6 {
+ return nil, errors.Errorf("invalid port format - when v6 address specified, must be [ipv6]:hostPort:ctrPort")
+ }
hostIP = &(splitPort[0])
hostPort = &(splitPort[1])
ctrPort = splitPort[2]
diff --git a/cmd/podman/containers/attach.go b/cmd/podman/containers/attach.go
index 9f29d1664..9ef9d79f0 100644
--- a/cmd/podman/containers/attach.go
+++ b/cmd/podman/containers/attach.go
@@ -18,7 +18,7 @@ var (
Short: "Attach to a running container",
Long: attachDescription,
RunE: attach,
- Args: validate.IdOrLatestArgs,
+ Args: validate.IDOrLatestArgs,
Example: `podman attach ctrID
podman attach 1234
podman attach --no-stdin foobar`,
@@ -29,7 +29,7 @@ var (
Short: attachCommand.Short,
Long: attachCommand.Long,
RunE: attachCommand.RunE,
- Args: validate.IdOrLatestArgs,
+ Args: validate.IDOrLatestArgs,
Example: `podman container attach ctrID
podman container attach 1234
podman container attach --no-stdin foobar`,
diff --git a/cmd/podman/containers/container.go b/cmd/podman/containers/container.go
index a102318fb..3ff341dcd 100644
--- a/cmd/podman/containers/container.go
+++ b/cmd/podman/containers/container.go
@@ -10,7 +10,7 @@ import (
var (
// Pull in configured json library
- json = registry.JsonLibrary()
+ json = registry.JSONLibrary()
// Command: podman _container_
containerCmd = &cobra.Command{
diff --git a/cmd/podman/containers/create.go b/cmd/podman/containers/create.go
index c8007bc2f..ed09585ba 100644
--- a/cmd/podman/containers/create.go
+++ b/cmd/podman/containers/create.go
@@ -161,24 +161,25 @@ func createInit(c *cobra.Command) error {
if c.Flag("no-hosts").Changed && c.Flag("add-host").Changed {
return errors.Errorf("--no-hosts and --add-host cannot be set together")
}
- if c.Flag("userns").Changed {
- cliVals.UserNS = c.Flag("userns").Value.String()
- }
- if c.Flag("ipc").Changed {
- cliVals.IPC = c.Flag("ipc").Value.String()
- }
- if c.Flag("uts").Changed {
- cliVals.UTS = c.Flag("uts").Value.String()
- }
- if c.Flag("pid").Changed {
- cliVals.PID = c.Flag("pid").Value.String()
+ cliVals.UserNS = c.Flag("userns").Value.String()
+ // if user did not modify --userns flag and did turn on
+ // uid/gid mappsings, set userns flag to "private"
+ if !c.Flag("userns").Changed && cliVals.UserNS == "host" {
+ if len(cliVals.UIDMap) > 0 ||
+ len(cliVals.GIDMap) > 0 ||
+ cliVals.SubUIDName != "" ||
+ cliVals.SubGIDName != "" {
+ cliVals.UserNS = "private"
+ }
}
+
+ cliVals.IPC = c.Flag("ipc").Value.String()
+ cliVals.UTS = c.Flag("uts").Value.String()
+ cliVals.PID = c.Flag("pid").Value.String()
+ cliVals.CGroupsNS = c.Flag("cgroupns").Value.String()
if !c.Flag("pids-limit").Changed {
cliVals.PIDsLimit = -1
}
- if c.Flag("cgroupns").Changed {
- cliVals.CGroupsNS = c.Flag("cgroupns").Value.String()
- }
if c.Flag("entrypoint").Changed {
val := c.Flag("entrypoint").Value.String()
cliVals.Entrypoint = &val
diff --git a/cmd/podman/containers/diff.go b/cmd/podman/containers/diff.go
index 59b788010..33b1c1126 100644
--- a/cmd/podman/containers/diff.go
+++ b/cmd/podman/containers/diff.go
@@ -13,7 +13,7 @@ var (
// podman container _diff_
diffCmd = &cobra.Command{
Use: "diff [flags] CONTAINER",
- Args: validate.IdOrLatestArgs,
+ Args: validate.IDOrLatestArgs,
Short: "Inspect changes on container's file systems",
Long: `Displays changes on a container filesystem. The container will be compared to its parent layer.`,
RunE: diff,
diff --git a/cmd/podman/containers/exec.go b/cmd/podman/containers/exec.go
index 41f100768..ce48af618 100644
--- a/cmd/podman/containers/exec.go
+++ b/cmd/podman/containers/exec.go
@@ -84,7 +84,7 @@ func init() {
}
func exec(cmd *cobra.Command, args []string) error {
- var nameOrId string
+ var nameOrID string
if len(args) == 0 && !execOpts.Latest {
return errors.New("exec requires the name or ID of a container or the --latest flag")
@@ -92,7 +92,7 @@ func exec(cmd *cobra.Command, args []string) error {
execOpts.Cmd = args
if !execOpts.Latest {
execOpts.Cmd = args[1:]
- nameOrId = args[0]
+ nameOrID = args[0]
}
// Validate given environment variables
execOpts.Envs = make(map[string]string)
@@ -122,12 +122,12 @@ func exec(cmd *cobra.Command, args []string) error {
streams.AttachOutput = true
streams.AttachError = true
- exitCode, err := registry.ContainerEngine().ContainerExec(registry.GetContext(), nameOrId, execOpts, streams)
+ exitCode, err := registry.ContainerEngine().ContainerExec(registry.GetContext(), nameOrID, execOpts, streams)
registry.SetExitCode(exitCode)
return err
}
- id, err := registry.ContainerEngine().ContainerExecDetached(registry.GetContext(), nameOrId, execOpts)
+ id, err := registry.ContainerEngine().ContainerExecDetached(registry.GetContext(), nameOrID, execOpts)
if err != nil {
return err
}
diff --git a/cmd/podman/containers/inspect.go b/cmd/podman/containers/inspect.go
index 4549a4ef6..8556ebe83 100644
--- a/cmd/podman/containers/inspect.go
+++ b/cmd/podman/containers/inspect.go
@@ -26,9 +26,15 @@ func init() {
Command: inspectCmd,
Parent: containerCmd,
})
- inspectOpts = inspect.AddInspectFlagSet(inspectCmd)
+ inspectOpts = new(entities.InspectOptions)
+ flags := inspectCmd.Flags()
+ flags.BoolVarP(&inspectOpts.Size, "size", "s", false, "Display total file size")
+ flags.StringVarP(&inspectOpts.Format, "format", "f", "json", "Format the output to a Go template or json")
+ flags.BoolVarP(&inspectOpts.Latest, "latest", "l", false, "Act on the latest container Podman is aware of")
}
func inspectExec(cmd *cobra.Command, args []string) error {
+ // Force container type
+ inspectOpts.Type = inspect.ContainerType
return inspect.Inspect(args, *inspectOpts)
}
diff --git a/cmd/podman/containers/ps.go b/cmd/podman/containers/ps.go
index 4d12d2534..a29b4da3d 100644
--- a/cmd/podman/containers/ps.go
+++ b/cmd/podman/containers/ps.go
@@ -67,7 +67,7 @@ func listFlagSet(flags *pflag.FlagSet) {
flags.BoolVar(&listOpts.Sync, "sync", false, "Sync container state with OCI runtime")
flags.UintVarP(&listOpts.Watch, "watch", "w", 0, "Watch the ps output on an interval in seconds")
- sort := validate.ChoiceValue(&listOpts.Sort, "command", "created", "id", "image", "names", "runningfor", "size", "status")
+ sort := validate.Value(&listOpts.Sort, "command", "created", "id", "image", "names", "runningfor", "size", "status")
flags.Var(sort, "sort", "Sort output by: "+sort.Choices())
if registry.IsRemote() {
diff --git a/cmd/podman/containers/stats.go b/cmd/podman/containers/stats.go
index c61b161e4..11aa3a4d2 100644
--- a/cmd/podman/containers/stats.go
+++ b/cmd/podman/containers/stats.go
@@ -87,13 +87,13 @@ func init() {
func checkStatOptions(cmd *cobra.Command, args []string) error {
opts := 0
if statsOptions.All {
- opts += 1
+ opts++
}
if statsOptions.Latest {
- opts += 1
+ opts++
}
if len(args) > 0 {
- opts += 1
+ opts++
}
if opts > 1 {
return errors.Errorf("--all, --latest and containers cannot be used together")
@@ -219,9 +219,9 @@ func combineHumanValues(a, b uint64) string {
func outputJSON(stats []*containerStats) error {
type jstat struct {
- Id string `json:"id"`
+ Id string `json:"id"` //nolint
Name string `json:"name"`
- CpuPercent string `json:"cpu_percent"`
+ CpuPercent string `json:"cpu_percent"` //nolint
MemUsage string `json:"mem_usage"`
MemPerc string `json:"mem_percent"`
NetIO string `json:"net_io"`
diff --git a/cmd/podman/containers/stop.go b/cmd/podman/containers/stop.go
index 22c487961..0f2a91af0 100644
--- a/cmd/podman/containers/stop.go
+++ b/cmd/podman/containers/stop.go
@@ -85,9 +85,8 @@ func stop(cmd *cobra.Command, args []string) error {
var (
errs utils.OutputErrors
)
- stopOptions.Timeout = containerConfig.Engine.StopTimeout
if cmd.Flag("time").Changed {
- stopOptions.Timeout = stopTimeout
+ stopOptions.Timeout = &stopTimeout
}
responses, err := registry.ContainerEngine().ContainerStop(context.Background(), args, stopOptions)
diff --git a/cmd/podman/containers/wait.go b/cmd/podman/containers/wait.go
index 1f4d4159b..115bb3eea 100644
--- a/cmd/podman/containers/wait.go
+++ b/cmd/podman/containers/wait.go
@@ -23,9 +23,8 @@ var (
Short: "Block on one or more containers",
Long: waitDescription,
RunE: wait,
- Args: validate.IdOrLatestArgs,
- Example: `podman wait --latest
- podman wait --interval 5000 ctrID
+ Args: validate.IDOrLatestArgs,
+ Example: `podman wait --interval 5000 ctrID
podman wait ctrID1 ctrID2`,
}
@@ -34,9 +33,8 @@ var (
Short: waitCommand.Short,
Long: waitCommand.Long,
RunE: waitCommand.RunE,
- Args: validate.IdOrLatestArgs,
- Example: `podman container wait --latest
- podman container wait --interval 5000 ctrID
+ Args: validate.IDOrLatestArgs,
+ Example: `podman container wait --interval 5000 ctrID
podman container wait ctrID1 ctrID2`,
}
)
@@ -48,11 +46,9 @@ var (
func waitFlags(flags *pflag.FlagSet) {
flags.DurationVarP(&waitOptions.Interval, "interval", "i", time.Duration(250), "Milliseconds to wait before polling for completion")
- flags.BoolVarP(&waitOptions.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
flags.StringVar(&waitCondition, "condition", "stopped", "Condition to wait on")
- if registry.IsRemote() {
- // TODO: This is the same as V1. We could skip creating the flag altogether in V2...
- _ = flags.MarkHidden("latest")
+ if !registry.IsRemote() {
+ flags.BoolVarP(&waitOptions.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
}
}
diff --git a/cmd/podman/diff.go b/cmd/podman/diff.go
index 1ff2fce40..d635ea57a 100644
--- a/cmd/podman/diff.go
+++ b/cmd/podman/diff.go
@@ -18,7 +18,7 @@ var (
diffDescription = `Displays changes on a container or image's filesystem. The container or image will be compared to its parent layer.`
diffCmd = &cobra.Command{
Use: "diff [flags] {CONTAINER_ID | IMAGE_ID}",
- Args: validate.IdOrLatestArgs,
+ Args: validate.IDOrLatestArgs,
Short: "Display the changes of object's file system",
Long: diffDescription,
TraverseChildren: true,
diff --git a/cmd/podman/images/image.go b/cmd/podman/images/image.go
index 790c16c05..ebef126c0 100644
--- a/cmd/podman/images/image.go
+++ b/cmd/podman/images/image.go
@@ -9,7 +9,7 @@ import (
var (
// Pull in configured json library
- json = registry.JsonLibrary()
+ json = registry.JSONLibrary()
// Command: podman _image_
imageCmd = &cobra.Command{
diff --git a/cmd/podman/images/inspect.go b/cmd/podman/images/inspect.go
index 8c727eb07..f6a10ba44 100644
--- a/cmd/podman/images/inspect.go
+++ b/cmd/podman/images/inspect.go
@@ -27,11 +27,12 @@ func init() {
Command: inspectCmd,
Parent: imageCmd,
})
- inspectOpts = inspect.AddInspectFlagSet(inspectCmd)
+ inspectOpts = new(entities.InspectOptions)
flags := inspectCmd.Flags()
- _ = flags.MarkHidden("latest") // Shared with container-inspect but not wanted here.
+ flags.StringVarP(&inspectOpts.Format, "format", "f", "json", "Format the output to a Go template or json")
}
func inspectExec(cmd *cobra.Command, args []string) error {
+ inspectOpts.Type = inspect.ImageType
return inspect.Inspect(args, *inspectOpts)
}
diff --git a/cmd/podman/images/list.go b/cmd/podman/images/list.go
index 23757104b..236ae15b4 100644
--- a/cmd/podman/images/list.go
+++ b/cmd/podman/images/list.go
@@ -100,7 +100,7 @@ func images(cmd *cobra.Command, args []string) error {
switch {
case listFlag.quiet:
- return writeId(summaries)
+ return writeID(summaries)
case cmd.Flag("format").Changed && listFlag.format == "json":
return writeJSON(summaries)
default:
@@ -108,7 +108,7 @@ func images(cmd *cobra.Command, args []string) error {
}
}
-func writeId(imageS []*entities.ImageSummary) error {
+func writeID(imageS []*entities.ImageSummary) error {
var ids = map[string]struct{}{}
for _, e := range imageS {
i := "sha256:" + e.ID
diff --git a/cmd/podman/networks/list.go b/cmd/podman/networks/list.go
index 24604c055..498a4dc18 100644
--- a/cmd/podman/networks/list.go
+++ b/cmd/podman/networks/list.go
@@ -33,8 +33,8 @@ var (
var (
networkListOptions entities.NetworkListOptions
- headers string = "NAME\tVERSION\tPLUGINS\n"
- defaultListRow string = "{{.Name}}\t{{.Version}}\t{{.Plugins}}\n"
+ headers = "NAME\tVERSION\tPLUGINS\n"
+ defaultListRow = "{{.Name}}\t{{.Version}}\t{{.Plugins}}\n"
)
func networkListFlags(flags *pflag.FlagSet) {
@@ -57,7 +57,7 @@ func init() {
func networkList(cmd *cobra.Command, args []string) error {
var (
- nlprs []NetworkListPrintReports
+ nlprs []ListPrintReports
)
// validate the filter pattern.
@@ -83,7 +83,7 @@ func networkList(cmd *cobra.Command, args []string) error {
}
for _, r := range responses {
- nlprs = append(nlprs, NetworkListPrintReports{r})
+ nlprs = append(nlprs, ListPrintReports{r})
}
row := networkListOptions.Format
@@ -125,14 +125,14 @@ func jsonOut(responses []*entities.NetworkListReport) error {
return nil
}
-type NetworkListPrintReports struct {
+type ListPrintReports struct {
*entities.NetworkListReport
}
-func (n NetworkListPrintReports) Version() string {
+func (n ListPrintReports) Version() string {
return n.CNIVersion
}
-func (n NetworkListPrintReports) Plugins() string {
+func (n ListPrintReports) Plugins() string {
return network.GetCNIPlugins(n.NetworkConfigList)
}
diff --git a/cmd/podman/pods/create.go b/cmd/podman/pods/create.go
index 62b5b849e..5ed5fa57c 100644
--- a/cmd/podman/pods/create.go
+++ b/cmd/podman/pods/create.go
@@ -73,8 +73,8 @@ func aliasNetworkFlag(_ *pflag.FlagSet, name string) pflag.NormalizedName {
func create(cmd *cobra.Command, args []string) error {
var (
- err error
- podIdFile *os.File
+ err error
+ podIDFD *os.File
)
createOptions.Labels, err = parse.GetAllLabels(labelFile, labels)
if err != nil {
@@ -101,15 +101,15 @@ func create(cmd *cobra.Command, args []string) error {
}
if cmd.Flag("pod-id-file").Changed {
- podIdFile, err = util.OpenExclusiveFile(podIDFile)
+ podIDFD, err = util.OpenExclusiveFile(podIDFile)
if err != nil && os.IsExist(err) {
return errors.Errorf("pod id file exists. Ensure another pod is not using it or delete %s", podIDFile)
}
if err != nil {
return errors.Errorf("error opening pod-id-file %s", podIDFile)
}
- defer errorhandling.CloseQuiet(podIdFile)
- defer errorhandling.SyncQuiet(podIdFile)
+ defer errorhandling.CloseQuiet(podIDFD)
+ defer errorhandling.SyncQuiet(podIDFD)
}
createOptions.Net, err = common.NetFlagsToNetOptions(cmd)
diff --git a/cmd/podman/pods/pod.go b/cmd/podman/pods/pod.go
index ed265ef90..9dc538c71 100644
--- a/cmd/podman/pods/pod.go
+++ b/cmd/podman/pods/pod.go
@@ -10,7 +10,7 @@ import (
var (
// Pull in configured json library
- json = registry.JsonLibrary()
+ json = registry.JSONLibrary()
// Command: podman _pod_
podCmd = &cobra.Command{
diff --git a/cmd/podman/pods/ps.go b/cmd/podman/pods/ps.go
index 1385ff270..bcd1db84c 100644
--- a/cmd/podman/pods/ps.go
+++ b/cmd/podman/pods/ps.go
@@ -195,7 +195,7 @@ func (l ListPodReporter) ID() string {
}
// Id returns the Pod id
-func (l ListPodReporter) Id() string {
+func (l ListPodReporter) Id() string { //nolint
if noTrunc {
return l.ListPodsReport.Id
}
@@ -209,7 +209,7 @@ func (l ListPodReporter) InfraID() string {
// InfraId returns the infra container id for the pod
// depending on trunc
-func (l ListPodReporter) InfraId() string {
+func (l ListPodReporter) InfraId() string { //nolint
if len(l.ListPodsReport.InfraId) == 0 {
return ""
}
@@ -252,7 +252,7 @@ func sortPodPsOutput(sortBy string, lprs []*entities.ListPodsReport) error {
case "created":
sort.Sort(podPsSortedCreated{lprs})
case "id":
- sort.Sort(podPsSortedId{lprs})
+ sort.Sort(podPsSortedID{lprs})
case "name":
sort.Sort(podPsSortedName{lprs})
case "number":
@@ -276,9 +276,9 @@ func (a podPsSortedCreated) Less(i, j int) bool {
return a.lprSort[i].Created.After(a.lprSort[j].Created)
}
-type podPsSortedId struct{ lprSort }
+type podPsSortedID struct{ lprSort }
-func (a podPsSortedId) Less(i, j int) bool { return a.lprSort[i].Id < a.lprSort[j].Id }
+func (a podPsSortedID) Less(i, j int) bool { return a.lprSort[i].Id < a.lprSort[j].Id }
type podPsSortedNumber struct{ lprSort }
diff --git a/cmd/podman/pods/stats.go b/cmd/podman/pods/stats.go
index d3950fdbc..d14632f01 100644
--- a/cmd/podman/pods/stats.go
+++ b/cmd/podman/pods/stats.go
@@ -71,7 +71,7 @@ func stats(cmd *cobra.Command, args []string) error {
}
format := statsOptions.Format
- doJson := strings.ToLower(format) == formats.JSONString
+ doJSON := strings.ToLower(format) == formats.JSONString
header := getPodStatsHeader(format)
for {
@@ -80,7 +80,7 @@ func stats(cmd *cobra.Command, args []string) error {
return err
}
// Print the stats in the requested format and configuration.
- if doJson {
+ if doJSON {
if err := printJSONPodStats(reports); err != nil {
return err
}
diff --git a/cmd/podman/registry/config_abi.go b/cmd/podman/registry/config_abi.go
index 55430e1bf..4a909c17e 100644
--- a/cmd/podman/registry/config_abi.go
+++ b/cmd/podman/registry/config_abi.go
@@ -1,4 +1,4 @@
-// +build ABISupport
+// +build !remote
package registry
diff --git a/cmd/podman/registry/config_tunnel.go b/cmd/podman/registry/config_tunnel.go
index 29e744dac..bb3da947e 100644
--- a/cmd/podman/registry/config_tunnel.go
+++ b/cmd/podman/registry/config_tunnel.go
@@ -1,4 +1,4 @@
-// +build !ABISupport
+// +build remote
package registry
diff --git a/cmd/podman/registry/json.go b/cmd/podman/registry/json.go
index f25406c3c..a8a1623f5 100644
--- a/cmd/podman/registry/json.go
+++ b/cmd/podman/registry/json.go
@@ -11,8 +11,8 @@ var (
jsonSync sync.Once
)
-// JsonLibrary provides a "encoding/json" compatible API
-func JsonLibrary() jsoniter.API {
+// JSONLibrary provides a "encoding/json" compatible API
+func JSONLibrary() jsoniter.API {
jsonSync.Do(func() {
json = jsoniter.ConfigCompatibleWithStandardLibrary
})
diff --git a/cmd/podman/report/report.go b/cmd/podman/report/report.go
index 8392f10e0..ce349ef35 100644
--- a/cmd/podman/report/report.go
+++ b/cmd/podman/report/report.go
@@ -3,4 +3,4 @@ package report
import "github.com/containers/libpod/cmd/podman/registry"
// Pull in configured json library
-var json = registry.JsonLibrary()
+var json = registry.JSONLibrary()
diff --git a/cmd/podman/root.go b/cmd/podman/root.go
index 3796b8e27..4f834e87d 100644
--- a/cmd/podman/root.go
+++ b/cmd/podman/root.go
@@ -4,12 +4,14 @@ import (
"fmt"
"os"
"path"
+ "runtime"
"runtime/pprof"
"strings"
"github.com/containers/libpod/cmd/podman/registry"
"github.com/containers/libpod/cmd/podman/validate"
"github.com/containers/libpod/pkg/domain/entities"
+ "github.com/containers/libpod/pkg/parallel"
"github.com/containers/libpod/pkg/rootless"
"github.com/containers/libpod/pkg/tracing"
"github.com/containers/libpod/version"
@@ -103,6 +105,11 @@ func persistentPreRunE(cmd *cobra.Command, args []string) error {
cfg := registry.PodmanConfig()
+ // Help is a special case, no need for more setup
+ if cmd.Name() == "help" {
+ return nil
+ }
+
// Prep the engines
if _, err := registry.NewImageEngine(cmd, args); err != nil {
return err
@@ -112,10 +119,10 @@ func persistentPreRunE(cmd *cobra.Command, args []string) error {
}
if cmd.Flag("cpu-profile").Changed {
- f, err := os.Create(cfg.CpuProfile)
+ f, err := os.Create(cfg.CPUProfile)
if err != nil {
return errors.Wrapf(err, "unable to create cpu profiling file %s",
- cfg.CpuProfile)
+ cfg.CPUProfile)
}
if err := pprof.StartCPUProfile(f); err != nil {
return err
@@ -132,6 +139,13 @@ func persistentPreRunE(cmd *cobra.Command, args []string) error {
opentracing.StartSpanFromContext(cfg.SpanCtx, cmd.Name())
}
+ if cfg.MaxWorks <= 0 {
+ return errors.Errorf("maximum workers must be set to a positive number (got %d)", cfg.MaxWorks)
+ }
+ if err := parallel.SetMaxThreads(uint(cfg.MaxWorks)); err != nil {
+ return err
+ }
+
// Setup Rootless environment, IFF:
// 1) in ABI mode
// 2) running as non-root
@@ -150,6 +164,11 @@ func persistentPostRunE(cmd *cobra.Command, args []string) error {
// TODO: Remove trace statement in podman V2.1
logrus.Debugf("Called %s.PersistentPostRunE(%s)", cmd.Name(), strings.Join(os.Args, " "))
+ // Help is a special case, no need for more cleanup
+ if cmd.Name() == "help" {
+ return nil
+ }
+
cfg := registry.PodmanConfig()
if cmd.Flag("cpu-profile").Changed {
pprof.StopCPUProfile()
@@ -191,19 +210,22 @@ func loggingHook() {
func rootFlags(opts *entities.PodmanConfig, flags *pflag.FlagSet) {
// V2 flags
- flags.StringVarP(&opts.Uri, "remote", "r", registry.DefaultAPIAddress(), "URL to access Podman service")
- flags.StringSliceVar(&opts.Identities, "identity", []string{}, "path to SSH identity file")
+ flags.BoolVarP(&opts.Remote, "remote", "r", false, "Access remote Podman service (default false)")
+ // TODO Read uri from containers.config when available
+ flags.StringVar(&opts.URI, "url", registry.DefaultAPIAddress(), "URL to access Podman service (CONTAINER_HOST)")
+ flags.StringSliceVar(&opts.Identities, "identity", []string{}, "path to SSH identity file, (CONTAINER_SSHKEY)")
+ flags.StringVar(&opts.PassPhrase, "passphrase", "", "passphrase for identity file (not secure, CONTAINER_PASSPHRASE), ssh-agent always supported")
cfg := opts.Config
flags.StringVar(&cfg.Engine.CgroupManager, "cgroup-manager", cfg.Engine.CgroupManager, "Cgroup manager to use (\"cgroupfs\"|\"systemd\")")
- flags.StringVar(&opts.CpuProfile, "cpu-profile", "", "Path for the cpu profiling results")
+ flags.StringVar(&opts.CPUProfile, "cpu-profile", "", "Path for the cpu profiling results")
flags.StringVar(&opts.ConmonPath, "conmon", "", "Path of the conmon binary")
flags.StringVar(&cfg.Engine.NetworkCmdPath, "network-cmd-path", cfg.Engine.NetworkCmdPath, "Path to the command for configuring the network")
flags.StringVar(&cfg.Network.NetworkConfigDir, "cni-config-dir", cfg.Network.NetworkConfigDir, "Path of the configuration directory for CNI networks")
flags.StringVar(&cfg.Containers.DefaultMountsFile, "default-mounts-file", cfg.Containers.DefaultMountsFile, "Path to default mounts file")
flags.StringVar(&cfg.Engine.EventsLogger, "events-backend", cfg.Engine.EventsLogger, `Events backend to use ("file"|"journald"|"none")`)
flags.StringSliceVar(&cfg.Engine.HooksDir, "hooks-dir", cfg.Engine.HooksDir, "Set the OCI hooks directory path (may be set multiple times)")
- flags.IntVar(&opts.MaxWorks, "max-workers", 0, "The maximum number of workers for parallel operations")
+ flags.IntVar(&opts.MaxWorks, "max-workers", (runtime.NumCPU()*3)+1, "The maximum number of workers for parallel operations")
flags.StringVar(&cfg.Engine.Namespace, "namespace", cfg.Engine.Namespace, "Set the libpod namespace, used to create separate views of the containers and pods on the system")
flags.StringVar(&cfg.Engine.StaticDir, "root", "", "Path to the root directory in which data, including images, is stored")
flags.StringVar(&opts.RegistriesConf, "registries-conf", "", "Path to a registries.conf to use for image processing")
diff --git a/cmd/podman/system/df.go b/cmd/podman/system/df.go
index 8fe035209..9318bba12 100644
--- a/cmd/podman/system/df.go
+++ b/cmd/podman/system/df.go
@@ -63,7 +63,7 @@ func printSummary(reports *entities.SystemDfReport, userFormat string) error {
dfSummaries []*dfSummary
active int
size, reclaimable int64
- format string = "{{.Type}}\t{{.Total}}\t{{.Active}}\t{{.Size}}\t{{.Reclaimable}}\n"
+ format = "{{.Type}}\t{{.Total}}\t{{.Active}}\t{{.Size}}\t{{.Reclaimable}}\n"
w io.Writer = os.Stdout
)
@@ -74,7 +74,7 @@ func printSummary(reports *entities.SystemDfReport, userFormat string) error {
for _, i := range reports.Images {
if i.Containers > 0 {
- active += 1
+ active++
}
size += i.Size
if i.Containers < 1 {
@@ -99,7 +99,7 @@ func printSummary(reports *entities.SystemDfReport, userFormat string) error {
)
for _, c := range reports.Containers {
if c.Status == "running" {
- conActive += 1
+ conActive++
} else {
conReclaimable += c.RWSize
}
diff --git a/cmd/podman/system/events.go b/cmd/podman/system/events.go
index 27e80138e..c401c5a92 100644
--- a/cmd/podman/system/events.go
+++ b/cmd/podman/system/events.go
@@ -17,8 +17,10 @@ import (
)
var (
- eventsDescription = "Monitor podman events"
- eventsCommand = &cobra.Command{
+ eventsDescription = `Monitor podman events.
+
+ By default, streaming mode is used, printing new events as they occur. Previous events can be listed via --since and --until.`
+ eventsCommand = &cobra.Command{
Use: "events",
Args: validate.NoArgs,
Short: "Show podman events",
diff --git a/cmd/podman/system/service.go b/cmd/podman/system/service.go
index 1b07ee301..ecd17c251 100644
--- a/cmd/podman/system/service.go
+++ b/cmd/podman/system/service.go
@@ -64,7 +64,7 @@ func aliasTimeoutFlag(_ *pflag.FlagSet, name string) pflag.NormalizedName {
}
func service(cmd *cobra.Command, args []string) error {
- apiURI, err := resolveApiURI(args)
+ apiURI, err := resolveAPIURI(args)
if err != nil {
return err
}
@@ -103,7 +103,7 @@ func service(cmd *cobra.Command, args []string) error {
return restService(opts, cmd.Flags(), registry.PodmanConfig())
}
-func resolveApiURI(_url []string) (string, error) {
+func resolveAPIURI(_url []string) (string, error) {
// When determining _*THE*_ listening endpoint --
// 1) User input wins always
// 2) systemd socket activation
diff --git a/cmd/podman/system/service_abi.go b/cmd/podman/system/service_abi.go
index 501650839..f5386c4f1 100644
--- a/cmd/podman/system/service_abi.go
+++ b/cmd/podman/system/service_abi.go
@@ -1,4 +1,4 @@
-// +build ABISupport,!remote
+// +build linux,!remote
package system
diff --git a/cmd/podman/system/service_unsupported.go b/cmd/podman/system/service_unsupported.go
deleted file mode 100644
index 82272c882..000000000
--- a/cmd/podman/system/service_unsupported.go
+++ /dev/null
@@ -1,14 +0,0 @@
-// +build !ABISupport,!remote
-
-package system
-
-import (
- "errors"
-
- "github.com/containers/libpod/pkg/domain/entities"
- "github.com/spf13/pflag"
-)
-
-func restService(opts entities.ServiceOptions, flags *pflag.FlagSet, cfg *entities.PodmanConfig) error {
- return errors.New("not supported")
-}
diff --git a/cmd/podman/system/system.go b/cmd/podman/system/system.go
index d9691ad2a..acf41a32d 100644
--- a/cmd/podman/system/system.go
+++ b/cmd/podman/system/system.go
@@ -9,7 +9,7 @@ import (
var (
// Pull in configured json library
- json = registry.JsonLibrary()
+ json = registry.JSONLibrary()
// Command: podman _system_
systemCmd = &cobra.Command{
diff --git a/cmd/podman/validate/args.go b/cmd/podman/validate/args.go
index 14b4d7897..69240798f 100644
--- a/cmd/podman/validate/args.go
+++ b/cmd/podman/validate/args.go
@@ -23,8 +23,8 @@ func SubCommandExists(cmd *cobra.Command, args []string) error {
return errors.Errorf("missing command '%[1]s COMMAND'\nTry '%[1]s --help' for more information.", cmd.CommandPath())
}
-// IdOrLatestArgs used to validate a nameOrId was provided or the "--latest" flag
-func IdOrLatestArgs(cmd *cobra.Command, args []string) error {
+// IDOrLatestArgs used to validate a nameOrId was provided or the "--latest" flag
+func IDOrLatestArgs(cmd *cobra.Command, args []string) error {
if len(args) > 1 || (len(args) == 0 && !cmd.Flag("latest").Changed) {
return fmt.Errorf("`%s` requires a name, id or the \"--latest\" flag", cmd.CommandPath())
}
diff --git a/cmd/podman/validate/choice.go b/cmd/podman/validate/choice.go
index 572c5f4a5..8bb21c591 100644
--- a/cmd/podman/validate/choice.go
+++ b/cmd/podman/validate/choice.go
@@ -6,28 +6,28 @@ import (
)
// Honors cobra.Value interface
-type choiceValue struct {
+type ChoiceValue struct {
value *string
choices []string
}
-// ChoiceValue may be used in cobra FlagSet methods Var/VarP/VarPF() to select from a set of values
+// Value may be used in cobra FlagSet methods Var/VarP/VarPF() to select from a set of values
//
// Example:
// created := validate.ChoiceValue(&opts.Sort, "command", "created", "id", "image", "names", "runningfor", "size", "status")
// flags.Var(created, "sort", "Sort output by: "+created.Choices())
-func ChoiceValue(p *string, choices ...string) *choiceValue {
- return &choiceValue{
+func Value(p *string, choices ...string) *ChoiceValue {
+ return &ChoiceValue{
value: p,
choices: choices,
}
}
-func (c *choiceValue) String() string {
+func (c *ChoiceValue) String() string {
return *c.value
}
-func (c *choiceValue) Set(value string) error {
+func (c *ChoiceValue) Set(value string) error {
for _, v := range c.choices {
if v == value {
*c.value = value
@@ -37,10 +37,10 @@ func (c *choiceValue) Set(value string) error {
return fmt.Errorf("%q is not a valid value. Choose from: %q", value, c.Choices())
}
-func (c *choiceValue) Choices() string {
+func (c *ChoiceValue) Choices() string {
return strings.Join(c.choices, ", ")
}
-func (c *choiceValue) Type() string {
+func (c *ChoiceValue) Type() string {
return "choice"
}
diff --git a/cmd/podman/volumes/create.go b/cmd/podman/volumes/create.go
index 1bec8d0e7..16ac3771e 100644
--- a/cmd/podman/volumes/create.go
+++ b/cmd/podman/volumes/create.go
@@ -67,6 +67,6 @@ func create(cmd *cobra.Command, args []string) error {
if err != nil {
return err
}
- fmt.Println(response.IdOrName)
+ fmt.Println(response.IDOrName)
return nil
}
diff --git a/cmd/podman/volumes/volume.go b/cmd/podman/volumes/volume.go
index 3e90d178c..12947a6b1 100644
--- a/cmd/podman/volumes/volume.go
+++ b/cmd/podman/volumes/volume.go
@@ -9,7 +9,7 @@ import (
var (
// Pull in configured json library
- json = registry.JsonLibrary()
+ json = registry.JSONLibrary()
// Command: podman _volume_
volumeCmd = &cobra.Command{
diff --git a/contrib/cirrus/README.md b/contrib/cirrus/README.md
index 541cf2f54..c8ec766e7 100644
--- a/contrib/cirrus/README.md
+++ b/contrib/cirrus/README.md
@@ -167,26 +167,50 @@ env:
### `docs` Task
-Builds swagger API documentation YAML and uploads to google storage for both
-PR's (for testing the process) and after a merge into any branch. For PR's
+Builds swagger API documentation YAML and uploads to google storage (an online
+service for storing unstructured data) for both
+PR's (for testing the process) and the master branch. For PR's
the YAML is uploaded into a [dedicated short-pruning cycle
-bucket.](https://storage.googleapis.com/libpod-pr-releases/) For branches,
-a [separate bucket is
-used.](https://storage.googleapis.com/libpod-master-releases)
-In both cases the filename includes the source
-PR number or branch name.
-
-***Note***: [The online documentation](http://docs.podman.io/en/latest/_static/api.html)
-is presented through javascript on the client-side. This requires CORS to be properly
-configured on the bucket, for the `http://docs.podman.io` origin. Please see
-[Configuring CORS on a bucket](https://cloud.google.com/storage/docs/configuring-cors#configure-cors-bucket)
-for details. This may be performed by anybody with admin access to the google storage bucket,
-using the following JSON:
+bucket.](https://storage.googleapis.com/libpod-pr-releases/) for testing purposes
+only. For the master branch, a [separate bucket is
+used](https://storage.googleapis.com/libpod-master-releases) and provides the
+content rendered on [the API Reference page](https://docs.podman.io/en/latest/_static/api.html)
+
+The online API reference is presented by javascript to the client. To prevent hijacking
+of the client by malicious data, the [javascript utilises CORS](https://cloud.google.com/storage/docs/cross-origin).
+This CORS metadata is served by `https://storage.googleapis.com` when configured correctly.
+It will appear in [the request and response headers from the
+client](https://cloud.google.com/storage/docs/configuring-cors#troubleshooting) when accessing
+the API reference page.
+
+However, when the CORS metadata is missing or incorrectly configured, clients will receive an
+error-message similar to:
+
+![Javascript Stack Trace Image](swagger_stack_trace.png)
+
+For documentation built by Read The Docs from the master branch, CORS metadata is
+set on the `libpod-master-releases` storage bucket. Viewing or setting the CORS
+metadata on the bucket requires having locally [installed and
+configured the google-cloud SDK](https://cloud.google.com/sdk/docs). It also requires having
+admin access to the google-storage bucket. Contact a project owner for help if you are
+unsure of your permissions or need help resolving an error similar to the picture above.
+
+Assuming the SDK is installed, and you have the required admin access, the following command
+will display the current CORS metadata:
+
+```
+gsutil cors get gs://libpod-master-releases
+```
+
+To function properly (allow client "trust" of content from `storage.googleapis.com`) the followiing
+metadata JSON should be used. Following the JSON, is an example of the command used to set this
+metadata on the libpod-master-releases bucket. For additional information about configuring CORS
+please referr to [the google-storage documentation](https://cloud.google.com/storage/docs/configuring-cors).
```JSON
[
{
- "origin": ["http://docs.podman.io"],
+ "origin": ["http://docs.podman.io", "https://docs.podman.io"],
"responseHeader": ["Content-Type"],
"method": ["GET"],
"maxAgeSeconds": 600
@@ -194,6 +218,14 @@ using the following JSON:
]
```
+```
+gsutil cors set /path/to/file.json gs://libpod-master-releases
+```
+
+***Note:*** The CORS metadata does _NOT_ change after the `docs` task uploads a new swagger YAML
+file. Therefore, if it is not functioning or misconfigured, a person must have altered it or
+changes were made to the referring site (e.g. `docs.podman.io`).
+
## Base-images
Base-images are VM disk-images specially prepared for executing as GCE VMs.
diff --git a/contrib/cirrus/check_image.sh b/contrib/cirrus/check_image.sh
index 5423f67d6..0d33e55bf 100755
--- a/contrib/cirrus/check_image.sh
+++ b/contrib/cirrus/check_image.sh
@@ -6,7 +6,7 @@ source $(dirname $0)/lib.sh
EVIL_UNITS="$($CIRRUS_WORKING_DIR/$PACKER_BASE/systemd_banish.sh --list)"
-req_env_var PACKER_BUILDER_NAME TEST_REMOTE_CLIENT EVIL_UNITS OS_RELEASE_ID
+req_env_var PACKER_BUILDER_NAME TEST_REMOTE_CLIENT EVIL_UNITS OS_RELEASE_ID CG_FS_TYPE
NFAILS=0
echo "Validating VM image"
@@ -22,7 +22,8 @@ item_test 'Minimum available memory' $MEM_FREE -ge $MIN_MEM_MB || let "NFAILS+=1
# We're testing a custom-built podman; make sure there isn't a distro-provided
# binary anywhere; that could potentially taint our results.
-item_test "remove_packaged_podman_files() did it's job" -z "$(type -P podman)" || let "NFAILS+=1"
+remove_packaged_podman_files
+item_test "remove_packaged_podman_files() does it's job" -z "$(type -P podman)" || let "NFAILS+=1"
# Integration Tests require varlink in Fedora
item_test "The varlink executable is present" -x "$(type -P varlink)" || let "NFAILS+=1"
@@ -39,8 +40,10 @@ for REQ_UNIT in google-accounts-daemon.service \
google-shutdown-scripts.service \
google-startup-scripts.service
do
- item_test "required $REQ_UNIT enabled" \
- "$(systemctl list-unit-files --no-legend $REQ_UNIT)" = "$REQ_UNIT enabled" || let "NFAILS+=1"
+ # enabled/disabled appears at the end of the line, on some Ubuntu's it appears twice
+ service_status=$(systemctl list-unit-files --no-legend $REQ_UNIT | tac -s ' ' | head -1)
+ item_test "required $REQ_UNIT status is enabled" \
+ "$service_status" = "enabled" || let "NFAILS+=1"
done
for evil_unit in $EVIL_UNITS
@@ -50,19 +53,28 @@ do
item_test "No $evil_unit unit is present or active:" "$unit_status" -ne "0" || let "NFAILS+=1"
done
-if [[ "$OS_RELEASE_ID" == "ubuntu" ]] && [[ -x "/usr/lib/cri-o-runc/sbin/runc" ]]
-then
- SAMESAME=$(diff --brief /usr/lib/cri-o-runc/sbin/runc /usr/bin/runc &> /dev/null; echo $?)
- item_test "On ubuntu /usr/bin/runc is /usr/lib/cri-o-runc/sbin/runc" "$SAMESAME" -eq "0" || let "NFAILS+=1"
-fi
-
-if [[ "$OS_RELEASE_ID" == "ubuntu" ]]
-then
- item_test "On ubuntu, no periodic apt crap is enabled" -z "$(egrep $PERIODIC_APT_RE /etc/apt/apt.conf.d/*)"
-fi
-
echo "Checking items specific to ${PACKER_BUILDER_NAME}${BUILT_IMAGE_SUFFIX}"
case "$PACKER_BUILDER_NAME" in
+ ubuntu*)
+ item_test "On ubuntu, no periodic apt crap is enabled" -z "$(egrep $PERIODIC_APT_RE /etc/apt/apt.conf.d/*)"
+ ;;
+ fedora*)
+ # Only runc -OR- crun should be installed, never both
+ case "$CG_FS_TYPE" in
+ tmpfs)
+ HAS=runc
+ HAS_NOT=crun
+ ;;
+ cgroup2fs)
+ HAS=crun
+ HAS_NOT=runc
+ ;;
+ esac
+ HAS_RC=$(rpm -qV $HAS &> /dev/null; echo $?)
+ HAS_NOT_RC=$(rpm -qV $HAS_NOT &> /dev/null; echo $?)
+ item_test "With a cgroups-fs type $CG_FS_TYPE, the $HAS package is installed" $HAS_RC -eq 0
+ item_test "With a cgroups-fs type $CG_FS_TYPE, the $HAS_NOT package is not installed" $HAS_NOT_RC -ne 0
+ ;;
xfedora*)
echo "Kernel Command-line: $(cat /proc/cmdline)"
item_test \
diff --git a/contrib/cirrus/integration_test.sh b/contrib/cirrus/integration_test.sh
index c92f123fd..33e9fbc6b 100755
--- a/contrib/cirrus/integration_test.sh
+++ b/contrib/cirrus/integration_test.sh
@@ -6,6 +6,11 @@ source $(dirname $0)/lib.sh
req_env_var GOSRC SCRIPT_BASE OS_RELEASE_ID OS_RELEASE_VER CONTAINER_RUNTIME VARLINK_LOG
+LOCAL_OR_REMOTE=local
+if [[ "$TEST_REMOTE_CLIENT" = "true" ]]; then
+ LOCAL_OR_REMOTE=remote
+fi
+
# Our name must be of the form xxxx_test or xxxx_test.sh, where xxxx is
# the test suite to run; currently (2019-05) the only option is 'integration'
# but pr2947 intends to add 'system'.
@@ -18,7 +23,7 @@ cd "$GOSRC"
case "$SPECIALMODE" in
in_podman)
- ${CONTAINER_RUNTIME} run --rm --privileged --net=host \
+ ${CONTAINER_RUNTIME} run --rm --privileged --net=host --cgroupns=host \
-v $GOSRC:$GOSRC:Z \
--workdir $GOSRC \
-e "CGROUP_MANAGER=cgroupfs" \
@@ -34,7 +39,7 @@ case "$SPECIALMODE" in
req_env_var ROOTLESS_USER
ssh $ROOTLESS_USER@localhost \
-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no \
- -o CheckHostIP=no $GOSRC/$SCRIPT_BASE/rootless_test.sh ${TESTSUITE}
+ -o CheckHostIP=no $GOSRC/$SCRIPT_BASE/rootless_test.sh ${TESTSUITE} ${LOCAL_OR_REMOTE}
;;
endpoint)
make
@@ -52,12 +57,8 @@ case "$SPECIALMODE" in
make
make install PREFIX=/usr ETCDIR=/etc
make test-binaries
- if [[ "$TEST_REMOTE_CLIENT" == "true" ]]
- then
- make remote${TESTSUITE} VARLINK_LOG=$VARLINK_LOG
- else
- make local${TESTSUITE}
- fi
+ make .install.bats
+ make ${LOCAL_OR_REMOTE}${TESTSUITE} PODMAN_SERVER_LOG=$PODMAN_SERVER_LOG
;;
*)
die 110 "Unsupported \$SPECIALMODE: $SPECIALMODE"
diff --git a/contrib/cirrus/lib.sh b/contrib/cirrus/lib.sh
index cc5a3ffa7..66e8060cf 100644
--- a/contrib/cirrus/lib.sh
+++ b/contrib/cirrus/lib.sh
@@ -39,6 +39,8 @@ PACKER_BASE=${PACKER_BASE:-./contrib/cirrus/packer}
# Important filepaths
SETUP_MARKER_FILEPATH="${SETUP_MARKER_FILEPATH:-/var/tmp/.setup_environment_sh_complete}"
AUTHOR_NICKS_FILEPATH="${CIRRUS_WORKING_DIR}/${SCRIPT_BASE}/git_authors_to_irc_nicks.csv"
+# Downloaded, but not installed packages.
+PACKAGE_DOWNLOAD_DIR=/var/cache/download
# Log remote-client system test varlink output here
export VARLINK_LOG=/var/tmp/varlink.log
@@ -422,7 +424,7 @@ remove_packaged_podman_files() {
then
LISTING_CMD="$SUDO dpkg-query -L podman"
else
- LISTING_CMD='$SUDO rpm -ql podman'
+ LISTING_CMD="$SUDO rpm -ql podman"
fi
# yum/dnf/dpkg may list system directories, only remove files
@@ -437,6 +439,14 @@ remove_packaged_podman_files() {
sync && echo 3 > /proc/sys/vm/drop_caches
}
+# The version of CRI-O and Kubernetes must always match
+get_kubernetes_version(){
+ # TODO: Look up the kube RPM/DEB version installed, or in $PACKAGE_DOWNLOAD_DIR
+ # and retrieve the major-minor version directly.
+ local KUBERNETES_VERSION="1.15"
+ echo "$KUBERNETES_VERSION"
+}
+
canonicalize_image_names() {
req_env_var IMGNAMES
echo "Adding all current base images to \$IMGNAMES for timestamp update"
@@ -479,6 +489,7 @@ _finalize() {
fi
echo "Re-initializing so next boot does 'first-boot' setup again."
cd /
+ $SUDO rm -rf $GOPATH/src # Actual source will be cloned at runtime
$SUDO rm -rf /var/lib/cloud/instanc*
$SUDO rm -rf /root/.ssh/*
$SUDO rm -rf /etc/ssh/*key*
diff --git a/contrib/cirrus/packer/fedora_packaging.sh b/contrib/cirrus/packer/fedora_packaging.sh
index e80d48bc8..aecaaef93 100644
--- a/contrib/cirrus/packer/fedora_packaging.sh
+++ b/contrib/cirrus/packer/fedora_packaging.sh
@@ -11,6 +11,8 @@ echo "Updating/Installing repos and packages for $OS_REL_VER"
source $GOSRC/$SCRIPT_BASE/lib.sh
+req_env_var GOSRC SCRIPT_BASE BIGTO INSTALL_AUTOMATION_VERSION FEDORA_BASE_IMAGE PRIOR_FEDORA_BASE_IMAGE
+
# Pre-req. to install automation tooing
$LILTO $SUDO dnf install -y git
@@ -35,7 +37,7 @@ fi
$BIGTO ooe.sh $SUDO dnf update -y
-REMOVE_PACKAGES=()
+REMOVE_PACKAGES=(runc)
INSTALL_PACKAGES=(\
autoconf
automake
@@ -50,8 +52,11 @@ INSTALL_PACKAGES=(\
containernetworking-plugins
containers-common
criu
+ crun
+ curl
device-mapper-devel
dnsmasq
+ e2fsprogs-devel
emacs-nox
file
findutils
@@ -60,16 +65,26 @@ INSTALL_PACKAGES=(\
gcc
git
glib2-devel
+ glibc-devel
glibc-static
gnupg
go-md2man
golang
+ gpgme
gpgme-devel
+ grubby
+ hostname
iproute
iptables
jq
+ krb5-workstation
+ libassuan
libassuan-devel
+ libblkid-devel
libcap-devel
+ libffi-devel
+ libgpg-error-devel
+ libguestfs-tools
libmsi1
libnet
libnet-devel
@@ -79,56 +94,60 @@ INSTALL_PACKAGES=(\
libselinux-devel
libtool
libvarlink-util
+ libxml2-devel
+ libxslt-devel
lsof
make
+ mlocate
msitools
+ nfs-utils
nmap-ncat
+ openssl
+ openssl-devel
ostree-devel
pandoc
+ pkgconfig
podman
+ policycoreutils
procps-ng
protobuf
protobuf-c
protobuf-c-devel
protobuf-devel
- python
+ python2
+ python3-PyYAML
python3-dateutil
python3-psutil
python3-pytoml
+ python3-libsemanage
+ python3-libselinux
+ python3-libvirt
+ redhat-rpm-config
+ rpcbind
rsync
+ sed
selinux-policy-devel
skopeo
skopeo-containers
slirp4netns
+ socat
+ tar
unzip
vim
wget
which
xz
zip
+ zlib-devel
+)
+DOWNLOAD_PACKAGES=(\
+ "cri-o-$(get_kubernetes_version)*"
+ cri-tools
+ "kubernetes-$(get_kubernetes_version)*"
+ runc
+ oci-umount
+ parallel
)
-
-case "$OS_RELEASE_VER" in
- 30)
- INSTALL_PACKAGES+=(\
- atomic-registries
- golang-github-cpuguy83-go-md2man
- python2-future
- runc
- )
- REMOVE_PACKAGES+=(crun)
- ;;
- 31)
- INSTALL_PACKAGES+=(crun)
- REMOVE_PACKAGES+=(runc)
- ;;
- 32)
- INSTALL_PACKAGES+=(crun)
- REMOVE_PACKAGES+=(runc)
- ;;
- *)
- bad_os_id_ver ;;
-esac
echo "Installing general build/test dependencies for Fedora '$OS_RELEASE_VER'"
$BIGTO ooe.sh $SUDO dnf install -y ${INSTALL_PACKAGES[@]}
@@ -136,6 +155,18 @@ $BIGTO ooe.sh $SUDO dnf install -y ${INSTALL_PACKAGES[@]}
[[ ${#REMOVE_PACKAGES[@]} -eq 0 ]] || \
$LILTO ooe.sh $SUDO dnf erase -y ${REMOVE_PACKAGES[@]}
-export GOPATH="$(mktemp -d)"
-trap "$SUDO rm -rf $GOPATH" EXIT
-ooe.sh $SUDO $GOSRC/hack/install_catatonit.sh
+if [[ ${#DOWNLOAD_PACKAGES[@]} -gt 0 ]]; then
+ echo "Downloading packages for optional installation at runtime, as needed."
+ # Required for cri-o
+ ooe.sh $SUDO dnf -y module enable cri-o:$(get_kubernetes_version)
+ $SUDO mkdir -p "$PACKAGE_DOWNLOAD_DIR"
+ cd "$PACKAGE_DOWNLOAD_DIR"
+ $LILTO ooe.sh $SUDO dnf download -y --resolve ${DOWNLOAD_PACKAGES[@]}
+ ls -la "$PACKAGE_DOWNLOAD_DIR/"
+fi
+
+echo "Installing runtime tooling"
+# Save some runtime by having these already available
+cd $GOSRC
+$SUDO make install.tools
+$SUDO $GOSRC/hack/install_catatonit.sh
diff --git a/contrib/cirrus/packer/fedora_setup.sh b/contrib/cirrus/packer/fedora_setup.sh
index 3830b3bc4..25b568e8a 100644
--- a/contrib/cirrus/packer/fedora_setup.sh
+++ b/contrib/cirrus/packer/fedora_setup.sh
@@ -12,11 +12,11 @@ req_env_var SCRIPT_BASE PACKER_BASE INSTALL_AUTOMATION_VERSION PACKER_BUILDER_NA
workaround_bfq_bug
-# Do not enable update-stesting on the previous Fedora release
-if [[ "$FEDORA_BASE_IMAGE" =~ "${OS_RELEASE_ID}-cloud-base-${OS_RELEASE_VER}" ]]; then
- DISABLE_UPDATES_TESTING=0
-else
+# Do not enable updates-testing on the previous Fedora release
+if [[ "$PRIOR_FEDORA_BASE_IMAGE" =~ "${OS_RELEASE_ID}-cloud-base-${OS_RELEASE_VER}" ]]; then
DISABLE_UPDATES_TESTING=1
+else
+ DISABLE_UPDATES_TESTING=0
fi
bash $PACKER_BASE/fedora_packaging.sh
diff --git a/contrib/cirrus/packer/ubuntu_packaging.sh b/contrib/cirrus/packer/ubuntu_packaging.sh
index fd0280230..09f9aab9f 100644
--- a/contrib/cirrus/packer/ubuntu_packaging.sh
+++ b/contrib/cirrus/packer/ubuntu_packaging.sh
@@ -11,6 +11,8 @@ echo "Updating/Installing repos and packages for $OS_REL_VER"
source $GOSRC/$SCRIPT_BASE/lib.sh
+req_env_var GOSRC SCRIPT_BASE BIGTO SUDOAPTGET INSTALL_AUTOMATION_VERSION
+
echo "Updating/configuring package repositories."
$BIGTO $SUDOAPTGET update
@@ -99,6 +101,7 @@ INSTALL_PACKAGES=(\
protobuf-c-compiler
protobuf-compiler
python-protobuf
+ python2
python3-dateutil
python3-pip
python3-psutil
@@ -118,6 +121,11 @@ INSTALL_PACKAGES=(\
zip
zlib1g-dev
)
+DOWNLOAD_PACKAGES=(\
+ cri-o-$(get_kubernetes_version)
+ cri-tools
+ parallel
+)
# These aren't resolvable on Ubuntu 20
if [[ "$OS_RELEASE_VER" -le 19 ]]; then
@@ -137,16 +145,15 @@ echo "Installing general testing and system dependencies"
$LILTO ooe.sh $SUDOAPTGET update
$BIGTO ooe.sh $SUDOAPTGET install ${INSTALL_PACKAGES[@]}
-export GOPATH="$(mktemp -d)"
-trap "$SUDO rm -rf $GOPATH" EXIT
-echo "Installing cataonit and libseccomp.sudo"
-cd $GOSRC
-ooe.sh $SUDO hack/install_catatonit.sh
-ooe.sh $SUDO make install.libseccomp.sudo
-
-CRIO_RUNC_PATH="/usr/lib/cri-o-runc/sbin/runc"
-if $SUDO dpkg -L cri-o-runc | grep -m 1 -q "$CRIO_RUNC_PATH"
-then
- echo "Linking $CRIO_RUNC_PATH to /usr/bin/runc for ease of testing."
- $SUDO ln -f "$CRIO_RUNC_PATH" "/usr/bin/runc"
+if [[ ${#DOWNLOAD_PACKAGES[@]} -gt 0 ]]; then
+ echo "Downloading packages for optional installation at runtime, as needed."
+ $SUDO ln -s /var/cache/apt/archives "$PACKAGE_DOWNLOAD_DIR"
+ $LILTO ooe.sh $SUDOAPTGET install --download-only ${DOWNLOAD_PACKAGES[@]}
+ ls -la "$PACKAGE_DOWNLOAD_DIR/"
fi
+
+echo "Installing runtime tooling"
+cd $GOSRC
+$SUDO hack/install_catatonit.sh
+$SUDO make install.libseccomp.sudo
+$SUDO make install.tools
diff --git a/contrib/cirrus/rootless_test.sh b/contrib/cirrus/rootless_test.sh
index 3f45aac84..9e1b1d911 100755
--- a/contrib/cirrus/rootless_test.sh
+++ b/contrib/cirrus/rootless_test.sh
@@ -2,14 +2,6 @@
set -e
-remote=0
-
-# The TEST_REMOTE_CLIENT environment variable decides whether
-# to test varlink
-if [[ "$TEST_REMOTE_CLIENT" == "true" ]]; then
- remote=1
-fi
-
source $(dirname $0)/lib.sh
if [[ "$UID" == "0" ]]
@@ -18,11 +10,8 @@ then
exit 1
fi
-# Which set of tests to run; possible alternative is "system"
-TESTSUITE=integration
-if [[ -n "$*" ]]; then
- TESTSUITE="$1"
-fi
+TESTSUITE=${1?Missing TESTSUITE argument (arg1)}
+LOCAL_OR_REMOTE=${2?Missing LOCAL_OR_REMOTE argument (arg2)}
# Ensure environment setup correctly
req_env_var GOSRC ROOTLESS_USER
@@ -31,7 +20,6 @@ echo "."
echo "Hello, my name is $USER and I live in $PWD can I be your friend?"
echo "."
-export PODMAN_VARLINK_ADDRESS=unix:/tmp/podman-$(id -u)
show_env_vars
set -x
@@ -39,8 +27,4 @@ cd "$GOSRC"
make
make varlink_generate
make test-binaries
-if [ $remote -eq 0 ]; then
- make local${TESTSUITE}
-else
- make remote${TESTSUITE}
-fi
+make ${LOCAL_OR_REMOTE}${TESTSUITE}
diff --git a/contrib/cirrus/setup_environment.sh b/contrib/cirrus/setup_environment.sh
index 25b7ff941..323e7c35b 100755
--- a/contrib/cirrus/setup_environment.sh
+++ b/contrib/cirrus/setup_environment.sh
@@ -39,6 +39,17 @@ done
cd "${GOSRC}/"
case "${OS_RELEASE_ID}" in
ubuntu)
+ apt-get update
+ apt-get install -y containers-common
+ sed -ie 's/^\(# \)\?apparmor_profile =.*/apparmor_profile = ""/' /etc/containers/containers.conf
+ if [[ "$OS_RELEASE_VER" == "19" ]]; then
+ apt-get purge -y --auto-remove golang*
+ apt-get install -y golang-1.13
+ ln -s /usr/lib/go-1.13/bin/go /usr/bin/go
+ fi
+ if [[ "$OS_RELEASE_VER" == "20" ]]; then
+ apt-get install -y python-is-python3
+ fi
;;
fedora)
# All SELinux distros need this for systemd-in-a-container
@@ -78,14 +89,6 @@ case "$CG_FS_TYPE" in
warn "Forcing testing with crun instead of runc"
X=$(echo "export OCI_RUNTIME=/usr/bin/crun" | \
tee -a /etc/environment) && eval "$X" && echo "$X"
-
- if [[ "$OS_RELEASE_ID" == "fedora" ]]; then
- warn "Upgrading to the latest crun"
- # Normally not something to do for stable testing
- # but crun is new, and late-breaking fixes may be required
- # on short notice
- dnf update -y crun containers-common
- fi
;;
*)
die 110 "Unsure how to handle cgroup filesystem type '$CG_FS_TYPE'"
diff --git a/contrib/cirrus/swagger_stack_trace.png b/contrib/cirrus/swagger_stack_trace.png
new file mode 100644
index 000000000..6aa063bab
--- /dev/null
+++ b/contrib/cirrus/swagger_stack_trace.png
Binary files differ
diff --git a/contrib/gate/Dockerfile b/contrib/gate/Dockerfile
index f86709b00..657b5accf 100644
--- a/contrib/gate/Dockerfile
+++ b/contrib/gate/Dockerfile
@@ -13,7 +13,7 @@ COPY . $GOSRC
# Note: adding conmon and crun so podman command checks will work
RUN dnf -y install \
$(grep "^[^#]" $GOSRC/contrib/dependencies.txt) diffutils containers-common fuse-overlayfs conmon crun runc --exclude container-selinux; \
- sed -i -e 's|^#mount_program|mount_program|g' /etc/containers/storage.conf \
+ sed -i -e 's|^#mount_program|mount_program|g' -e 's/# size.*/skip_mount_home = "true"/g' /etc/containers/storage.conf \
&& dnf clean all
# Install dependencies
diff --git a/contrib/spec/podman.spec.in b/contrib/spec/podman.spec.in
index 9ab0db3ae..8d3cba612 100644
--- a/contrib/spec/podman.spec.in
+++ b/contrib/spec/podman.spec.in
@@ -80,8 +80,12 @@ Requires: iptables
%if 0%{?rhel} <= 7
Requires: container-selinux
%else
+%if 0%{?rhel} || 0%{?centos}
+Requires: runc
+%else
Requires: oci-runtime
Recommends: crun
+%endif
Recommends: container-selinux
Recommends: slirp4netns
Recommends: fuse-overlayfs
diff --git a/docs/Readme.md b/docs/Readme.md
index 987a5b8e4..9d3b9d06f 100644
--- a/docs/Readme.md
+++ b/docs/Readme.md
@@ -30,10 +30,26 @@ link on that page.
## API Reference
The [latest online documentation](http://docs.podman.io/en/latest/_static/api.html) is
-automatically generated from committed upstream sources. There is a short-duration
-cache involved, in case old content or an error is returned, try clearing your browser
-cache or returning to the site after 10-30 minutes.
-
-***Maintainers Note***: Please refer to [the Cirrus-CI tasks
-documentation](../contrib/cirrus/README.md#docs-task) for
-important operational details.
+automatically generated by two cooperating automation systems based on committed upstream
+source code. Firstly, [the Cirrus-CI docs task](../contrib/cirrus/README.md#docs-task) builds
+`pkg/api/swagger.yaml` and uploads it to a public-facing location (Google Storage Bucket -
+an online service for storing unstructured data). Second, [Read The Docs](readthedocs.com)
+reacts to the github.com repository change, building the content for the [libpod documentation
+site](https://podman.readthedocs.io/). This site includes for the API section,
+some javascript which consumes the uploaded `swagger.yaml` file directly from the Google
+Storage Bucket.
+
+Since there are multiple systems and local cache is involved, it's possible that updates to
+documentation (especially the swagger/API docs) will lag by 10-or-so minutes. However,
+because the client (i.e. your web browser) is fetching content from multiple locations that
+do not share a common domain, accessing the API section may show a stack-trace similar to
+the following:
+
+![Javascript Stack Trace Image](../contrib/cirrus/swagger_stack_trace.png)
+
+If reloading the page, or clearing your local cache does not fix the problem, it is
+likely caused by broken metadata needed to protect clients from cross-site-scripting
+style attacks. Please [notify a maintainer](https://github.com/containers/libpod#communications)
+so they may investigate how/why the swagger.yaml file's CORS-metadata is incorrect. See
+[the Cirrus-CI tasks documentation](../contrib/cirrus/README.md#docs-task) for
+details regarding this situation.
diff --git a/docs/source/markdown/podman-events.1.md b/docs/source/markdown/podman-events.1.md
index a05047684..abfc6e9c1 100644
--- a/docs/source/markdown/podman-events.1.md
+++ b/docs/source/markdown/podman-events.1.md
@@ -15,6 +15,8 @@ value to `file`. Only `file` and `journald` are accepted. A `none` logger is al
available but this logging mechanism completely disables events; nothing will be reported by
`podman events`.
+By default, streaming mode is used, printing new events as they occur. Previous events can be listed via `--since` and `--until`.
+
The *container* event type will report the follow statuses:
* attach
* checkpoint
diff --git a/docs/source/markdown/podman-info.1.md b/docs/source/markdown/podman-info.1.md
index 24ab97c91..19dd61c15 100644
--- a/docs/source/markdown/podman-info.1.md
+++ b/docs/source/markdown/podman-info.1.md
@@ -71,6 +71,9 @@ host:
commit: 3e425f80a8c931f88e6d94a8c831b9d5aa481657
spec: 1.0.1-dev
os: linux
+ remoteSocket:
+ exists: false
+ path: /run/user/1000/podman/podman.sock
rootless: true
slirp4netns:
executable: /bin/slirp4netns
@@ -179,6 +182,10 @@ Run podman info with JSON formatted response:
"version": "runc version 1.0.0-rc8+dev\ncommit: 3e425f80a8c931f88e6d94a8c831b9d5aa481657\nspec: 1.0.1-dev"
},
"os": "linux",
+ "remoteSocket": {
+ "path": "/run/user/1000/podman/podman.sock",
+ "exists": false
+ },
"rootless": true,
"slirp4netns": {
"executable": "/bin/slirp4netns",
diff --git a/docs/source/markdown/podman.1.md b/docs/source/markdown/podman.1.md
index 02f23e6cc..8dc486b65 100644
--- a/docs/source/markdown/podman.1.md
+++ b/docs/source/markdown/podman.1.md
@@ -61,6 +61,9 @@ Podman and libpod currently support an additional `precreate` state which is cal
**--identity**=*path*
Path to SSH identity file
+**--passphrase**=*secret*
+pass phrase for SSH identity file
+
**--log-level**=*level*
Log messages above specified level: debug, info, warn, error (default), fatal or panic (default: "error")
@@ -73,18 +76,21 @@ When namespace is set, created containers and pods will join the given namespace
**--network-cmd-path**=*path*
Path to the command binary to use for setting up a network. It is currently only used for setting up a slirp4netns network. If "" is used then the binary is looked up using the $PATH environment variable.
-**--remote**, **-r**=*url*
-URL to access Podman service (default "unix:/run/user/3267/podman/podman.sock")
+**--remote**, **-r**
+Access Podman service will be remote
+
+**--url**=*value*
+URL to access Podman service (default from `containers.conf`, rootless "unix://run/user/$UID/podman/podman.sock" or as root "unix://run/podman/podman.sock).
**--root**=*value*
Storage root dir in which data, including images, is stored (default: "/var/lib/containers/storage" for UID 0, "$HOME/.local/share/containers/storage" for other users).
-Default root dir is configured in `/etc/containers/storage.conf`.
+Default root dir configured in `/etc/containers/storage.conf`.
**--runroot**=*value*
Storage state directory where all state information is stored (default: "/var/run/containers/storage" for UID 0, "/var/run/user/$UID/run" for other users).
-Default state dir is configured in `/etc/containers/storage.conf`.
+Default state dir configured in `/etc/containers/storage.conf`.
**--runtime**=*value*
diff --git a/go.mod b/go.mod
index 617f118f1..bacc8d72f 100644
--- a/go.mod
+++ b/go.mod
@@ -11,11 +11,11 @@ require (
github.com/containernetworking/cni v0.7.2-0.20200304161608-4fae32b84921
github.com/containernetworking/plugins v0.8.6
github.com/containers/buildah v1.14.9-0.20200523094741-de0f541d9224
- github.com/containers/common v0.12.0
- github.com/containers/conmon v2.0.16+incompatible
+ github.com/containers/common v0.13.0
+ github.com/containers/conmon v2.0.17+incompatible
github.com/containers/image/v5 v5.4.5-0.20200529084758-46b2ee6aebb0
github.com/containers/psgo v1.5.1
- github.com/containers/storage v1.20.1
+ github.com/containers/storage v1.20.2
github.com/coreos/go-systemd/v22 v22.1.0
github.com/cri-o/ocicni v0.2.0
github.com/cyphar/filepath-securejoin v0.2.2
@@ -33,7 +33,7 @@ require (
github.com/gorilla/schema v1.1.0
github.com/hashicorp/go-multierror v1.0.0
github.com/hpcloud/tail v1.0.0
- github.com/json-iterator/go v1.1.9
+ github.com/json-iterator/go v1.1.10
github.com/mrunalp/fileutils v0.0.0-20171103030105-7d4729fb3618
github.com/onsi/ginkgo v1.12.3
github.com/onsi/gomega v1.10.1
@@ -47,11 +47,11 @@ require (
github.com/pkg/errors v0.9.1
github.com/pmezard/go-difflib v1.0.0
github.com/rootless-containers/rootlesskit v0.9.5
- github.com/seccomp/containers-golang v0.4.1
+ github.com/seccomp/containers-golang v0.5.0
github.com/sirupsen/logrus v1.6.0
github.com/spf13/cobra v0.0.7
github.com/spf13/pflag v1.0.5
- github.com/stretchr/testify v1.6.0
+ github.com/stretchr/testify v1.6.1
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2
github.com/uber/jaeger-client-go v2.23.1+incompatible
github.com/uber/jaeger-lib v2.2.0+incompatible // indirect
diff --git a/go.sum b/go.sum
index 38fdfe902..9ac2c82c9 100644
--- a/go.sum
+++ b/go.sum
@@ -70,10 +70,10 @@ github.com/containernetworking/plugins v0.8.6/go.mod h1:qnw5mN19D8fIwkqW7oHHYDHV
github.com/containers/buildah v1.14.9-0.20200523094741-de0f541d9224 h1:EqwBZRqyUYvU7JOmmSSPviSaAoUP1wN0cefXXDZ9ATo=
github.com/containers/buildah v1.14.9-0.20200523094741-de0f541d9224/go.mod h1:5ZkWjOuK90yl55L5R+purJNLfUo0VUr8pstJazNtYck=
github.com/containers/common v0.11.2/go.mod h1:2w3QE6VUmhltGYW4wV00h4okq1Crs7hNI1ZD2I0QRUY=
-github.com/containers/common v0.12.0 h1:LR/sYyzFa22rFhfu6J9dEYhVkrWjagUigz/ewHhHL9s=
-github.com/containers/common v0.12.0/go.mod h1:PKlahPDnQQYcXuIw5qq8mq6yNuCHBtgABphzy6pN0iI=
-github.com/containers/conmon v2.0.16+incompatible h1:QFOlb9Id4WoJ24BelCFWwDSPTquwKMp3L3g2iGmRTq4=
-github.com/containers/conmon v2.0.16+incompatible/go.mod h1:hgwZ2mtuDrppv78a/cOBNiCm6O0UMWGx1mu7P00nu5I=
+github.com/containers/common v0.13.0 h1:+7FHpPNz3YR2YcVIVNnPg2sVrXytxNgNHbd3n7SosL0=
+github.com/containers/common v0.13.0/go.mod h1:LJlijBz9zi7pJqZvlbxCOsw6qNn31rzb7Zo6NBJNQxU=
+github.com/containers/conmon v2.0.17+incompatible h1:8BooocmNIwjOwAUGAoDD6fi3u0RrFyQ/fDkQzdiVtrI=
+github.com/containers/conmon v2.0.17+incompatible/go.mod h1:hgwZ2mtuDrppv78a/cOBNiCm6O0UMWGx1mu7P00nu5I=
github.com/containers/image/v5 v5.4.3/go.mod h1:pN0tvp3YbDd7BWavK2aE0mvJUqVd2HmhPjekyWSFm0U=
github.com/containers/image/v5 v5.4.4/go.mod h1:g7cxNXitiLi6pEr9/L9n/0wfazRuhDKXU15kV86N8h8=
github.com/containers/image/v5 v5.4.5-0.20200529084758-46b2ee6aebb0 h1:K1ez+qAi9hCMHv/akPF4ddZumQTq/PBGf2Nzc7e+7lI=
@@ -89,6 +89,8 @@ github.com/containers/storage v1.19.1/go.mod h1:KbXjSwKnx17ejOsjFcCXSf78mCgZkQSL
github.com/containers/storage v1.19.2/go.mod h1:gYCp3jzgXkvubO0rI14QAjz5Mxm/qKJgLmHFyqayDnw=
github.com/containers/storage v1.20.1 h1:2XE4eRIqSa6YjhAZjNwIkIKE6+Miy+5WV8l1KzY2ZKk=
github.com/containers/storage v1.20.1/go.mod h1:RoKzO8KSDogCT6c06rEbanZTcKYxshorB33JikEGc3A=
+github.com/containers/storage v1.20.2 h1:tw/uKRPDnmVrluIzer3dawTFG/bTJLP8IEUyHFhltYk=
+github.com/containers/storage v1.20.2/go.mod h1:oOB9Ie8OVPojvoaKWEGSEtHbXUAs+tSyr7RO7ZGteMc=
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 h1:DpHb9vJrZQEFMcVLFKAAGMUVX0XoRC0ptCthinRYm38=
@@ -246,8 +248,8 @@ github.com/json-iterator/go v0.0.0-20180701071628-ab8a2e0c74be/go.mod h1:+SdeFBv
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
-github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
-github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
+github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
@@ -257,6 +259,8 @@ github.com/klauspost/compress v1.10.5 h1:7q6vHIqubShURwQz8cQK6yIe/xC3IF0Vm7TGfqj
github.com/klauspost/compress v1.10.5/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.10.6 h1:SP6zavvTG3YjOosWePXFDlExpKIWMTO4SE/Y8MZB2vI=
github.com/klauspost/compress v1.10.6/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
+github.com/klauspost/compress v1.10.7 h1:7rix8v8GpI3ZBb0nSozFRgbtXKv+hOe+qfEpZqybrAg=
+github.com/klauspost/compress v1.10.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/pgzip v1.2.3/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
github.com/klauspost/pgzip v1.2.4 h1:TQ7CNpYKovDOmqzRHKxJh0BeaBI7UdQZYc6p7pMQh1A=
github.com/klauspost/pgzip v1.2.4/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
@@ -314,8 +318,6 @@ github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+
github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
-github.com/onsi/ginkgo v1.12.2 h1:Ke9m3h2Hu0wsZ45yewCqhYr3Z+emcNTuLY2nMWCkrSI=
-github.com/onsi/ginkgo v1.12.2/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
github.com/onsi/ginkgo v1.12.3 h1:+RYp9QczoWz9zfUyLP/5SLXQVhfr6gZOoKGfQqHuLZQ=
github.com/onsi/ginkgo v1.12.3/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
@@ -403,6 +405,8 @@ github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8 h1:2c1EFnZHIPCW8q
github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4=
github.com/seccomp/containers-golang v0.4.1 h1:6hsmsP8Y9T6PWKJELqAkRWkc6Te60+zK64avkjInd44=
github.com/seccomp/containers-golang v0.4.1/go.mod h1:5fP9lgyYyklJ8fg8Geq193G1QLe0ikf34z+hZKIjmnE=
+github.com/seccomp/containers-golang v0.5.0 h1:uUMOZIz/7TUiEO6h4ursAJY5JT55AzYiN/X5GOj9rvY=
+github.com/seccomp/containers-golang v0.5.0/go.mod h1:5fP9lgyYyklJ8fg8Geq193G1QLe0ikf34z+hZKIjmnE=
github.com/seccomp/libseccomp-golang v0.9.1 h1:NJjM5DNFOs0s3kYE1WUOr6G8V97sdt46rlXTMfXGWBo=
github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
@@ -439,6 +443,8 @@ github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.0 h1:jlIyCplCJFULU/01vCkhKuTyc3OorI3bJFuw6obfgho=
github.com/stretchr/testify v1.6.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
+github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2 h1:b6uOv7YOFK0TYG7HtkIgExQo+2RdLuwRft63jn2HWj8=
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
@@ -560,6 +566,7 @@ golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191127021746-63cb32ae39b2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
diff --git a/hack/golangci-lint.sh b/hack/golangci-lint.sh
index f4e60d8f5..8c81a3743 100755
--- a/hack/golangci-lint.sh
+++ b/hack/golangci-lint.sh
@@ -5,12 +5,12 @@
declare -A BUILD_TAGS
# TODO: add systemd tag
BUILD_TAGS[default]="apparmor,seccomp,selinux"
-BUILD_TAGS[abi]="${BUILD_TAGS[default]},ABISupport,varlink,!remoteclient"
-BUILD_TAGS[tunnel]="${BUILD_TAGS[default]},!ABISupport,varlink,remoteclient"
+BUILD_TAGS[abi]="${BUILD_TAGS[default]},varlink,!remoteclient"
+BUILD_TAGS[tunnel]="${BUILD_TAGS[default]},remote,varlink,remoteclient"
declare -A SKIP_DIRS
SKIP_DIRS[abi]=""
-# TODO: add "ABISupport" build tag to pkg/api
+# TODO: add "remote" build tag to pkg/api
SKIP_DIRS[tunnel]="pkg/api"
[[ $1 == run ]] && shift
diff --git a/hack/install_bats.sh b/hack/install_bats.sh
new file mode 100755
index 000000000..00ded07a9
--- /dev/null
+++ b/hack/install_bats.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+set -e
+
+die() { echo "${1:-No error message given} (from $(basename $0))"; exit 1; }
+
+buildDir=$(mktemp -d)
+git clone https://github.com/bats-core/bats-core $buildDir
+
+pushd $buildDir
+pwd
+git reset --hard ${VERSION}
+./install.sh /usr/local
+popd
+
+rm -rf $buildDir
diff --git a/libpod/container_internal.go b/libpod/container_internal.go
index 43e873bd6..f6fc3c1a4 100644
--- a/libpod/container_internal.go
+++ b/libpod/container_internal.go
@@ -1209,13 +1209,35 @@ func (c *Container) stop(timeout uint) error {
}
}
+ // Check if conmon is still alive.
+ // If it is not, we won't be getting an exit file.
+ conmonAlive, err := c.ociRuntime.CheckConmonRunning(c)
+ if err != nil {
+ return err
+ }
+
if err := c.ociRuntime.StopContainer(c, timeout, all); err != nil {
return err
}
+ c.newContainerEvent(events.Stop)
+
c.state.PID = 0
c.state.ConmonPID = 0
c.state.StoppedByUser = true
+
+ if !conmonAlive {
+ // Conmon is dead, so we can't epect an exit code.
+ c.state.ExitCode = -1
+ c.state.FinishedTime = time.Now()
+ c.state.State = define.ContainerStateStopped
+ if err := c.save(); err != nil {
+ logrus.Errorf("Error saving container %s status: %v", c.ID(), err)
+ }
+
+ return errors.Wrapf(define.ErrConmonDead, "container %s conmon process missing, cannot retrieve exit code", c.ID())
+ }
+
if err := c.save(); err != nil {
return errors.Wrapf(err, "error saving container %s state after stopping", c.ID())
}
@@ -1225,8 +1247,6 @@ func (c *Container) stop(timeout uint) error {
return err
}
- c.newContainerEvent(events.Stop)
-
return nil
}
diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go
index d08e012a6..e3ca3f6b2 100644
--- a/libpod/container_internal_linux.go
+++ b/libpod/container_internal_linux.go
@@ -392,7 +392,7 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
}
for _, i := range c.config.Spec.Linux.Namespaces {
- if i.Type == spec.UTSNamespace {
+ if i.Type == spec.UTSNamespace && i.Path == "" {
hostname := c.Hostname()
g.SetHostname(hostname)
g.AddProcessEnv("HOSTNAME", hostname)
@@ -591,7 +591,8 @@ func (c *Container) addNamespaceContainer(g *generate.Generator, ns LinuxNS, ctr
if specNS == spec.UTSNamespace {
hostname := nsCtr.Hostname()
- g.SetHostname(hostname)
+ // Joining an existing namespace, cannot set the hostname
+ g.SetHostname("")
g.AddProcessEnv("HOSTNAME", hostname)
}
@@ -1171,6 +1172,15 @@ func (c *Container) makeBindMounts() error {
// finally, save it in the new container
c.state.BindMounts["/etc/hosts"] = hostsPath
}
+
+ if !hasCurrentUserMapped(c) {
+ if err := makeAccessible(resolvPath, c.RootUID(), c.RootGID()); err != nil {
+ return err
+ }
+ if err := makeAccessible(hostsPath, c.RootUID(), c.RootGID()); err != nil {
+ return err
+ }
+ }
} else {
if !c.config.UseImageResolvConf {
newResolv, err := c.generateResolvConf()
diff --git a/libpod/container_log.go b/libpod/container_log.go
index bfa303e84..c3a84d048 100644
--- a/libpod/container_log.go
+++ b/libpod/container_log.go
@@ -19,7 +19,7 @@ func (r *Runtime) Log(containers []*Container, options *logs.LogOptions, logChan
return nil
}
-// ReadLog reads a containers log based on the input options and returns loglines over a channel
+// ReadLog reads a containers log based on the input options and returns loglines over a channel.
func (c *Container) ReadLog(options *logs.LogOptions, logChannel chan *logs.LogLine) error {
// TODO Skip sending logs until journald logs can be read
// TODO make this not a magic string
@@ -61,7 +61,7 @@ func (c *Container) readFromLogFile(options *logs.LogOptions, logChannel chan *l
partial += nll.Msg
continue
} else if !nll.Partial() && len(partial) > 1 {
- nll.Msg = partial
+ nll.Msg = partial + nll.Msg
partial = ""
}
nll.CID = c.ID()
diff --git a/libpod/define/errors.go b/libpod/define/errors.go
index 16df2a1cc..083553b7e 100644
--- a/libpod/define/errors.go
+++ b/libpod/define/errors.go
@@ -141,6 +141,9 @@ var (
// ErrConmonOutdated indicates the version of conmon found (whether via the configuration or $PATH)
// is out of date for the current podman version
ErrConmonOutdated = errors.New("outdated conmon version")
+ // ErrConmonDead indicates that the container's conmon process has been
+ // killed, preventing normal operation.
+ ErrConmonDead = errors.New("conmon process killed")
// ErrImageInUse indicates the requested operation failed because the image was in use
ErrImageInUse = errors.New("image is being used")
diff --git a/libpod/define/info.go b/libpod/define/info.go
index 906aa523f..f136936f7 100644
--- a/libpod/define/info.go
+++ b/libpod/define/info.go
@@ -27,6 +27,7 @@ type HostInfo struct {
MemTotal int64 `json:"memTotal"`
OCIRuntime *OCIRuntimeInfo `json:"ociRuntime"`
OS string `json:"os"`
+ RemoteSocket *RemoteSocket `json:"remoteSocket,omitempty"`
Rootless bool `json:"rootless"`
RuntimeInfo map[string]interface{} `json:"runtimeInfo,omitempty"`
Slirp4NetNS SlirpInfo `json:"slirp4netns,omitempty"`
@@ -36,6 +37,12 @@ type HostInfo struct {
Linkmode string `json:"linkmode"`
}
+// RemoteSocket describes information about the API socket
+type RemoteSocket struct {
+ Path string `json:"path,omitempty"`
+ Exists bool `json:"exists,omitempty"`
+}
+
// SlirpInfo describes the slirp exectuable that
// is being being used.
type SlirpInfo struct {
diff --git a/libpod/filters/pods.go b/libpod/filters/pods.go
index 9bf436eab..0edb9fbf2 100644
--- a/libpod/filters/pods.go
+++ b/libpod/filters/pods.go
@@ -57,13 +57,13 @@ func GeneratePodFilterFunc(filter, filterValue string) (
return nil, errors.Errorf("%s is not a valid status", filterValue)
}
return func(p *libpod.Pod) bool {
- ctr_statuses, err := p.Status()
+ ctrStatuses, err := p.Status()
if err != nil {
return false
}
- for _, ctr_status := range ctr_statuses {
- state := ctr_status.String()
- if ctr_status == define.ContainerStateConfigured {
+ for _, ctrStatus := range ctrStatuses {
+ state := ctrStatus.String()
+ if ctrStatus == define.ContainerStateConfigured {
state = "created"
}
if state == filterValue {
diff --git a/libpod/image/filters.go b/libpod/image/filters.go
index 747eba165..9d99fb344 100644
--- a/libpod/image/filters.go
+++ b/libpod/image/filters.go
@@ -102,8 +102,8 @@ func ReferenceFilter(ctx context.Context, referenceFilter string) ResultFilter {
}
}
-// IdFilter allows you to filter by image Id
-func IdFilter(idFilter string) ResultFilter {
+// IDFilter allows you to filter by image Id
+func IDFilter(idFilter string) ResultFilter {
return func(i *Image) bool {
return i.ID() == idFilter
}
@@ -172,7 +172,7 @@ func (ir *Runtime) createFilterFuncs(filters []string, img *Image) ([]ResultFilt
case "reference":
filterFuncs = append(filterFuncs, ReferenceFilter(ctx, splitFilter[1]))
case "id":
- filterFuncs = append(filterFuncs, IdFilter(splitFilter[1]))
+ filterFuncs = append(filterFuncs, IDFilter(splitFilter[1]))
default:
return nil, errors.Errorf("invalid filter %s ", splitFilter[0])
}
diff --git a/libpod/networking_linux.go b/libpod/networking_linux.go
index 83344ebbe..0c9d28701 100644
--- a/libpod/networking_linux.go
+++ b/libpod/networking_linux.go
@@ -550,7 +550,7 @@ func getContainerNetNS(ctr *Container) (string, error) {
if err = c.syncContainer(); err != nil {
return "", err
}
- return c.state.NetNS.Path(), nil
+ return getContainerNetNS(c)
}
return "", nil
}
diff --git a/libpod/oci.go b/libpod/oci.go
index 684a7ba42..c2f0041b1 100644
--- a/libpod/oci.go
+++ b/libpod/oci.go
@@ -107,6 +107,13 @@ type OCIRuntime interface {
// error.
CheckpointContainer(ctr *Container, options ContainerCheckpointOptions) error
+ // CheckConmonRunning verifies that the given container's Conmon
+ // instance is still running. Runtimes without Conmon, or systems where
+ // the PID of conmon is not available, should mock this as True.
+ // True indicates that Conmon for the instance is running, False
+ // indicates it is not.
+ CheckConmonRunning(ctr *Container) (bool, error)
+
// SupportsCheckpoint returns whether this OCI runtime
// implementation supports the CheckpointContainer() operation.
SupportsCheckpoint() bool
diff --git a/libpod/oci_conmon_linux.go b/libpod/oci_conmon_linux.go
index 9c92b036e..0921a532b 100644
--- a/libpod/oci_conmon_linux.go
+++ b/libpod/oci_conmon_linux.go
@@ -669,6 +669,31 @@ func (r *ConmonOCIRuntime) CheckpointContainer(ctr *Container, options Container
return utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, nil, r.path, args...)
}
+func (r *ConmonOCIRuntime) CheckConmonRunning(ctr *Container) (bool, error) {
+ if ctr.state.ConmonPID == 0 {
+ // If the container is running or paused, assume Conmon is
+ // running. We didn't record Conmon PID on some old versions, so
+ // that is likely what's going on...
+ // Unusual enough that we should print a warning message though.
+ if ctr.ensureState(define.ContainerStateRunning, define.ContainerStatePaused) {
+ logrus.Warnf("Conmon PID is not set, but container is running!")
+ return true, nil
+ }
+ // Container's not running, so conmon PID being unset is
+ // expected. Conmon is not running.
+ return false, nil
+ }
+
+ // We have a conmon PID. Ping it with signal 0.
+ if err := unix.Kill(ctr.state.ConmonPID, 0); err != nil {
+ if err == unix.ESRCH {
+ return false, nil
+ }
+ return false, errors.Wrapf(err, "error pinging container %s conmon with signal 0", ctr.ID())
+ }
+ return true, nil
+}
+
// SupportsCheckpoint checks if the OCI runtime supports checkpointing
// containers.
func (r *ConmonOCIRuntime) SupportsCheckpoint() bool {
diff --git a/libpod/oci_missing.go b/libpod/oci_missing.go
index 4da16876c..90e90cc6c 100644
--- a/libpod/oci_missing.go
+++ b/libpod/oci_missing.go
@@ -163,6 +163,11 @@ func (r *MissingRuntime) CheckpointContainer(ctr *Container, options ContainerCh
return r.printError()
}
+// CheckConmonRunning is not available as the runtime is missing
+func (r *MissingRuntime) CheckConmonRunning(ctr *Container) (bool, error) {
+ return false, r.printError()
+}
+
// SupportsCheckpoint returns false as checkpointing requires a working runtime
func (r *MissingRuntime) SupportsCheckpoint() bool {
return false
diff --git a/libpod/oci_util.go b/libpod/oci_util.go
index 53567d2d0..8b40dad81 100644
--- a/libpod/oci_util.go
+++ b/libpod/oci_util.go
@@ -36,14 +36,30 @@ func bindPorts(ports []ocicni.PortMapping) ([]*os.File, error) {
var files []*os.File
notifySCTP := false
for _, i := range ports {
+ isV6 := net.ParseIP(i.HostIP).To4() == nil
+ if i.HostIP == "" {
+ isV6 = false
+ }
switch i.Protocol {
case "udp":
- addr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", i.HostIP, i.HostPort))
+ var (
+ addr *net.UDPAddr
+ err error
+ )
+ if isV6 {
+ addr, err = net.ResolveUDPAddr("udp6", fmt.Sprintf("[%s]:%d", i.HostIP, i.HostPort))
+ } else {
+ addr, err = net.ResolveUDPAddr("udp4", fmt.Sprintf("%s:%d", i.HostIP, i.HostPort))
+ }
if err != nil {
return nil, errors.Wrapf(err, "cannot resolve the UDP address")
}
- server, err := net.ListenUDP("udp", addr)
+ proto := "udp4"
+ if isV6 {
+ proto = "udp6"
+ }
+ server, err := net.ListenUDP(proto, addr)
if err != nil {
return nil, errors.Wrapf(err, "cannot listen on the UDP port")
}
@@ -54,12 +70,24 @@ func bindPorts(ports []ocicni.PortMapping) ([]*os.File, error) {
files = append(files, f)
case "tcp":
- addr, err := net.ResolveTCPAddr("tcp4", fmt.Sprintf("%s:%d", i.HostIP, i.HostPort))
+ var (
+ addr *net.TCPAddr
+ err error
+ )
+ if isV6 {
+ addr, err = net.ResolveTCPAddr("tcp6", fmt.Sprintf("[%s]:%d", i.HostIP, i.HostPort))
+ } else {
+ addr, err = net.ResolveTCPAddr("tcp4", fmt.Sprintf("%s:%d", i.HostIP, i.HostPort))
+ }
if err != nil {
return nil, errors.Wrapf(err, "cannot resolve the TCP address")
}
- server, err := net.ListenTCP("tcp4", addr)
+ proto := "tcp4"
+ if isV6 {
+ proto = "tcp6"
+ }
+ server, err := net.ListenTCP(proto, addr)
if err != nil {
return nil, errors.Wrapf(err, "cannot listen on the TCP port")
}
diff --git a/libpod/pod.go b/libpod/pod.go
index 34ceef5ef..8afaa6052 100644
--- a/libpod/pod.go
+++ b/libpod/pod.go
@@ -171,6 +171,11 @@ func (p *Pod) SharesCgroup() bool {
return p.config.UsePodCgroupNS
}
+// Hostname returns the hostname of the pod.
+func (p *Pod) Hostname() string {
+ return p.config.Hostname
+}
+
// CgroupPath returns the path to the pod's CGroup
func (p *Pod) CgroupPath() (string, error) {
p.lock.Lock()
diff --git a/libpod/pod_api.go b/libpod/pod_api.go
index 0be9f2573..e2c4b515d 100644
--- a/libpod/pod_api.go
+++ b/libpod/pod_api.go
@@ -490,7 +490,7 @@ func (p *Pod) Inspect() (*define.InspectPodData, error) {
Namespace: p.Namespace(),
Created: p.CreatedTime(),
State: podState,
- Hostname: "",
+ Hostname: p.config.Hostname,
Labels: p.Labels(),
CreateCgroup: false,
CgroupParent: p.CgroupParent(),
diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go
index 655b42e51..aa91dff03 100644
--- a/libpod/runtime_ctr.go
+++ b/libpod/runtime_ctr.go
@@ -464,9 +464,11 @@ func (r *Runtime) removeContainer(ctx context.Context, c *Container, force bool,
}
}
- // Check that the container's in a good state to be removed
+ // Check that the container's in a good state to be removed.
if c.state.State == define.ContainerStateRunning {
- if err := c.stop(c.StopTimeout()); err != nil {
+ // Ignore ErrConmonDead - we couldn't retrieve the container's
+ // exit code properly, but it's still stopped.
+ if err := c.stop(c.StopTimeout()); err != nil && errors.Cause(err) != define.ErrConmonDead {
return errors.Wrapf(err, "cannot remove container %s as it could not be stopped", c.ID())
}
}
diff --git a/pkg/api/handlers/compat/containers.go b/pkg/api/handlers/compat/containers.go
index cea4bd0f6..b90f3d625 100644
--- a/pkg/api/handlers/compat/containers.go
+++ b/pkg/api/handlers/compat/containers.go
@@ -348,7 +348,7 @@ func LogsFromContainer(w http.ResponseWriter, r *http.Request) {
}
func LibpodToContainer(l *libpod.Container, sz bool) (*handlers.Container, error) {
- imageId, imageName := l.Image()
+ imageID, imageName := l.Image()
var (
err error
@@ -378,7 +378,7 @@ func LibpodToContainer(l *libpod.Container, sz bool) (*handlers.Container, error
ID: l.ID(),
Names: []string{fmt.Sprintf("/%s", l.Name())},
Image: imageName,
- ImageID: imageId,
+ ImageID: imageID,
Command: strings.Join(l.Command(), " "),
Created: l.CreatedTime().Unix(),
Ports: nil,
diff --git a/pkg/api/handlers/compat/images.go b/pkg/api/handlers/compat/images.go
index b64ed0036..ce9ff1b19 100644
--- a/pkg/api/handlers/compat/images.go
+++ b/pkg/api/handlers/compat/images.go
@@ -224,7 +224,7 @@ func CreateImageFromSrc(w http.ResponseWriter, r *http.Request) {
Status string `json:"status"`
Progress string `json:"progress"`
ProgressDetail map[string]string `json:"progressDetail"`
- Id string `json:"id"`
+ Id string `json:"id"` //nolint
}{
Status: iid,
ProgressDetail: map[string]string{},
@@ -289,7 +289,7 @@ func CreateImageFromImage(w http.ResponseWriter, r *http.Request) {
Error string `json:"error"`
Progress string `json:"progress"`
ProgressDetail map[string]string `json:"progressDetail"`
- Id string `json:"id"`
+ Id string `json:"id"` //nolint
}{
Status: fmt.Sprintf("pulling image (%s) from %s", img.Tag, strings.Join(img.Names(), ", ")),
ProgressDetail: map[string]string{},
diff --git a/pkg/api/handlers/compat/images_build.go b/pkg/api/handlers/compat/images_build.go
index e9d8fd719..6cc766a38 100644
--- a/pkg/api/handlers/compat/images_build.go
+++ b/pkg/api/handlers/compat/images_build.go
@@ -59,10 +59,10 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
ForceRm bool `schema:"forcerm"`
Memory int64 `schema:"memory"`
MemSwap int64 `schema:"memswap"`
- CpuShares uint64 `schema:"cpushares"`
- CpuSetCpus string `schema:"cpusetcpus"`
- CpuPeriod uint64 `schema:"cpuperiod"`
- CpuQuota int64 `schema:"cpuquota"`
+ CpuShares uint64 `schema:"cpushares"` //nolint
+ CpuSetCpus string `schema:"cpusetcpus"` //nolint
+ CpuPeriod uint64 `schema:"cpuperiod"` //nolint
+ CpuQuota int64 `schema:"cpuquota"` //nolint
BuildArgs string `schema:"buildargs"`
ShmSize int `schema:"shmsize"`
Squash bool `schema:"squash"`
diff --git a/pkg/api/handlers/compat/info.go b/pkg/api/handlers/compat/info.go
index e9756a03f..d4a933c54 100644
--- a/pkg/api/handlers/compat/info.go
+++ b/pkg/api/handlers/compat/info.go
@@ -177,7 +177,7 @@ func getContainersState(r *libpod.Runtime) map[define.ContainerStatus]int {
if err != nil {
continue
}
- states[state] += 1
+ states[state]++
}
}
return states
diff --git a/pkg/api/handlers/compat/networks.go b/pkg/api/handlers/compat/networks.go
index c52ca093f..8734ba405 100644
--- a/pkg/api/handlers/compat/networks.go
+++ b/pkg/api/handlers/compat/networks.go
@@ -20,10 +20,6 @@ import (
"github.com/pkg/errors"
)
-type CompatInspectNetwork struct {
- types.NetworkResource
-}
-
func InspectNetwork(w http.ResponseWriter, r *http.Request) {
runtime := r.Context().Value("runtime").(*libpod.Runtime)
diff --git a/pkg/api/handlers/compat/ping.go b/pkg/api/handlers/compat/ping.go
index abee3d8e8..d275c4a02 100644
--- a/pkg/api/handlers/compat/ping.go
+++ b/pkg/api/handlers/compat/ping.go
@@ -14,13 +14,13 @@ import (
// Clients will use the Header availability to test which backend engine is in use.
// Note: Additionally handler supports GET and HEAD methods
func Ping(w http.ResponseWriter, r *http.Request) {
- w.Header().Set("API-Version", utils.ApiVersion[utils.CompatTree][utils.CurrentApiVersion].String())
+ w.Header().Set("API-Version", utils.APIVersion[utils.CompatTree][utils.CurrentAPIVersion].String())
w.Header().Set("BuildKit-Version", "")
w.Header().Set("Docker-Experimental", "true")
w.Header().Set("Cache-Control", "no-cache")
w.Header().Set("Pragma", "no-cache")
- w.Header().Set("Libpod-API-Version", utils.ApiVersion[utils.LibpodTree][utils.CurrentApiVersion].String())
+ w.Header().Set("Libpod-API-Version", utils.APIVersion[utils.LibpodTree][utils.CurrentAPIVersion].String())
w.Header().Set("Libpod-Buildha-Version", buildah.Version)
w.WriteHeader(http.StatusOK)
diff --git a/pkg/api/handlers/compat/version.go b/pkg/api/handlers/compat/version.go
index bfc226bb8..3164b16b9 100644
--- a/pkg/api/handlers/compat/version.go
+++ b/pkg/api/handlers/compat/version.go
@@ -34,14 +34,14 @@ func VersionHandler(w http.ResponseWriter, r *http.Request) {
Name: "Podman Engine",
Version: versionInfo.Version,
Details: map[string]string{
- "APIVersion": utils.ApiVersion[utils.LibpodTree][utils.CurrentApiVersion].String(),
+ "APIVersion": utils.APIVersion[utils.LibpodTree][utils.CurrentAPIVersion].String(),
"Arch": goRuntime.GOARCH,
"BuildTime": time.Unix(versionInfo.Built, 0).Format(time.RFC3339),
"Experimental": "true",
"GitCommit": versionInfo.GitCommit,
"GoVersion": versionInfo.GoVersion,
"KernelVersion": infoData.Host.Kernel,
- "MinAPIVersion": utils.ApiVersion[utils.LibpodTree][utils.MinimalApiVersion].String(),
+ "MinAPIVersion": utils.APIVersion[utils.LibpodTree][utils.MinimalAPIVersion].String(),
"Os": goRuntime.GOOS,
},
}}
diff --git a/pkg/api/handlers/decoder.go b/pkg/api/handlers/decoder.go
index 03b86275d..e46cd8837 100644
--- a/pkg/api/handlers/decoder.go
+++ b/pkg/api/handlers/decoder.go
@@ -17,7 +17,7 @@ func NewAPIDecoder() *schema.Decoder {
d := schema.NewDecoder()
d.IgnoreUnknownKeys(true)
- d.RegisterConverter(map[string][]string{}, convertUrlValuesString)
+ d.RegisterConverter(map[string][]string{}, convertURLValuesString)
d.RegisterConverter(time.Time{}, convertTimeString)
var Signal syscall.Signal
@@ -35,12 +35,12 @@ func NewAPIDecoder() *schema.Decoder {
// panic(err)
// }
// payload = url.QueryEscape(payload)
-func convertUrlValuesString(query string) reflect.Value {
+func convertURLValuesString(query string) reflect.Value {
f := map[string][]string{}
err := json.Unmarshal([]byte(query), &f)
if err != nil {
- logrus.Infof("convertUrlValuesString: Failed to Unmarshal %s: %s", query, err.Error())
+ logrus.Infof("convertURLValuesString: Failed to Unmarshal %s: %s", query, err.Error())
}
return reflect.ValueOf(f)
diff --git a/pkg/api/handlers/libpod/pods.go b/pkg/api/handlers/libpod/pods.go
index c3f8d5d66..7d4d03144 100644
--- a/pkg/api/handlers/libpod/pods.go
+++ b/pkg/api/handlers/libpod/pods.go
@@ -17,6 +17,7 @@ import (
"github.com/containers/libpod/pkg/util"
"github.com/gorilla/schema"
"github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
)
func PodCreate(w http.ResponseWriter, r *http.Request) {
@@ -31,11 +32,11 @@ func PodCreate(w http.ResponseWriter, r *http.Request) {
}
pod, err := generate.MakePod(&psg, runtime)
if err != nil {
- http_code := http.StatusInternalServerError
+ httpCode := http.StatusInternalServerError
if errors.Cause(err) == define.ErrPodExists {
- http_code = http.StatusConflict
+ httpCode = http.StatusConflict
}
- utils.Error(w, "Something went wrong.", http_code, err)
+ utils.Error(w, "Something went wrong.", httpCode, err)
return
}
utils.WriteResponse(w, http.StatusCreated, handlers.IDResponse{ID: pod.ID()})
@@ -375,6 +376,7 @@ func PodKill(w http.ResponseWriter, r *http.Request) {
sig, err := util.ParseSignal(signal)
if err != nil {
utils.InternalServerError(w, errors.Wrapf(err, "unable to parse signal value"))
+ return
}
name := utils.GetName(r)
pod, err := runtime.LookupPod(name)
@@ -382,6 +384,7 @@ func PodKill(w http.ResponseWriter, r *http.Request) {
utils.PodNotFound(w, name, err)
return
}
+ logrus.Debugf("Killing pod %s with signal %d", pod.ID(), sig)
podStates, err := pod.Status()
if err != nil {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, err)
diff --git a/pkg/api/handlers/libpod/volumes.go b/pkg/api/handlers/libpod/volumes.go
index c42ca407b..b5574b87b 100644
--- a/pkg/api/handlers/libpod/volumes.go
+++ b/pkg/api/handlers/libpod/volumes.go
@@ -46,7 +46,7 @@ func CreateVolume(w http.ResponseWriter, r *http.Request) {
volumeOptions = append(volumeOptions, libpod.WithVolumeLabels(input.Label))
}
if len(input.Options) > 0 {
- parsedOptions, err := parse.ParseVolumeOptions(input.Options)
+ parsedOptions, err := parse.VolumeOptions(input.Options)
if err != nil {
utils.InternalServerError(w, err)
return
diff --git a/pkg/api/handlers/types.go b/pkg/api/handlers/types.go
index aa3d0fe91..79aeff2f8 100644
--- a/pkg/api/handlers/types.go
+++ b/pkg/api/handlers/types.go
@@ -334,16 +334,25 @@ func ImageDataToImageInspect(ctx context.Context, l *libpodImage.Image) (*ImageI
func portsToPortSet(input map[string]struct{}) (nat.PortSet, error) {
ports := make(nat.PortSet)
for k := range input {
- npTCP, err := nat.NewPort("tcp", k)
- if err != nil {
- return nil, errors.Wrapf(err, "unable to create tcp port from %s", k)
- }
- npUDP, err := nat.NewPort("udp", k)
- if err != nil {
- return nil, errors.Wrapf(err, "unable to create udp port from %s", k)
+ proto, port := nat.SplitProtoPort(k)
+ switch proto {
+ // See the OCI image spec for details:
+ // https://github.com/opencontainers/image-spec/blob/e562b04403929d582d449ae5386ff79dd7961a11/config.md#properties
+ case "tcp", "":
+ p, err := nat.NewPort("tcp", port)
+ if err != nil {
+ return nil, errors.Wrapf(err, "unable to create tcp port from %s", k)
+ }
+ ports[p] = struct{}{}
+ case "udp":
+ p, err := nat.NewPort("udp", port)
+ if err != nil {
+ return nil, errors.Wrapf(err, "unable to create tcp port from %s", k)
+ }
+ ports[p] = struct{}{}
+ default:
+ return nil, errors.Errorf("invalid port proto %q in %q", proto, k)
}
- ports[npTCP] = struct{}{}
- ports[npUDP] = struct{}{}
}
return ports, nil
}
diff --git a/pkg/api/handlers/utils/containers.go b/pkg/api/handlers/utils/containers.go
index a46b308b5..4bcac6e72 100644
--- a/pkg/api/handlers/utils/containers.go
+++ b/pkg/api/handlers/utils/containers.go
@@ -62,7 +62,7 @@ func WaitContainer(w http.ResponseWriter, r *http.Request) (int32, error) {
func CreateContainer(ctx context.Context, w http.ResponseWriter, runtime *libpod.Runtime, cc *createconfig.CreateConfig) {
var pod *libpod.Pod
- ctr, err := createconfig.CreateContainerFromCreateConfig(runtime, cc, ctx, pod)
+ ctr, err := createconfig.CreateContainerFromCreateConfig(ctx, runtime, cc, pod)
if err != nil {
Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "CreateContainerFromCreateConfig()"))
return
diff --git a/pkg/api/handlers/utils/handler.go b/pkg/api/handlers/utils/handler.go
index 2f4a54b98..62fdc05dd 100644
--- a/pkg/api/handlers/utils/handler.go
+++ b/pkg/api/handlers/utils/handler.go
@@ -28,27 +28,27 @@ const (
// CompatTree supports Libpod endpoints
CompatTree
- // CurrentApiVersion announces what is the current API level
- CurrentApiVersion = VersionLevel(iota)
- // MinimalApiVersion announces what is the oldest API level supported
- MinimalApiVersion
+ // CurrentAPIVersion announces what is the current API level
+ CurrentAPIVersion = VersionLevel(iota)
+ // MinimalAPIVersion announces what is the oldest API level supported
+ MinimalAPIVersion
)
var (
// See https://docs.docker.com/engine/api/v1.40/
// libpod compat handlers are expected to honor docker API versions
- // ApiVersion provides the current and minimal API versions for compat and libpod endpoint trees
+ // APIVersion provides the current and minimal API versions for compat and libpod endpoint trees
// Note: GET|HEAD /_ping is never versioned and provides the API-Version and Libpod-API-Version headers to allow
// clients to shop for the Version they wish to support
- ApiVersion = map[VersionTree]map[VersionLevel]semver.Version{
+ APIVersion = map[VersionTree]map[VersionLevel]semver.Version{
LibpodTree: {
- CurrentApiVersion: semver.MustParse("1.0.0"),
- MinimalApiVersion: semver.MustParse("1.0.0"),
+ CurrentAPIVersion: semver.MustParse("1.0.0"),
+ MinimalAPIVersion: semver.MustParse("1.0.0"),
},
CompatTree: {
- CurrentApiVersion: semver.MustParse("1.40.0"),
- MinimalApiVersion: semver.MustParse("1.24.0"),
+ CurrentAPIVersion: semver.MustParse("1.40.0"),
+ MinimalAPIVersion: semver.MustParse("1.24.0"),
},
}
@@ -103,8 +103,8 @@ func SupportedVersionWithDefaults(r *http.Request) (semver.Version, error) {
}
return SupportedVersion(r,
- fmt.Sprintf(">=%s <=%s", ApiVersion[tree][MinimalApiVersion].String(),
- ApiVersion[tree][CurrentApiVersion].String()))
+ fmt.Sprintf(">=%s <=%s", APIVersion[tree][MinimalAPIVersion].String(),
+ APIVersion[tree][CurrentAPIVersion].String()))
}
// WriteResponse encodes the given value as JSON or string and renders it for http client
diff --git a/pkg/api/handlers/utils/handler_test.go b/pkg/api/handlers/utils/handler_test.go
index 6009432b5..d9fd22b80 100644
--- a/pkg/api/handlers/utils/handler_test.go
+++ b/pkg/api/handlers/utils/handler_test.go
@@ -12,12 +12,12 @@ import (
func TestSupportedVersion(t *testing.T) {
req, err := http.NewRequest("GET",
- fmt.Sprintf("/v%s/libpod/testing/versions", ApiVersion[LibpodTree][CurrentApiVersion]),
+ fmt.Sprintf("/v%s/libpod/testing/versions", APIVersion[LibpodTree][CurrentAPIVersion]),
nil)
if err != nil {
t.Fatal(err)
}
- req = mux.SetURLVars(req, map[string]string{"version": ApiVersion[LibpodTree][CurrentApiVersion].String()})
+ req = mux.SetURLVars(req, map[string]string{"version": APIVersion[LibpodTree][CurrentAPIVersion].String()})
rr := httptest.NewRecorder()
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
diff --git a/pkg/api/handlers/utils/pods.go b/pkg/api/handlers/utils/pods.go
index 5b6f6d34d..4a5cbd05c 100644
--- a/pkg/api/handlers/utils/pods.go
+++ b/pkg/api/handlers/utils/pods.go
@@ -54,7 +54,7 @@ func GetPods(w http.ResponseWriter, r *http.Request) ([]*entities.ListPodsReport
if err != nil {
return nil, err
}
- infraId, err := pod.InfraContainerID()
+ infraID, err := pod.InfraContainerID()
if err != nil {
return nil, err
}
@@ -65,7 +65,7 @@ func GetPods(w http.ResponseWriter, r *http.Request) ([]*entities.ListPodsReport
Name: pod.Name(),
Namespace: pod.Namespace(),
Status: status,
- InfraId: infraId,
+ InfraId: infraID,
Labels: pod.Labels(),
}
for _, ctr := range ctrs {
diff --git a/pkg/api/server/handler_api.go b/pkg/api/server/handler_api.go
index 7a7db12f3..dbdb7f17b 100644
--- a/pkg/api/server/handler_api.go
+++ b/pkg/api/server/handler_api.go
@@ -34,9 +34,9 @@ func (s *APIServer) APIHandler(h http.HandlerFunc) http.HandlerFunc {
}
// TODO: Use r.ConnContext when ported to go 1.13
- c := context.WithValue(r.Context(), "decoder", s.Decoder)
- c = context.WithValue(c, "runtime", s.Runtime)
- c = context.WithValue(c, "shutdownFunc", s.Shutdown)
+ c := context.WithValue(r.Context(), "decoder", s.Decoder) //nolint
+ c = context.WithValue(c, "runtime", s.Runtime) //nolint
+ c = context.WithValue(c, "shutdownFunc", s.Shutdown) //nolint
r = r.WithContext(c)
h(w, r)
diff --git a/pkg/api/server/server.go b/pkg/api/server/server.go
index 499a4c58a..bd6a99b96 100644
--- a/pkg/api/server/server.go
+++ b/pkg/api/server/server.go
@@ -257,7 +257,7 @@ func (t *IdleTracker) ConnState(conn net.Conn, state http.ConnState) {
if oldActive == 0 {
t.timer.Stop()
}
- t.total += 1
+ t.total++
case http.StateIdle, http.StateClosed:
delete(t.active, conn)
// Restart the timer if we've become idle
diff --git a/pkg/bindings/bindings.go b/pkg/bindings/bindings.go
index 7e2a444bd..94f7a45d0 100644
--- a/pkg/bindings/bindings.go
+++ b/pkg/bindings/bindings.go
@@ -5,11 +5,16 @@
// This package exposes a series of methods that allow users to firstly
// create their connection with the API endpoints. Once the connection
// is established, users can then manage the Podman container runtime.
-
package bindings
import (
+ "errors"
+ "fmt"
+ "io"
+ "os"
+
"github.com/blang/semver"
+ "golang.org/x/crypto/ssh/terminal"
)
var (
@@ -22,6 +27,43 @@ var (
pFalse = false
PFalse = &pFalse
- // _*YES*- podman will fail to run if this value is wrong
+ // APIVersion - podman will fail to run if this value is wrong
APIVersion = semver.MustParse("1.0.0")
)
+
+// readPassword prompts for a secret and returns value input by user from stdin
+// Unlike terminal.ReadPassword(), $(echo $SECRET | podman...) is supported.
+// Additionally, all input after `<secret>/n` is queued to podman command.
+func readPassword(prompt string) (pw []byte, err error) {
+ fd := int(os.Stdin.Fd())
+ if terminal.IsTerminal(fd) {
+ fmt.Fprint(os.Stderr, prompt)
+ pw, err = terminal.ReadPassword(fd)
+ fmt.Fprintln(os.Stderr)
+ return
+ }
+
+ var b [1]byte
+ for {
+ n, err := os.Stdin.Read(b[:])
+ // terminal.ReadPassword discards any '\r', so we do the same
+ if n > 0 && b[0] != '\r' {
+ if b[0] == '\n' {
+ return pw, nil
+ }
+ pw = append(pw, b[0])
+ // limit size, so that a wrong input won't fill up the memory
+ if len(pw) > 1024 {
+ err = errors.New("password too long, 1024 byte limit")
+ }
+ }
+ if err != nil {
+ // terminal.ReadPassword accepts EOF-terminated passwords
+ // if non-empty, so we do the same
+ if err == io.EOF && len(pw) > 0 {
+ err = nil
+ }
+ return pw, err
+ }
+ }
+}
diff --git a/pkg/bindings/connection.go b/pkg/bindings/connection.go
index c26093a7f..aa7f3707c 100644
--- a/pkg/bindings/connection.go
+++ b/pkg/bindings/connection.go
@@ -13,6 +13,7 @@ import (
"path/filepath"
"strconv"
"strings"
+ "sync"
"time"
"github.com/blang/semver"
@@ -20,6 +21,7 @@ import (
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"golang.org/x/crypto/ssh"
+ "golang.org/x/crypto/ssh/agent"
"k8s.io/client-go/util/homedir"
)
@@ -29,6 +31,8 @@ var (
Host: "d",
Path: "/v" + APIVersion.String() + "/libpod",
}
+ passPhrase []byte
+ phraseSync sync.Once
)
type APIResponse struct {
@@ -37,7 +41,7 @@ type APIResponse struct {
}
type Connection struct {
- Uri *url.URL
+ URI *url.URL
Client *http.Client
}
@@ -61,6 +65,10 @@ func JoinURL(elements ...string) string {
return "/" + strings.Join(elements, "/")
}
+func NewConnection(ctx context.Context, uri string) (context.Context, error) {
+ return NewConnectionWithIdentity(ctx, uri, "")
+}
+
// NewConnection takes a URI as a string and returns a context with the
// Connection embedded as a value. This context needs to be passed to each
// endpoint to work correctly.
@@ -69,23 +77,28 @@ func JoinURL(elements ...string) string {
// For example tcp://localhost:<port>
// or unix:///run/podman/podman.sock
// or ssh://<user>@<host>[:port]/run/podman/podman.sock?secure=True
-func NewConnection(ctx context.Context, uri string, identity ...string) (context.Context, error) {
+func NewConnectionWithIdentity(ctx context.Context, uri string, passPhrase string, identities ...string) (context.Context, error) {
var (
err error
secure bool
)
- if v, found := os.LookupEnv("PODMAN_HOST"); found {
+ if v, found := os.LookupEnv("CONTAINER_HOST"); found && uri == "" {
uri = v
}
- if v, found := os.LookupEnv("PODMAN_SSHKEY"); found {
- identity = []string{v}
+ if v, found := os.LookupEnv("CONTAINER_SSHKEY"); found && len(identities) == 0 {
+ identities = append(identities, v)
+ }
+
+ if v, found := os.LookupEnv("CONTAINER_PASSPHRASE"); found && passPhrase == "" {
+ passPhrase = v
}
_url, err := url.Parse(uri)
if err != nil {
- return nil, errors.Wrapf(err, "Value of PODMAN_HOST is not a valid url: %s", uri)
+ return nil, errors.Wrapf(err, "Value of CONTAINER_HOST is not a valid url: %s", uri)
}
+ // TODO Fill in missing defaults for _url...
// Now we setup the http Client to use the connection above
var connection Connection
@@ -95,7 +108,7 @@ func NewConnection(ctx context.Context, uri string, identity ...string) (context
if err != nil {
secure = false
}
- connection, err = sshClient(_url, identity[0], secure)
+ connection, err = sshClient(_url, secure, passPhrase, identities...)
case "unix":
if !strings.HasPrefix(uri, "unix:///") {
// autofix unix://path_element vs unix:///path_element
@@ -124,7 +137,7 @@ func NewConnection(ctx context.Context, uri string, identity ...string) (context
func tcpClient(_url *url.URL) (Connection, error) {
connection := Connection{
- Uri: _url,
+ URI: _url,
}
connection.Client = &http.Client{
Transport: &http.Transport{
@@ -172,10 +185,31 @@ func pingNewConnection(ctx context.Context) error {
return errors.Errorf("ping response was %q", response.StatusCode)
}
-func sshClient(_url *url.URL, identity string, secure bool) (Connection, error) {
- auth, err := publicKey(identity)
- if err != nil {
- return Connection{}, errors.Wrapf(err, "Failed to parse identity %s: %v\n", _url.String(), identity)
+func sshClient(_url *url.URL, secure bool, passPhrase string, identities ...string) (Connection, error) {
+ var authMethods []ssh.AuthMethod
+
+ for _, i := range identities {
+ auth, err := publicKey(i, []byte(passPhrase))
+ if err != nil {
+ fmt.Fprint(os.Stderr, errors.Wrapf(err, "failed to parse identity %q", i).Error()+"\n")
+ continue
+ }
+ authMethods = append(authMethods, auth)
+ }
+
+ if sock, found := os.LookupEnv("SSH_AUTH_SOCK"); found {
+ logrus.Debugf("Found SSH_AUTH_SOCK %q, ssh-agent signer enabled", sock)
+
+ c, err := net.Dial("unix", sock)
+ if err != nil {
+ return Connection{}, err
+ }
+ a := agent.NewClient(c)
+ authMethods = append(authMethods, ssh.PublicKeysCallback(a.Signers))
+ }
+
+ if pw, found := _url.User.Password(); found {
+ authMethods = append(authMethods, ssh.Password(pw))
}
callback := ssh.InsecureIgnoreHostKey()
@@ -195,7 +229,7 @@ func sshClient(_url *url.URL, identity string, secure bool) (Connection, error)
net.JoinHostPort(_url.Hostname(), port),
&ssh.ClientConfig{
User: _url.User.Username(),
- Auth: []ssh.AuthMethod{auth},
+ Auth: authMethods,
HostKeyCallback: callback,
HostKeyAlgorithms: []string{
ssh.KeyAlgoRSA,
@@ -212,7 +246,7 @@ func sshClient(_url *url.URL, identity string, secure bool) (Connection, error)
return Connection{}, errors.Wrapf(err, "Connection to bastion host (%s) failed.", _url.String())
}
- connection := Connection{Uri: _url}
+ connection := Connection{URI: _url}
connection.Client = &http.Client{
Transport: &http.Transport{
DialContext: func(ctx context.Context, _, _ string) (net.Conn, error) {
@@ -223,7 +257,7 @@ func sshClient(_url *url.URL, identity string, secure bool) (Connection, error)
}
func unixClient(_url *url.URL) (Connection, error) {
- connection := Connection{Uri: _url}
+ connection := Connection{URI: _url}
connection.Client = &http.Client{
Transport: &http.Transport{
DialContext: func(ctx context.Context, _, _ string) (net.Conn, error) {
@@ -307,7 +341,7 @@ func (h *APIResponse) IsServerError() bool {
return h.Response.StatusCode/100 == 5
}
-func publicKey(path string) (ssh.AuthMethod, error) {
+func publicKey(path string, passphrase []byte) (ssh.AuthMethod, error) {
key, err := ioutil.ReadFile(path)
if err != nil {
return nil, err
@@ -315,12 +349,30 @@ func publicKey(path string) (ssh.AuthMethod, error) {
signer, err := ssh.ParsePrivateKey(key)
if err != nil {
- return nil, err
+ if _, ok := err.(*ssh.PassphraseMissingError); !ok {
+ return nil, err
+ }
+ if len(passphrase) == 0 {
+ phraseSync.Do(promptPassphrase)
+ passphrase = passPhrase
+ }
+ signer, err = ssh.ParsePrivateKeyWithPassphrase(key, passphrase)
+ if err != nil {
+ return nil, err
+ }
}
-
return ssh.PublicKeys(signer), nil
}
+func promptPassphrase() {
+ phrase, err := readPassword("Key Passphrase: ")
+ if err != nil {
+ passPhrase = []byte{}
+ return
+ }
+ passPhrase = phrase
+}
+
func hostKey(host string) ssh.PublicKey {
// parse OpenSSH known_hosts file
// ssh or use ssh-keyscan to get initial key
diff --git a/pkg/bindings/containers/attach.go b/pkg/bindings/containers/attach.go
index b7f35c30d..44c7f4002 100644
--- a/pkg/bindings/containers/attach.go
+++ b/pkg/bindings/containers/attach.go
@@ -25,7 +25,7 @@ import (
)
// Attach attaches to a running container
-func Attach(ctx context.Context, nameOrId string, detachKeys *string, logs, stream *bool, stdin io.Reader, stdout io.Writer, stderr io.Writer, attachReady chan bool) error {
+func Attach(ctx context.Context, nameOrID string, detachKeys *string, logs, stream *bool, stdin io.Reader, stdout io.Writer, stderr io.Writer, attachReady chan bool) error {
isSet := struct {
stdin bool
stdout bool
@@ -52,7 +52,7 @@ func Attach(ctx context.Context, nameOrId string, detachKeys *string, logs, stre
}
// Do we need to wire in stdin?
- ctnr, err := Inspect(ctx, nameOrId, bindings.PFalse)
+ ctnr, err := Inspect(ctx, nameOrID, bindings.PFalse)
if err != nil {
return err
}
@@ -115,7 +115,7 @@ func Attach(ctx context.Context, nameOrId string, detachKeys *string, logs, stre
IdleConnTimeout: time.Duration(0),
}
conn.Client.Transport = t
- response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/attach", params, headers, nameOrId)
+ response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/attach", params, headers, nameOrID)
if err != nil {
return err
}
@@ -129,7 +129,7 @@ func Attach(ctx context.Context, nameOrId string, detachKeys *string, logs, stre
winCtx, winCancel := context.WithCancel(ctx)
defer winCancel()
- go attachHandleResize(ctx, winCtx, winChange, false, nameOrId, file)
+ go attachHandleResize(ctx, winCtx, winChange, false, nameOrID, file)
}
// If we are attaching around a start, we need to "signal"
@@ -243,13 +243,13 @@ func DemuxFrame(r io.Reader, buffer []byte, length int) (frame []byte, err error
}
// ResizeContainerTTY sets container's TTY height and width in characters
-func ResizeContainerTTY(ctx context.Context, nameOrId string, height *int, width *int) error {
- return resizeTTY(ctx, bindings.JoinURL("containers", nameOrId, "resize"), height, width)
+func ResizeContainerTTY(ctx context.Context, nameOrID string, height *int, width *int) error {
+ return resizeTTY(ctx, bindings.JoinURL("containers", nameOrID, "resize"), height, width)
}
// ResizeExecTTY sets session's TTY height and width in characters
-func ResizeExecTTY(ctx context.Context, nameOrId string, height *int, width *int) error {
- return resizeTTY(ctx, bindings.JoinURL("exec", nameOrId, "resize"), height, width)
+func ResizeExecTTY(ctx context.Context, nameOrID string, height *int, width *int) error {
+ return resizeTTY(ctx, bindings.JoinURL("exec", nameOrID, "resize"), height, width)
}
// resizeTTY set size of TTY of container
diff --git a/pkg/bindings/containers/checkpoint.go b/pkg/bindings/containers/checkpoint.go
index f483a9297..916ec8071 100644
--- a/pkg/bindings/containers/checkpoint.go
+++ b/pkg/bindings/containers/checkpoint.go
@@ -10,9 +10,9 @@ import (
"github.com/containers/libpod/pkg/domain/entities"
)
-// Checkpoint checkpoints the given container (identified by nameOrId). All additional
+// Checkpoint checkpoints the given container (identified by nameOrID). All additional
// options are options and allow for more fine grained control of the checkpoint process.
-func Checkpoint(ctx context.Context, nameOrId string, keep, leaveRunning, tcpEstablished, ignoreRootFS *bool, export *string) (*entities.CheckpointReport, error) {
+func Checkpoint(ctx context.Context, nameOrID string, keep, leaveRunning, tcpEstablished, ignoreRootFS *bool, export *string) (*entities.CheckpointReport, error) {
var report entities.CheckpointReport
conn, err := bindings.GetClient(ctx)
if err != nil {
@@ -34,16 +34,16 @@ func Checkpoint(ctx context.Context, nameOrId string, keep, leaveRunning, tcpEst
if export != nil {
params.Set("export", *export)
}
- response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/checkpoint", params, nil, nameOrId)
+ response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/checkpoint", params, nil, nameOrID)
if err != nil {
return nil, err
}
return &report, response.Process(&report)
}
-// Restore restores a checkpointed container to running. The container is identified by the nameOrId option. All
+// Restore restores a checkpointed container to running. The container is identified by the nameOrID option. All
// additional options are optional and allow finer control of the restore processs.
-func Restore(ctx context.Context, nameOrId string, keep, tcpEstablished, ignoreRootFS, ignoreStaticIP, ignoreStaticMAC *bool, name, importArchive *string) (*entities.RestoreReport, error) {
+func Restore(ctx context.Context, nameOrID string, keep, tcpEstablished, ignoreRootFS, ignoreStaticIP, ignoreStaticMAC *bool, name, importArchive *string) (*entities.RestoreReport, error) {
var report entities.RestoreReport
conn, err := bindings.GetClient(ctx)
if err != nil {
@@ -71,7 +71,7 @@ func Restore(ctx context.Context, nameOrId string, keep, tcpEstablished, ignoreR
if importArchive != nil {
params.Set("import", *importArchive)
}
- response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/restore", params, nil, nameOrId)
+ response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/restore", params, nil, nameOrID)
if err != nil {
return nil, err
}
diff --git a/pkg/bindings/containers/commit.go b/pkg/bindings/containers/commit.go
index 780d42272..1a9ddc970 100644
--- a/pkg/bindings/containers/commit.go
+++ b/pkg/bindings/containers/commit.go
@@ -10,16 +10,16 @@ import (
"github.com/containers/libpod/pkg/bindings"
)
-// Commit creates a container image from a container. The container is defined by nameOrId. Use
+// Commit creates a container image from a container. The container is defined by nameOrID. Use
// the CommitOptions for finer grain control on characteristics of the resulting image.
-func Commit(ctx context.Context, nameOrId string, options CommitOptions) (handlers.IDResponse, error) {
+func Commit(ctx context.Context, nameOrID string, options CommitOptions) (handlers.IDResponse, error) {
id := handlers.IDResponse{}
conn, err := bindings.GetClient(ctx)
if err != nil {
return id, err
}
params := url.Values{}
- params.Set("container", nameOrId)
+ params.Set("container", nameOrID)
if options.Author != nil {
params.Set("author", *options.Author)
}
diff --git a/pkg/bindings/containers/diff.go b/pkg/bindings/containers/diff.go
index 06a828c30..e7a50248a 100644
--- a/pkg/bindings/containers/diff.go
+++ b/pkg/bindings/containers/diff.go
@@ -9,13 +9,13 @@ import (
)
// Diff provides the changes between two container layers
-func Diff(ctx context.Context, nameOrId string) ([]archive.Change, error) {
+func Diff(ctx context.Context, nameOrID string) ([]archive.Change, error) {
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
- response, err := conn.DoRequest(nil, http.MethodGet, "/containers/%s/changes", nil, nil, nameOrId)
+ response, err := conn.DoRequest(nil, http.MethodGet, "/containers/%s/changes", nil, nil, nameOrID)
if err != nil {
return nil, err
}
diff --git a/pkg/bindings/generate/generate.go b/pkg/bindings/generate/generate.go
index 161b722f3..5e4be4896 100644
--- a/pkg/bindings/generate/generate.go
+++ b/pkg/bindings/generate/generate.go
@@ -10,7 +10,7 @@ import (
"github.com/containers/libpod/pkg/domain/entities"
)
-func GenerateKube(ctx context.Context, nameOrID string, options entities.GenerateKubeOptions) (*entities.GenerateKubeReport, error) {
+func Kube(ctx context.Context, nameOrID string, options entities.GenerateKubeOptions) (*entities.GenerateKubeReport, error) {
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
diff --git a/pkg/bindings/images/diff.go b/pkg/bindings/images/diff.go
index e2d344ea0..25cbde188 100644
--- a/pkg/bindings/images/diff.go
+++ b/pkg/bindings/images/diff.go
@@ -9,13 +9,13 @@ import (
)
// Diff provides the changes between two container layers
-func Diff(ctx context.Context, nameOrId string) ([]archive.Change, error) {
+func Diff(ctx context.Context, nameOrID string) ([]archive.Change, error) {
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
- response, err := conn.DoRequest(nil, http.MethodGet, "/images/%s/changes", nil, nil, nameOrId)
+ response, err := conn.DoRequest(nil, http.MethodGet, "/images/%s/changes", nil, nil, nameOrID)
if err != nil {
return nil, err
}
diff --git a/pkg/bindings/images/images.go b/pkg/bindings/images/images.go
index e0802a6e1..a82a9080b 100644
--- a/pkg/bindings/images/images.go
+++ b/pkg/bindings/images/images.go
@@ -80,7 +80,7 @@ func GetImage(ctx context.Context, nameOrID string, size *bool) (*entities.Image
}
// Tree retrieves a "tree" based representation of the given image
-func Tree(ctx context.Context, nameOrId string, whatRequires *bool) (*entities.ImageTreeReport, error) {
+func Tree(ctx context.Context, nameOrID string, whatRequires *bool) (*entities.ImageTreeReport, error) {
var report entities.ImageTreeReport
conn, err := bindings.GetClient(ctx)
if err != nil {
@@ -90,7 +90,7 @@ func Tree(ctx context.Context, nameOrId string, whatRequires *bool) (*entities.I
if whatRequires != nil {
params.Set("size", strconv.FormatBool(*whatRequires))
}
- response, err := conn.DoRequest(nil, http.MethodGet, "/images/%s/tree", params, nil, nameOrId)
+ response, err := conn.DoRequest(nil, http.MethodGet, "/images/%s/tree", params, nil, nameOrID)
if err != nil {
return nil, err
}
diff --git a/pkg/bindings/play/play.go b/pkg/bindings/play/play.go
index 288cca454..9a4f56b6d 100644
--- a/pkg/bindings/play/play.go
+++ b/pkg/bindings/play/play.go
@@ -13,7 +13,7 @@ import (
"github.com/containers/libpod/pkg/domain/entities"
)
-func PlayKube(ctx context.Context, path string, options entities.PlayKubeOptions) (*entities.PlayKubeReport, error) {
+func Kube(ctx context.Context, path string, options entities.PlayKubeOptions) (*entities.PlayKubeReport, error) {
var report entities.PlayKubeReport
conn, err := bindings.GetClient(ctx)
if err != nil {
diff --git a/pkg/domain/entities/container_ps.go b/pkg/domain/entities/container_ps.go
index fd94d93be..c5e11f188 100644
--- a/pkg/domain/entities/container_ps.go
+++ b/pkg/domain/entities/container_ps.go
@@ -85,9 +85,9 @@ func (a psSortedCommand) Less(i, j int) bool {
return strings.Join(a.SortListContainers[i].Command, " ") < strings.Join(a.SortListContainers[j].Command, " ")
}
-type psSortedId struct{ SortListContainers }
+type psSortedID struct{ SortListContainers }
-func (a psSortedId) Less(i, j int) bool {
+func (a psSortedID) Less(i, j int) bool {
return a.SortListContainers[i].ID < a.SortListContainers[j].ID
}
@@ -139,7 +139,7 @@ func (a PsSortedCreateTime) Less(i, j int) bool {
func SortPsOutput(sortBy string, psOutput SortListContainers) (SortListContainers, error) {
switch sortBy {
case "id":
- sort.Sort(psSortedId{psOutput})
+ sort.Sort(psSortedID{psOutput})
case "image":
sort.Sort(psSortedImage{psOutput})
case "command":
diff --git a/pkg/domain/entities/containers.go b/pkg/domain/entities/containers.go
index 8d85a9b23..b4d8e6c29 100644
--- a/pkg/domain/entities/containers.go
+++ b/pkg/domain/entities/containers.go
@@ -56,7 +56,7 @@ type WaitOptions struct {
}
type WaitReport struct {
- Id string
+ Id string //nolint
Error error
ExitCode int32
}
@@ -76,7 +76,7 @@ type PauseUnPauseOptions struct {
type PauseUnpauseReport struct {
Err error
- Id string
+ Id string //nolint
}
type StopOptions struct {
@@ -84,12 +84,12 @@ type StopOptions struct {
CIDFiles []string
Ignore bool
Latest bool
- Timeout uint
+ Timeout *uint
}
type StopReport struct {
Err error
- Id string
+ Id string //nolint
}
type TopOptions struct {
@@ -110,7 +110,7 @@ type KillOptions struct {
type KillReport struct {
Err error
- Id string
+ Id string //nolint
}
type RestartOptions struct {
@@ -122,7 +122,7 @@ type RestartOptions struct {
type RestartReport struct {
Err error
- Id string
+ Id string //nolint
}
type RmOptions struct {
@@ -137,7 +137,7 @@ type RmOptions struct {
type RmReport struct {
Err error
- Id string
+ Id string //nolint
}
type ContainerInspectReport struct {
@@ -157,7 +157,7 @@ type CommitOptions struct {
}
type CommitReport struct {
- Id string
+ Id string //nolint
}
type ContainerExportOptions struct {
@@ -176,7 +176,7 @@ type CheckpointOptions struct {
type CheckpointReport struct {
Err error
- Id string
+ Id string //nolint
}
type RestoreOptions struct {
@@ -193,11 +193,11 @@ type RestoreOptions struct {
type RestoreReport struct {
Err error
- Id string
+ Id string //nolint
}
type ContainerCreateReport struct {
- Id string
+ Id string //nolint
}
// AttachOptions describes the cli and other values
@@ -263,7 +263,7 @@ type ContainerStartOptions struct {
// ContainerStartReport describes the response from starting
// containers from the cli
type ContainerStartReport struct {
- Id string
+ Id string //nolint
RawInput string
Err error
ExitCode int
@@ -303,7 +303,7 @@ type ContainerRunOptions struct {
// a container
type ContainerRunReport struct {
ExitCode int
- Id string
+ Id string //nolint
}
// ContainerCleanupOptions are the CLI values for the
@@ -320,7 +320,7 @@ type ContainerCleanupOptions struct {
// container cleanup
type ContainerCleanupReport struct {
CleanErr error
- Id string
+ Id string //nolint
RmErr error
RmiErr error
}
@@ -336,7 +336,7 @@ type ContainerInitOptions struct {
// container init
type ContainerInitReport struct {
Err error
- Id string
+ Id string //nolint
}
//ContainerMountOptions describes the input values for mounting containers
@@ -358,7 +358,7 @@ type ContainerUnmountOptions struct {
// ContainerMountReport describes the response from container mount
type ContainerMountReport struct {
Err error
- Id string
+ Id string //nolint
Name string
Path string
}
@@ -366,7 +366,7 @@ type ContainerMountReport struct {
// ContainerUnmountReport describes the response from umounting a container
type ContainerUnmountReport struct {
Err error
- Id string
+ Id string //nolint
}
// ContainerPruneOptions describes the options needed
@@ -392,7 +392,7 @@ type ContainerPortOptions struct {
// ContainerPortReport describes the output needed for
// the CLI to output ports
type ContainerPortReport struct {
- Id string
+ Id string //nolint
Ports []ocicni.PortMapping
}
diff --git a/pkg/domain/entities/engine.go b/pkg/domain/entities/engine.go
index db58befa5..1f056bad7 100644
--- a/pkg/domain/entities/engine.go
+++ b/pkg/domain/entities/engine.go
@@ -39,18 +39,20 @@ type PodmanConfig struct {
CGroupUsage string // rootless code determines Usage message
ConmonPath string // --conmon flag will set Engine.ConmonPath
- CpuProfile string // Hidden: Should CPU profile be taken
+ CPUProfile string // Hidden: Should CPU profile be taken
EngineMode EngineMode // ABI or Tunneling mode
Identities []string // ssh identities for connecting to server
MaxWorks int // maximum number of parallel threads
+ PassPhrase string // ssh passphrase for identity for connecting to server
RegistriesConf string // allows for specifying a custom registries.conf
+ Remote bool // Connection to Podman API Service will use RESTful API
RuntimePath string // --runtime flag will set Engine.RuntimePath
+ Span opentracing.Span // tracing object
SpanCloser io.Closer // Close() for tracing object
SpanCtx context.Context // context to use when tracing
- Span opentracing.Span // tracing object
Syslog bool // write to StdOut and Syslog, not supported when tunneling
Trace bool // Hidden: Trace execution
- Uri string // URI to API Service
+ URI string // URI to RESTful API Service
Runroot string
StorageDriver string
diff --git a/pkg/domain/entities/engine_container.go b/pkg/domain/entities/engine_container.go
index 3d5161745..979df7581 100644
--- a/pkg/domain/entities/engine_container.go
+++ b/pkg/domain/entities/engine_container.go
@@ -12,25 +12,25 @@ import (
type ContainerEngine interface {
AutoUpdate(ctx context.Context, options AutoUpdateOptions) (*AutoUpdateReport, []error)
Config(ctx context.Context) (*config.Config, error)
- ContainerAttach(ctx context.Context, nameOrId string, options AttachOptions) error
+ ContainerAttach(ctx context.Context, nameOrID string, options AttachOptions) error
ContainerCheckpoint(ctx context.Context, namesOrIds []string, options CheckpointOptions) ([]*CheckpointReport, error)
ContainerCleanup(ctx context.Context, namesOrIds []string, options ContainerCleanupOptions) ([]*ContainerCleanupReport, error)
- ContainerCommit(ctx context.Context, nameOrId string, options CommitOptions) (*CommitReport, error)
+ ContainerCommit(ctx context.Context, nameOrID string, options CommitOptions) (*CommitReport, error)
ContainerCp(ctx context.Context, source, dest string, options ContainerCpOptions) (*ContainerCpReport, error)
ContainerCreate(ctx context.Context, s *specgen.SpecGenerator) (*ContainerCreateReport, error)
- ContainerDiff(ctx context.Context, nameOrId string, options DiffOptions) (*DiffReport, error)
- ContainerExec(ctx context.Context, nameOrId string, options ExecOptions, streams define.AttachStreams) (int, error)
+ ContainerDiff(ctx context.Context, nameOrID string, options DiffOptions) (*DiffReport, error)
+ ContainerExec(ctx context.Context, nameOrID string, options ExecOptions, streams define.AttachStreams) (int, error)
ContainerExecDetached(ctx context.Context, nameOrID string, options ExecOptions) (string, error)
- ContainerExists(ctx context.Context, nameOrId string) (*BoolReport, error)
- ContainerExport(ctx context.Context, nameOrId string, options ContainerExportOptions) error
+ ContainerExists(ctx context.Context, nameOrID string) (*BoolReport, error)
+ ContainerExport(ctx context.Context, nameOrID string, options ContainerExportOptions) error
ContainerInit(ctx context.Context, namesOrIds []string, options ContainerInitOptions) ([]*ContainerInitReport, error)
ContainerInspect(ctx context.Context, namesOrIds []string, options InspectOptions) ([]*ContainerInspectReport, error)
ContainerKill(ctx context.Context, namesOrIds []string, options KillOptions) ([]*KillReport, error)
ContainerList(ctx context.Context, options ContainerListOptions) ([]ListContainer, error)
ContainerLogs(ctx context.Context, containers []string, options ContainerLogsOptions) error
- ContainerMount(ctx context.Context, nameOrIds []string, options ContainerMountOptions) ([]*ContainerMountReport, error)
+ ContainerMount(ctx context.Context, nameOrIDs []string, options ContainerMountOptions) ([]*ContainerMountReport, error)
ContainerPause(ctx context.Context, namesOrIds []string, options PauseUnPauseOptions) ([]*PauseUnpauseReport, error)
- ContainerPort(ctx context.Context, nameOrId string, options ContainerPortOptions) ([]*ContainerPortReport, error)
+ ContainerPort(ctx context.Context, nameOrID string, options ContainerPortOptions) ([]*ContainerPortReport, error)
ContainerPrune(ctx context.Context, options ContainerPruneOptions) (*ContainerPruneReport, error)
ContainerRestart(ctx context.Context, namesOrIds []string, options RestartOptions) ([]*RestartReport, error)
ContainerRestore(ctx context.Context, namesOrIds []string, options RestoreOptions) ([]*RestoreReport, error)
@@ -41,14 +41,14 @@ type ContainerEngine interface {
ContainerStats(ctx context.Context, namesOrIds []string, options ContainerStatsOptions) error
ContainerStop(ctx context.Context, namesOrIds []string, options StopOptions) ([]*StopReport, error)
ContainerTop(ctx context.Context, options TopOptions) (*StringSliceReport, error)
- ContainerUnmount(ctx context.Context, nameOrIds []string, options ContainerUnmountOptions) ([]*ContainerUnmountReport, error)
+ ContainerUnmount(ctx context.Context, nameOrIDs []string, options ContainerUnmountOptions) ([]*ContainerUnmountReport, error)
ContainerUnpause(ctx context.Context, namesOrIds []string, options PauseUnPauseOptions) ([]*PauseUnpauseReport, error)
ContainerWait(ctx context.Context, namesOrIds []string, options WaitOptions) ([]WaitReport, error)
Events(ctx context.Context, opts EventsOptions) error
GenerateSystemd(ctx context.Context, nameOrID string, opts GenerateSystemdOptions) (*GenerateSystemdReport, error)
GenerateKube(ctx context.Context, nameOrID string, opts GenerateKubeOptions) (*GenerateKubeReport, error)
SystemPrune(ctx context.Context, options SystemPruneOptions) (*SystemPruneReport, error)
- HealthCheckRun(ctx context.Context, nameOrId string, options HealthCheckOptions) (*define.HealthCheckResults, error)
+ HealthCheckRun(ctx context.Context, nameOrID string, options HealthCheckOptions) (*define.HealthCheckResults, error)
Info(ctx context.Context) (*define.Info, error)
NetworkCreate(ctx context.Context, name string, options NetworkCreateOptions) (*NetworkCreateReport, error)
NetworkInspect(ctx context.Context, namesOrIds []string, options NetworkInspectOptions) ([]NetworkInspectReport, error)
@@ -56,7 +56,7 @@ type ContainerEngine interface {
NetworkRm(ctx context.Context, namesOrIds []string, options NetworkRmOptions) ([]*NetworkRmReport, error)
PlayKube(ctx context.Context, path string, opts PlayKubeOptions) (*PlayKubeReport, error)
PodCreate(ctx context.Context, opts PodCreateOptions) (*PodCreateReport, error)
- PodExists(ctx context.Context, nameOrId string) (*BoolReport, error)
+ PodExists(ctx context.Context, nameOrID string) (*BoolReport, error)
PodInspect(ctx context.Context, options PodInspectOptions) (*PodInspectReport, error)
PodKill(ctx context.Context, namesOrIds []string, options PodKillOptions) ([]*PodKillReport, error)
PodPause(ctx context.Context, namesOrIds []string, options PodPauseOptions) ([]*PodPauseReport, error)
@@ -75,7 +75,7 @@ type ContainerEngine interface {
Unshare(ctx context.Context, args []string) error
VarlinkService(ctx context.Context, opts ServiceOptions) error
Version(ctx context.Context) (*SystemVersionReport, error)
- VolumeCreate(ctx context.Context, opts VolumeCreateOptions) (*IdOrNameResponse, error)
+ VolumeCreate(ctx context.Context, opts VolumeCreateOptions) (*IDOrNameResponse, error)
VolumeInspect(ctx context.Context, namesOrIds []string, opts VolumeInspectOptions) ([]*VolumeInspectReport, error)
VolumeList(ctx context.Context, opts VolumeListOptions) ([]*VolumeListReport, error)
VolumePrune(ctx context.Context, opts VolumePruneOptions) ([]*VolumePruneReport, error)
diff --git a/pkg/domain/entities/engine_image.go b/pkg/domain/entities/engine_image.go
index 7d7099838..60fb20b6e 100644
--- a/pkg/domain/entities/engine_image.go
+++ b/pkg/domain/entities/engine_image.go
@@ -9,9 +9,9 @@ import (
type ImageEngine interface {
Build(ctx context.Context, containerFiles []string, opts BuildOptions) (*BuildReport, error)
Config(ctx context.Context) (*config.Config, error)
- Diff(ctx context.Context, nameOrId string, options DiffOptions) (*DiffReport, error)
- Exists(ctx context.Context, nameOrId string) (*BoolReport, error)
- History(ctx context.Context, nameOrId string, opts ImageHistoryOptions) (*ImageHistoryReport, error)
+ Diff(ctx context.Context, nameOrID string, options DiffOptions) (*DiffReport, error)
+ Exists(ctx context.Context, nameOrID string) (*BoolReport, error)
+ History(ctx context.Context, nameOrID string, opts ImageHistoryOptions) (*ImageHistoryReport, error)
Import(ctx context.Context, opts ImageImportOptions) (*ImageImportReport, error)
Inspect(ctx context.Context, namesOrIDs []string, opts InspectOptions) ([]*ImageInspectReport, error)
List(ctx context.Context, opts ImageListOptions) ([]*ImageSummary, error)
@@ -20,14 +20,14 @@ type ImageEngine interface {
Pull(ctx context.Context, rawImage string, opts ImagePullOptions) (*ImagePullReport, error)
Push(ctx context.Context, source string, destination string, opts ImagePushOptions) error
Remove(ctx context.Context, images []string, opts ImageRemoveOptions) (*ImageRemoveReport, []error)
- Save(ctx context.Context, nameOrId string, tags []string, options ImageSaveOptions) error
+ Save(ctx context.Context, nameOrID string, tags []string, options ImageSaveOptions) error
Search(ctx context.Context, term string, opts ImageSearchOptions) ([]ImageSearchReport, error)
SetTrust(ctx context.Context, args []string, options SetTrustOptions) error
ShowTrust(ctx context.Context, args []string, options ShowTrustOptions) (*ShowTrustReport, error)
Shutdown(ctx context.Context)
- Tag(ctx context.Context, nameOrId string, tags []string, options ImageTagOptions) error
- Tree(ctx context.Context, nameOrId string, options ImageTreeOptions) (*ImageTreeReport, error)
- Untag(ctx context.Context, nameOrId string, tags []string, options ImageUntagOptions) error
+ Tag(ctx context.Context, nameOrID string, tags []string, options ImageTagOptions) error
+ Tree(ctx context.Context, nameOrID string, options ImageTreeOptions) (*ImageTreeReport, error)
+ Untag(ctx context.Context, nameOrID string, tags []string, options ImageUntagOptions) error
ManifestCreate(ctx context.Context, names, images []string, opts ManifestCreateOptions) (string, error)
ManifestInspect(ctx context.Context, name string) ([]byte, error)
ManifestAdd(ctx context.Context, opts ManifestAddOptions) (string, error)
diff --git a/pkg/domain/entities/filters.go b/pkg/domain/entities/filters.go
index c7e227244..2ddbffbcd 100644
--- a/pkg/domain/entities/filters.go
+++ b/pkg/domain/entities/filters.go
@@ -20,14 +20,14 @@ type Names interface {
Names() []string
}
-// IdOrName interface allows filters to access ID() or Name() of object
-type IdOrNamed interface {
+// IDOrName interface allows filters to access ID() or Name() of object
+type IDOrNamed interface {
Identifier
Named
}
-// IdOrName interface allows filters to access ID() or Names() of object
-type IdOrNames interface {
+// IDOrName interface allows filters to access ID() or Names() of object
+type IDOrNames interface {
Identifier
Names
}
@@ -42,11 +42,11 @@ func CompileImageFilters(filters url.Values) ImageFilter {
for name, targets := range filters {
switch name {
case "id":
- fns = append(fns, FilterIdFn(targets))
+ fns = append(fns, FilterIDFn(targets))
case "name":
fns = append(fns, FilterNamesFn(targets))
case "idOrName":
- fns = append(fns, FilterIdOrNameFn(targets))
+ fns = append(fns, FilterIDOrNameFn(targets))
}
}
@@ -66,11 +66,11 @@ func CompileContainerFilters(filters url.Values) ContainerFilter {
for name, targets := range filters {
switch name {
case "id":
- fns = append(fns, FilterIdFn(targets))
+ fns = append(fns, FilterIDFn(targets))
case "name":
fns = append(fns, FilterNameFn(targets))
case "idOrName":
- fns = append(fns, FilterIdOrNameFn(targets))
+ fns = append(fns, FilterIDOrNameFn(targets))
}
}
@@ -89,7 +89,7 @@ func CompileVolumeFilters(filters url.Values) VolumeFilter {
for name, targets := range filters {
if name == "id" {
- fns = append(fns, FilterIdFn(targets))
+ fns = append(fns, FilterIDFn(targets))
}
}
@@ -103,7 +103,7 @@ func CompileVolumeFilters(filters url.Values) VolumeFilter {
}
}
-func FilterIdFn(id []string) func(Identifier) bool {
+func FilterIDFn(id []string) func(Identifier) bool {
return func(obj Identifier) bool {
for _, v := range id {
if strings.Contains(obj.Id(), v) {
@@ -138,8 +138,8 @@ func FilterNamesFn(name []string) func(Names) bool {
}
}
-func FilterIdOrNameFn(id []string) func(IdOrNamed) bool {
- return func(obj IdOrNamed) bool {
+func FilterIDOrNameFn(id []string) func(IDOrNamed) bool {
+ return func(obj IDOrNamed) bool {
for _, v := range id {
if strings.Contains(obj.Id(), v) || strings.Contains(obj.Name(), v) {
return true
diff --git a/pkg/domain/entities/images.go b/pkg/domain/entities/images.go
index 19a2c87f5..81f52fef5 100644
--- a/pkg/domain/entities/images.go
+++ b/pkg/domain/entities/images.go
@@ -45,13 +45,13 @@ type Image struct {
HealthCheck *manifest.Schema2HealthConfig `json:",omitempty"`
}
-func (i *Image) Id() string {
+func (i *Image) Id() string { //nolint
return i.ID
}
type ImageSummary struct {
ID string `json:"Id"`
- ParentId string `json:",omitempty"`
+ ParentId string `json:",omitempty"` // nolint
RepoTags []string `json:",omitempty"`
Created time.Time `json:",omitempty"`
Size int64 `json:",omitempty"`
@@ -70,7 +70,7 @@ type ImageSummary struct {
History []string `json:",omitempty"`
}
-func (i *ImageSummary) Id() string {
+func (i *ImageSummary) Id() string { //nolint
return i.ID
}
@@ -266,7 +266,7 @@ type ImageImportOptions struct {
}
type ImageImportReport struct {
- Id string
+ Id string //nolint
}
type ImageSaveOptions struct {
@@ -299,7 +299,7 @@ type ShowTrustReport struct {
Raw []byte
SystemRegistriesDirPath string
JSONOutput []byte
- Policies []*trust.TrustPolicy
+ Policies []*trust.Policy
}
// SetTrustOptions describes the CLI options for setting trust
diff --git a/pkg/domain/entities/pods.go b/pkg/domain/entities/pods.go
index 37acba6e6..a85333c75 100644
--- a/pkg/domain/entities/pods.go
+++ b/pkg/domain/entities/pods.go
@@ -17,15 +17,15 @@ type PodKillOptions struct {
type PodKillReport struct {
Errs []error
- Id string
+ Id string //nolint
}
type ListPodsReport struct {
Cgroup string
Containers []*ListPodContainer
Created time.Time
- Id string
- InfraId string
+ Id string //nolint
+ InfraId string //nolint
Name string
Namespace string
Status string
@@ -33,7 +33,7 @@ type ListPodsReport struct {
}
type ListPodContainer struct {
- Id string
+ Id string //nolint
Names string
Status string
}
@@ -45,7 +45,7 @@ type PodPauseOptions struct {
type PodPauseReport struct {
Errs []error
- Id string
+ Id string //nolint
}
type PodunpauseOptions struct {
@@ -55,7 +55,7 @@ type PodunpauseOptions struct {
type PodUnpauseReport struct {
Errs []error
- Id string
+ Id string //nolint
}
type PodStopOptions struct {
@@ -67,7 +67,7 @@ type PodStopOptions struct {
type PodStopReport struct {
Errs []error
- Id string
+ Id string //nolint
}
type PodRestartOptions struct {
@@ -77,7 +77,7 @@ type PodRestartOptions struct {
type PodRestartReport struct {
Errs []error
- Id string
+ Id string //nolint
}
type PodStartOptions struct {
@@ -87,7 +87,7 @@ type PodStartOptions struct {
type PodStartReport struct {
Errs []error
- Id string
+ Id string //nolint
}
type PodRmOptions struct {
@@ -99,7 +99,7 @@ type PodRmOptions struct {
type PodRmReport struct {
Err error
- Id string
+ Id string //nolint
}
type PodCreateOptions struct {
@@ -115,7 +115,7 @@ type PodCreateOptions struct {
}
type PodCreateReport struct {
- Id string
+ Id string //nolint
}
func (p PodCreateOptions) ToPodSpecGen(s *specgen.PodSpecGenerator) {
@@ -155,7 +155,7 @@ type PodPruneOptions struct {
type PodPruneReport struct {
Err error
- Id string
+ Id string //nolint
}
type PodTopOptions struct {
diff --git a/pkg/domain/entities/set.go b/pkg/domain/entities/set.go
index c8d6cb1a9..1d31d82f9 100644
--- a/pkg/domain/entities/set.go
+++ b/pkg/domain/entities/set.go
@@ -4,12 +4,12 @@ import (
"strings"
)
-type stringSet struct {
+type StringSet struct {
m map[string]struct{}
}
-func NewStringSet(elem ...string) *stringSet {
- s := &stringSet{}
+func NewStringSet(elem ...string) *StringSet {
+ s := &StringSet{}
s.m = make(map[string]struct{}, len(elem))
for _, e := range elem {
s.Add(e)
@@ -17,20 +17,20 @@ func NewStringSet(elem ...string) *stringSet {
return s
}
-func (s *stringSet) Add(elem string) {
+func (s *StringSet) Add(elem string) {
s.m[elem] = struct{}{}
}
-func (s *stringSet) Remove(elem string) {
+func (s *StringSet) Remove(elem string) {
delete(s.m, elem)
}
-func (s *stringSet) Contains(elem string) bool {
+func (s *StringSet) Contains(elem string) bool {
_, ok := s.m[elem]
return ok
}
-func (s *stringSet) Elements() []string {
+func (s *StringSet) Elements() []string {
keys := make([]string, len(s.m))
i := 0
for k := range s.m {
@@ -40,6 +40,6 @@ func (s *stringSet) Elements() []string {
return keys
}
-func (s *stringSet) String() string {
+func (s *StringSet) String() string {
return strings.Join(s.Elements(), ", ")
}
diff --git a/pkg/domain/entities/types.go b/pkg/domain/entities/types.go
index 21ab025de..622f74838 100644
--- a/pkg/domain/entities/types.go
+++ b/pkg/domain/entities/types.go
@@ -11,7 +11,7 @@ import (
)
type Container struct {
- IdOrNamed
+ IDOrNamed
}
type Volume struct {
@@ -19,7 +19,7 @@ type Volume struct {
}
type Report struct {
- Id []string
+ Id []string //nolint
Err map[string]error
}
diff --git a/pkg/domain/entities/volumes.go b/pkg/domain/entities/volumes.go
index 23c066083..7cf7d82a2 100644
--- a/pkg/domain/entities/volumes.go
+++ b/pkg/domain/entities/volumes.go
@@ -16,9 +16,9 @@ type VolumeCreateOptions struct {
Options map[string]string `schema:"opts"`
}
-type IdOrNameResponse struct {
+type IDOrNameResponse struct {
// The Id or Name of an object
- IdOrName string
+ IDOrName string
}
type VolumeConfigResponse struct {
@@ -63,7 +63,7 @@ type VolumeRmOptions struct {
type VolumeRmReport struct {
Err error
- Id string
+ Id string //nolint
}
type VolumeInspectOptions struct {
@@ -80,7 +80,7 @@ type VolumePruneOptions struct {
type VolumePruneReport struct {
Err error
- Id string
+ Id string //nolint
}
type VolumeListOptions struct {
diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go
index 706fcec47..4d6d0d59a 100644
--- a/pkg/domain/infra/abi/containers.go
+++ b/pkg/domain/infra/abi/containers.go
@@ -23,6 +23,7 @@ import (
"github.com/containers/libpod/pkg/checkpoint"
"github.com/containers/libpod/pkg/domain/entities"
"github.com/containers/libpod/pkg/domain/infra/abi/terminal"
+ "github.com/containers/libpod/pkg/parallel"
"github.com/containers/libpod/pkg/ps"
"github.com/containers/libpod/pkg/rootless"
"github.com/containers/libpod/pkg/signal"
@@ -44,8 +45,10 @@ func getContainersAndInputByContext(all, latest bool, names []string, runtime *l
ctrs, err = runtime.GetAllContainers()
case latest:
ctr, err = runtime.GetLatestContainer()
- rawInput = append(rawInput, ctr.ID())
- ctrs = append(ctrs, ctr)
+ if err == nil {
+ rawInput = append(rawInput, ctr.ID())
+ ctrs = append(ctrs, ctr)
+ }
default:
for _, n := range names {
ctr, e := runtime.LookupContainer(n)
@@ -72,8 +75,8 @@ func getContainersByContext(all, latest bool, names []string, runtime *libpod.Ru
}
// TODO: Should return *entities.ContainerExistsReport, error
-func (ic *ContainerEngine) ContainerExists(ctx context.Context, nameOrId string) (*entities.BoolReport, error) {
- _, err := ic.Libpod.LookupContainer(nameOrId)
+func (ic *ContainerEngine) ContainerExists(ctx context.Context, nameOrID string) (*entities.BoolReport, error) {
+ _, err := ic.Libpod.LookupContainer(nameOrID)
if err != nil && errors.Cause(err) != define.ErrNoSuchCtr {
return nil, err
}
@@ -159,26 +162,33 @@ func (ic *ContainerEngine) ContainerStop(ctx context.Context, namesOrIds []strin
if err != nil && !(options.Ignore && errors.Cause(err) == define.ErrNoSuchCtr) {
return nil, err
}
- for _, con := range ctrs {
- report := entities.StopReport{Id: con.ID()}
- err = con.StopWithTimeout(options.Timeout)
+ errMap, err := parallel.ContainerOp(ctx, ctrs, func(c *libpod.Container) error {
+ var err error
+ if options.Timeout != nil {
+ err = c.StopWithTimeout(*options.Timeout)
+ } else {
+ err = c.Stop()
+ }
if err != nil {
- // These first two are considered non-fatal under the right conditions
- if errors.Cause(err) == define.ErrCtrStopped {
- logrus.Debugf("Container %s is already stopped", con.ID())
- reports = append(reports, &report)
- continue
-
- } else if options.All && errors.Cause(err) == define.ErrCtrStateInvalid {
- logrus.Debugf("Container %s is not running, could not stop", con.ID())
- reports = append(reports, &report)
- continue
+ switch {
+ case errors.Cause(err) == define.ErrCtrStopped:
+ logrus.Debugf("Container %s is already stopped", c.ID())
+ case options.All && errors.Cause(err) == define.ErrCtrStateInvalid:
+ logrus.Debugf("Container %s is not running, could not stop", c.ID())
+ default:
+ return err
}
- report.Err = err
- reports = append(reports, &report)
- continue
}
- reports = append(reports, &report)
+ return c.Cleanup(ctx)
+ })
+ if err != nil {
+ return nil, err
+ }
+ for ctr, err := range errMap {
+ report := new(entities.StopReport)
+ report.Id = ctr.ID()
+ report.Err = err
+ reports = append(reports, report)
}
return reports, nil
}
@@ -313,21 +323,25 @@ func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string,
return reports, nil
}
- for _, c := range ctrs {
- report := entities.RmReport{Id: c.ID()}
+ errMap, err := parallel.ContainerOp(ctx, ctrs, func(c *libpod.Container) error {
err := ic.Libpod.RemoveContainer(ctx, c, options.Force, options.Volumes)
if err != nil {
if options.Ignore && errors.Cause(err) == define.ErrNoSuchCtr {
logrus.Debugf("Ignoring error (--allow-missing): %v", err)
- reports = append(reports, &report)
- continue
+ return nil
}
logrus.Debugf("Failed to remove container %s: %s", c.ID(), err.Error())
- report.Err = err
- reports = append(reports, &report)
- continue
}
- reports = append(reports, &report)
+ return err
+ })
+ if err != nil {
+ return nil, err
+ }
+ for ctr, err := range errMap {
+ report := new(entities.RmReport)
+ report.Id = ctr.ID()
+ report.Err = err
+ reports = append(reports, report)
}
return reports, nil
}
@@ -370,11 +384,11 @@ func (ic *ContainerEngine) ContainerTop(ctx context.Context, options entities.To
return report, err
}
-func (ic *ContainerEngine) ContainerCommit(ctx context.Context, nameOrId string, options entities.CommitOptions) (*entities.CommitReport, error) {
+func (ic *ContainerEngine) ContainerCommit(ctx context.Context, nameOrID string, options entities.CommitOptions) (*entities.CommitReport, error) {
var (
mimeType string
)
- ctr, err := ic.Libpod.LookupContainer(nameOrId)
+ ctr, err := ic.Libpod.LookupContainer(nameOrID)
if err != nil {
return nil, err
}
@@ -415,8 +429,8 @@ func (ic *ContainerEngine) ContainerCommit(ctx context.Context, nameOrId string,
return &entities.CommitReport{Id: newImage.ID()}, nil
}
-func (ic *ContainerEngine) ContainerExport(ctx context.Context, nameOrId string, options entities.ContainerExportOptions) error {
- ctr, err := ic.Libpod.LookupContainer(nameOrId)
+func (ic *ContainerEngine) ContainerExport(ctx context.Context, nameOrID string, options entities.ContainerExportOptions) error {
+ ctr, err := ic.Libpod.LookupContainer(nameOrID)
if err != nil {
return err
}
@@ -514,8 +528,8 @@ func (ic *ContainerEngine) ContainerCreate(ctx context.Context, s *specgen.SpecG
return &entities.ContainerCreateReport{Id: ctr.ID()}, nil
}
-func (ic *ContainerEngine) ContainerAttach(ctx context.Context, nameOrId string, options entities.AttachOptions) error {
- ctrs, err := getContainersByContext(false, options.Latest, []string{nameOrId}, ic.Libpod)
+func (ic *ContainerEngine) ContainerAttach(ctx context.Context, nameOrID string, options entities.AttachOptions) error {
+ ctrs, err := getContainersByContext(false, options.Latest, []string{nameOrID}, ic.Libpod)
if err != nil {
return err
}
@@ -577,12 +591,12 @@ func checkExecPreserveFDs(options entities.ExecOptions) (int, error) {
return ec, nil
}
-func (ic *ContainerEngine) ContainerExec(ctx context.Context, nameOrId string, options entities.ExecOptions, streams define.AttachStreams) (int, error) {
+func (ic *ContainerEngine) ContainerExec(ctx context.Context, nameOrID string, options entities.ExecOptions, streams define.AttachStreams) (int, error) {
ec, err := checkExecPreserveFDs(options)
if err != nil {
return ec, err
}
- ctrs, err := getContainersByContext(false, options.Latest, []string{nameOrId}, ic.Libpod)
+ ctrs, err := getContainersByContext(false, options.Latest, []string{nameOrID}, ic.Libpod)
if err != nil {
return ec, err
}
@@ -594,12 +608,12 @@ func (ic *ContainerEngine) ContainerExec(ctx context.Context, nameOrId string, o
return define.TranslateExecErrorToExitCode(ec, err), err
}
-func (ic *ContainerEngine) ContainerExecDetached(ctx context.Context, nameOrId string, options entities.ExecOptions) (string, error) {
+func (ic *ContainerEngine) ContainerExecDetached(ctx context.Context, nameOrID string, options entities.ExecOptions) (string, error) {
_, err := checkExecPreserveFDs(options)
if err != nil {
return "", err
}
- ctrs, err := getContainersByContext(false, options.Latest, []string{nameOrId}, ic.Libpod)
+ ctrs, err := getContainersByContext(false, options.Latest, []string{nameOrID}, ic.Libpod)
if err != nil {
return "", err
}
@@ -753,15 +767,15 @@ func (ic *ContainerEngine) ContainerList(ctx context.Context, options entities.C
}
// ContainerDiff provides changes to given container
-func (ic *ContainerEngine) ContainerDiff(ctx context.Context, nameOrId string, opts entities.DiffOptions) (*entities.DiffReport, error) {
+func (ic *ContainerEngine) ContainerDiff(ctx context.Context, nameOrID string, opts entities.DiffOptions) (*entities.DiffReport, error) {
if opts.Latest {
ctnr, err := ic.Libpod.GetLatestContainer()
if err != nil {
return nil, errors.Wrap(err, "unable to get latest container")
}
- nameOrId = ctnr.ID()
+ nameOrID = ctnr.ID()
}
- changes, err := ic.Libpod.GetDiff("", nameOrId)
+ changes, err := ic.Libpod.GetDiff("", nameOrID)
return &entities.DiffReport{Changes: changes}, err
}
@@ -963,7 +977,7 @@ func (ic *ContainerEngine) ContainerInit(ctx context.Context, namesOrIds []strin
return reports, nil
}
-func (ic *ContainerEngine) ContainerMount(ctx context.Context, nameOrIds []string, options entities.ContainerMountOptions) ([]*entities.ContainerMountReport, error) {
+func (ic *ContainerEngine) ContainerMount(ctx context.Context, nameOrIDs []string, options entities.ContainerMountOptions) ([]*entities.ContainerMountReport, error) {
if os.Geteuid() != 0 {
if driver := ic.Libpod.StorageConfig().GraphDriverName; driver != "vfs" {
// Do not allow to mount a graphdriver that is not vfs if we are creating the userns as part
@@ -980,7 +994,7 @@ func (ic *ContainerEngine) ContainerMount(ctx context.Context, nameOrIds []strin
}
}
var reports []*entities.ContainerMountReport
- ctrs, err := getContainersByContext(options.All, options.Latest, nameOrIds, ic.Libpod)
+ ctrs, err := getContainersByContext(options.All, options.Latest, nameOrIDs, ic.Libpod)
if err != nil {
return nil, err
}
@@ -1015,9 +1029,9 @@ func (ic *ContainerEngine) ContainerMount(ctx context.Context, nameOrIds []strin
return reports, nil
}
-func (ic *ContainerEngine) ContainerUnmount(ctx context.Context, nameOrIds []string, options entities.ContainerUnmountOptions) ([]*entities.ContainerUnmountReport, error) {
+func (ic *ContainerEngine) ContainerUnmount(ctx context.Context, nameOrIDs []string, options entities.ContainerUnmountOptions) ([]*entities.ContainerUnmountReport, error) {
var reports []*entities.ContainerUnmountReport
- ctrs, err := getContainersByContext(options.All, options.Latest, nameOrIds, ic.Libpod)
+ ctrs, err := getContainersByContext(options.All, options.Latest, nameOrIDs, ic.Libpod)
if err != nil {
return nil, err
}
@@ -1050,9 +1064,9 @@ func (ic *ContainerEngine) Config(_ context.Context) (*config.Config, error) {
return ic.Libpod.GetConfig()
}
-func (ic *ContainerEngine) ContainerPort(ctx context.Context, nameOrId string, options entities.ContainerPortOptions) ([]*entities.ContainerPortReport, error) {
+func (ic *ContainerEngine) ContainerPort(ctx context.Context, nameOrID string, options entities.ContainerPortOptions) ([]*entities.ContainerPortReport, error) {
var reports []*entities.ContainerPortReport
- ctrs, err := getContainersByContext(options.All, options.Latest, []string{nameOrId}, ic.Libpod)
+ ctrs, err := getContainersByContext(options.All, options.Latest, []string{nameOrID}, ic.Libpod)
if err != nil {
return nil, err
}
diff --git a/pkg/domain/infra/abi/healthcheck.go b/pkg/domain/infra/abi/healthcheck.go
index 4e925ef56..dfa9a6fa5 100644
--- a/pkg/domain/infra/abi/healthcheck.go
+++ b/pkg/domain/infra/abi/healthcheck.go
@@ -7,8 +7,8 @@ import (
"github.com/containers/libpod/pkg/domain/entities"
)
-func (ic *ContainerEngine) HealthCheckRun(ctx context.Context, nameOrId string, options entities.HealthCheckOptions) (*define.HealthCheckResults, error) {
- status, err := ic.Libpod.HealthCheck(nameOrId)
+func (ic *ContainerEngine) HealthCheckRun(ctx context.Context, nameOrID string, options entities.HealthCheckOptions) (*define.HealthCheckResults, error) {
+ status, err := ic.Libpod.HealthCheck(nameOrID)
if err != nil {
return nil, err
}
diff --git a/pkg/domain/infra/abi/images.go b/pkg/domain/infra/abi/images.go
index d8af4d339..67f331aac 100644
--- a/pkg/domain/infra/abi/images.go
+++ b/pkg/domain/infra/abi/images.go
@@ -38,8 +38,8 @@ import (
// SignatureStoreDir defines default directory to store signatures
const SignatureStoreDir = "/var/lib/containers/sigstore"
-func (ir *ImageEngine) Exists(_ context.Context, nameOrId string) (*entities.BoolReport, error) {
- _, err := ir.Libpod.ImageRuntime().NewFromLocal(nameOrId)
+func (ir *ImageEngine) Exists(_ context.Context, nameOrID string) (*entities.BoolReport, error) {
+ _, err := ir.Libpod.ImageRuntime().NewFromLocal(nameOrID)
if err != nil && errors.Cause(err) != define.ErrNoSuchImage {
return nil, err
}
@@ -65,8 +65,8 @@ func (ir *ImageEngine) pruneImagesHelper(ctx context.Context, all bool, filters
return &report, nil
}
-func (ir *ImageEngine) History(ctx context.Context, nameOrId string, opts entities.ImageHistoryOptions) (*entities.ImageHistoryReport, error) {
- image, err := ir.Libpod.ImageRuntime().NewFromLocal(nameOrId)
+func (ir *ImageEngine) History(ctx context.Context, nameOrID string, opts entities.ImageHistoryOptions) (*entities.ImageHistoryReport, error) {
+ image, err := ir.Libpod.ImageRuntime().NewFromLocal(nameOrID)
if err != nil {
return nil, err
}
@@ -261,8 +261,8 @@ func (ir *ImageEngine) Push(ctx context.Context, source string, destination stri
nil)
}
-// func (r *imageRuntime) Delete(ctx context.Context, nameOrId string, opts entities.ImageDeleteOptions) (*entities.ImageDeleteReport, error) {
-// image, err := r.libpod.ImageEngine().NewFromLocal(nameOrId)
+// func (r *imageRuntime) Delete(ctx context.Context, nameOrID string, opts entities.ImageDeleteOptions) (*entities.ImageDeleteReport, error) {
+// image, err := r.libpod.ImageEngine().NewFromLocal(nameOrID)
// if err != nil {
// return nil, err
// }
@@ -292,8 +292,8 @@ func (ir *ImageEngine) Push(ctx context.Context, source string, destination stri
// return &report, nil
// }
-func (ir *ImageEngine) Tag(ctx context.Context, nameOrId string, tags []string, options entities.ImageTagOptions) error {
- newImage, err := ir.Libpod.ImageRuntime().NewFromLocal(nameOrId)
+func (ir *ImageEngine) Tag(ctx context.Context, nameOrID string, tags []string, options entities.ImageTagOptions) error {
+ newImage, err := ir.Libpod.ImageRuntime().NewFromLocal(nameOrID)
if err != nil {
return err
}
@@ -305,8 +305,8 @@ func (ir *ImageEngine) Tag(ctx context.Context, nameOrId string, tags []string,
return nil
}
-func (ir *ImageEngine) Untag(ctx context.Context, nameOrId string, tags []string, options entities.ImageUntagOptions) error {
- newImage, err := ir.Libpod.ImageRuntime().NewFromLocal(nameOrId)
+func (ir *ImageEngine) Untag(ctx context.Context, nameOrID string, tags []string, options entities.ImageUntagOptions) error {
+ newImage, err := ir.Libpod.ImageRuntime().NewFromLocal(nameOrID)
if err != nil {
return err
}
@@ -356,16 +356,16 @@ func (ir *ImageEngine) Import(ctx context.Context, opts entities.ImageImportOpti
return &entities.ImageImportReport{Id: id}, nil
}
-func (ir *ImageEngine) Save(ctx context.Context, nameOrId string, tags []string, options entities.ImageSaveOptions) error {
- newImage, err := ir.Libpod.ImageRuntime().NewFromLocal(nameOrId)
+func (ir *ImageEngine) Save(ctx context.Context, nameOrID string, tags []string, options entities.ImageSaveOptions) error {
+ newImage, err := ir.Libpod.ImageRuntime().NewFromLocal(nameOrID)
if err != nil {
return err
}
- return newImage.Save(ctx, nameOrId, options.Format, options.Output, tags, options.Quiet, options.Compress)
+ return newImage.Save(ctx, nameOrID, options.Format, options.Output, tags, options.Quiet, options.Compress)
}
-func (ir *ImageEngine) Diff(_ context.Context, nameOrId string, _ entities.DiffOptions) (*entities.DiffReport, error) {
- changes, err := ir.Libpod.GetDiff("", nameOrId)
+func (ir *ImageEngine) Diff(_ context.Context, nameOrID string, _ entities.DiffOptions) (*entities.DiffReport, error) {
+ changes, err := ir.Libpod.GetDiff("", nameOrID)
if err != nil {
return nil, err
}
@@ -420,8 +420,8 @@ func (ir *ImageEngine) Build(ctx context.Context, containerFiles []string, opts
return &entities.BuildReport{ID: id}, nil
}
-func (ir *ImageEngine) Tree(ctx context.Context, nameOrId string, opts entities.ImageTreeOptions) (*entities.ImageTreeReport, error) {
- img, err := ir.Libpod.ImageRuntime().NewFromLocal(nameOrId)
+func (ir *ImageEngine) Tree(ctx context.Context, nameOrID string, opts entities.ImageTreeOptions) (*entities.ImageTreeReport, error) {
+ img, err := ir.Libpod.ImageRuntime().NewFromLocal(nameOrID)
if err != nil {
return nil, err
}
diff --git a/pkg/domain/infra/abi/manifest.go b/pkg/domain/infra/abi/manifest.go
index 6e311dec7..a2b5fc0fc 100644
--- a/pkg/domain/infra/abi/manifest.go
+++ b/pkg/domain/infra/abi/manifest.go
@@ -1,4 +1,4 @@
-// +build ABISupport
+// +build !remote
package abi
diff --git a/pkg/domain/infra/abi/parse/parse.go b/pkg/domain/infra/abi/parse/parse.go
index 6c0e1ee55..2320c6a32 100644
--- a/pkg/domain/infra/abi/parse/parse.go
+++ b/pkg/domain/infra/abi/parse/parse.go
@@ -12,7 +12,7 @@ import (
// Handle volume options from CLI.
// Parse "o" option to find UID, GID.
-func ParseVolumeOptions(opts map[string]string) ([]libpod.VolumeCreateOption, error) {
+func VolumeOptions(opts map[string]string) ([]libpod.VolumeCreateOption, error) {
libpodOptions := []libpod.VolumeCreateOption{}
volumeOptions := make(map[string]string)
diff --git a/pkg/domain/infra/abi/play.go b/pkg/domain/infra/abi/play.go
index e06251ca7..f5b93c51b 100644
--- a/pkg/domain/infra/abi/play.go
+++ b/pkg/domain/infra/abi/play.go
@@ -297,7 +297,7 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
if err != nil {
return nil, err
}
- ctr, err := createconfig.CreateContainerFromCreateConfig(ic.Libpod, conf, ctx, pod)
+ ctr, err := createconfig.CreateContainerFromCreateConfig(ctx, ic.Libpod, conf, pod)
if err != nil {
return nil, err
}
diff --git a/pkg/domain/infra/abi/pods.go b/pkg/domain/infra/abi/pods.go
index 320880920..eb6f1e191 100644
--- a/pkg/domain/infra/abi/pods.go
+++ b/pkg/domain/infra/abi/pods.go
@@ -45,8 +45,8 @@ func getPodsByContext(all, latest bool, pods []string, runtime *libpod.Runtime)
return outpods, err
}
-func (ic *ContainerEngine) PodExists(ctx context.Context, nameOrId string) (*entities.BoolReport, error) {
- _, err := ic.Libpod.LookupPod(nameOrId)
+func (ic *ContainerEngine) PodExists(ctx context.Context, nameOrID string) (*entities.BoolReport, error) {
+ _, err := ic.Libpod.LookupPod(nameOrID)
if err != nil && errors.Cause(err) != define.ErrNoSuchPod {
return nil, err
}
@@ -347,7 +347,7 @@ func (ic *ContainerEngine) PodPs(ctx context.Context, options entities.PodPSOpti
Status: state.String(),
})
}
- infraId, err := p.InfraContainerID()
+ infraID, err := p.InfraContainerID()
if err != nil {
return nil, err
}
@@ -356,7 +356,7 @@ func (ic *ContainerEngine) PodPs(ctx context.Context, options entities.PodPSOpti
Containers: lpcs,
Created: p.CreatedTime(),
Id: p.ID(),
- InfraId: infraId,
+ InfraId: infraID,
Name: p.Name(),
Namespace: p.Namespace(),
Status: status,
diff --git a/pkg/domain/infra/abi/system.go b/pkg/domain/infra/abi/system.go
index 52dfaba7d..b91dd513d 100644
--- a/pkg/domain/infra/abi/system.go
+++ b/pkg/domain/infra/abi/system.go
@@ -25,7 +25,38 @@ import (
)
func (ic *ContainerEngine) Info(ctx context.Context) (*define.Info, error) {
- return ic.Libpod.Info()
+ info, err := ic.Libpod.Info()
+ if err != nil {
+ return nil, err
+ }
+ xdg, err := util.GetRuntimeDir()
+ if err != nil {
+ return nil, err
+ }
+ if len(xdg) == 0 {
+ // If no xdg is returned, assume root socket
+ xdg = "/run"
+ }
+
+ // Glue the socket path together
+ socketPath := filepath.Join(xdg, "podman", "podman.sock")
+ rs := define.RemoteSocket{
+ Path: socketPath,
+ Exists: false,
+ }
+
+ // Check if the socket exists
+ if fi, err := os.Stat(socketPath); err == nil {
+ if fi.Mode()&os.ModeSocket != 0 {
+ rs.Exists = true
+ }
+ }
+ // TODO
+ // it was suggested future versions of this could perform
+ // a ping on the socket for greater confidence the socket is
+ // actually active.
+ info.Host.RemoteSocket = &rs
+ return info, err
}
func (ic *ContainerEngine) SetupRootless(_ context.Context, cmd *cobra.Command) error {
@@ -307,7 +338,7 @@ func (ic *ContainerEngine) SystemDf(ctx context.Context, options entities.System
}
for _, viu := range inUse {
if util.StringInSlice(viu, runningContainers) {
- consInUse += 1
+ consInUse++
}
}
report := entities.SystemDfVolumeReport{
@@ -345,12 +376,12 @@ func (se *SystemEngine) Renumber(ctx context.Context, flags *pflag.FlagSet, conf
return nil
}
-func (s SystemEngine) Migrate(ctx context.Context, flags *pflag.FlagSet, config *entities.PodmanConfig, options entities.SystemMigrateOptions) error {
+func (se SystemEngine) Migrate(ctx context.Context, flags *pflag.FlagSet, config *entities.PodmanConfig, options entities.SystemMigrateOptions) error {
return nil
}
-func (s SystemEngine) Shutdown(ctx context.Context) {
- if err := s.Libpod.Shutdown(false); err != nil {
+func (se SystemEngine) Shutdown(ctx context.Context) {
+ if err := se.Libpod.Shutdown(false); err != nil {
logrus.Error(err)
}
}
diff --git a/pkg/domain/infra/abi/trust.go b/pkg/domain/infra/abi/trust.go
index 5b89c91d9..03986ad0e 100644
--- a/pkg/domain/infra/abi/trust.go
+++ b/pkg/domain/infra/abi/trust.go
@@ -112,8 +112,8 @@ func (ir *ImageEngine) SetTrust(ctx context.Context, args []string, options enti
return ioutil.WriteFile(policyPath, data, 0644)
}
-func getPolicyShowOutput(policyContentStruct trust.PolicyContent, systemRegistriesDirPath string) ([]*trust.TrustPolicy, error) {
- var output []*trust.TrustPolicy
+func getPolicyShowOutput(policyContentStruct trust.PolicyContent, systemRegistriesDirPath string) ([]*trust.Policy, error) {
+ var output []*trust.Policy
registryConfigs, err := trust.LoadAndMergeConfig(systemRegistriesDirPath)
if err != nil {
@@ -121,7 +121,7 @@ func getPolicyShowOutput(policyContentStruct trust.PolicyContent, systemRegistri
}
if len(policyContentStruct.Default) > 0 {
- defaultPolicyStruct := trust.TrustPolicy{
+ defaultPolicyStruct := trust.Policy{
Name: "* (default)",
RepoName: "default",
Type: trustTypeDescription(policyContentStruct.Default[0].Type),
@@ -130,7 +130,7 @@ func getPolicyShowOutput(policyContentStruct trust.PolicyContent, systemRegistri
}
for _, transval := range policyContentStruct.Transports {
for repo, repoval := range transval {
- tempTrustShowOutput := trust.TrustPolicy{
+ tempTrustShowOutput := trust.Policy{
Name: repo,
RepoName: repo,
Type: repoval[0].Type,
diff --git a/pkg/domain/infra/abi/volumes.go b/pkg/domain/infra/abi/volumes.go
index 91b2440df..a311e0c4e 100644
--- a/pkg/domain/infra/abi/volumes.go
+++ b/pkg/domain/infra/abi/volumes.go
@@ -10,7 +10,7 @@ import (
"github.com/pkg/errors"
)
-func (ic *ContainerEngine) VolumeCreate(ctx context.Context, opts entities.VolumeCreateOptions) (*entities.IdOrNameResponse, error) {
+func (ic *ContainerEngine) VolumeCreate(ctx context.Context, opts entities.VolumeCreateOptions) (*entities.IDOrNameResponse, error) {
var (
volumeOptions []libpod.VolumeCreateOption
)
@@ -24,7 +24,7 @@ func (ic *ContainerEngine) VolumeCreate(ctx context.Context, opts entities.Volum
volumeOptions = append(volumeOptions, libpod.WithVolumeLabels(opts.Label))
}
if len(opts.Options) > 0 {
- parsedOptions, err := parse.ParseVolumeOptions(opts.Options)
+ parsedOptions, err := parse.VolumeOptions(opts.Options)
if err != nil {
return nil, err
}
@@ -34,7 +34,7 @@ func (ic *ContainerEngine) VolumeCreate(ctx context.Context, opts entities.Volum
if err != nil {
return nil, err
}
- return &entities.IdOrNameResponse{IdOrName: vol.Name()}, nil
+ return &entities.IDOrNameResponse{IDOrName: vol.Name()}, nil
}
func (ic *ContainerEngine) VolumeRm(ctx context.Context, namesOrIds []string, opts entities.VolumeRmOptions) ([]*entities.VolumeRmReport, error) {
diff --git a/pkg/domain/infra/runtime_abi.go b/pkg/domain/infra/runtime_abi.go
index 67c1cd534..60d0c6e86 100644
--- a/pkg/domain/infra/runtime_abi.go
+++ b/pkg/domain/infra/runtime_abi.go
@@ -1,4 +1,4 @@
-// +build ABISupport
+// +build !remote
package infra
@@ -20,7 +20,7 @@ func NewContainerEngine(facts *entities.PodmanConfig) (entities.ContainerEngine,
r, err := NewLibpodRuntime(facts.FlagSet, facts)
return r, err
case entities.TunnelMode:
- ctx, err := bindings.NewConnection(context.Background(), facts.Uri, facts.Identities...)
+ ctx, err := bindings.NewConnectionWithIdentity(context.Background(), facts.URI, facts.PassPhrase, facts.Identities...)
return &tunnel.ContainerEngine{ClientCxt: ctx}, err
}
return nil, fmt.Errorf("runtime mode '%v' is not supported", facts.EngineMode)
@@ -33,7 +33,7 @@ func NewImageEngine(facts *entities.PodmanConfig) (entities.ImageEngine, error)
r, err := NewLibpodImageRuntime(facts.FlagSet, facts)
return r, err
case entities.TunnelMode:
- ctx, err := bindings.NewConnection(context.Background(), facts.Uri, facts.Identities...)
+ ctx, err := bindings.NewConnectionWithIdentity(context.Background(), facts.URI, facts.PassPhrase, facts.Identities...)
return &tunnel.ImageEngine{ClientCxt: ctx}, err
}
return nil, fmt.Errorf("runtime mode '%v' is not supported", facts.EngineMode)
diff --git a/pkg/domain/infra/runtime_abi_unsupported.go b/pkg/domain/infra/runtime_abi_unsupported.go
index c4e25e990..3d7d457fc 100644
--- a/pkg/domain/infra/runtime_abi_unsupported.go
+++ b/pkg/domain/infra/runtime_abi_unsupported.go
@@ -1,4 +1,4 @@
-// +build !ABISupport
+// +build remote
package infra
diff --git a/pkg/domain/infra/runtime_libpod.go b/pkg/domain/infra/runtime_libpod.go
index a57eadc63..2f2b0f90f 100644
--- a/pkg/domain/infra/runtime_libpod.go
+++ b/pkg/domain/infra/runtime_libpod.go
@@ -1,4 +1,4 @@
-// +build ABISupport
+// +build !remote
package infra
diff --git a/pkg/domain/infra/runtime_proxy.go b/pkg/domain/infra/runtime_proxy.go
index e7002e20f..fed9b1008 100644
--- a/pkg/domain/infra/runtime_proxy.go
+++ b/pkg/domain/infra/runtime_proxy.go
@@ -1,4 +1,4 @@
-// +build ABISupport
+// +build !remote
package infra
diff --git a/pkg/domain/infra/runtime_tunnel.go b/pkg/domain/infra/runtime_tunnel.go
index 752218aaf..24a93b888 100644
--- a/pkg/domain/infra/runtime_tunnel.go
+++ b/pkg/domain/infra/runtime_tunnel.go
@@ -1,4 +1,4 @@
-// +build !ABISupport
+// +build remote
package infra
@@ -16,7 +16,7 @@ func NewContainerEngine(facts *entities.PodmanConfig) (entities.ContainerEngine,
case entities.ABIMode:
return nil, fmt.Errorf("direct runtime not supported")
case entities.TunnelMode:
- ctx, err := bindings.NewConnection(context.Background(), facts.Uri, facts.Identities...)
+ ctx, err := bindings.NewConnectionWithIdentity(context.Background(), facts.URI, facts.PassPhrase, facts.Identities...)
return &tunnel.ContainerEngine{ClientCxt: ctx}, err
}
return nil, fmt.Errorf("runtime mode '%v' is not supported", facts.EngineMode)
@@ -28,7 +28,7 @@ func NewImageEngine(facts *entities.PodmanConfig) (entities.ImageEngine, error)
case entities.ABIMode:
return nil, fmt.Errorf("direct image runtime not supported")
case entities.TunnelMode:
- ctx, err := bindings.NewConnection(context.Background(), facts.Uri, facts.Identities...)
+ ctx, err := bindings.NewConnectionWithIdentity(context.Background(), facts.URI, facts.PassPhrase, facts.Identities...)
return &tunnel.ImageEngine{ClientCxt: ctx}, err
}
return nil, fmt.Errorf("runtime mode '%v' is not supported", facts.EngineMode)
diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go
index af9d94293..68a8b0329 100644
--- a/pkg/domain/infra/tunnel/containers.go
+++ b/pkg/domain/infra/tunnel/containers.go
@@ -4,6 +4,7 @@ import (
"context"
"fmt"
"io"
+ "io/ioutil"
"os"
"strconv"
"strings"
@@ -25,8 +26,8 @@ func (ic *ContainerEngine) ContainerRunlabel(ctx context.Context, label string,
return errors.New("not implemented")
}
-func (ic *ContainerEngine) ContainerExists(ctx context.Context, nameOrId string) (*entities.BoolReport, error) {
- exists, err := containers.Exists(ic.ClientCxt, nameOrId)
+func (ic *ContainerEngine) ContainerExists(ctx context.Context, nameOrID string) (*entities.BoolReport, error) {
+ exists, err := containers.Exists(ic.ClientCxt, nameOrID)
return &entities.BoolReport{Value: exists}, err
}
@@ -85,13 +86,21 @@ func (ic *ContainerEngine) ContainerStop(ctx context.Context, namesOrIds []strin
var (
reports []*entities.StopReport
)
+ for _, cidFile := range options.CIDFiles {
+ content, err := ioutil.ReadFile(cidFile)
+ if err != nil {
+ return nil, errors.Wrapf(err, "error reading CIDFile %s", cidFile)
+ }
+ id := strings.Split(string(content), "\n")[0]
+ namesOrIds = append(namesOrIds, id)
+ }
ctrs, err := getContainersByContext(ic.ClientCxt, options.All, namesOrIds)
- if err != nil {
+ if err != nil && !(options.Ignore && errors.Cause(err) == define.ErrNoSuchCtr) {
return nil, err
}
for _, c := range ctrs {
report := entities.StopReport{Id: c.ID}
- if err = containers.Stop(ic.ClientCxt, c.ID, &options.Timeout); err != nil {
+ if err = containers.Stop(ic.ClientCxt, c.ID, options.Timeout); err != nil {
// These first two are considered non-fatal under the right conditions
if errors.Cause(err).Error() == define.ErrCtrStopped.Error() {
logrus.Debugf("Container %s is already stopped", c.ID)
@@ -162,8 +171,16 @@ func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string,
var (
reports []*entities.RmReport
)
+ for _, cidFile := range options.CIDFiles {
+ content, err := ioutil.ReadFile(cidFile)
+ if err != nil {
+ return nil, errors.Wrapf(err, "error reading CIDFile %s", cidFile)
+ }
+ id := strings.Split(string(content), "\n")[0]
+ namesOrIds = append(namesOrIds, id)
+ }
ctrs, err := getContainersByContext(ic.ClientCxt, options.All, namesOrIds)
- if err != nil {
+ if err != nil && !(options.Ignore && errors.Cause(err) == define.ErrNoSuchCtr) {
return nil, err
}
// TODO there is no endpoint for container eviction. Need to discuss
@@ -213,10 +230,10 @@ func (ic *ContainerEngine) ContainerTop(ctx context.Context, options entities.To
return &entities.StringSliceReport{Value: topOutput}, nil
}
-func (ic *ContainerEngine) ContainerCommit(ctx context.Context, nameOrId string, options entities.CommitOptions) (*entities.CommitReport, error) {
+func (ic *ContainerEngine) ContainerCommit(ctx context.Context, nameOrID string, options entities.CommitOptions) (*entities.CommitReport, error) {
var (
repo string
- tag string = "latest"
+ tag = "latest"
)
if len(options.ImageName) > 0 {
ref, err := reference.Parse(options.ImageName)
@@ -242,14 +259,14 @@ func (ic *ContainerEngine) ContainerCommit(ctx context.Context, nameOrId string,
Repo: &repo,
Tag: &tag,
}
- response, err := containers.Commit(ic.ClientCxt, nameOrId, commitOpts)
+ response, err := containers.Commit(ic.ClientCxt, nameOrID, commitOpts)
if err != nil {
return nil, err
}
return &entities.CommitReport{Id: response.ID}, nil
}
-func (ic *ContainerEngine) ContainerExport(ctx context.Context, nameOrId string, options entities.ContainerExportOptions) error {
+func (ic *ContainerEngine) ContainerExport(ctx context.Context, nameOrID string, options entities.ContainerExportOptions) error {
var (
err error
w io.Writer
@@ -260,7 +277,7 @@ func (ic *ContainerEngine) ContainerExport(ctx context.Context, nameOrId string,
return err
}
}
- return containers.Export(ic.ClientCxt, nameOrId, w)
+ return containers.Export(ic.ClientCxt, nameOrID, w)
}
func (ic *ContainerEngine) ContainerCheckpoint(ctx context.Context, namesOrIds []string, options entities.CheckpointOptions) ([]*entities.CheckpointReport, error) {
@@ -340,7 +357,7 @@ func (ic *ContainerEngine) ContainerCreate(ctx context.Context, s *specgen.SpecG
return &entities.ContainerCreateReport{Id: response.ID}, nil
}
-func (ic *ContainerEngine) ContainerLogs(_ context.Context, nameOrIds []string, options entities.ContainerLogsOptions) error {
+func (ic *ContainerEngine) ContainerLogs(_ context.Context, nameOrIDs []string, options entities.ContainerLogsOptions) error {
since := options.Since.Format(time.RFC3339)
tail := strconv.FormatInt(options.Tail, 10)
stdout := options.Writer != nil
@@ -358,7 +375,7 @@ func (ic *ContainerEngine) ContainerLogs(_ context.Context, nameOrIds []string,
outCh := make(chan string)
ctx, cancel := context.WithCancel(context.Background())
go func() {
- err = containers.Logs(ic.ClientCxt, nameOrIds[0], opts, outCh, outCh)
+ err = containers.Logs(ic.ClientCxt, nameOrIDs[0], opts, outCh, outCh)
cancel()
}()
@@ -372,8 +389,8 @@ func (ic *ContainerEngine) ContainerLogs(_ context.Context, nameOrIds []string,
}
}
-func (ic *ContainerEngine) ContainerAttach(ctx context.Context, nameOrId string, options entities.AttachOptions) error {
- return containers.Attach(ic.ClientCxt, nameOrId, &options.DetachKeys, nil, bindings.PTrue, options.Stdin, options.Stdout, options.Stderr, nil)
+func (ic *ContainerEngine) ContainerAttach(ctx context.Context, nameOrID string, options entities.AttachOptions) error {
+ return containers.Attach(ic.ClientCxt, nameOrID, &options.DetachKeys, nil, bindings.PTrue, options.Stdin, options.Stdout, options.Stderr, nil)
}
func makeExecConfig(options entities.ExecOptions) *handlers.ExecCreateConfig {
@@ -398,10 +415,10 @@ func makeExecConfig(options entities.ExecOptions) *handlers.ExecCreateConfig {
return createConfig
}
-func (ic *ContainerEngine) ContainerExec(ctx context.Context, nameOrId string, options entities.ExecOptions, streams define.AttachStreams) (int, error) {
+func (ic *ContainerEngine) ContainerExec(ctx context.Context, nameOrID string, options entities.ExecOptions, streams define.AttachStreams) (int, error) {
createConfig := makeExecConfig(options)
- sessionID, err := containers.ExecCreate(ic.ClientCxt, nameOrId, createConfig)
+ sessionID, err := containers.ExecCreate(ic.ClientCxt, nameOrID, createConfig)
if err != nil {
return 125, err
}
@@ -418,10 +435,10 @@ func (ic *ContainerEngine) ContainerExec(ctx context.Context, nameOrId string, o
return inspectOut.ExitCode, nil
}
-func (ic *ContainerEngine) ContainerExecDetached(ctx context.Context, nameOrId string, options entities.ExecOptions) (string, error) {
+func (ic *ContainerEngine) ContainerExecDetached(ctx context.Context, nameOrID string, options entities.ExecOptions) (string, error) {
createConfig := makeExecConfig(options)
- sessionID, err := containers.ExecCreate(ic.ClientCxt, nameOrId, createConfig)
+ sessionID, err := containers.ExecCreate(ic.ClientCxt, nameOrID, createConfig)
if err != nil {
return "", err
}
@@ -508,8 +525,8 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta
return &report, err
}
-func (ic *ContainerEngine) ContainerDiff(ctx context.Context, nameOrId string, _ entities.DiffOptions) (*entities.DiffReport, error) {
- changes, err := containers.Diff(ic.ClientCxt, nameOrId)
+func (ic *ContainerEngine) ContainerDiff(ctx context.Context, nameOrID string, _ entities.DiffOptions) (*entities.DiffReport, error) {
+ changes, err := containers.Diff(ic.ClientCxt, nameOrID)
return &entities.DiffReport{Changes: changes}, err
}
@@ -538,11 +555,11 @@ func (ic *ContainerEngine) ContainerInit(ctx context.Context, namesOrIds []strin
return reports, nil
}
-func (ic *ContainerEngine) ContainerMount(ctx context.Context, nameOrIds []string, options entities.ContainerMountOptions) ([]*entities.ContainerMountReport, error) {
+func (ic *ContainerEngine) ContainerMount(ctx context.Context, nameOrIDs []string, options entities.ContainerMountOptions) ([]*entities.ContainerMountReport, error) {
return nil, errors.New("mounting containers is not supported for remote clients")
}
-func (ic *ContainerEngine) ContainerUnmount(ctx context.Context, nameOrIds []string, options entities.ContainerUnmountOptions) ([]*entities.ContainerUnmountReport, error) {
+func (ic *ContainerEngine) ContainerUnmount(ctx context.Context, nameOrIDs []string, options entities.ContainerUnmountOptions) ([]*entities.ContainerUnmountReport, error) {
return nil, errors.New("unmounting containers is not supported for remote clients")
}
@@ -550,13 +567,13 @@ func (ic *ContainerEngine) Config(_ context.Context) (*config.Config, error) {
return config.Default()
}
-func (ic *ContainerEngine) ContainerPort(ctx context.Context, nameOrId string, options entities.ContainerPortOptions) ([]*entities.ContainerPortReport, error) {
+func (ic *ContainerEngine) ContainerPort(ctx context.Context, nameOrID string, options entities.ContainerPortOptions) ([]*entities.ContainerPortReport, error) {
var (
reports []*entities.ContainerPortReport
namesOrIds []string
)
- if len(nameOrId) > 0 {
- namesOrIds = append(namesOrIds, nameOrId)
+ if len(nameOrID) > 0 {
+ namesOrIds = append(namesOrIds, nameOrID)
}
ctrs, err := getContainersByContext(ic.ClientCxt, options.All, namesOrIds)
if err != nil {
diff --git a/pkg/domain/infra/tunnel/generate.go b/pkg/domain/infra/tunnel/generate.go
index eb5587f89..519dc5907 100644
--- a/pkg/domain/infra/tunnel/generate.go
+++ b/pkg/domain/infra/tunnel/generate.go
@@ -13,5 +13,5 @@ func (ic *ContainerEngine) GenerateSystemd(ctx context.Context, nameOrID string,
}
func (ic *ContainerEngine) GenerateKube(ctx context.Context, nameOrID string, options entities.GenerateKubeOptions) (*entities.GenerateKubeReport, error) {
- return generate.GenerateKube(ic.ClientCxt, nameOrID, options)
+ return generate.Kube(ic.ClientCxt, nameOrID, options)
}
diff --git a/pkg/domain/infra/tunnel/healthcheck.go b/pkg/domain/infra/tunnel/healthcheck.go
index e589489b3..56bdd6759 100644
--- a/pkg/domain/infra/tunnel/healthcheck.go
+++ b/pkg/domain/infra/tunnel/healthcheck.go
@@ -8,6 +8,6 @@ import (
"github.com/containers/libpod/pkg/domain/entities"
)
-func (ic *ContainerEngine) HealthCheckRun(ctx context.Context, nameOrId string, options entities.HealthCheckOptions) (*define.HealthCheckResults, error) {
- return containers.RunHealthCheck(ic.ClientCxt, nameOrId)
+func (ic *ContainerEngine) HealthCheckRun(ctx context.Context, nameOrID string, options entities.HealthCheckOptions) (*define.HealthCheckResults, error) {
+ return containers.RunHealthCheck(ic.ClientCxt, nameOrID)
}
diff --git a/pkg/domain/infra/tunnel/helpers.go b/pkg/domain/infra/tunnel/helpers.go
index 862c7a5d6..2bbc0e7a5 100644
--- a/pkg/domain/infra/tunnel/helpers.go
+++ b/pkg/domain/infra/tunnel/helpers.go
@@ -13,11 +13,11 @@ import (
"github.com/pkg/errors"
)
-func getContainersByContext(contextWithConnection context.Context, all bool, namesOrIds []string) ([]entities.ListContainer, error) {
+func getContainersByContext(contextWithConnection context.Context, all bool, namesOrIDs []string) ([]entities.ListContainer, error) {
var (
cons []entities.ListContainer
)
- if all && len(namesOrIds) > 0 {
+ if all && len(namesOrIDs) > 0 {
return nil, errors.New("cannot lookup containers and all")
}
c, err := containers.List(contextWithConnection, nil, bindings.PTrue, nil, nil, nil, bindings.PTrue)
@@ -27,7 +27,7 @@ func getContainersByContext(contextWithConnection context.Context, all bool, nam
if all {
return c, err
}
- for _, id := range namesOrIds {
+ for _, id := range namesOrIDs {
var found bool
for _, con := range c {
if id == con.ID || strings.HasPrefix(con.ID, id) || util.StringInSlice(id, con.Names) {
@@ -43,11 +43,11 @@ func getContainersByContext(contextWithConnection context.Context, all bool, nam
return cons, nil
}
-func getPodsByContext(contextWithConnection context.Context, all bool, namesOrIds []string) ([]*entities.ListPodsReport, error) {
+func getPodsByContext(contextWithConnection context.Context, all bool, namesOrIDs []string) ([]*entities.ListPodsReport, error) {
var (
sPods []*entities.ListPodsReport
)
- if all && len(namesOrIds) > 0 {
+ if all && len(namesOrIDs) > 0 {
return nil, errors.New("cannot lookup specific pods and all")
}
@@ -58,17 +58,17 @@ func getPodsByContext(contextWithConnection context.Context, all bool, namesOrId
if all {
return fPods, nil
}
- for _, nameOrId := range namesOrIds {
+ for _, nameOrID := range namesOrIDs {
var found bool
for _, f := range fPods {
- if f.Name == nameOrId || strings.HasPrefix(f.Id, nameOrId) {
+ if f.Name == nameOrID || strings.HasPrefix(f.Id, nameOrID) {
sPods = append(sPods, f)
found = true
break
}
}
if !found {
- return nil, errors.Wrapf(define.ErrNoSuchPod, "unable to find pod %q", nameOrId)
+ return nil, errors.Wrapf(define.ErrNoSuchPod, "unable to find pod %q", nameOrID)
}
}
return sPods, nil
diff --git a/pkg/domain/infra/tunnel/images.go b/pkg/domain/infra/tunnel/images.go
index c300e74d0..fc7ac0aa8 100644
--- a/pkg/domain/infra/tunnel/images.go
+++ b/pkg/domain/infra/tunnel/images.go
@@ -18,8 +18,8 @@ import (
"github.com/pkg/errors"
)
-func (ir *ImageEngine) Exists(_ context.Context, nameOrId string) (*entities.BoolReport, error) {
- found, err := images.Exists(ir.ClientCxt, nameOrId)
+func (ir *ImageEngine) Exists(_ context.Context, nameOrID string) (*entities.BoolReport, error) {
+ found, err := images.Exists(ir.ClientCxt, nameOrID)
return &entities.BoolReport{Value: found}, err
}
@@ -50,8 +50,8 @@ func (ir *ImageEngine) List(ctx context.Context, opts entities.ImageListOptions)
return is, nil
}
-func (ir *ImageEngine) History(ctx context.Context, nameOrId string, opts entities.ImageHistoryOptions) (*entities.ImageHistoryReport, error) {
- results, err := images.History(ir.ClientCxt, nameOrId)
+func (ir *ImageEngine) History(ctx context.Context, nameOrID string, opts entities.ImageHistoryOptions) (*entities.ImageHistoryReport, error) {
+ results, err := images.History(ir.ClientCxt, nameOrID)
if err != nil {
return nil, err
}
@@ -98,7 +98,7 @@ func (ir *ImageEngine) Pull(ctx context.Context, rawImage string, options entiti
return &entities.ImagePullReport{Images: pulledImages}, nil
}
-func (ir *ImageEngine) Tag(ctx context.Context, nameOrId string, tags []string, options entities.ImageTagOptions) error {
+func (ir *ImageEngine) Tag(ctx context.Context, nameOrID string, tags []string, options entities.ImageTagOptions) error {
for _, newTag := range tags {
var (
tag, repo string
@@ -114,19 +114,19 @@ func (ir *ImageEngine) Tag(ctx context.Context, nameOrId string, tags []string,
repo = r.Name()
}
if len(repo) < 1 {
- return errors.Errorf("invalid image name %q", nameOrId)
+ return errors.Errorf("invalid image name %q", nameOrID)
}
- if err := images.Tag(ir.ClientCxt, nameOrId, tag, repo); err != nil {
+ if err := images.Tag(ir.ClientCxt, nameOrID, tag, repo); err != nil {
return err
}
}
return nil
}
-func (ir *ImageEngine) Untag(ctx context.Context, nameOrId string, tags []string, options entities.ImageUntagOptions) error {
+func (ir *ImageEngine) Untag(ctx context.Context, nameOrID string, tags []string, options entities.ImageUntagOptions) error {
// Remove all tags if none are provided
if len(tags) == 0 {
- newImage, err := images.GetImage(ir.ClientCxt, nameOrId, bindings.PFalse)
+ newImage, err := images.GetImage(ir.ClientCxt, nameOrID, bindings.PFalse)
if err != nil {
return err
}
@@ -148,9 +148,9 @@ func (ir *ImageEngine) Untag(ctx context.Context, nameOrId string, tags []string
repo = r.Name()
}
if len(repo) < 1 {
- return errors.Errorf("invalid image name %q", nameOrId)
+ return errors.Errorf("invalid image name %q", nameOrID)
}
- if err := images.Untag(ir.ClientCxt, nameOrId, tag, repo); err != nil {
+ if err := images.Untag(ir.ClientCxt, nameOrID, tag, repo); err != nil {
return err
}
}
@@ -199,7 +199,7 @@ func (ir *ImageEngine) Push(ctx context.Context, source string, destination stri
return images.Push(ir.ClientCxt, source, destination, options)
}
-func (ir *ImageEngine) Save(ctx context.Context, nameOrId string, tags []string, options entities.ImageSaveOptions) error {
+func (ir *ImageEngine) Save(ctx context.Context, nameOrID string, tags []string, options entities.ImageSaveOptions) error {
var (
f *os.File
err error
@@ -217,7 +217,7 @@ func (ir *ImageEngine) Save(ctx context.Context, nameOrId string, tags []string,
return err
}
- exErr := images.Export(ir.ClientCxt, nameOrId, f, &options.Format, &options.Compress)
+ exErr := images.Export(ir.ClientCxt, nameOrID, f, &options.Format, &options.Compress)
if err := f.Close(); err != nil {
return err
}
@@ -250,8 +250,8 @@ func (ir *ImageEngine) Save(ctx context.Context, nameOrId string, tags []string,
}
// Diff reports the changes to the given image
-func (ir *ImageEngine) Diff(ctx context.Context, nameOrId string, _ entities.DiffOptions) (*entities.DiffReport, error) {
- changes, err := images.Diff(ir.ClientCxt, nameOrId)
+func (ir *ImageEngine) Diff(ctx context.Context, nameOrID string, _ entities.DiffOptions) (*entities.DiffReport, error) {
+ changes, err := images.Diff(ir.ClientCxt, nameOrID)
if err != nil {
return nil, err
}
@@ -277,8 +277,8 @@ func (ir *ImageEngine) Build(ctx context.Context, containerFiles []string, opts
return images.Build(ir.ClientCxt, containerFiles, opts, tarfile)
}
-func (ir *ImageEngine) Tree(ctx context.Context, nameOrId string, opts entities.ImageTreeOptions) (*entities.ImageTreeReport, error) {
- return images.Tree(ir.ClientCxt, nameOrId, &opts.WhatRequires)
+func (ir *ImageEngine) Tree(ctx context.Context, nameOrID string, opts entities.ImageTreeOptions) (*entities.ImageTreeReport, error) {
+ return images.Tree(ir.ClientCxt, nameOrID, &opts.WhatRequires)
}
// Shutdown Libpod engine
diff --git a/pkg/domain/infra/tunnel/play.go b/pkg/domain/infra/tunnel/play.go
index 15383a703..5f6bc4a2a 100644
--- a/pkg/domain/infra/tunnel/play.go
+++ b/pkg/domain/infra/tunnel/play.go
@@ -8,5 +8,5 @@ import (
)
func (ic *ContainerEngine) PlayKube(ctx context.Context, path string, options entities.PlayKubeOptions) (*entities.PlayKubeReport, error) {
- return play.PlayKube(ic.ClientCxt, path, options)
+ return play.Kube(ic.ClientCxt, path, options)
}
diff --git a/pkg/domain/infra/tunnel/pods.go b/pkg/domain/infra/tunnel/pods.go
index c193c6752..5ca4a6a80 100644
--- a/pkg/domain/infra/tunnel/pods.go
+++ b/pkg/domain/infra/tunnel/pods.go
@@ -3,14 +3,16 @@ package tunnel
import (
"context"
+ "github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/pkg/bindings/pods"
"github.com/containers/libpod/pkg/domain/entities"
"github.com/containers/libpod/pkg/specgen"
+ "github.com/containers/libpod/pkg/util"
"github.com/pkg/errors"
)
-func (ic *ContainerEngine) PodExists(ctx context.Context, nameOrId string) (*entities.BoolReport, error) {
- exists, err := pods.Exists(ic.ClientCxt, nameOrId)
+func (ic *ContainerEngine) PodExists(ctx context.Context, nameOrID string) (*entities.BoolReport, error) {
+ exists, err := pods.Exists(ic.ClientCxt, nameOrID)
return &entities.BoolReport{Value: exists}, err
}
@@ -18,6 +20,12 @@ func (ic *ContainerEngine) PodKill(ctx context.Context, namesOrIds []string, opt
var (
reports []*entities.PodKillReport
)
+
+ _, err := util.ParseSignal(options.Signal)
+ if err != nil {
+ return nil, err
+ }
+
foundPods, err := getPodsByContext(ic.ClientCxt, options.All, namesOrIds)
if err != nil {
return nil, err
@@ -86,10 +94,10 @@ func (ic *ContainerEngine) PodUnpause(ctx context.Context, namesOrIds []string,
func (ic *ContainerEngine) PodStop(ctx context.Context, namesOrIds []string, options entities.PodStopOptions) ([]*entities.PodStopReport, error) {
var (
reports []*entities.PodStopReport
- timeout int = -1
+ timeout = -1
)
foundPods, err := getPodsByContext(ic.ClientCxt, options.All, namesOrIds)
- if err != nil {
+ if err != nil && !(options.Ignore && errors.Cause(err) == define.ErrNoSuchPod) {
return nil, err
}
if options.Timeout != -1 {
@@ -155,7 +163,7 @@ func (ic *ContainerEngine) PodStart(ctx context.Context, namesOrIds []string, op
func (ic *ContainerEngine) PodRm(ctx context.Context, namesOrIds []string, options entities.PodRmOptions) ([]*entities.PodRmReport, error) {
var reports []*entities.PodRmReport
foundPods, err := getPodsByContext(ic.ClientCxt, options.All, namesOrIds)
- if err != nil {
+ if err != nil && !(options.Ignore && errors.Cause(err) == define.ErrNoSuchPod) {
return nil, err
}
for _, p := range foundPods {
diff --git a/pkg/domain/infra/tunnel/volumes.go b/pkg/domain/infra/tunnel/volumes.go
index e48a7fa7c..5b65c66ea 100644
--- a/pkg/domain/infra/tunnel/volumes.go
+++ b/pkg/domain/infra/tunnel/volumes.go
@@ -7,12 +7,12 @@ import (
"github.com/containers/libpod/pkg/domain/entities"
)
-func (ic *ContainerEngine) VolumeCreate(ctx context.Context, opts entities.VolumeCreateOptions) (*entities.IdOrNameResponse, error) {
+func (ic *ContainerEngine) VolumeCreate(ctx context.Context, opts entities.VolumeCreateOptions) (*entities.IDOrNameResponse, error) {
response, err := volumes.Create(ic.ClientCxt, opts)
if err != nil {
return nil, err
}
- return &entities.IdOrNameResponse{IdOrName: response.Name}, nil
+ return &entities.IDOrNameResponse{IDOrName: response.Name}, nil
}
func (ic *ContainerEngine) VolumeRm(ctx context.Context, namesOrIds []string, opts entities.VolumeRmOptions) ([]*entities.VolumeRmReport, error) {
diff --git a/pkg/domain/utils/utils.go b/pkg/domain/utils/utils.go
index c17769f62..ee213e1b6 100644
--- a/pkg/domain/utils/utils.go
+++ b/pkg/domain/utils/utils.go
@@ -31,7 +31,7 @@ func ToLibpodFilters(f url.Values) (filters []string) {
return
}
-func ToUrlValues(f []string) (filters url.Values) {
+func ToURLValues(f []string) (filters url.Values) {
filters = make(url.Values)
for _, v := range f {
t := strings.SplitN(v, "=", 2)
diff --git a/pkg/network/network.go b/pkg/network/network.go
index 526ee92d8..3ff664316 100644
--- a/pkg/network/network.go
+++ b/pkg/network/network.go
@@ -14,7 +14,7 @@ import (
)
// DefaultNetworkDriver is the default network type used
-var DefaultNetworkDriver string = "bridge"
+var DefaultNetworkDriver = "bridge"
// SupportedNetworkDrivers describes the list of supported drivers
var SupportedNetworkDrivers = []string{DefaultNetworkDriver}
diff --git a/pkg/parallel/parallel.go b/pkg/parallel/parallel.go
new file mode 100644
index 000000000..c9e4da50d
--- /dev/null
+++ b/pkg/parallel/parallel.go
@@ -0,0 +1,44 @@
+package parallel
+
+import (
+ "sync"
+
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+ "golang.org/x/sync/semaphore"
+)
+
+var (
+ // Maximum number of jobs that will be used.
+ // Set a low, but non-zero, default. We'll be overriding it by default
+ // anyways.
+ numThreads uint = 8
+ // Semaphore to control thread creation and ensure numThreads is
+ // respected.
+ jobControl *semaphore.Weighted
+ // Lock to control changing the semaphore - we don't want to do it
+ // while anyone is using it.
+ jobControlLock sync.RWMutex
+)
+
+// SetMaxThreads sets the number of threads that will be used for parallel jobs.
+func SetMaxThreads(threads uint) error {
+ if threads == 0 {
+ return errors.New("must give a non-zero number of threads to execute with")
+ }
+
+ jobControlLock.Lock()
+ defer jobControlLock.Unlock()
+
+ numThreads = threads
+ jobControl = semaphore.NewWeighted(int64(threads))
+ logrus.Infof("Setting parallel job count to %d", threads)
+
+ return nil
+}
+
+// GetMaxThreads returns the current number of threads that will be used for
+// parallel jobs.
+func GetMaxThreads() uint {
+ return numThreads
+}
diff --git a/pkg/parallel/parallel_linux.go b/pkg/parallel/parallel_linux.go
new file mode 100644
index 000000000..472571972
--- /dev/null
+++ b/pkg/parallel/parallel_linux.go
@@ -0,0 +1,57 @@
+package parallel
+
+import (
+ "context"
+ "sync"
+
+ "github.com/containers/libpod/libpod"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+)
+
+// ContainerOp performs the given function on the given set of
+// containers, using a number of parallel threads.
+// If no error is returned, each container specified in ctrs will have an entry
+// in the resulting map; containers with no error will be set to nil.
+func ContainerOp(ctx context.Context, ctrs []*libpod.Container, applyFunc func(*libpod.Container) error) (map[*libpod.Container]error, error) {
+ jobControlLock.RLock()
+ defer jobControlLock.RUnlock()
+
+ // We could use a sync.Map but given Go's lack of generic I'd rather
+ // just use a lock on a normal map...
+ // The expectation is that most of the time is spent in applyFunc
+ // anyways.
+ var (
+ errMap = make(map[*libpod.Container]error)
+ errLock sync.Mutex
+ allDone sync.WaitGroup
+ )
+
+ for _, ctr := range ctrs {
+ // Block until a thread is available
+ if err := jobControl.Acquire(ctx, 1); err != nil {
+ return nil, errors.Wrapf(err, "error acquiring job control semaphore")
+ }
+
+ allDone.Add(1)
+
+ c := ctr
+ go func() {
+ logrus.Debugf("Launching job on container %s", c.ID())
+
+ err := applyFunc(c)
+ errLock.Lock()
+ errMap[c] = err
+ errLock.Unlock()
+
+ allDone.Done()
+ jobControl.Release(1)
+ }()
+ }
+
+ allDone.Wait()
+
+ return errMap, nil
+}
+
+// TODO: Add an Enqueue() function that returns a promise
diff --git a/pkg/spec/createconfig.go b/pkg/spec/createconfig.go
index 2cf30a59e..e19c582b5 100644
--- a/pkg/spec/createconfig.go
+++ b/pkg/spec/createconfig.go
@@ -399,7 +399,7 @@ func AddPrivilegedDevices(g *generate.Generator) error {
return addPrivilegedDevices(g)
}
-func CreateContainerFromCreateConfig(r *libpod.Runtime, createConfig *CreateConfig, ctx context.Context, pod *libpod.Pod) (*libpod.Container, error) {
+func CreateContainerFromCreateConfig(ctx context.Context, r *libpod.Runtime, createConfig *CreateConfig, pod *libpod.Pod) (*libpod.Container, error) {
runtimeSpec, options, err := createConfig.MakeContainerConfig(r, pod)
if err != nil {
return nil, err
diff --git a/pkg/specgen/config_linux.go b/pkg/specgen/config_linux.go
deleted file mode 100644
index 82a371492..000000000
--- a/pkg/specgen/config_linux.go
+++ /dev/null
@@ -1,93 +0,0 @@
-package specgen
-
-//func createBlockIO() (*spec.LinuxBlockIO, error) {
-// var ret *spec.LinuxBlockIO
-// bio := &spec.LinuxBlockIO{}
-// if c.Resources.BlkioWeight > 0 {
-// ret = bio
-// bio.Weight = &c.Resources.BlkioWeight
-// }
-// if len(c.Resources.BlkioWeightDevice) > 0 {
-// var lwds []spec.LinuxWeightDevice
-// ret = bio
-// for _, i := range c.Resources.BlkioWeightDevice {
-// wd, err := ValidateweightDevice(i)
-// if err != nil {
-// return ret, errors.Wrapf(err, "invalid values for blkio-weight-device")
-// }
-// wdStat, err := GetStatFromPath(wd.Path)
-// if err != nil {
-// return ret, errors.Wrapf(err, "error getting stat from path %q", wd.Path)
-// }
-// lwd := spec.LinuxWeightDevice{
-// Weight: &wd.Weight,
-// }
-// lwd.Major = int64(unix.Major(wdStat.Rdev))
-// lwd.Minor = int64(unix.Minor(wdStat.Rdev))
-// lwds = append(lwds, lwd)
-// }
-// bio.WeightDevice = lwds
-// }
-// if len(c.Resources.DeviceReadBps) > 0 {
-// ret = bio
-// readBps, err := makeThrottleArray(c.Resources.DeviceReadBps, bps)
-// if err != nil {
-// return ret, err
-// }
-// bio.ThrottleReadBpsDevice = readBps
-// }
-// if len(c.Resources.DeviceWriteBps) > 0 {
-// ret = bio
-// writeBpds, err := makeThrottleArray(c.Resources.DeviceWriteBps, bps)
-// if err != nil {
-// return ret, err
-// }
-// bio.ThrottleWriteBpsDevice = writeBpds
-// }
-// if len(c.Resources.DeviceReadIOps) > 0 {
-// ret = bio
-// readIOps, err := makeThrottleArray(c.Resources.DeviceReadIOps, iops)
-// if err != nil {
-// return ret, err
-// }
-// bio.ThrottleReadIOPSDevice = readIOps
-// }
-// if len(c.Resources.DeviceWriteIOps) > 0 {
-// ret = bio
-// writeIOps, err := makeThrottleArray(c.Resources.DeviceWriteIOps, iops)
-// if err != nil {
-// return ret, err
-// }
-// bio.ThrottleWriteIOPSDevice = writeIOps
-// }
-// return ret, nil
-//}
-
-//func makeThrottleArray(throttleInput []string, rateType int) ([]spec.LinuxThrottleDevice, error) {
-// var (
-// ltds []spec.LinuxThrottleDevice
-// t *throttleDevice
-// err error
-// )
-// for _, i := range throttleInput {
-// if rateType == bps {
-// t, err = validateBpsDevice(i)
-// } else {
-// t, err = validateIOpsDevice(i)
-// }
-// if err != nil {
-// return []spec.LinuxThrottleDevice{}, err
-// }
-// ltdStat, err := GetStatFromPath(t.path)
-// if err != nil {
-// return ltds, errors.Wrapf(err, "error getting stat from path %q", t.path)
-// }
-// ltd := spec.LinuxThrottleDevice{
-// Rate: t.rate,
-// }
-// ltd.Major = int64(unix.Major(ltdStat.Rdev))
-// ltd.Minor = int64(unix.Minor(ltdStat.Rdev))
-// ltds = append(ltds, ltd)
-// }
-// return ltds, nil
-//}
diff --git a/pkg/specgen/container_validate.go b/pkg/specgen/container_validate.go
index 75da38c0e..45179343b 100644
--- a/pkg/specgen/container_validate.go
+++ b/pkg/specgen/container_validate.go
@@ -10,7 +10,7 @@ import (
var (
// ErrInvalidSpecConfig describes an error that the given SpecGenerator is invalid
- ErrInvalidSpecConfig error = errors.New("invalid configuration")
+ ErrInvalidSpecConfig = errors.New("invalid configuration")
// SystemDValues describes the only values that SystemD can be
SystemDValues = []string{"true", "false", "always"}
// ImageVolumeModeValues describes the only values that ImageVolumeMode can be
@@ -38,7 +38,7 @@ func (s *SpecGenerator) Validate() error {
}
// systemd values must be true, false, or always
if len(s.ContainerBasicConfig.Systemd) > 0 && !util.StringInSlice(strings.ToLower(s.ContainerBasicConfig.Systemd), SystemDValues) {
- return errors.Wrapf(ErrInvalidSpecConfig, "SystemD values must be one of %s", strings.Join(SystemDValues, ","))
+ return errors.Wrapf(ErrInvalidSpecConfig, "--systemd values must be one of %q", strings.Join(SystemDValues, ", "))
}
//
diff --git a/pkg/specgen/generate/container.go b/pkg/specgen/generate/container.go
index a217125f4..3d70571d5 100644
--- a/pkg/specgen/generate/container.go
+++ b/pkg/specgen/generate/container.go
@@ -194,7 +194,7 @@ func finishThrottleDevices(s *specgen.SpecGenerator) error {
s.ResourceLimits.BlockIO.ThrottleReadIOPSDevice = append(s.ResourceLimits.BlockIO.ThrottleReadIOPSDevice, v)
}
}
- if iops := s.ThrottleWriteBpsDevice; len(iops) > 0 {
+ if iops := s.ThrottleWriteIOPSDevice; len(iops) > 0 {
for k, v := range iops {
statT := unix.Stat_t{}
if err := unix.Stat(k, &statT); err != nil {
diff --git a/pkg/specgen/generate/container_create.go b/pkg/specgen/generate/container_create.go
index 7ddfed339..33075b543 100644
--- a/pkg/specgen/generate/container_create.go
+++ b/pkg/specgen/generate/container_create.go
@@ -3,12 +3,14 @@ package generate
import (
"context"
"os"
+ "path/filepath"
"github.com/containers/common/pkg/config"
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/libpod/image"
"github.com/containers/libpod/pkg/specgen"
+ "github.com/containers/libpod/pkg/util"
"github.com/containers/storage"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@@ -114,7 +116,7 @@ func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGener
}
options = append(options, libpod.WithExitCommand(exitCommandArgs))
- runtimeSpec, err := SpecGenToOCI(ctx, s, rt, rtc, newImage, finalMounts)
+ runtimeSpec, err := SpecGenToOCI(ctx, s, rt, rtc, newImage, finalMounts, pod)
if err != nil {
return nil, err
}
@@ -128,7 +130,41 @@ func createContainerOptions(ctx context.Context, rt *libpod.Runtime, s *specgen.
if s.Stdin {
options = append(options, libpod.WithStdin())
}
- if len(s.Systemd) > 0 {
+
+ useSystemd := false
+ switch s.Systemd {
+ case "always":
+ useSystemd = true
+ case "false":
+ break
+ case "", "true":
+ command := s.Command
+ if len(command) == 0 {
+ command, err = img.Cmd(ctx)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ if len(command) > 0 {
+ if command[0] == "/usr/sbin/init" || command[0] == "/sbin/init" || (filepath.Base(command[0]) == "systemd") {
+ useSystemd = true
+ }
+ }
+ default:
+ return nil, errors.Wrapf(err, "invalid value %q systemd option requires 'true, false, always'", s.Systemd)
+ }
+ if useSystemd {
+ // is StopSignal was not set by the user then set it to systemd
+ // expected StopSigal
+ if s.StopSignal == nil {
+ stopSignal, err := util.ParseSignal("RTMIN+3")
+ if err != nil {
+ return nil, errors.Wrapf(err, "error parsing systemd signal")
+ }
+ s.StopSignal = &stopSignal
+ }
+
options = append(options, libpod.WithSystemd())
}
if len(s.Name) > 0 {
@@ -194,7 +230,7 @@ func createContainerOptions(ctx context.Context, rt *libpod.Runtime, s *specgen.
options = append(options, libpod.WithPrivileged(s.Privileged))
// Get namespace related options
- namespaceOptions, err := GenerateNamespaceOptions(ctx, s, rt, pod, img)
+ namespaceOptions, err := namespaceOptions(ctx, s, rt, pod, img)
if err != nil {
return nil, err
}
diff --git a/pkg/specgen/generate/namespaces.go b/pkg/specgen/generate/namespaces.go
index 138d9e0cd..e67afe1bf 100644
--- a/pkg/specgen/generate/namespaces.go
+++ b/pkg/specgen/generate/namespaces.go
@@ -72,13 +72,13 @@ func GetDefaultNamespaceMode(nsType string, cfg *config.Config, pod *libpod.Pod)
return toReturn, errors.Wrapf(define.ErrInvalidArg, "invalid namespace type %q passed", nsType)
}
-// GenerateNamespaceOptions generates container creation options for all
+// namespaceOptions generates container creation options for all
// namespaces in a SpecGenerator.
// Pod is the pod the container will join. May be nil is the container is not
// joining a pod.
// TODO: Consider grouping options that are not directly attached to a namespace
// elsewhere.
-func GenerateNamespaceOptions(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runtime, pod *libpod.Pod, img *image.Image) ([]libpod.CtrCreateOption, error) {
+func namespaceOptions(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runtime, pod *libpod.Pod, img *image.Image) ([]libpod.CtrCreateOption, error) {
toReturn := []libpod.CtrCreateOption{}
// If pod is not nil, get infra container.
@@ -265,7 +265,7 @@ func GenerateNamespaceOptions(ctx context.Context, s *specgen.SpecGenerator, rt
return toReturn, nil
}
-func specConfigureNamespaces(s *specgen.SpecGenerator, g *generate.Generator, rt *libpod.Runtime) error {
+func specConfigureNamespaces(s *specgen.SpecGenerator, g *generate.Generator, rt *libpod.Runtime, pod *libpod.Pod) error {
// PID
switch s.PidNS.NSMode {
case specgen.Path:
@@ -326,6 +326,8 @@ func specConfigureNamespaces(s *specgen.SpecGenerator, g *generate.Generator, rt
hostname := s.Hostname
if hostname == "" {
switch {
+ case s.UtsNS.NSMode == specgen.FromPod:
+ hostname = pod.Hostname()
case s.UtsNS.NSMode == specgen.FromContainer:
utsCtr, err := rt.LookupContainer(s.UtsNS.Value)
if err != nil {
diff --git a/pkg/specgen/generate/oci.go b/pkg/specgen/generate/oci.go
index 11b18e2d0..266abd28d 100644
--- a/pkg/specgen/generate/oci.go
+++ b/pkg/specgen/generate/oci.go
@@ -118,7 +118,7 @@ func makeCommand(ctx context.Context, s *specgen.SpecGenerator, img *image.Image
return finalCommand, nil
}
-func SpecGenToOCI(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runtime, rtc *config.Config, newImage *image.Image, mounts []spec.Mount) (*spec.Spec, error) {
+func SpecGenToOCI(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runtime, rtc *config.Config, newImage *image.Image, mounts []spec.Mount, pod *libpod.Pod) (*spec.Spec, error) {
var (
inUserNS bool
)
@@ -300,7 +300,7 @@ func SpecGenToOCI(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runt
}
// NAMESPACES
- if err := specConfigureNamespaces(s, &g, rt); err != nil {
+ if err := specConfigureNamespaces(s, &g, rt, pod); err != nil {
return nil, err
}
configSpec := g.Config
diff --git a/pkg/specgen/pod_validate.go b/pkg/specgen/pod_validate.go
index 640447e71..2d57cdb91 100644
--- a/pkg/specgen/pod_validate.go
+++ b/pkg/specgen/pod_validate.go
@@ -7,7 +7,7 @@ import (
var (
// ErrInvalidPodSpecConfig describes an error given when the podspecgenerator is invalid
- ErrInvalidPodSpecConfig error = errors.New("invalid pod spec")
+ ErrInvalidPodSpecConfig = errors.New("invalid pod spec")
// containerConfig has the default configurations defined in containers.conf
containerConfig = util.DefaultContainerConfig()
)
diff --git a/pkg/systemd/generate/systemdgen_test.go b/pkg/systemd/generate/systemdgen_test.go
index 3269405a6..cc5db5e24 100644
--- a/pkg/systemd/generate/systemdgen_test.go
+++ b/pkg/systemd/generate/systemdgen_test.go
@@ -170,7 +170,7 @@ Type=forking
[Install]
WantedBy=multi-user.target default.target`
- goodIdNew := `# container-639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401.service
+ goodIDNew := `# container-639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401.service
# autogenerated by Podman CI
[Unit]
@@ -323,7 +323,7 @@ WantedBy=multi-user.target default.target`
New: true,
CreateCommand: []string{"I'll get stripped", "container", "run", "awesome-image:latest"},
},
- goodIdNew,
+ goodIDNew,
false,
},
}
diff --git a/pkg/trust/config.go b/pkg/trust/config.go
index 0bafc722b..164df2a90 100644
--- a/pkg/trust/config.go
+++ b/pkg/trust/config.go
@@ -1,7 +1,7 @@
package trust
-// Trust Policy describes a basic trust policy configuration
-type TrustPolicy struct {
+// Policy describes a basic trust policy configuration
+type Policy struct {
Name string `json:"name"`
RepoName string `json:"repo_name,omitempty"`
Keys []string `json:"keys,omitempty"`
diff --git a/pkg/varlinkapi/create.go b/pkg/varlinkapi/create.go
index 571ce6115..d921130e7 100644
--- a/pkg/varlinkapi/create.go
+++ b/pkg/varlinkapi/create.go
@@ -220,7 +220,7 @@ func CreateContainer(ctx context.Context, c *GenericCLIResults, runtime *libpod.
}
}
- ctr, err := CreateContainerFromCreateConfig(runtime, createConfig, ctx, pod)
+ ctr, err := CreateContainerFromCreateConfig(ctx, runtime, createConfig, pod)
if err != nil {
return nil, nil, err
}
@@ -909,7 +909,7 @@ func ParseCreateOpts(ctx context.Context, c *GenericCLIResults, runtime *libpod.
return config, nil
}
-func CreateContainerFromCreateConfig(r *libpod.Runtime, createConfig *cc.CreateConfig, ctx context.Context, pod *libpod.Pod) (*libpod.Container, error) {
+func CreateContainerFromCreateConfig(ctx context.Context, r *libpod.Runtime, createConfig *cc.CreateConfig, pod *libpod.Pod) (*libpod.Container, error) {
runtimeSpec, options, err := createConfig.MakeContainerConfig(r, pod)
if err != nil {
return nil, err
diff --git a/pkg/varlinkapi/volumes.go b/pkg/varlinkapi/volumes.go
index aa0eb1fb5..3b6276287 100644
--- a/pkg/varlinkapi/volumes.go
+++ b/pkg/varlinkapi/volumes.go
@@ -25,7 +25,7 @@ func (i *VarlinkAPI) VolumeCreate(call iopodman.VarlinkCall, options iopodman.Vo
volumeOptions = append(volumeOptions, libpod.WithVolumeLabels(options.Labels))
}
if len(options.Options) > 0 {
- parsedOptions, err := parse.ParseVolumeOptions(options.Options)
+ parsedOptions, err := parse.VolumeOptions(options.Options)
if err != nil {
return call.ReplyErrorOccurred(err.Error())
}
diff --git a/test/apiv2/20-containers.at b/test/apiv2/20-containers.at
index 7fb39b221..60f6d97aa 100644
--- a/test/apiv2/20-containers.at
+++ b/test/apiv2/20-containers.at
@@ -19,7 +19,7 @@ t GET libpod/containers/json 200 length=0
t GET libpod/containers/json?all=true 200 \
length=1 \
- .[0].Id~[0-9a-f]\\{12\\} \
+ .[0].Id~[0-9a-f]\\{64\\} \
.[0].Image=$IMAGE \
.[0].Command[0]="true" \
.[0].State~\\\(exited\\\|stopped\\\) \
@@ -30,4 +30,56 @@ cid=$(jq -r '.[0].Id' <<<"$output")
t DELETE libpod/containers/$cid 204
+CNAME=myfoo
+podman run --name $CNAME $IMAGE -td top
+t GET libpod/containers/json?all=true 200 \
+ .[0].Id~[0-9a-f]\\{64\\}
+cid=$(jq -r '.[0].Id' <<<"$output")
+
+# No such container
+t POST "libpod/commit?container=nonesuch" '' 404
+
+# Comment can only be used with docker format, not OCI
+cparam="repo=newrepo&comment=foo&author=bob"
+t POST "libpod/commit?container=$CNAME&$cparam" '' 500
+
+# Commit a new image from the container
+t POST "libpod/commit?container=$CNAME" '' 200 \
+ .Id~[0-9a-f]\\{64\\}
+iid=$(jq -r '.Id' <<<"$output")
+t GET libpod/images/$iid/json 200 \
+ .RepoTags[0]=null \
+ .Author="" \
+ .Comment=""
+
+# Commit a new image w/o tag
+cparam="repo=newrepo&comment=foo&author=bob&format=docker"
+t POST "libpod/commit?container=$CNAME&$cparam" '' 200
+t GET libpod/images/newrepo:latest/json 200 \
+ .RepoTags[0]=localhost/newrepo:latest \
+ .Author=bob \
+ .Comment=foo
+
+# Commit a new image w/ specified tag and author
+cparam="repo=newrepo&tag=v1&author=alice"
+t POST "libpod/commit?container=$cid&$cparam&pause=false" '' 200
+t GET libpod/images/newrepo:v1/json 200 \
+ .RepoTags[0]=localhost/newrepo:v1 \
+ .Author=alice
+
+# Commit a new image w/ full parameters
+cparam="repo=newrepo&tag=v2&comment=bar&author=eric"
+cparam="$cparam&format=docker&changes=CMD=/bin/foo"
+t POST "libpod/commit?container=${cid:0:12}&$cparam&pause=true" '' 200
+t GET libpod/images/newrepo:v2/json 200 \
+ .RepoTags[0]=localhost/newrepo:v2 \
+ .Author=eric \
+ .Comment=bar \
+ .Config.Cmd[-1]="/bin/foo"
+
+t DELETE images/localhost/newrepo:latest?force=true 200
+t DELETE images/localhost/newrepo:v1?force=true 200
+t DELETE images/localhost/newrepo:v2?force=true 200
+t DELETE libpod/containers/$cid 204
+
# vim: filetype=sh
diff --git a/test/dockerpy/README.md b/test/dockerpy/README.md
new file mode 100644
index 000000000..32e426d58
--- /dev/null
+++ b/test/dockerpy/README.md
@@ -0,0 +1,30 @@
+# Dockerpy regression test
+
+Python test suite to validate Podman endpoints using dockerpy library
+
+Running tests
+=============
+To run the tests locally in your sandbox:
+
+#### Run the entire test
+
+```
+sudo PYTHONPATH=/usr/bin/python python -m dockerpy.images
+```
+
+Passing the -v option to your test script will instruct unittest.main() to enable a higher level of verbosity, and produce detailed output:
+
+```
+sudo PYTHONPATH=/usr/bin/python python -m unittest -v dockerpy.images
+```
+#### Run a specific test class
+
+```
+sudo PYTHONPATH=/usr/bin/python python -m unittest -v dockerpy.images.TestImages
+```
+
+#### Run a specific test within the test class
+
+```
+sudo PYTHONPATH=/usr/bin/python python -m unittest -v dockerpy.images.TestImages.test_list_images
+```
diff --git a/test/dockerpy/__init__.py b/test/dockerpy/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/test/dockerpy/__init__.py
diff --git a/test/dockerpy/common.py b/test/dockerpy/common.py
new file mode 100644
index 000000000..fdacb49be
--- /dev/null
+++ b/test/dockerpy/common.py
@@ -0,0 +1,68 @@
+import docker
+import subprocess
+import os
+import sys
+import time
+from docker import Client
+from . import constant
+
+alpineDict = {
+ "name": "docker.io/library/alpine:latest",
+ "shortName": "alpine",
+ "tarballName": "alpine.tar"}
+
+def get_client():
+ client = docker.Client(base_url="http://localhost:8080",timeout=15)
+ return client
+
+client = get_client()
+
+def podman():
+ binary = os.getenv("PODMAN_BINARY")
+ if binary is None:
+ binary = "bin/podman"
+ return binary
+
+def restore_image_from_cache():
+ client.load_image(constant.ImageCacheDir+alpineDict["tarballName"])
+
+def run_top_container():
+ client.pull(constant.ALPINE)
+ c = client.create_container(constant.ALPINE,name=constant.TOP)
+ client.start(container=c.get("Id"))
+
+def enable_sock(TestClass):
+ TestClass.podman = subprocess.Popen(
+ [
+ podman(), "system", "service", "tcp:localhost:8080",
+ "--log-level=debug", "--time=0"
+ ],
+ shell=False,
+ stdin=subprocess.DEVNULL,
+ stdout=subprocess.DEVNULL,
+ stderr=subprocess.DEVNULL,
+ )
+ time.sleep(2)
+
+def terminate_connection(TestClass):
+ TestClass.podman.terminate()
+ stdout, stderr = TestClass.podman.communicate(timeout=0.5)
+ if stdout:
+ print("\nService Stdout:\n" + stdout.decode('utf-8'))
+ if stderr:
+ print("\nService Stderr:\n" + stderr.decode('utf-8'))
+
+ if TestClass.podman.returncode > 0:
+ sys.stderr.write("podman exited with error code {}\n".format(
+ TestClass.podman.returncode))
+ sys.exit(2)
+
+def remove_all_containers():
+ containers = client.containers(quiet=True)
+ for c in containers:
+ client.remove_container(container=c.get("Id"), force=True)
+
+def remove_all_images():
+ allImages = client.images()
+ for image in allImages:
+ client.remove_image(image,force=True)
diff --git a/test/dockerpy/constant.py b/test/dockerpy/constant.py
new file mode 100644
index 000000000..8a3f1d984
--- /dev/null
+++ b/test/dockerpy/constant.py
@@ -0,0 +1,13 @@
+BB = "docker.io/library/busybox:latest"
+NGINX = "docker.io/library/nginx:latest"
+ALPINE = "docker.io/library/alpine:latest"
+ALPINE_SHORTNAME = "alpine"
+ALPINELISTTAG = "docker.io/library/alpine:3.10.2"
+ALPINELISTDIGEST = "docker.io/library/alpine@sha256:72c42ed48c3a2db31b7dafe17d275b634664a708d901ec9fd57b1529280f01fb"
+ALPINEAMD64DIGEST = "docker.io/library/alpine@sha256:acd3ca9941a85e8ed16515bfc5328e4e2f8c128caa72959a58a127b7801ee01f"
+ALPINEAMD64ID = "961769676411f082461f9ef46626dd7a2d1e2b2a38e6a44364bcbecf51e66dd4"
+ALPINEARM64DIGEST = "docker.io/library/alpine@sha256:db7f3dcef3d586f7dd123f107c93d7911515a5991c4b9e51fa2a43e46335a43e"
+ALPINEARM64ID = "915beeae46751fc564998c79e73a1026542e945ca4f73dc841d09ccc6c2c0672"
+infra = "k8s.gcr.io/pause:3.2"
+TOP = "top"
+ImageCacheDir = "/tmp/podman/imagecachedir"
diff --git a/test/dockerpy/containers.py b/test/dockerpy/containers.py
new file mode 100644
index 000000000..d70ec932c
--- /dev/null
+++ b/test/dockerpy/containers.py
@@ -0,0 +1,46 @@
+
+import unittest
+import docker
+import requests
+import os
+from docker import Client
+from . import constant
+from . import common
+
+client = common.get_client()
+
+class TestContainers(unittest.TestCase):
+
+ podman = None
+
+ def setUp(self):
+ super().setUp()
+ common.run_top_container()
+
+ def tearDown(self):
+ common.remove_all_containers()
+ common.remove_all_images()
+ return super().tearDown()
+
+ @classmethod
+ def setUpClass(cls):
+ super().setUpClass()
+ common.enable_sock(cls)
+
+ @classmethod
+ def tearDownClass(cls):
+ common.terminate_connection(cls)
+ return super().tearDownClass()
+
+ def test_inspect_container(self):
+ # Inspect bogus container
+ with self.assertRaises(requests.HTTPError):
+ client.inspect_container("dummy")
+ # Inspect valid container
+ container = client.inspect_container(constant.TOP)
+ self.assertIn(constant.TOP , container["Name"])
+
+
+if __name__ == '__main__':
+ # Setup temporary space
+ unittest.main()
diff --git a/test/dockerpy/images.py b/test/dockerpy/images.py
new file mode 100644
index 000000000..1e07d25c7
--- /dev/null
+++ b/test/dockerpy/images.py
@@ -0,0 +1,151 @@
+
+import unittest
+import docker
+import requests
+import os
+from docker import Client
+from . import constant
+from . import common
+
+client = common.get_client()
+
+class TestImages(unittest.TestCase):
+
+ podman = None
+ def setUp(self):
+ super().setUp()
+ client.pull(constant.ALPINE)
+
+ def tearDown(self):
+ common.remove_all_images()
+ return super().tearDown()
+
+ @classmethod
+ def setUpClass(cls):
+ super().setUpClass()
+ common.enable_sock(cls)
+
+
+ @classmethod
+ def tearDownClass(cls):
+ common.terminate_connection(cls)
+ return super().tearDownClass()
+
+
+# Inspect Image
+
+ def test_inspect_image(self):
+ # Check for error with wrong image name
+ with self.assertRaises(requests.HTTPError):
+ client.inspect_image("dummy")
+ alpine_image = client.inspect_image(constant.ALPINE)
+ self.assertIn(constant.ALPINE, alpine_image["RepoTags"])
+
+# Tag Image
+
+ # Validates if invalid image name is given a bad response is encountered.
+ def test_tag_invalid_image(self):
+ with self.assertRaises(requests.HTTPError):
+ client.tag("dummy","demo")
+
+
+
+ # Validates if the image is tagged successfully.
+ def test_tag_valid_image(self):
+ client.tag(constant.ALPINE,"demo",constant.ALPINE_SHORTNAME)
+ alpine_image = client.inspect_image(constant.ALPINE)
+ for x in alpine_image["RepoTags"]:
+ if("demo:alpine" in x):
+ self.assertTrue
+ self.assertFalse
+
+ # Validates if name updates when the image is retagged.
+ @unittest.skip("dosent work now")
+ def test_retag_valid_image(self):
+ client.tag(constant.ALPINE_SHORTNAME, "demo","rename")
+ alpine_image = client.inspect_image(constant.ALPINE)
+ self.assertNotIn("demo:test", alpine_image["RepoTags"])
+
+# List Image
+ # List All Images
+ def test_list_images(self):
+ allImages = client.images()
+ self.assertEqual(len(allImages), 1)
+ # Add more images
+ client.pull(constant.BB)
+ client.pull(constant.NGINX)
+ allImages = client.images()
+ self.assertEqual(len(allImages) , 3)
+
+
+ # List images with filter
+ filters = {'reference':'alpine'}
+ allImages = client.images(filters = filters)
+ self.assertEqual(len(allImages) , 1)
+
+# Search Image
+ def test_search_image(self):
+ response = client.search("alpine")
+ for i in response:
+ # Alpine found
+ if "docker.io/library/alpine" in i["Name"]:
+ self.assertTrue
+ self.assertFalse
+
+# Image Exist (No docker-py support yet)
+
+# Remove Image
+ def test_remove_image(self):
+ # Check for error with wrong image name
+ with self.assertRaises(requests.HTTPError):
+ client.remove_image("dummy")
+ allImages = client.images()
+ self.assertEqual(len(allImages) , 1)
+ alpine_image = client.inspect_image(constant.ALPINE)
+ client.remove_image(alpine_image)
+ allImages = client.images()
+ self.assertEqual(len(allImages) , 0)
+
+# Image History
+ def test_image_history(self):
+ # Check for error with wrong image name
+ with self.assertRaises(requests.HTTPError):
+ client.remove_image("dummy")
+ imageHistory = client.history(constant.ALPINE)
+ alpine_image = client.inspect_image(constant.ALPINE)
+ for h in imageHistory:
+ if h["Id"] in alpine_image["Id"]:
+ self.assertTrue
+ self.assertFalse
+
+# Prune Image (No docker-py support yet)
+
+# Export Image
+
+ def test_export_image(self):
+ client.pull(constant.BB)
+ file = os.path.join(constant.ImageCacheDir , "busybox.tar")
+ if not os.path.exists(constant.ImageCacheDir):
+ os.makedirs(constant.ImageCacheDir)
+ # Check for error with wrong image name
+ with self.assertRaises(requests.HTTPError):
+ client.get_image("dummy")
+ response = client.get_image(constant.BB)
+ image_tar = open(file,mode="wb")
+ image_tar.write(response.data)
+ image_tar.close()
+ os.stat(file)
+
+# Import|Load Image
+
+ def test_import_image(self):
+ allImages = client.images()
+ self.assertEqual(len(allImages), 1)
+ file = os.path.join(constant.ImageCacheDir , "busybox.tar")
+ client.import_image_from_file(filename=file)
+ allImages = client.images()
+ self.assertEqual(len(allImages), 2)
+
+if __name__ == '__main__':
+ # Setup temporary space
+ unittest.main()
diff --git a/test/e2e/checkpoint_test.go b/test/e2e/checkpoint_test.go
index e6a3d2f7a..663205209 100644
--- a/test/e2e/checkpoint_test.go
+++ b/test/e2e/checkpoint_test.go
@@ -232,6 +232,8 @@ var _ = Describe("Podman checkpoint", func() {
})
It("podman checkpoint container with established tcp connections", func() {
+ // Broken on Ubuntu.
+ SkipIfNotFedora()
localRunString := getRunString([]string{redis})
session := podmanTest.Podman(localRunString)
session.WaitWithDefaultTimeout()
diff --git a/test/e2e/cp_test.go b/test/e2e/cp_test.go
index f95f8646c..6ae54ba34 100644
--- a/test/e2e/cp_test.go
+++ b/test/e2e/cp_test.go
@@ -141,6 +141,8 @@ var _ = Describe("Podman cp", func() {
})
It("podman cp stdin/stdout", func() {
+ SkipIfRemote()
+ Skip("Looks like SkipIfRemote() is not working")
session := podmanTest.Podman([]string{"create", ALPINE, "ls", "foo"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
diff --git a/test/e2e/create_test.go b/test/e2e/create_test.go
index 0a6373bfa..f40472a7c 100644
--- a/test/e2e/create_test.go
+++ b/test/e2e/create_test.go
@@ -301,7 +301,6 @@ var _ = Describe("Podman create", func() {
})
It("podman create --authfile with nonexist authfile", func() {
- SkipIfRemote()
session := podmanTest.PodmanNoCache([]string{"create", "--authfile", "/tmp/nonexist", "--name=foo", ALPINE})
session.WaitWithDefaultTimeout()
Expect(session).To(Not(Equal(0)))
diff --git a/test/e2e/diff_test.go b/test/e2e/diff_test.go
index d273f9463..fbbe49eac 100644
--- a/test/e2e/diff_test.go
+++ b/test/e2e/diff_test.go
@@ -61,7 +61,6 @@ var _ = Describe("Podman diff", func() {
})
It("podman diff container and committed image", func() {
- SkipIfRemote()
session := podmanTest.Podman([]string{"run", "--name=diff-test", ALPINE, "touch", "/tmp/diff-test"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
@@ -82,11 +81,10 @@ var _ = Describe("Podman diff", func() {
})
It("podman diff latest container", func() {
- SkipIfRemote()
- session := podmanTest.Podman([]string{"run", "--name=diff-test", ALPINE, "touch", "/tmp/diff-test"})
+ session := podmanTest.Podman([]string{"run", "--name", "diff-test", ALPINE, "touch", "/tmp/diff-test"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- session = podmanTest.Podman([]string{"diff", "-l"})
+ session = podmanTest.Podman([]string{"diff", "diff-test"})
session.WaitWithDefaultTimeout()
containerDiff := session.OutputToStringArray()
sort.Strings(containerDiff)
diff --git a/test/e2e/exists_test.go b/test/e2e/exists_test.go
index e26fad51d..8f3b371d8 100644
--- a/test/e2e/exists_test.go
+++ b/test/e2e/exists_test.go
@@ -112,7 +112,6 @@ var _ = Describe("Podman image|container exists", func() {
})
It("podman pod does not exist in local storage", func() {
// The exit code for non-existing pod is incorrect (125 vs 1)
- SkipIfRemote()
session := podmanTest.Podman([]string{"pod", "exists", "foobar"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(1))
diff --git a/test/e2e/generate_kube_test.go b/test/e2e/generate_kube_test.go
index 395cc1ea4..7872a9fbf 100644
--- a/test/e2e/generate_kube_test.go
+++ b/test/e2e/generate_kube_test.go
@@ -254,6 +254,8 @@ var _ = Describe("Podman generate kube", func() {
})
It("podman generate with user and reimport kube on pod", func() {
+ // This test fails on ubuntu due to https://github.com/seccomp/containers-golang/pull/27
+ SkipIfNotFedora()
podName := "toppod"
_, rc, _ := podmanTest.CreatePod(podName)
Expect(rc).To(Equal(0))
diff --git a/test/e2e/healthcheck_run_test.go b/test/e2e/healthcheck_run_test.go
index 8e63d9f4c..d8e3f045f 100644
--- a/test/e2e/healthcheck_run_test.go
+++ b/test/e2e/healthcheck_run_test.go
@@ -42,7 +42,6 @@ var _ = Describe("Podman healthcheck run", func() {
})
It("podman disable healthcheck with --no-healthcheck on valid container", func() {
- SkipIfRemote()
session := podmanTest.Podman([]string{"run", "-dt", "--no-healthcheck", "--name", "hc", healthcheck})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
@@ -52,7 +51,6 @@ var _ = Describe("Podman healthcheck run", func() {
})
It("podman disable healthcheck with --health-cmd=none on valid container", func() {
- SkipIfRemote()
session := podmanTest.Podman([]string{"run", "-dt", "--health-cmd", "none", "--name", "hc", healthcheck})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
diff --git a/test/e2e/inspect_test.go b/test/e2e/inspect_test.go
index 77cfe4fd3..62f69f1c1 100644
--- a/test/e2e/inspect_test.go
+++ b/test/e2e/inspect_test.go
@@ -132,28 +132,27 @@ var _ = Describe("Podman inspect", func() {
})
It("podman inspect with mount filters", func() {
- SkipIfRemote()
- ctrSession := podmanTest.Podman([]string{"create", "-v", "/tmp:/test1", ALPINE, "top"})
+ ctrSession := podmanTest.Podman([]string{"create", "--name", "test", "-v", "/tmp:/test1", ALPINE, "top"})
ctrSession.WaitWithDefaultTimeout()
Expect(ctrSession.ExitCode()).To(Equal(0))
- inspectSource := podmanTest.Podman([]string{"inspect", "-l", "--format", "{{(index .Mounts 0).Source}}"})
+ inspectSource := podmanTest.Podman([]string{"inspect", "test", "--format", "{{(index .Mounts 0).Source}}"})
inspectSource.WaitWithDefaultTimeout()
Expect(inspectSource.ExitCode()).To(Equal(0))
Expect(inspectSource.OutputToString()).To(Equal("/tmp"))
- inspectSrc := podmanTest.Podman([]string{"inspect", "-l", "--format", "{{(index .Mounts 0).Src}}"})
+ inspectSrc := podmanTest.Podman([]string{"inspect", "test", "--format", "{{(index .Mounts 0).Src}}"})
inspectSrc.WaitWithDefaultTimeout()
Expect(inspectSrc.ExitCode()).To(Equal(0))
Expect(inspectSrc.OutputToString()).To(Equal("/tmp"))
- inspectDestination := podmanTest.Podman([]string{"inspect", "-l", "--format", "{{(index .Mounts 0).Destination}}"})
+ inspectDestination := podmanTest.Podman([]string{"inspect", "test", "--format", "{{(index .Mounts 0).Destination}}"})
inspectDestination.WaitWithDefaultTimeout()
Expect(inspectDestination.ExitCode()).To(Equal(0))
Expect(inspectDestination.OutputToString()).To(Equal("/test1"))
- inspectDst := podmanTest.Podman([]string{"inspect", "-l", "--format", "{{(index .Mounts 0).Dst}}"})
+ inspectDst := podmanTest.Podman([]string{"inspect", "test", "--format", "{{(index .Mounts 0).Dst}}"})
inspectDst.WaitWithDefaultTimeout()
Expect(inspectDst.ExitCode()).To(Equal(0))
Expect(inspectDst.OutputToString()).To(Equal("/test1"))
@@ -171,4 +170,57 @@ var _ = Describe("Podman inspect", func() {
Expect(imageData[0].HealthCheck.Interval).To(BeNumerically("==", 60000000000))
Expect(imageData[0].HealthCheck.Test).To(Equal([]string{"CMD-SHELL", "curl -f http://localhost/ || exit 1"}))
})
+
+ It("podman inspect --latest with no container fails", func() {
+ SkipIfRemote()
+
+ session := podmanTest.Podman([]string{"inspect", "--latest"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Not(Equal(0)))
+ })
+
+ It("podman [image,container] inspect on image", func() {
+ baseInspect := podmanTest.Podman([]string{"inspect", ALPINE})
+ baseInspect.WaitWithDefaultTimeout()
+ Expect(baseInspect.ExitCode()).To(Equal(0))
+ baseJSON := baseInspect.InspectImageJSON()
+ Expect(len(baseJSON)).To(Equal(1))
+
+ ctrInspect := podmanTest.Podman([]string{"container", "inspect", ALPINE})
+ ctrInspect.WaitWithDefaultTimeout()
+ Expect(ctrInspect.ExitCode()).To(Not(Equal(0)))
+
+ imageInspect := podmanTest.Podman([]string{"image", "inspect", ALPINE})
+ imageInspect.WaitWithDefaultTimeout()
+ Expect(imageInspect.ExitCode()).To(Equal(0))
+ imageJSON := imageInspect.InspectImageJSON()
+ Expect(len(imageJSON)).To(Equal(1))
+
+ Expect(baseJSON[0].ID).To(Equal(imageJSON[0].ID))
+ })
+
+ It("podman [image, container] inspect on container", func() {
+ ctrName := "testCtr"
+ create := podmanTest.Podman([]string{"create", "--name", ctrName, ALPINE, "sh"})
+ create.WaitWithDefaultTimeout()
+ Expect(create.ExitCode()).To(Equal(0))
+
+ baseInspect := podmanTest.Podman([]string{"inspect", ctrName})
+ baseInspect.WaitWithDefaultTimeout()
+ Expect(baseInspect.ExitCode()).To(Equal(0))
+ baseJSON := baseInspect.InspectContainerToJSON()
+ Expect(len(baseJSON)).To(Equal(1))
+
+ ctrInspect := podmanTest.Podman([]string{"container", "inspect", ctrName})
+ ctrInspect.WaitWithDefaultTimeout()
+ Expect(ctrInspect.ExitCode()).To(Equal(0))
+ ctrJSON := ctrInspect.InspectContainerToJSON()
+ Expect(len(ctrJSON)).To(Equal(1))
+
+ imageInspect := podmanTest.Podman([]string{"image", "inspect", ctrName})
+ imageInspect.WaitWithDefaultTimeout()
+ Expect(imageInspect.ExitCode()).To(Not(Equal(0)))
+
+ Expect(baseJSON[0].ID).To(Equal(ctrJSON[0].ID))
+ })
})
diff --git a/test/e2e/libpod_suite_remote_test.go b/test/e2e/libpod_suite_remote_test.go
index dde853413..b94b6e267 100644
--- a/test/e2e/libpod_suite_remote_test.go
+++ b/test/e2e/libpod_suite_remote_test.go
@@ -36,7 +36,7 @@ func SkipIfRootlessV2() {
// Podman is the exec call to podman on the filesystem
func (p *PodmanTestIntegration) Podman(args []string) *PodmanSessionIntegration {
- var remoteArgs = []string{"--remote", p.RemoteSocket}
+ var remoteArgs = []string{"--remote", "--url", p.RemoteSocket}
remoteArgs = append(remoteArgs, args...)
podmanSession := p.PodmanBase(remoteArgs, false, false)
return &PodmanSessionIntegration{podmanSession}
@@ -44,7 +44,7 @@ func (p *PodmanTestIntegration) Podman(args []string) *PodmanSessionIntegration
// PodmanExtraFiles is the exec call to podman on the filesystem and passes down extra files
func (p *PodmanTestIntegration) PodmanExtraFiles(args []string, extraFiles []*os.File) *PodmanSessionIntegration {
- var remoteArgs = []string{"--remote", p.RemoteSocket}
+ var remoteArgs = []string{"--remote", "--url", p.RemoteSocket}
remoteArgs = append(remoteArgs, args...)
podmanSession := p.PodmanAsUserBase(remoteArgs, 0, 0, "", nil, false, false, extraFiles)
return &PodmanSessionIntegration{podmanSession}
@@ -52,7 +52,7 @@ func (p *PodmanTestIntegration) PodmanExtraFiles(args []string, extraFiles []*os
// PodmanNoCache calls podman with out adding the imagecache
func (p *PodmanTestIntegration) PodmanNoCache(args []string) *PodmanSessionIntegration {
- var remoteArgs = []string{"--remote", p.RemoteSocket}
+ var remoteArgs = []string{"--remote", "--url", p.RemoteSocket}
remoteArgs = append(remoteArgs, args...)
podmanSession := p.PodmanBase(remoteArgs, false, true)
return &PodmanSessionIntegration{podmanSession}
diff --git a/test/e2e/pod_create_test.go b/test/e2e/pod_create_test.go
index e56db54a2..a7d5783cb 100644
--- a/test/e2e/pod_create_test.go
+++ b/test/e2e/pod_create_test.go
@@ -238,7 +238,6 @@ var _ = Describe("Podman pod create", func() {
})
It("podman create pod with IP address", func() {
- SkipIfRemote()
SkipIfRootless()
name := "test"
ip := GetRandomIPAddress()
diff --git a/test/e2e/pod_rm_test.go b/test/e2e/pod_rm_test.go
index e10b3c98f..4060e1268 100644
--- a/test/e2e/pod_rm_test.go
+++ b/test/e2e/pod_rm_test.go
@@ -213,7 +213,6 @@ var _ = Describe("Podman pod rm", func() {
})
It("podman rm --ignore bogus pod and a running pod", func() {
- SkipIfRemote()
_, ec, podid1 := podmanTest.CreatePod("")
Expect(ec).To(Equal(0))
diff --git a/test/e2e/pod_stats_test.go b/test/e2e/pod_stats_test.go
index 9bba59073..778b44d1e 100644
--- a/test/e2e/pod_stats_test.go
+++ b/test/e2e/pod_stats_test.go
@@ -178,4 +178,21 @@ var _ = Describe("Podman pod stats", func() {
Expect(stats).To(ExitWithError())
})
+ It("podman stats on net=host post", func() {
+ // --net=host not supported for rootless pods at present
+ SkipIfRootless()
+ podName := "testPod"
+ podCreate := podmanTest.Podman([]string{"pod", "create", "--net=host", "--name", podName})
+ podCreate.WaitWithDefaultTimeout()
+ Expect(podCreate.ExitCode()).To(Equal(0))
+
+ ctrRun := podmanTest.Podman([]string{"run", "-d", "--pod", podName, ALPINE, "top"})
+ ctrRun.WaitWithDefaultTimeout()
+ Expect(ctrRun.ExitCode()).To(Equal(0))
+
+ stats := podmanTest.Podman([]string{"pod", "stats", "--format", "json", "--no-stream", podName})
+ stats.WaitWithDefaultTimeout()
+ Expect(stats.ExitCode()).To(Equal(0))
+ Expect(stats.IsJSONOutputValid()).To(BeTrue())
+ })
})
diff --git a/test/e2e/pod_stop_test.go b/test/e2e/pod_stop_test.go
index 298f3da2f..0a46b07c9 100644
--- a/test/e2e/pod_stop_test.go
+++ b/test/e2e/pod_stop_test.go
@@ -39,7 +39,6 @@ var _ = Describe("Podman pod stop", func() {
})
It("podman pod stop --ignore bogus pod", func() {
- SkipIfRemote()
session := podmanTest.Podman([]string{"pod", "stop", "--ignore", "123"})
session.WaitWithDefaultTimeout()
@@ -60,7 +59,6 @@ var _ = Describe("Podman pod stop", func() {
})
It("podman stop --ignore bogus pod and a running pod", func() {
- SkipIfRemote()
_, ec, podid1 := podmanTest.CreatePod("")
Expect(ec).To(Equal(0))
diff --git a/test/e2e/ps_test.go b/test/e2e/ps_test.go
index 12ce4661f..0dc8e01af 100644
--- a/test/e2e/ps_test.go
+++ b/test/e2e/ps_test.go
@@ -362,8 +362,6 @@ var _ = Describe("Podman ps", func() {
})
It("podman --pod with a non-empty pod name", func() {
- SkipIfRemote()
-
podName := "testPodName"
_, ec, podid := podmanTest.CreatePod(podName)
Expect(ec).To(Equal(0))
diff --git a/test/e2e/pull_test.go b/test/e2e/pull_test.go
index 96340ef30..ac882927f 100644
--- a/test/e2e/pull_test.go
+++ b/test/e2e/pull_test.go
@@ -351,7 +351,6 @@ var _ = Describe("Podman pull", func() {
})
It("podman pull from docker with nonexist --authfile", func() {
- SkipIfRemote()
session := podmanTest.PodmanNoCache([]string{"pull", "--authfile", "/tmp/nonexist", ALPINE})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Not(Equal(0)))
diff --git a/test/e2e/rm_test.go b/test/e2e/rm_test.go
index 87e3de922..d0dbd527a 100644
--- a/test/e2e/rm_test.go
+++ b/test/e2e/rm_test.go
@@ -141,7 +141,6 @@ var _ = Describe("Podman rm", func() {
})
It("podman rm --cidfile", func() {
- SkipIfRemote()
tmpDir, err := ioutil.TempDir("", "")
Expect(err).To(BeNil())
@@ -164,7 +163,6 @@ var _ = Describe("Podman rm", func() {
})
It("podman rm multiple --cidfile", func() {
- SkipIfRemote()
tmpDir, err := ioutil.TempDir("", "")
Expect(err).To(BeNil())
@@ -235,7 +233,6 @@ var _ = Describe("Podman rm", func() {
})
It("podman rm --ignore bogus container and a running container", func() {
- SkipIfRemote()
session := podmanTest.RunTopContainer("test1")
session.WaitWithDefaultTimeout()
diff --git a/test/e2e/run_networking_test.go b/test/e2e/run_networking_test.go
index 9db2f5d49..4fad85f00 100644
--- a/test/e2e/run_networking_test.go
+++ b/test/e2e/run_networking_test.go
@@ -129,6 +129,32 @@ var _ = Describe("Podman run networking", func() {
Expect(inspectOut[0].NetworkSettings.Ports[0].HostIP).To(Equal("127.0.0.1"))
})
+ It("podman run -p [::1]:8080:80/udp", func() {
+ name := "testctr"
+ session := podmanTest.Podman([]string{"create", "-t", "-p", "[::1]:8080:80/udp", "--name", name, ALPINE, "/bin/sh"})
+ session.WaitWithDefaultTimeout()
+ inspectOut := podmanTest.InspectContainer(name)
+ Expect(len(inspectOut)).To(Equal(1))
+ Expect(len(inspectOut[0].NetworkSettings.Ports)).To(Equal(1))
+ Expect(inspectOut[0].NetworkSettings.Ports[0].HostPort).To(Equal(int32(8080)))
+ Expect(inspectOut[0].NetworkSettings.Ports[0].ContainerPort).To(Equal(int32(80)))
+ Expect(inspectOut[0].NetworkSettings.Ports[0].Protocol).To(Equal("udp"))
+ Expect(inspectOut[0].NetworkSettings.Ports[0].HostIP).To(Equal("::1"))
+ })
+
+ It("podman run -p [::1]:8080:80/tcp", func() {
+ name := "testctr"
+ session := podmanTest.Podman([]string{"create", "-t", "-p", "[::1]:8080:80/tcp", "--name", name, ALPINE, "/bin/sh"})
+ session.WaitWithDefaultTimeout()
+ inspectOut := podmanTest.InspectContainer(name)
+ Expect(len(inspectOut)).To(Equal(1))
+ Expect(len(inspectOut[0].NetworkSettings.Ports)).To(Equal(1))
+ Expect(inspectOut[0].NetworkSettings.Ports[0].HostPort).To(Equal(int32(8080)))
+ Expect(inspectOut[0].NetworkSettings.Ports[0].ContainerPort).To(Equal(int32(80)))
+ Expect(inspectOut[0].NetworkSettings.Ports[0].Protocol).To(Equal("tcp"))
+ Expect(inspectOut[0].NetworkSettings.Ports[0].HostIP).To(Equal("::1"))
+ })
+
It("podman run --expose 80 -P", func() {
name := "testctr"
session := podmanTest.Podman([]string{"create", "-t", "--expose", "80", "-P", "--name", name, ALPINE, "/bin/sh"})
diff --git a/test/e2e/stop_test.go b/test/e2e/stop_test.go
index cd78a54e1..4ed0b6293 100644
--- a/test/e2e/stop_test.go
+++ b/test/e2e/stop_test.go
@@ -233,7 +233,6 @@ var _ = Describe("Podman stop", func() {
})
It("podman stop --cidfile", func() {
- SkipIfRemote()
tmpDir, err := ioutil.TempDir("", "")
Expect(err).To(BeNil())
@@ -258,7 +257,6 @@ var _ = Describe("Podman stop", func() {
})
It("podman stop multiple --cidfile", func() {
- SkipIfRemote()
tmpDir, err := ioutil.TempDir("", "")
Expect(err).To(BeNil())
diff --git a/test/e2e/systemd_test.go b/test/e2e/systemd_test.go
index 1275670eb..a35e5113a 100644
--- a/test/e2e/systemd_test.go
+++ b/test/e2e/systemd_test.go
@@ -8,7 +8,6 @@ import (
"strings"
"time"
- "github.com/containers/libpod/pkg/cgroups"
. "github.com/containers/libpod/test/utils"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
@@ -82,13 +81,6 @@ WantedBy=multi-user.target
})
It("podman run container with systemd PID1", func() {
- cgroupsv2, err := cgroups.IsCgroup2UnifiedMode()
- Expect(err).To(BeNil())
- if cgroupsv2 {
- // TODO: Find a way to enable this for v2
- Skip("systemd test does not work in cgroups V2 mode yet")
- }
-
systemdImage := "fedora"
pull := podmanTest.Podman([]string{"pull", systemdImage})
pull.WaitWithDefaultTimeout()
diff --git a/test/e2e/volume_rm_test.go b/test/e2e/volume_rm_test.go
index 6f2020828..742d4e0dc 100644
--- a/test/e2e/volume_rm_test.go
+++ b/test/e2e/volume_rm_test.go
@@ -48,7 +48,6 @@ var _ = Describe("Podman volume rm", func() {
})
It("podman volume rm with --force flag", func() {
- SkipIfRemote()
session := podmanTest.Podman([]string{"create", "-v", "myvol:/myvol", ALPINE, "ls"})
cid := session.OutputToString()
session.WaitWithDefaultTimeout()
diff --git a/test/system/080-pause.bats b/test/system/080-pause.bats
new file mode 100644
index 000000000..4ec0906f4
--- /dev/null
+++ b/test/system/080-pause.bats
@@ -0,0 +1,58 @@
+#!/usr/bin/env bats -*- bats -*-
+#
+# tests for podman pause/unpause functionality
+#
+
+load helpers
+
+@test "podman pause/unpause" {
+ skip_if_rootless "pause does not work rootless"
+
+ cname=$(random_string 10)
+ run_podman run -d --name $cname $IMAGE \
+ sh -c 'while :;do date +%s;sleep 1;done'
+ cid="$output"
+ # Wait for first time value
+ wait_for_output '[0-9]\{10,\}' $cid
+
+ # Pause container, sleep a bit, unpause, sleep again to give process
+ # time to write a new post-restart time value. Pause by CID, unpause
+ # by name, just to exercise code paths. While paused, check 'ps'
+ # and 'inspect', then check again after restarting.
+ run_podman pause $cid
+ run_podman inspect --format '{{.State.Status}}' $cid
+ is "$output" "paused" "podman inspect .State.Status"
+ sleep 3
+ run_podman ps -a --format '{{.ID}} {{.Names}} {{.Status}}'
+ is "$output" "${cid:0:12} $cname paused" "podman ps on paused container"
+ run_podman unpause $cname
+ run_podman ps -a --format '{{.ID}} {{.Names}} {{.Status}}'
+ is "$output" "${cid:0:12} $cname Up .*" "podman ps on resumed container"
+ sleep 1
+
+ # Get full logs, and iterate through them computing delta_t between entries
+ run_podman logs $cid
+ i=1
+ max_delta=0
+ while [ $i -lt ${#lines[*]} ]; do
+ this_delta=$(( ${lines[$i]} - ${lines[$(($i - 1))]} ))
+ if [ $this_delta -gt $max_delta ]; then
+ max_delta=$this_delta
+ fi
+ i=$(( $i + 1 ))
+ done
+
+ # There should be a 3-4 second gap, *maybe* 5. Never 1 or 2, that
+ # would imply that the container never paused.
+ is "$max_delta" "[3456]" "delta t between paused and restarted"
+
+ run_podman rm -f $cname
+
+ # Pause/unpause on nonexistent name or id - these should all fail
+ run_podman 125 pause $cid
+ run_podman 125 pause $cname
+ run_podman 125 unpause $cid
+ run_podman 125 unpause $cname
+}
+
+# vim: filetype=sh
diff --git a/test/system/200-pod.bats b/test/system/200-pod.bats
index 0d14ca990..9a6b39057 100644
--- a/test/system/200-pod.bats
+++ b/test/system/200-pod.bats
@@ -73,6 +73,12 @@ function teardown() {
run_podman run -d --pod $podname $IMAGE nc -l -p $port
cid1="$output"
+ # (While we're here, test the 'Pod' field of 'podman ps'. Expect two ctrs)
+ run_podman ps --format '{{.Pod}}'
+ newline="
+"
+ is "$output" "${podid:0:12}${newline}${podid:0:12}" "sdfdsf"
+
# Talker: send the message via common port on localhost
message=$(random_string 15)
run_podman run --rm --pod $podname $IMAGE \
diff --git a/test/system/220-healthcheck.bats b/test/system/220-healthcheck.bats
new file mode 100644
index 000000000..e649ad3d2
--- /dev/null
+++ b/test/system/220-healthcheck.bats
@@ -0,0 +1,116 @@
+#!/usr/bin/env bats -*- bats -*-
+#
+# tests for podman healthcheck
+#
+#
+
+load helpers
+
+
+# Helper function: run 'podman inspect' and check various given fields
+function _check_health {
+ local testname="$1"
+ local tests="$2"
+
+ run_podman inspect --format json healthcheck_c
+
+ parse_table "$tests" | while read field expect;do
+ # (kludge to deal with parse_table and empty strings)
+ if [ "$expect" = "''" ]; then expect=""; fi
+
+ actual=$(jq -r ".[0].State.Healthcheck.$field" <<<"$output")
+ is "$actual" "$expect" "$testname - .State.Healthcheck.$field"
+ done
+}
+
+
+@test "podman healthcheck" {
+
+ # Create an image with a healthcheck script; said script will
+ # pass until the file /uh-oh gets created (by us, via exec)
+ cat >${PODMAN_TMPDIR}/healthcheck <<EOF
+#!/bin/sh
+
+if test -e /uh-oh; then
+ echo "Uh-oh on stdout!"
+ echo "Uh-oh on stderr!" >&2
+ exit 1
+else
+ echo "Life is Good on stdout"
+ echo "Life is Good on stderr" >&2
+ exit 0
+fi
+EOF
+
+ cat >${PODMAN_TMPDIR}/entrypoint <<EOF
+#!/bin/sh
+
+while :; do
+ sleep 1
+done
+EOF
+
+ cat >${PODMAN_TMPDIR}/Containerfile <<EOF
+FROM $IMAGE
+
+COPY healthcheck /healthcheck
+COPY entrypoint /entrypoint
+
+RUN chmod 755 /healthcheck /entrypoint
+
+CMD ["/entrypoint"]
+EOF
+
+ run_podman build -t healthcheck_i ${PODMAN_TMPDIR}
+
+ # Run that healthcheck image.
+ run_podman run -d --name healthcheck_c \
+ --health-cmd /healthcheck \
+ --health-interval 1s \
+ --health-retries 3 \
+ healthcheck_i
+
+ # We can't check for 'starting' because a 1-second interval is too
+ # short; it could run healthcheck before we get to our first check.
+ #
+ # So, just force a healthcheck run, then confirm that it's running.
+ run_podman healthcheck run healthcheck_c
+ is "$output" "healthy" "output from 'podman healthcheck run'"
+
+ _check_health "All healthy" "
+Status | healthy
+FailingStreak | 0
+Log[-1].ExitCode | 0
+Log[-1].Output |
+"
+
+ # Force a failure
+ run_podman exec healthcheck_c touch /uh-oh
+ sleep 2
+
+ _check_health "First failure" "
+Status | healthy
+FailingStreak | [123]
+Log[-1].ExitCode | 1
+Log[-1].Output |
+"
+
+ # After three successive failures, container should no longer be healthy
+ sleep 5
+ _check_health "Three or more failures" "
+Status | unhealthy
+FailingStreak | [3456]
+Log[-1].ExitCode | 1
+Log[-1].Output |
+"
+
+ # healthcheck should now fail, with exit status 1 and 'unhealthy' output
+ run_podman 1 healthcheck run healthcheck_c
+ is "$output" "unhealthy" "output from 'podman healthcheck run'"
+
+ # Clean up
+ run_podman rm -f healthcheck_c
+ run_podman rmi healthcheck_i
+}
+
+# vim: filetype=sh
diff --git a/test/utils/utils.go b/test/utils/utils.go
index 1d59e5468..0597cd292 100644
--- a/test/utils/utils.go
+++ b/test/utils/utils.go
@@ -73,7 +73,7 @@ func (p *PodmanTest) PodmanAsUserBase(args []string, uid, gid uint32, cwd string
podmanBinary = p.RemotePodmanBinary
}
if p.RemoteTest {
- podmanOptions = append([]string{"--remote", p.RemoteSocket}, podmanOptions...)
+ podmanOptions = append([]string{"--remote", "--url", p.RemoteSocket}, podmanOptions...)
}
if env == nil {
fmt.Printf("Running: %s %s\n", podmanBinary, strings.Join(podmanOptions, " "))
diff --git a/vendor/github.com/containers/common/pkg/config/config.go b/vendor/github.com/containers/common/pkg/config/config.go
index d0b56c7f6..9657ecb69 100644
--- a/vendor/github.com/containers/common/pkg/config/config.go
+++ b/vendor/github.com/containers/common/pkg/config/config.go
@@ -269,6 +269,9 @@ type EngineConfig struct {
// RemoteURI containers connection information used to connect to remote system.
RemoteURI string `toml:"remote_uri,omitempty"`
+ // Identity key file for RemoteURI
+ RemoteIdentity string `toml:"remote_identity,omitempty"`
+
// RuntimePath is the path to OCI runtime binary for launching containers.
// The first path pointing to a valid file will be used This is used only
// when there are no OCIRuntime/OCIRuntimes defined. It is used only to be
diff --git a/vendor/github.com/containers/storage/VERSION b/vendor/github.com/containers/storage/VERSION
index 0044d6cb9..769e37e15 100644
--- a/vendor/github.com/containers/storage/VERSION
+++ b/vendor/github.com/containers/storage/VERSION
@@ -1 +1 @@
-1.20.1
+1.20.2
diff --git a/vendor/github.com/containers/storage/drivers/devmapper/deviceset.go b/vendor/github.com/containers/storage/drivers/devmapper/deviceset.go
index f1c941f11..ff6e297f4 100644
--- a/vendor/github.com/containers/storage/drivers/devmapper/deviceset.go
+++ b/vendor/github.com/containers/storage/drivers/devmapper/deviceset.go
@@ -1544,8 +1544,8 @@ func getDeviceMajorMinor(file *os.File) (uint64, uint64, error) {
}
dev := stat.Rdev
- majorNum := major(dev)
- minorNum := minor(dev)
+ majorNum := major(uint64(dev))
+ minorNum := minor(uint64(dev))
logrus.Debugf("devmapper: Major:Minor for device: %s is:%v:%v", file.Name(), majorNum, minorNum)
return majorNum, minorNum, nil
diff --git a/vendor/github.com/containers/storage/drivers/overlay/overlay.go b/vendor/github.com/containers/storage/drivers/overlay/overlay.go
index 2906e3e08..930a57a97 100644
--- a/vendor/github.com/containers/storage/drivers/overlay/overlay.go
+++ b/vendor/github.com/containers/storage/drivers/overlay/overlay.go
@@ -311,6 +311,9 @@ func parseOptions(options []string) (*overlayOptions, error) {
return nil, fmt.Errorf("overlay: can't stat program %s: %v", val, err)
}
o.mountProgram = val
+ case "overlay2.skip_mount_home", "overlay.skip_mount_home", ".skip_mount_home":
+ logrus.Debugf("overlay: skip_mount_home=%s", val)
+ o.skipMountHome, err = strconv.ParseBool(val)
case ".ignore_chown_errors", "overlay2.ignore_chown_errors", "overlay.ignore_chown_errors":
logrus.Debugf("overlay: ignore_chown_errors=%s", val)
o.ignoreChownErrors, err = strconv.ParseBool(val)
diff --git a/vendor/github.com/containers/storage/go.mod b/vendor/github.com/containers/storage/go.mod
index a7d9ade60..01ac1827b 100644
--- a/vendor/github.com/containers/storage/go.mod
+++ b/vendor/github.com/containers/storage/go.mod
@@ -6,23 +6,23 @@ require (
github.com/Microsoft/hcsshim v0.8.9
github.com/docker/go-units v0.4.0
github.com/hashicorp/go-multierror v1.0.0
- github.com/klauspost/compress v1.10.5
+ github.com/klauspost/compress v1.10.7
github.com/klauspost/pgzip v1.2.4
github.com/mattn/go-shellwords v1.0.10
github.com/mistifyio/go-zfs v2.1.1+incompatible
github.com/opencontainers/go-digest v1.0.0
- github.com/opencontainers/runc v1.0.0-rc9
+ github.com/opencontainers/runc v1.0.0-rc90
github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700
- github.com/opencontainers/selinux v1.5.1
+ github.com/opencontainers/selinux v1.5.2
github.com/pkg/errors v0.9.1
github.com/pquerna/ffjson v0.0.0-20181028064349-e517b90714f7
github.com/sirupsen/logrus v1.6.0
- github.com/stretchr/testify v1.5.1
+ github.com/stretchr/testify v1.6.0
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2
github.com/tchap/go-patricia v2.3.0+incompatible
github.com/vbatts/tar-split v0.11.1
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9
- golang.org/x/sys v0.0.0-20191127021746-63cb32ae39b2
+ golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9
gotest.tools v2.2.0+incompatible
)
diff --git a/vendor/github.com/containers/storage/go.sum b/vendor/github.com/containers/storage/go.sum
index eab0fd61e..2b5a279c6 100644
--- a/vendor/github.com/containers/storage/go.sum
+++ b/vendor/github.com/containers/storage/go.sum
@@ -8,6 +8,7 @@ github.com/Microsoft/hcsshim v0.8.9/go.mod h1:5692vkUqntj1idxauYlpoINNKeqCiG6Sg3
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f h1:tSNMc+rJDfmYntojat8lljbt1mgKNpTxUZJsSzJ9Y1s=
github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko=
+github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1 h1:uict5mhHFTzKLUCufdSLym7z/J0CbBJT59lYbP9wtbg=
github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw=
github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
@@ -15,12 +16,14 @@ github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv
github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0=
github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o=
github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc=
+github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
+github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e h1:BWhy2j3IXJhjCbC68FptL43tDKIq8FladmaTs3Xs7Z8=
github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
@@ -29,6 +32,7 @@ github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfU
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
@@ -42,8 +46,8 @@ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
-github.com/klauspost/compress v1.10.5 h1:7q6vHIqubShURwQz8cQK6yIe/xC3IF0Vm7TGfqjewrc=
-github.com/klauspost/compress v1.10.5/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
+github.com/klauspost/compress v1.10.7 h1:7rix8v8GpI3ZBb0nSozFRgbtXKv+hOe+qfEpZqybrAg=
+github.com/klauspost/compress v1.10.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/pgzip v1.2.4 h1:TQ7CNpYKovDOmqzRHKxJh0BeaBI7UdQZYc6p7pMQh1A=
github.com/klauspost/pgzip v1.2.4/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
@@ -62,12 +66,12 @@ github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
-github.com/opencontainers/runc v1.0.0-rc9 h1:/k06BMULKF5hidyoZymkoDCzdJzltZpz/UU4LguQVtc=
-github.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
+github.com/opencontainers/runc v1.0.0-rc90 h1:4+xo8mtWixbHoEm451+WJNUrq12o2/tDsyK9Vgc/NcA=
+github.com/opencontainers/runc v1.0.0-rc90/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700 h1:eNUVfm/RFLIi1G7flU5/ZRTHvd4kcVuzfRnL6OFlzCI=
github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
-github.com/opencontainers/selinux v1.5.1 h1:jskKwSMFYqyTrHEuJgQoUlTcId0av64S6EWObrIfn5Y=
-github.com/opencontainers/selinux v1.5.1/go.mod h1:yTcKuYAh6R95iDpefGLQaPaRwJFwyzAJufJyiTt7s0g=
+github.com/opencontainers/selinux v1.5.2 h1:F6DgIsjgBIcDksLW4D5RG9bXok6oqZ3nvMwj4ZoFu/Q=
+github.com/opencontainers/selinux v1.5.2/go.mod h1:yTcKuYAh6R95iDpefGLQaPaRwJFwyzAJufJyiTt7s0g=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@@ -81,15 +85,17 @@ github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6Mwd
github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
-github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
-github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
+github.com/stretchr/testify v1.6.0 h1:jlIyCplCJFULU/01vCkhKuTyc3OorI3bJFuw6obfgho=
+github.com/stretchr/testify v1.6.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2 h1:b6uOv7YOFK0TYG7HtkIgExQo+2RdLuwRft63jn2HWj8=
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
github.com/tchap/go-patricia v2.3.0+incompatible h1:GkY4dP3cEfEASBPPkWd+AmjYxhmDkqO9/zg7R0lSQRs=
github.com/tchap/go-patricia v2.3.0+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I=
+github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5 h1:MCfT24H3f//U5+UCrZp1/riVO3B50BovxtDiNn0XKkk=
github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/vbatts/tar-split v0.11.1 h1:0Odu65rhcZ3JZaPHxl7tCI3V/C/Q9Zf82UFravl02dE=
github.com/vbatts/tar-split v0.11.1/go.mod h1:LEuURwDEiWjRjwu46yU3KVGuUdVv/dcnpcEPSzR8z6g=
@@ -120,8 +126,8 @@ golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191127021746-63cb32ae39b2 h1:/J2nHFg1MTqaRLFO7M+J78ASNsJoz3r0cvHBPQ77fsE=
-golang.org/x/sys v0.0.0-20191127021746-63cb32ae39b2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9 h1:1/DFK4b7JH8DmkqhUk48onnSfrPzImPoVxuomtbT2nk=
+golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -145,6 +151,8 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
diff --git a/vendor/github.com/containers/storage/pkg/config/config.go b/vendor/github.com/containers/storage/pkg/config/config.go
index 1ac6c04e3..4a35997ea 100644
--- a/vendor/github.com/containers/storage/pkg/config/config.go
+++ b/vendor/github.com/containers/storage/pkg/config/config.go
@@ -2,8 +2,6 @@ package config
import (
"fmt"
-
- "github.com/sirupsen/logrus"
)
// ThinpoolOptionsConfig represents the "storage.options.thinpool"
@@ -269,11 +267,11 @@ func GetGraphDriverOptions(driverName string, options OptionsConfig) []string {
} else if options.Size != "" {
doptions = append(doptions, fmt.Sprintf("%s.size=%s", driverName, options.Size))
}
-
- if options.Overlay.SkipMountHome != "" || options.SkipMountHome != "" {
- logrus.Warn("skip_mount_home option is no longer supported, ignoring option")
+ if options.Overlay.SkipMountHome != "" {
+ doptions = append(doptions, fmt.Sprintf("%s.skip_mount_home=%s", driverName, options.Overlay.SkipMountHome))
+ } else if options.SkipMountHome != "" {
+ doptions = append(doptions, fmt.Sprintf("%s.skip_mount_home=%s", driverName, options.SkipMountHome))
}
-
case "vfs":
if options.Vfs.IgnoreChownErrors != "" {
doptions = append(doptions, fmt.Sprintf("%s.ignore_chown_errors=%s", driverName, options.Vfs.IgnoreChownErrors))
diff --git a/vendor/github.com/containers/storage/storage.conf b/vendor/github.com/containers/storage/storage.conf
index c7f9b2cf8..19909e9c6 100644
--- a/vendor/github.com/containers/storage/storage.conf
+++ b/vendor/github.com/containers/storage/storage.conf
@@ -76,6 +76,9 @@ additionalimagestores = [
# mountopt specifies comma separated list of extra mount options
mountopt = "nodev"
+# Set to skip a PRIVATE bind mount on the storage home directory.
+# skip_mount_home = "false"
+
# Size is used to set a maximum size of the container image.
# size = ""
diff --git a/vendor/github.com/containers/storage/store.go b/vendor/github.com/containers/storage/store.go
index eaf622f43..263f4edb2 100644
--- a/vendor/github.com/containers/storage/store.go
+++ b/vendor/github.com/containers/storage/store.go
@@ -3481,6 +3481,9 @@ func ReloadConfigurationFile(configFile string, storeOptions *StoreOptions) {
if config.Storage.Options.MountProgram != "" {
storeOptions.GraphDriverOptions = append(storeOptions.GraphDriverOptions, fmt.Sprintf("%s.mount_program=%s", config.Storage.Driver, config.Storage.Options.MountProgram))
}
+ if config.Storage.Options.SkipMountHome != "" {
+ storeOptions.GraphDriverOptions = append(storeOptions.GraphDriverOptions, fmt.Sprintf("%s.skip_mount_home=%s", config.Storage.Driver, config.Storage.Options.SkipMountHome))
+ }
if config.Storage.Options.IgnoreChownErrors != "" {
storeOptions.GraphDriverOptions = append(storeOptions.GraphDriverOptions, fmt.Sprintf("%s.ignore_chown_errors=%s", config.Storage.Driver, config.Storage.Options.IgnoreChownErrors))
}
diff --git a/vendor/github.com/json-iterator/go/README.md b/vendor/github.com/json-iterator/go/README.md
index 50d56ffbf..52b111d5f 100644
--- a/vendor/github.com/json-iterator/go/README.md
+++ b/vendor/github.com/json-iterator/go/README.md
@@ -1,5 +1,5 @@
[![Sourcegraph](https://sourcegraph.com/github.com/json-iterator/go/-/badge.svg)](https://sourcegraph.com/github.com/json-iterator/go?badge)
-[![GoDoc](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)](http://godoc.org/github.com/json-iterator/go)
+[![GoDoc](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)](https://pkg.go.dev/github.com/json-iterator/go)
[![Build Status](https://travis-ci.org/json-iterator/go.svg?branch=master)](https://travis-ci.org/json-iterator/go)
[![codecov](https://codecov.io/gh/json-iterator/go/branch/master/graph/badge.svg)](https://codecov.io/gh/json-iterator/go)
[![rcard](https://goreportcard.com/badge/github.com/json-iterator/go)](https://goreportcard.com/report/github.com/json-iterator/go)
@@ -18,16 +18,16 @@ Source code: https://github.com/json-iterator/go-benchmark/blob/master/src/githu
Raw Result (easyjson requires static code generation)
-| | ns/op | allocation bytes | allocation times |
-| --- | --- | --- | --- |
-| std decode | 35510 ns/op | 1960 B/op | 99 allocs/op |
-| easyjson decode | 8499 ns/op | 160 B/op | 4 allocs/op |
-| jsoniter decode | 5623 ns/op | 160 B/op | 3 allocs/op |
-| std encode | 2213 ns/op | 712 B/op | 5 allocs/op |
-| easyjson encode | 883 ns/op | 576 B/op | 3 allocs/op |
-| jsoniter encode | 837 ns/op | 384 B/op | 4 allocs/op |
+| | ns/op | allocation bytes | allocation times |
+| --------------- | ----------- | ---------------- | ---------------- |
+| std decode | 35510 ns/op | 1960 B/op | 99 allocs/op |
+| easyjson decode | 8499 ns/op | 160 B/op | 4 allocs/op |
+| jsoniter decode | 5623 ns/op | 160 B/op | 3 allocs/op |
+| std encode | 2213 ns/op | 712 B/op | 5 allocs/op |
+| easyjson encode | 883 ns/op | 576 B/op | 3 allocs/op |
+| jsoniter encode | 837 ns/op | 384 B/op | 4 allocs/op |
-Always benchmark with your own workload.
+Always benchmark with your own workload.
The result depends heavily on the data input.
# Usage
@@ -41,10 +41,10 @@ import "encoding/json"
json.Marshal(&data)
```
-with
+with
```go
-import "github.com/json-iterator/go"
+import jsoniter "github.com/json-iterator/go"
var json = jsoniter.ConfigCompatibleWithStandardLibrary
json.Marshal(&data)
@@ -60,7 +60,7 @@ json.Unmarshal(input, &data)
with
```go
-import "github.com/json-iterator/go"
+import jsoniter "github.com/json-iterator/go"
var json = jsoniter.ConfigCompatibleWithStandardLibrary
json.Unmarshal(input, &data)
@@ -78,10 +78,10 @@ go get github.com/json-iterator/go
Contributors
-* [thockin](https://github.com/thockin)
-* [mattn](https://github.com/mattn)
-* [cch123](https://github.com/cch123)
-* [Oleg Shaldybin](https://github.com/olegshaldybin)
-* [Jason Toffaletti](https://github.com/toffaletti)
+- [thockin](https://github.com/thockin)
+- [mattn](https://github.com/mattn)
+- [cch123](https://github.com/cch123)
+- [Oleg Shaldybin](https://github.com/olegshaldybin)
+- [Jason Toffaletti](https://github.com/toffaletti)
Report issue or pull request, or email taowen@gmail.com, or [![Gitter chat](https://badges.gitter.im/gitterHQ/gitter.png)](https://gitter.im/json-iterator/Lobby)
diff --git a/vendor/github.com/json-iterator/go/any_str.go b/vendor/github.com/json-iterator/go/any_str.go
index a4b93c78c..1f12f6612 100644
--- a/vendor/github.com/json-iterator/go/any_str.go
+++ b/vendor/github.com/json-iterator/go/any_str.go
@@ -64,7 +64,6 @@ func (any *stringAny) ToInt64() int64 {
flag := 1
startPos := 0
- endPos := 0
if any.val[0] == '+' || any.val[0] == '-' {
startPos = 1
}
@@ -73,6 +72,7 @@ func (any *stringAny) ToInt64() int64 {
flag = -1
}
+ endPos := startPos
for i := startPos; i < len(any.val); i++ {
if any.val[i] >= '0' && any.val[i] <= '9' {
endPos = i + 1
@@ -98,7 +98,6 @@ func (any *stringAny) ToUint64() uint64 {
}
startPos := 0
- endPos := 0
if any.val[0] == '-' {
return 0
@@ -107,6 +106,7 @@ func (any *stringAny) ToUint64() uint64 {
startPos = 1
}
+ endPos := startPos
for i := startPos; i < len(any.val); i++ {
if any.val[i] >= '0' && any.val[i] <= '9' {
endPos = i + 1
diff --git a/vendor/github.com/json-iterator/go/config.go b/vendor/github.com/json-iterator/go/config.go
index 8c58fcba5..2adcdc3b7 100644
--- a/vendor/github.com/json-iterator/go/config.go
+++ b/vendor/github.com/json-iterator/go/config.go
@@ -183,11 +183,11 @@ func (cfg *frozenConfig) validateJsonRawMessage(extension EncoderExtension) {
encoder := &funcEncoder{func(ptr unsafe.Pointer, stream *Stream) {
rawMessage := *(*json.RawMessage)(ptr)
iter := cfg.BorrowIterator([]byte(rawMessage))
+ defer cfg.ReturnIterator(iter)
iter.Read()
- if iter.Error != nil {
+ if iter.Error != nil && iter.Error != io.EOF {
stream.WriteRaw("null")
} else {
- cfg.ReturnIterator(iter)
stream.WriteRaw(string(rawMessage))
}
}, func(ptr unsafe.Pointer) bool {
diff --git a/vendor/github.com/json-iterator/go/iter_object.go b/vendor/github.com/json-iterator/go/iter_object.go
index b65137114..58ee89c84 100644
--- a/vendor/github.com/json-iterator/go/iter_object.go
+++ b/vendor/github.com/json-iterator/go/iter_object.go
@@ -150,7 +150,7 @@ func (iter *Iterator) ReadObjectCB(callback func(*Iterator, string) bool) bool {
if c == '}' {
return iter.decrementDepth()
}
- iter.ReportError("ReadObjectCB", `expect " after }, but found `+string([]byte{c}))
+ iter.ReportError("ReadObjectCB", `expect " after {, but found `+string([]byte{c}))
iter.decrementDepth()
return false
}
@@ -206,7 +206,7 @@ func (iter *Iterator) ReadMapCB(callback func(*Iterator, string) bool) bool {
if c == '}' {
return iter.decrementDepth()
}
- iter.ReportError("ReadMapCB", `expect " after }, but found `+string([]byte{c}))
+ iter.ReportError("ReadMapCB", `expect " after {, but found `+string([]byte{c}))
iter.decrementDepth()
return false
}
diff --git a/vendor/github.com/json-iterator/go/reflect_extension.go b/vendor/github.com/json-iterator/go/reflect_extension.go
index 80320cd64..74a97bfe5 100644
--- a/vendor/github.com/json-iterator/go/reflect_extension.go
+++ b/vendor/github.com/json-iterator/go/reflect_extension.go
@@ -475,7 +475,7 @@ func calcFieldNames(originalFieldName string, tagProvidedFieldName string, whole
fieldNames = []string{tagProvidedFieldName}
}
// private?
- isNotExported := unicode.IsLower(rune(originalFieldName[0]))
+ isNotExported := unicode.IsLower(rune(originalFieldName[0])) || originalFieldName[0] == '_'
if isNotExported {
fieldNames = []string{}
}
diff --git a/vendor/github.com/json-iterator/go/reflect_map.go b/vendor/github.com/json-iterator/go/reflect_map.go
index 9e2b623fe..582967130 100644
--- a/vendor/github.com/json-iterator/go/reflect_map.go
+++ b/vendor/github.com/json-iterator/go/reflect_map.go
@@ -49,6 +49,33 @@ func decoderOfMapKey(ctx *ctx, typ reflect2.Type) ValDecoder {
return decoder
}
}
+
+ ptrType := reflect2.PtrTo(typ)
+ if ptrType.Implements(unmarshalerType) {
+ return &referenceDecoder{
+ &unmarshalerDecoder{
+ valType: ptrType,
+ },
+ }
+ }
+ if typ.Implements(unmarshalerType) {
+ return &unmarshalerDecoder{
+ valType: typ,
+ }
+ }
+ if ptrType.Implements(textUnmarshalerType) {
+ return &referenceDecoder{
+ &textUnmarshalerDecoder{
+ valType: ptrType,
+ },
+ }
+ }
+ if typ.Implements(textUnmarshalerType) {
+ return &textUnmarshalerDecoder{
+ valType: typ,
+ }
+ }
+
switch typ.Kind() {
case reflect.String:
return decoderOfType(ctx, reflect2.DefaultTypeOfKind(reflect.String))
@@ -63,31 +90,6 @@ func decoderOfMapKey(ctx *ctx, typ reflect2.Type) ValDecoder {
typ = reflect2.DefaultTypeOfKind(typ.Kind())
return &numericMapKeyDecoder{decoderOfType(ctx, typ)}
default:
- ptrType := reflect2.PtrTo(typ)
- if ptrType.Implements(unmarshalerType) {
- return &referenceDecoder{
- &unmarshalerDecoder{
- valType: ptrType,
- },
- }
- }
- if typ.Implements(unmarshalerType) {
- return &unmarshalerDecoder{
- valType: typ,
- }
- }
- if ptrType.Implements(textUnmarshalerType) {
- return &referenceDecoder{
- &textUnmarshalerDecoder{
- valType: ptrType,
- },
- }
- }
- if typ.Implements(textUnmarshalerType) {
- return &textUnmarshalerDecoder{
- valType: typ,
- }
- }
return &lazyErrorDecoder{err: fmt.Errorf("unsupported map key type: %v", typ)}
}
}
@@ -103,6 +105,19 @@ func encoderOfMapKey(ctx *ctx, typ reflect2.Type) ValEncoder {
return encoder
}
}
+
+ if typ == textMarshalerType {
+ return &directTextMarshalerEncoder{
+ stringEncoder: ctx.EncoderOf(reflect2.TypeOf("")),
+ }
+ }
+ if typ.Implements(textMarshalerType) {
+ return &textMarshalerEncoder{
+ valType: typ,
+ stringEncoder: ctx.EncoderOf(reflect2.TypeOf("")),
+ }
+ }
+
switch typ.Kind() {
case reflect.String:
return encoderOfType(ctx, reflect2.DefaultTypeOfKind(reflect.String))
@@ -117,17 +132,6 @@ func encoderOfMapKey(ctx *ctx, typ reflect2.Type) ValEncoder {
typ = reflect2.DefaultTypeOfKind(typ.Kind())
return &numericMapKeyEncoder{encoderOfType(ctx, typ)}
default:
- if typ == textMarshalerType {
- return &directTextMarshalerEncoder{
- stringEncoder: ctx.EncoderOf(reflect2.TypeOf("")),
- }
- }
- if typ.Implements(textMarshalerType) {
- return &textMarshalerEncoder{
- valType: typ,
- stringEncoder: ctx.EncoderOf(reflect2.TypeOf("")),
- }
- }
if typ.Kind() == reflect.Interface {
return &dynamicMapKeyEncoder{ctx, typ}
}
@@ -163,10 +167,6 @@ func (decoder *mapDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
if c == '}' {
return
}
- if c != '"' {
- iter.ReportError("ReadMapCB", `expect " after }, but found `+string([]byte{c}))
- return
- }
iter.unreadByte()
key := decoder.keyType.UnsafeNew()
decoder.keyDecoder.Decode(key, iter)
diff --git a/vendor/github.com/json-iterator/go/reflect_optional.go b/vendor/github.com/json-iterator/go/reflect_optional.go
index 43ec71d6d..fa71f4748 100644
--- a/vendor/github.com/json-iterator/go/reflect_optional.go
+++ b/vendor/github.com/json-iterator/go/reflect_optional.go
@@ -2,7 +2,6 @@ package jsoniter
import (
"github.com/modern-go/reflect2"
- "reflect"
"unsafe"
)
@@ -10,9 +9,6 @@ func decoderOfOptional(ctx *ctx, typ reflect2.Type) ValDecoder {
ptrType := typ.(*reflect2.UnsafePtrType)
elemType := ptrType.Elem()
decoder := decoderOfType(ctx, elemType)
- if ctx.prefix == "" && elemType.Kind() == reflect.Ptr {
- return &dereferenceDecoder{elemType, decoder}
- }
return &OptionalDecoder{elemType, decoder}
}
diff --git a/vendor/github.com/json-iterator/go/reflect_struct_decoder.go b/vendor/github.com/json-iterator/go/reflect_struct_decoder.go
index 5ad5cc561..d7eb0eb5c 100644
--- a/vendor/github.com/json-iterator/go/reflect_struct_decoder.go
+++ b/vendor/github.com/json-iterator/go/reflect_struct_decoder.go
@@ -507,7 +507,7 @@ func (decoder *generalStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator)
for c = ','; c == ','; c = iter.nextToken() {
decoder.decodeOneField(ptr, iter)
}
- if iter.Error != nil && iter.Error != io.EOF {
+ if iter.Error != nil && iter.Error != io.EOF && len(decoder.typ.Type1().Name()) != 0 {
iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error())
}
if c != '}' {
@@ -588,7 +588,7 @@ func (decoder *oneFieldStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator)
break
}
}
- if iter.Error != nil && iter.Error != io.EOF {
+ if iter.Error != nil && iter.Error != io.EOF && len(decoder.typ.Type1().Name()) != 0 {
iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error())
}
iter.decrementDepth()
@@ -622,7 +622,7 @@ func (decoder *twoFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator
break
}
}
- if iter.Error != nil && iter.Error != io.EOF {
+ if iter.Error != nil && iter.Error != io.EOF && len(decoder.typ.Type1().Name()) != 0 {
iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error())
}
iter.decrementDepth()
@@ -660,7 +660,7 @@ func (decoder *threeFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterat
break
}
}
- if iter.Error != nil && iter.Error != io.EOF {
+ if iter.Error != nil && iter.Error != io.EOF && len(decoder.typ.Type1().Name()) != 0 {
iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error())
}
iter.decrementDepth()
@@ -702,7 +702,7 @@ func (decoder *fourFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterato
break
}
}
- if iter.Error != nil && iter.Error != io.EOF {
+ if iter.Error != nil && iter.Error != io.EOF && len(decoder.typ.Type1().Name()) != 0 {
iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error())
}
iter.decrementDepth()
@@ -748,7 +748,7 @@ func (decoder *fiveFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterato
break
}
}
- if iter.Error != nil && iter.Error != io.EOF {
+ if iter.Error != nil && iter.Error != io.EOF && len(decoder.typ.Type1().Name()) != 0 {
iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error())
}
iter.decrementDepth()
@@ -798,7 +798,7 @@ func (decoder *sixFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator
break
}
}
- if iter.Error != nil && iter.Error != io.EOF {
+ if iter.Error != nil && iter.Error != io.EOF && len(decoder.typ.Type1().Name()) != 0 {
iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error())
}
iter.decrementDepth()
@@ -852,7 +852,7 @@ func (decoder *sevenFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterat
break
}
}
- if iter.Error != nil && iter.Error != io.EOF {
+ if iter.Error != nil && iter.Error != io.EOF && len(decoder.typ.Type1().Name()) != 0 {
iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error())
}
iter.decrementDepth()
@@ -910,7 +910,7 @@ func (decoder *eightFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterat
break
}
}
- if iter.Error != nil && iter.Error != io.EOF {
+ if iter.Error != nil && iter.Error != io.EOF && len(decoder.typ.Type1().Name()) != 0 {
iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error())
}
iter.decrementDepth()
@@ -972,7 +972,7 @@ func (decoder *nineFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterato
break
}
}
- if iter.Error != nil && iter.Error != io.EOF {
+ if iter.Error != nil && iter.Error != io.EOF && len(decoder.typ.Type1().Name()) != 0 {
iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error())
}
iter.decrementDepth()
@@ -1038,7 +1038,7 @@ func (decoder *tenFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator
break
}
}
- if iter.Error != nil && iter.Error != io.EOF {
+ if iter.Error != nil && iter.Error != io.EOF && len(decoder.typ.Type1().Name()) != 0 {
iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error())
}
iter.decrementDepth()
diff --git a/vendor/github.com/json-iterator/go/stream.go b/vendor/github.com/json-iterator/go/stream.go
index 17662fded..23d8a3ad6 100644
--- a/vendor/github.com/json-iterator/go/stream.go
+++ b/vendor/github.com/json-iterator/go/stream.go
@@ -103,14 +103,14 @@ func (stream *Stream) Flush() error {
if stream.Error != nil {
return stream.Error
}
- n, err := stream.out.Write(stream.buf)
+ _, err := stream.out.Write(stream.buf)
if err != nil {
if stream.Error == nil {
stream.Error = err
}
return err
}
- stream.buf = stream.buf[n:]
+ stream.buf = stream.buf[:0]
return nil
}
@@ -177,7 +177,6 @@ func (stream *Stream) WriteEmptyObject() {
func (stream *Stream) WriteMore() {
stream.writeByte(',')
stream.writeIndention(0)
- stream.Flush()
}
// WriteArrayStart write [ with possible indention
diff --git a/vendor/github.com/klauspost/compress/huff0/decompress.go b/vendor/github.com/klauspost/compress/huff0/decompress.go
index 97ae66a4a..fb42a398b 100644
--- a/vendor/github.com/klauspost/compress/huff0/decompress.go
+++ b/vendor/github.com/klauspost/compress/huff0/decompress.go
@@ -155,20 +155,70 @@ func ReadTable(in []byte, s *Scratch) (s2 *Scratch, remain []byte, err error) {
// The length of the supplied input must match the end of a block exactly.
// Before this is called, the table must be initialized with ReadTable unless
// the encoder re-used the table.
+// deprecated: Use the stateless Decoder() to get a concurrent version.
func (s *Scratch) Decompress1X(in []byte) (out []byte, err error) {
- if len(s.dt.single) == 0 {
+ if cap(s.Out) < s.MaxDecodedSize {
+ s.Out = make([]byte, s.MaxDecodedSize)
+ }
+ s.Out = s.Out[:0:s.MaxDecodedSize]
+ s.Out, err = s.Decoder().Decompress1X(s.Out, in)
+ return s.Out, err
+}
+
+// Decompress4X will decompress a 4X encoded stream.
+// Before this is called, the table must be initialized with ReadTable unless
+// the encoder re-used the table.
+// The length of the supplied input must match the end of a block exactly.
+// The destination size of the uncompressed data must be known and provided.
+// deprecated: Use the stateless Decoder() to get a concurrent version.
+func (s *Scratch) Decompress4X(in []byte, dstSize int) (out []byte, err error) {
+ if dstSize > s.MaxDecodedSize {
+ return nil, ErrMaxDecodedSizeExceeded
+ }
+ if cap(s.Out) < dstSize {
+ s.Out = make([]byte, s.MaxDecodedSize)
+ }
+ s.Out = s.Out[:0:dstSize]
+ s.Out, err = s.Decoder().Decompress4X(s.Out, in)
+ return s.Out, err
+}
+
+// Decoder will return a stateless decoder that can be used by multiple
+// decompressors concurrently.
+// Before this is called, the table must be initialized with ReadTable.
+// The Decoder is still linked to the scratch buffer so that cannot be reused.
+// However, it is safe to discard the scratch.
+func (s *Scratch) Decoder() *Decoder {
+ return &Decoder{
+ dt: s.dt,
+ actualTableLog: s.actualTableLog,
+ }
+}
+
+// Decoder provides stateless decoding.
+type Decoder struct {
+ dt dTable
+ actualTableLog uint8
+}
+
+// Decompress1X will decompress a 1X encoded stream.
+// The cap of the output buffer will be the maximum decompressed size.
+// The length of the supplied input must match the end of a block exactly.
+func (d *Decoder) Decompress1X(dst, src []byte) ([]byte, error) {
+ if len(d.dt.single) == 0 {
return nil, errors.New("no table loaded")
}
var br bitReader
- err = br.init(in)
+ err := br.init(src)
if err != nil {
- return nil, err
+ return dst, err
}
- s.Out = s.Out[:0]
+ maxDecodedSize := cap(dst)
+ dst = dst[:0]
decode := func() byte {
- val := br.peekBitsFast(s.actualTableLog) /* note : actualTableLog >= 1 */
- v := s.dt.single[val]
+ val := br.peekBitsFast(d.actualTableLog) /* note : actualTableLog >= 1 */
+ v := d.dt.single[val]
br.bitsRead += uint8(v.entry)
return uint8(v.entry >> 8)
}
@@ -180,88 +230,80 @@ func (s *Scratch) Decompress1X(in []byte) (out []byte, err error) {
// Avoid bounds check by always having full sized table.
const tlSize = 1 << tableLogMax
const tlMask = tlSize - 1
- dt := s.dt.single[:tlSize]
+ dt := d.dt.single[:tlSize]
// Use temp table to avoid bound checks/append penalty.
- var tmp = s.huffWeight[:256]
+ var buf [256]byte
var off uint8
for br.off >= 8 {
br.fillFast()
- tmp[off+0] = hasDec(dt[br.peekBitsFast(s.actualTableLog)&tlMask])
- tmp[off+1] = hasDec(dt[br.peekBitsFast(s.actualTableLog)&tlMask])
+ buf[off+0] = hasDec(dt[br.peekBitsFast(d.actualTableLog)&tlMask])
+ buf[off+1] = hasDec(dt[br.peekBitsFast(d.actualTableLog)&tlMask])
br.fillFast()
- tmp[off+2] = hasDec(dt[br.peekBitsFast(s.actualTableLog)&tlMask])
- tmp[off+3] = hasDec(dt[br.peekBitsFast(s.actualTableLog)&tlMask])
+ buf[off+2] = hasDec(dt[br.peekBitsFast(d.actualTableLog)&tlMask])
+ buf[off+3] = hasDec(dt[br.peekBitsFast(d.actualTableLog)&tlMask])
off += 4
if off == 0 {
- if len(s.Out)+256 > s.MaxDecodedSize {
+ if len(dst)+256 > maxDecodedSize {
br.close()
return nil, ErrMaxDecodedSizeExceeded
}
- s.Out = append(s.Out, tmp...)
+ dst = append(dst, buf[:]...)
}
}
- if len(s.Out)+int(off) > s.MaxDecodedSize {
+ if len(dst)+int(off) > maxDecodedSize {
br.close()
return nil, ErrMaxDecodedSizeExceeded
}
- s.Out = append(s.Out, tmp[:off]...)
+ dst = append(dst, buf[:off]...)
for !br.finished() {
br.fill()
- if len(s.Out) >= s.MaxDecodedSize {
+ if len(dst) >= maxDecodedSize {
br.close()
return nil, ErrMaxDecodedSizeExceeded
}
- s.Out = append(s.Out, decode())
+ dst = append(dst, decode())
}
- return s.Out, br.close()
+ return dst, br.close()
}
// Decompress4X will decompress a 4X encoded stream.
-// Before this is called, the table must be initialized with ReadTable unless
-// the encoder re-used the table.
// The length of the supplied input must match the end of a block exactly.
-// The destination size of the uncompressed data must be known and provided.
-func (s *Scratch) Decompress4X(in []byte, dstSize int) (out []byte, err error) {
+// The *capacity* of the dst slice must match the destination size of
+// the uncompressed data exactly.
+func (s *Decoder) Decompress4X(dst, src []byte) ([]byte, error) {
if len(s.dt.single) == 0 {
return nil, errors.New("no table loaded")
}
- if len(in) < 6+(4*1) {
+ if len(src) < 6+(4*1) {
return nil, errors.New("input too small")
}
- if dstSize > s.MaxDecodedSize {
- return nil, ErrMaxDecodedSizeExceeded
- }
- // TODO: We do not detect when we overrun a buffer, except if the last one does.
var br [4]bitReader
start := 6
for i := 0; i < 3; i++ {
- length := int(in[i*2]) | (int(in[i*2+1]) << 8)
- if start+length >= len(in) {
+ length := int(src[i*2]) | (int(src[i*2+1]) << 8)
+ if start+length >= len(src) {
return nil, errors.New("truncated input (or invalid offset)")
}
- err = br[i].init(in[start : start+length])
+ err := br[i].init(src[start : start+length])
if err != nil {
return nil, err
}
start += length
}
- err = br[3].init(in[start:])
+ err := br[3].init(src[start:])
if err != nil {
return nil, err
}
- // Prepare output
- if cap(s.Out) < dstSize {
- s.Out = make([]byte, 0, dstSize)
- }
- s.Out = s.Out[:dstSize]
// destination, offset to match first output
- dstOut := s.Out
+ dstSize := cap(dst)
+ dst = dst[:dstSize]
+ out := dst
dstEvery := (dstSize + 3) / 4
const tlSize = 1 << tableLogMax
@@ -276,7 +318,7 @@ func (s *Scratch) Decompress4X(in []byte, dstSize int) (out []byte, err error) {
}
// Use temp table to avoid bound checks/append penalty.
- var tmp = s.huffWeight[:256]
+ var buf [256]byte
var off uint8
var decoded int
@@ -300,8 +342,8 @@ bigloop:
val2 := br[stream].peekBitsFast(s.actualTableLog)
v2 := single[val2&tlMask]
- tmp[off+bufoff*stream+1] = uint8(v2.entry >> 8)
- tmp[off+bufoff*stream] = uint8(v.entry >> 8)
+ buf[off+bufoff*stream+1] = uint8(v2.entry >> 8)
+ buf[off+bufoff*stream] = uint8(v.entry >> 8)
br[stream].bitsRead += uint8(v2.entry)
}
@@ -313,8 +355,8 @@ bigloop:
val2 := br[stream].peekBitsFast(s.actualTableLog)
v2 := single[val2&tlMask]
- tmp[off+bufoff*stream+1] = uint8(v2.entry >> 8)
- tmp[off+bufoff*stream] = uint8(v.entry >> 8)
+ buf[off+bufoff*stream+1] = uint8(v2.entry >> 8)
+ buf[off+bufoff*stream] = uint8(v.entry >> 8)
br[stream].bitsRead += uint8(v2.entry)
}
@@ -326,8 +368,8 @@ bigloop:
val2 := br[stream].peekBitsFast(s.actualTableLog)
v2 := single[val2&tlMask]
- tmp[off+bufoff*stream+1] = uint8(v2.entry >> 8)
- tmp[off+bufoff*stream] = uint8(v.entry >> 8)
+ buf[off+bufoff*stream+1] = uint8(v2.entry >> 8)
+ buf[off+bufoff*stream] = uint8(v.entry >> 8)
br[stream].bitsRead += uint8(v2.entry)
}
@@ -339,8 +381,8 @@ bigloop:
val2 := br[stream].peekBitsFast(s.actualTableLog)
v2 := single[val2&tlMask]
- tmp[off+bufoff*stream+1] = uint8(v2.entry >> 8)
- tmp[off+bufoff*stream] = uint8(v.entry >> 8)
+ buf[off+bufoff*stream+1] = uint8(v2.entry >> 8)
+ buf[off+bufoff*stream] = uint8(v.entry >> 8)
br[stream].bitsRead += uint8(v2.entry)
}
@@ -350,30 +392,30 @@ bigloop:
if bufoff > dstEvery {
return nil, errors.New("corruption detected: stream overrun 1")
}
- copy(dstOut, tmp[:bufoff])
- copy(dstOut[dstEvery:], tmp[bufoff:bufoff*2])
- copy(dstOut[dstEvery*2:], tmp[bufoff*2:bufoff*3])
- copy(dstOut[dstEvery*3:], tmp[bufoff*3:bufoff*4])
+ copy(out, buf[:bufoff])
+ copy(out[dstEvery:], buf[bufoff:bufoff*2])
+ copy(out[dstEvery*2:], buf[bufoff*2:bufoff*3])
+ copy(out[dstEvery*3:], buf[bufoff*3:bufoff*4])
off = 0
- dstOut = dstOut[bufoff:]
+ out = out[bufoff:]
decoded += 256
// There must at least be 3 buffers left.
- if len(dstOut) < dstEvery*3 {
+ if len(out) < dstEvery*3 {
return nil, errors.New("corruption detected: stream overrun 2")
}
}
}
if off > 0 {
ioff := int(off)
- if len(dstOut) < dstEvery*3+ioff {
+ if len(out) < dstEvery*3+ioff {
return nil, errors.New("corruption detected: stream overrun 3")
}
- copy(dstOut, tmp[:off])
- copy(dstOut[dstEvery:dstEvery+ioff], tmp[bufoff:bufoff*2])
- copy(dstOut[dstEvery*2:dstEvery*2+ioff], tmp[bufoff*2:bufoff*3])
- copy(dstOut[dstEvery*3:dstEvery*3+ioff], tmp[bufoff*3:bufoff*4])
+ copy(out, buf[:off])
+ copy(out[dstEvery:dstEvery+ioff], buf[bufoff:bufoff*2])
+ copy(out[dstEvery*2:dstEvery*2+ioff], buf[bufoff*2:bufoff*3])
+ copy(out[dstEvery*3:dstEvery*3+ioff], buf[bufoff*3:bufoff*4])
decoded += int(off) * 4
- dstOut = dstOut[off:]
+ out = out[off:]
}
// Decode remaining.
@@ -382,10 +424,10 @@ bigloop:
br := &br[i]
for !br.finished() {
br.fill()
- if offset >= len(dstOut) {
+ if offset >= len(out) {
return nil, errors.New("corruption detected: stream overrun 4")
}
- dstOut[offset] = decode(br)
+ out[offset] = decode(br)
offset++
}
decoded += offset - dstEvery*i
@@ -397,7 +439,7 @@ bigloop:
if dstSize != decoded {
return nil, errors.New("corruption detected: short output block")
}
- return s.Out, nil
+ return dst, nil
}
// matches will compare a decoding table to a coding table.
diff --git a/vendor/github.com/klauspost/compress/zstd/README.md b/vendor/github.com/klauspost/compress/zstd/README.md
index bc977a302..f2a80b5d0 100644
--- a/vendor/github.com/klauspost/compress/zstd/README.md
+++ b/vendor/github.com/klauspost/compress/zstd/README.md
@@ -309,6 +309,20 @@ The decoder can be used for *concurrent* decompression of multiple buffers.
It will only allow a certain number of concurrent operations to run.
To tweak that yourself use the `WithDecoderConcurrency(n)` option when creating the decoder.
+### Dictionaries
+
+Data compressed with [dictionaries](https://github.com/facebook/zstd#the-case-for-small-data-compression) can be decompressed.
+
+Dictionaries are added individually to Decoders.
+Dictionaries are generated by the `zstd --train` command and contains an initial state for the decoder.
+To add a dictionary use the `RegisterDict(data)` with the dictionary data before starting any decompression.
+
+The dictionary will be used automatically for the data that specifies them.
+
+A re-used Decoder will still contain the dictionaries registered.
+
+When registering a dictionary with the same ID it will override the existing.
+
### Allocation-less operation
The decoder has been designed to operate without allocations after a warmup.
diff --git a/vendor/github.com/klauspost/compress/zstd/blockdec.go b/vendor/github.com/klauspost/compress/zstd/blockdec.go
index 19181caea..4a14242c7 100644
--- a/vendor/github.com/klauspost/compress/zstd/blockdec.go
+++ b/vendor/github.com/klauspost/compress/zstd/blockdec.go
@@ -461,26 +461,22 @@ func (b *blockDec) decodeCompressed(hist *history) error {
if huff == nil {
huff = &huff0.Scratch{}
}
- huff.Out = b.literalBuf[:0]
huff, literals, err = huff0.ReadTable(literals, huff)
if err != nil {
println("reading huffman table:", err)
return err
}
// Use our out buffer.
- huff.Out = b.literalBuf[:0]
- huff.MaxDecodedSize = litRegenSize
if fourStreams {
- literals, err = huff.Decompress4X(literals, litRegenSize)
+ literals, err = huff.Decoder().Decompress4X(b.literalBuf[:0:litRegenSize], literals)
} else {
- literals, err = huff.Decompress1X(literals)
+ literals, err = huff.Decoder().Decompress1X(b.literalBuf[:0:litRegenSize], literals)
}
if err != nil {
println("decoding compressed literals:", err)
return err
}
// Make sure we don't leak our literals buffer
- huff.Out = nil
if len(literals) != litRegenSize {
return fmt.Errorf("literal output size mismatch want %d, got %d", litRegenSize, len(literals))
}
@@ -631,15 +627,12 @@ func (b *blockDec) decodeCompressed(hist *history) error {
var err error
// Use our out buffer.
huff = hist.huffTree
- huff.Out = b.literalBuf[:0]
- huff.MaxDecodedSize = litRegenSize
if fourStreams {
- literals, err = huff.Decompress4X(literals, litRegenSize)
+ literals, err = huff.Decoder().Decompress4X(b.literalBuf[:0:litRegenSize], literals)
} else {
- literals, err = huff.Decompress1X(literals)
+ literals, err = huff.Decoder().Decompress1X(b.literalBuf[:0:litRegenSize], literals)
}
// Make sure we don't leak our literals buffer
- huff.Out = nil
if err != nil {
println("decompressing literals:", err)
return err
@@ -649,12 +642,13 @@ func (b *blockDec) decodeCompressed(hist *history) error {
}
} else {
if hist.huffTree != nil && huff != nil {
- huffDecoderPool.Put(hist.huffTree)
+ if hist.dict == nil || hist.dict.litDec != hist.huffTree {
+ huffDecoderPool.Put(hist.huffTree)
+ }
hist.huffTree = nil
}
}
if huff != nil {
- huff.Out = nil
hist.huffTree = huff
}
if debug {
@@ -687,14 +681,20 @@ func (b *blockDec) decodeCompressed(hist *history) error {
// If only recent offsets were not transferred, this would be an obvious win.
// Also, if first 3 sequences don't reference recent offsets, all sequences can be decoded.
- if err := seqs.initialize(br, hist, literals, b.dst); err != nil {
- println("initializing sequences:", err)
- return err
- }
hbytes := hist.b
if len(hbytes) > hist.windowSize {
hbytes = hbytes[len(hbytes)-hist.windowSize:]
+ // We do not need history any more.
+ if hist.dict != nil {
+ hist.dict.content = nil
+ }
}
+
+ if err := seqs.initialize(br, hist, literals, b.dst); err != nil {
+ println("initializing sequences:", err)
+ return err
+ }
+
err = seqs.decode(nSeqs, br, hbytes)
if err != nil {
return err
diff --git a/vendor/github.com/klauspost/compress/zstd/bytereader.go b/vendor/github.com/klauspost/compress/zstd/bytereader.go
index dc4378b64..f708df1c4 100644
--- a/vendor/github.com/klauspost/compress/zstd/bytereader.go
+++ b/vendor/github.com/klauspost/compress/zstd/bytereader.go
@@ -4,6 +4,8 @@
package zstd
+import "encoding/binary"
+
// byteReader provides a byte reader that reads
// little endian values from a byte stream.
// The input stream is manually advanced.
@@ -55,12 +57,7 @@ func (b byteReader) Uint32() uint32 {
}
return v
}
- b2 := b.b[b.off : b.off+4 : b.off+4]
- v3 := uint32(b2[3])
- v2 := uint32(b2[2])
- v1 := uint32(b2[1])
- v0 := uint32(b2[0])
- return v0 | (v1 << 8) | (v2 << 16) | (v3 << 24)
+ return binary.LittleEndian.Uint32(b.b[b.off : b.off+4])
}
// unread returns the unread portion of the input.
diff --git a/vendor/github.com/klauspost/compress/zstd/decoder.go b/vendor/github.com/klauspost/compress/zstd/decoder.go
index 324347623..8e34479ff 100644
--- a/vendor/github.com/klauspost/compress/zstd/decoder.go
+++ b/vendor/github.com/klauspost/compress/zstd/decoder.go
@@ -32,8 +32,9 @@ type Decoder struct {
// Current read position used for Reader functionality.
current decoderState
- // Custom dictionaries
- dicts map[uint32]struct{}
+ // Custom dictionaries.
+ // Always uses copies.
+ dicts map[uint32]dict
// streamWg is the waitgroup for all streams
streamWg sync.WaitGroup
@@ -295,10 +296,18 @@ func (d *Decoder) DecodeAll(input, dst []byte) ([]byte, error) {
frame.bBuf = input
for {
+ frame.history.reset()
err := frame.reset(&frame.bBuf)
if err == io.EOF {
return dst, nil
}
+ if frame.DictionaryID != nil {
+ dict, ok := d.dicts[*frame.DictionaryID]
+ if !ok {
+ return nil, ErrUnknownDictionary
+ }
+ frame.history.setDict(&dict)
+ }
if err != nil {
return dst, err
}
@@ -393,6 +402,19 @@ func (d *Decoder) Close() {
d.current.err = ErrDecoderClosed
}
+// RegisterDict will load a dictionary
+func (d *Decoder) RegisterDict(b []byte) error {
+ dc, err := loadDict(b)
+ if err != nil {
+ return err
+ }
+ if d.dicts == nil {
+ d.dicts = make(map[uint32]dict, 1)
+ }
+ d.dicts[dc.id] = *dc
+ return nil
+}
+
// IOReadCloser returns the decoder as an io.ReadCloser for convenience.
// Any changes to the decoder will be reflected, so the returned ReadCloser
// can be reused along with the decoder.
@@ -466,6 +488,14 @@ func (d *Decoder) startStreamDecoder(inStream chan decodeStream) {
if debug && err != nil {
println("Frame decoder returned", err)
}
+ if err == nil && frame.DictionaryID != nil {
+ dict, ok := d.dicts[*frame.DictionaryID]
+ if !ok {
+ err = ErrUnknownDictionary
+ } else {
+ frame.history.setDict(&dict)
+ }
+ }
if err != nil {
stream.output <- decodeOutput{
err: err,
diff --git a/vendor/github.com/klauspost/compress/zstd/dict.go b/vendor/github.com/klauspost/compress/zstd/dict.go
new file mode 100644
index 000000000..8eb6f6ba3
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/dict.go
@@ -0,0 +1,104 @@
+package zstd
+
+import (
+ "bytes"
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "io"
+
+ "github.com/klauspost/compress/huff0"
+)
+
+type dict struct {
+ id uint32
+
+ litDec *huff0.Scratch
+ llDec, ofDec, mlDec sequenceDec
+ offsets [3]int
+ content []byte
+}
+
+var dictMagic = [4]byte{0x37, 0xa4, 0x30, 0xec}
+
+// Load a dictionary as described in
+// https://github.com/facebook/zstd/blob/master/doc/zstd_compression_format.md#dictionary-format
+func loadDict(b []byte) (*dict, error) {
+ // Check static field size.
+ if len(b) <= 8+(3*4) {
+ return nil, io.ErrUnexpectedEOF
+ }
+ d := dict{
+ llDec: sequenceDec{fse: &fseDecoder{}},
+ ofDec: sequenceDec{fse: &fseDecoder{}},
+ mlDec: sequenceDec{fse: &fseDecoder{}},
+ }
+ if !bytes.Equal(b[:4], dictMagic[:]) {
+ return nil, ErrMagicMismatch
+ }
+ d.id = binary.LittleEndian.Uint32(b[4:8])
+ if d.id == 0 {
+ return nil, errors.New("dictionaries cannot have ID 0")
+ }
+
+ // Read literal table
+ var err error
+ d.litDec, b, err = huff0.ReadTable(b[8:], nil)
+ if err != nil {
+ return nil, err
+ }
+
+ br := byteReader{
+ b: b,
+ off: 0,
+ }
+ readDec := func(i tableIndex, dec *fseDecoder) error {
+ if err := dec.readNCount(&br, uint16(maxTableSymbol[i])); err != nil {
+ return err
+ }
+ if br.overread() {
+ return io.ErrUnexpectedEOF
+ }
+ err = dec.transform(symbolTableX[i])
+ if err != nil {
+ println("Transform table error:", err)
+ return err
+ }
+ if debug {
+ println("Read table ok", "symbolLen:", dec.symbolLen)
+ }
+ // Set decoders as predefined so they aren't reused.
+ dec.preDefined = true
+ return nil
+ }
+
+ if err := readDec(tableOffsets, d.ofDec.fse); err != nil {
+ return nil, err
+ }
+ if err := readDec(tableMatchLengths, d.mlDec.fse); err != nil {
+ return nil, err
+ }
+ if err := readDec(tableLiteralLengths, d.llDec.fse); err != nil {
+ return nil, err
+ }
+ if br.remain() < 12 {
+ return nil, io.ErrUnexpectedEOF
+ }
+
+ d.offsets[0] = int(br.Uint32())
+ br.advance(4)
+ d.offsets[1] = int(br.Uint32())
+ br.advance(4)
+ d.offsets[2] = int(br.Uint32())
+ br.advance(4)
+ if d.offsets[0] <= 0 || d.offsets[1] <= 0 || d.offsets[2] <= 0 {
+ return nil, errors.New("invalid offset in dictionary")
+ }
+ d.content = make([]byte, br.remain())
+ copy(d.content, br.unread())
+ if d.offsets[0] > len(d.content) || d.offsets[1] > len(d.content) || d.offsets[2] > len(d.content) {
+ return nil, fmt.Errorf("initial offset bigger than dictionary content size %d, offsets: %v", len(d.content), d.offsets)
+ }
+
+ return &d, nil
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/enc_dfast.go b/vendor/github.com/klauspost/compress/zstd/enc_dfast.go
index 5ebead9dc..50276bcde 100644
--- a/vendor/github.com/klauspost/compress/zstd/enc_dfast.go
+++ b/vendor/github.com/klauspost/compress/zstd/enc_dfast.go
@@ -671,4 +671,8 @@ encodeLoop:
println("returning, recent offsets:", blk.recentOffsets, "extra literals:", blk.extraLits)
}
+ // We do not store history, so we must offset e.cur to avoid false matches for next user.
+ if e.cur < bufferReset {
+ e.cur += int32(len(src))
+ }
}
diff --git a/vendor/github.com/klauspost/compress/zstd/enc_fast.go b/vendor/github.com/klauspost/compress/zstd/enc_fast.go
index d1d3658e6..4104b456c 100644
--- a/vendor/github.com/klauspost/compress/zstd/enc_fast.go
+++ b/vendor/github.com/klauspost/compress/zstd/enc_fast.go
@@ -383,6 +383,7 @@ func (e *fastEncoder) EncodeNoHist(blk *blockEnc, src []byte) {
panic("src too big")
}
}
+
// Protect against e.cur wraparound.
if e.cur >= bufferReset {
for i := range e.table[:] {
@@ -516,6 +517,9 @@ encodeLoop:
if debugAsserts && s-t > e.maxMatchOff {
panic("s - t >e.maxMatchOff")
}
+ if debugAsserts && t < 0 {
+ panic(fmt.Sprintf("t (%d) < 0, candidate.offset: %d, e.cur: %d, coffset0: %d, e.maxMatchOff: %d", t, candidate.offset, e.cur, coffset0, e.maxMatchOff))
+ }
break
}
@@ -548,6 +552,9 @@ encodeLoop:
panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
}
+ if debugAsserts && t < 0 {
+ panic(fmt.Sprintf("t (%d) < 0 ", t))
+ }
// Extend the 4-byte match as long as possible.
//l := e.matchlenNoHist(s+4, t+4, src) + 4
// l := int32(matchLen(src[s+4:], src[t+4:])) + 4
@@ -647,6 +654,10 @@ encodeLoop:
if debug {
println("returning, recent offsets:", blk.recentOffsets, "extra literals:", blk.extraLits)
}
+ // We do not store history, so we must offset e.cur to avoid false matches for next user.
+ if e.cur < bufferReset {
+ e.cur += int32(len(src))
+ }
}
func (e *fastBase) addBlock(src []byte) int32 {
@@ -714,7 +725,7 @@ func (e *fastBase) matchlen(s, t int32, src []byte) int32 {
}
// Reset the encoding table.
-func (e *fastBase) Reset() {
+func (e *fastBase) Reset(singleBlock bool) {
if e.blk == nil {
e.blk = &blockEnc{}
e.blk.init()
@@ -727,7 +738,7 @@ func (e *fastBase) Reset() {
} else {
e.crc.Reset()
}
- if cap(e.hist) < int(e.maxMatchOff*2) {
+ if !singleBlock && cap(e.hist) < int(e.maxMatchOff*2) {
l := e.maxMatchOff * 2
// Make it at least 1MB.
if l < 1<<20 {
diff --git a/vendor/github.com/klauspost/compress/zstd/encoder.go b/vendor/github.com/klauspost/compress/zstd/encoder.go
index af4f00b73..bf42bb1cf 100644
--- a/vendor/github.com/klauspost/compress/zstd/encoder.go
+++ b/vendor/github.com/klauspost/compress/zstd/encoder.go
@@ -35,7 +35,7 @@ type encoder interface {
AppendCRC([]byte) []byte
WindowSize(size int) int32
UseBlock(*blockEnc)
- Reset()
+ Reset(singleBlock bool)
}
type encoderState struct {
@@ -82,7 +82,10 @@ func (e *Encoder) initialize() {
}
e.encoders = make(chan encoder, e.o.concurrent)
for i := 0; i < e.o.concurrent; i++ {
- e.encoders <- e.o.encoder()
+ enc := e.o.encoder()
+ // If not single block, history will be allocated on first use.
+ enc.Reset(true)
+ e.encoders <- enc
}
}
@@ -112,7 +115,7 @@ func (e *Encoder) Reset(w io.Writer) {
s.filling = s.filling[:0]
s.current = s.current[:0]
s.previous = s.previous[:0]
- s.encoder.Reset()
+ s.encoder.Reset(false)
s.headerWritten = false
s.eofWritten = false
s.fullFrameWritten = false
@@ -445,11 +448,10 @@ func (e *Encoder) EncodeAll(src, dst []byte) []byte {
enc := <-e.encoders
defer func() {
// Release encoder reference to last block.
- enc.Reset()
+ // If a non-single block is needed the encoder will reset again.
+ enc.Reset(true)
e.encoders <- enc
}()
- enc.Reset()
- blk := enc.Block()
// Use single segments when above minimum window and below 1MB.
single := len(src) < 1<<20 && len(src) > MinWindowSize
if e.o.single != nil {
@@ -472,12 +474,13 @@ func (e *Encoder) EncodeAll(src, dst []byte) []byte {
panic(err)
}
- if len(src) <= e.o.blockSize && len(src) <= maxBlockSize {
+ // If we can do everything in one block, prefer that.
+ if len(src) <= maxCompressedBlockSize {
// Slightly faster with no history and everything in one block.
if e.o.crc {
_, _ = enc.CRC().Write(src)
}
- blk.reset(nil)
+ blk := enc.Block()
blk.last = true
enc.EncodeNoHist(blk, src)
@@ -504,6 +507,8 @@ func (e *Encoder) EncodeAll(src, dst []byte) []byte {
}
blk.output = oldout
} else {
+ enc.Reset(false)
+ blk := enc.Block()
for len(src) > 0 {
todo := src
if len(todo) > e.o.blockSize {
diff --git a/vendor/github.com/klauspost/compress/zstd/framedec.go b/vendor/github.com/klauspost/compress/zstd/framedec.go
index 780880ebe..fc4a566d3 100644
--- a/vendor/github.com/klauspost/compress/zstd/framedec.go
+++ b/vendor/github.com/klauspost/compress/zstd/framedec.go
@@ -40,7 +40,7 @@ type frameDec struct {
FrameContentSize uint64
frameDone sync.WaitGroup
- DictionaryID uint32
+ DictionaryID *uint32
HasCheckSum bool
SingleSegment bool
@@ -142,7 +142,7 @@ func (d *frameDec) reset(br byteBuffer) error {
// Read Dictionary_ID
// https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#dictionary_id
- d.DictionaryID = 0
+ d.DictionaryID = nil
if size := fhd & 3; size != 0 {
if size == 3 {
size = 4
@@ -154,19 +154,22 @@ func (d *frameDec) reset(br byteBuffer) error {
}
return io.ErrUnexpectedEOF
}
+ var id uint32
switch size {
case 1:
- d.DictionaryID = uint32(b[0])
+ id = uint32(b[0])
case 2:
- d.DictionaryID = uint32(b[0]) | (uint32(b[1]) << 8)
+ id = uint32(b[0]) | (uint32(b[1]) << 8)
case 4:
- d.DictionaryID = uint32(b[0]) | (uint32(b[1]) << 8) | (uint32(b[2]) << 16) | (uint32(b[3]) << 24)
+ id = uint32(b[0]) | (uint32(b[1]) << 8) | (uint32(b[2]) << 16) | (uint32(b[3]) << 24)
}
if debug {
- println("Dict size", size, "ID:", d.DictionaryID)
+ println("Dict size", size, "ID:", id)
}
- if d.DictionaryID != 0 {
- return ErrUnknownDictionary
+ if id > 0 {
+ // ID 0 means "sorry, no dictionary anyway".
+ // https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#dictionary-format
+ d.DictionaryID = &id
}
}
@@ -351,8 +354,6 @@ func (d *frameDec) initAsync() {
// When the frame has finished decoding the *bufio.Reader
// containing the remaining input will be sent on frameDec.frameDone.
func (d *frameDec) startDecoder(output chan decodeOutput) {
- // TODO: Init to dictionary
- d.history.reset()
written := int64(0)
defer func() {
@@ -445,8 +446,6 @@ func (d *frameDec) startDecoder(output chan decodeOutput) {
// runDecoder will create a sync decoder that will decode a block of data.
func (d *frameDec) runDecoder(dst []byte, dec *blockDec) ([]byte, error) {
- // TODO: Init to dictionary
- d.history.reset()
saved := d.history.b
// We use the history for output to avoid copying it.
diff --git a/vendor/github.com/klauspost/compress/zstd/fse_decoder.go b/vendor/github.com/klauspost/compress/zstd/fse_decoder.go
index e002be98b..957cfeb79 100644
--- a/vendor/github.com/klauspost/compress/zstd/fse_decoder.go
+++ b/vendor/github.com/klauspost/compress/zstd/fse_decoder.go
@@ -19,7 +19,7 @@ const (
* Increasing memory usage improves compression ratio
* Reduced memory usage can improve speed, due to cache effect
* Recommended max value is 14, for 16KB, which nicely fits into Intel x86 L1 cache */
- maxMemoryUsage = 11
+ maxMemoryUsage = tablelogAbsoluteMax + 2
maxTableLog = maxMemoryUsage - 2
maxTablesize = 1 << maxTableLog
diff --git a/vendor/github.com/klauspost/compress/zstd/history.go b/vendor/github.com/klauspost/compress/zstd/history.go
index e8c419bd5..f418f50fc 100644
--- a/vendor/github.com/klauspost/compress/zstd/history.go
+++ b/vendor/github.com/klauspost/compress/zstd/history.go
@@ -17,6 +17,7 @@ type history struct {
windowSize int
maxSize int
error bool
+ dict *dict
}
// reset will reset the history to initial state of a frame.
@@ -36,12 +37,27 @@ func (h *history) reset() {
}
h.decoders = sequenceDecs{}
if h.huffTree != nil {
- huffDecoderPool.Put(h.huffTree)
+ if h.dict == nil || h.dict.litDec != h.huffTree {
+ huffDecoderPool.Put(h.huffTree)
+ }
}
h.huffTree = nil
+ h.dict = nil
//printf("history created: %+v (l: %d, c: %d)", *h, len(h.b), cap(h.b))
}
+func (h *history) setDict(dict *dict) {
+ if dict == nil {
+ return
+ }
+ h.dict = dict
+ h.decoders.litLengths = dict.llDec
+ h.decoders.offsets = dict.ofDec
+ h.decoders.matchLengths = dict.mlDec
+ h.recentOffsets = dict.offsets
+ h.huffTree = dict.litDec
+}
+
// append bytes to history.
// This function will make sure there is space for it,
// if the buffer has been allocated with enough extra space.
diff --git a/vendor/github.com/klauspost/compress/zstd/seqdec.go b/vendor/github.com/klauspost/compress/zstd/seqdec.go
index 39238e16a..7ff870400 100644
--- a/vendor/github.com/klauspost/compress/zstd/seqdec.go
+++ b/vendor/github.com/klauspost/compress/zstd/seqdec.go
@@ -62,6 +62,7 @@ type sequenceDecs struct {
matchLengths sequenceDec
prevOffset [3]int
hist []byte
+ dict []byte
literals []byte
out []byte
windowSize int
@@ -85,6 +86,10 @@ func (s *sequenceDecs) initialize(br *bitReader, hist *history, literals, out []
s.maxBits = s.litLengths.fse.maxBits + s.offsets.fse.maxBits + s.matchLengths.fse.maxBits
s.windowSize = hist.windowSize
s.out = out
+ s.dict = nil
+ if hist.dict != nil {
+ s.dict = hist.dict.content
+ }
return nil
}
@@ -100,23 +105,78 @@ func (s *sequenceDecs) decode(seqs int, br *bitReader, hist []byte) error {
printf("reading sequence %d, exceeded available data\n", seqs-i)
return io.ErrUnexpectedEOF
}
- var litLen, matchOff, matchLen int
+ var ll, mo, ml int
if br.off > 4+((maxOffsetBits+16+16)>>3) {
- litLen, matchOff, matchLen = s.nextFast(br, llState, mlState, ofState)
+ // inlined function:
+ // ll, mo, ml = s.nextFast(br, llState, mlState, ofState)
+
+ // Final will not read from stream.
+ var llB, mlB, moB uint8
+ ll, llB = llState.final()
+ ml, mlB = mlState.final()
+ mo, moB = ofState.final()
+
+ // extra bits are stored in reverse order.
+ br.fillFast()
+ mo += br.getBits(moB)
+ if s.maxBits > 32 {
+ br.fillFast()
+ }
+ ml += br.getBits(mlB)
+ ll += br.getBits(llB)
+
+ if moB > 1 {
+ s.prevOffset[2] = s.prevOffset[1]
+ s.prevOffset[1] = s.prevOffset[0]
+ s.prevOffset[0] = mo
+ } else {
+ // mo = s.adjustOffset(mo, ll, moB)
+ // Inlined for rather big speedup
+ if ll == 0 {
+ // There is an exception though, when current sequence's literals_length = 0.
+ // In this case, repeated offsets are shifted by one, so an offset_value of 1 means Repeated_Offset2,
+ // an offset_value of 2 means Repeated_Offset3, and an offset_value of 3 means Repeated_Offset1 - 1_byte.
+ mo++
+ }
+
+ if mo == 0 {
+ mo = s.prevOffset[0]
+ } else {
+ var temp int
+ if mo == 3 {
+ temp = s.prevOffset[0] - 1
+ } else {
+ temp = s.prevOffset[mo]
+ }
+
+ if temp == 0 {
+ // 0 is not valid; input is corrupted; force offset to 1
+ println("temp was 0")
+ temp = 1
+ }
+
+ if mo != 1 {
+ s.prevOffset[2] = s.prevOffset[1]
+ }
+ s.prevOffset[1] = s.prevOffset[0]
+ s.prevOffset[0] = temp
+ mo = temp
+ }
+ }
br.fillFast()
} else {
- litLen, matchOff, matchLen = s.next(br, llState, mlState, ofState)
+ ll, mo, ml = s.next(br, llState, mlState, ofState)
br.fill()
}
if debugSequences {
- println("Seq", seqs-i-1, "Litlen:", litLen, "matchOff:", matchOff, "(abs) matchLen:", matchLen)
+ println("Seq", seqs-i-1, "Litlen:", ll, "mo:", mo, "(abs) ml:", ml)
}
- if litLen > len(s.literals) {
- return fmt.Errorf("unexpected literal count, want %d bytes, but only %d is available", litLen, len(s.literals))
+ if ll > len(s.literals) {
+ return fmt.Errorf("unexpected literal count, want %d bytes, but only %d is available", ll, len(s.literals))
}
- size := litLen + matchLen + len(s.out)
+ size := ll + ml + len(s.out)
if size-startSize > maxBlockSize {
return fmt.Errorf("output (%d) bigger than max block size", size)
}
@@ -127,52 +187,70 @@ func (s *sequenceDecs) decode(seqs int, br *bitReader, hist []byte) error {
s.out = append(s.out, make([]byte, maxBlockSize)...)
s.out = s.out[:len(s.out)-maxBlockSize]
}
- if matchLen > maxMatchLen {
- return fmt.Errorf("match len (%d) bigger than max allowed length", matchLen)
- }
- if matchOff > len(s.out)+len(hist)+litLen {
- return fmt.Errorf("match offset (%d) bigger than current history (%d)", matchOff, len(s.out)+len(hist)+litLen)
- }
- if matchOff > s.windowSize {
- return fmt.Errorf("match offset (%d) bigger than window size (%d)", matchOff, s.windowSize)
- }
- if matchOff == 0 && matchLen > 0 {
- return fmt.Errorf("zero matchoff and matchlen > 0")
+ if ml > maxMatchLen {
+ return fmt.Errorf("match len (%d) bigger than max allowed length", ml)
}
- s.out = append(s.out, s.literals[:litLen]...)
- s.literals = s.literals[litLen:]
+ // Add literals
+ s.out = append(s.out, s.literals[:ll]...)
+ s.literals = s.literals[ll:]
out := s.out
+ if mo > len(s.out)+len(hist) || mo > s.windowSize {
+ if len(s.dict) == 0 {
+ return fmt.Errorf("match offset (%d) bigger than current history (%d)", mo, len(s.out)+len(hist))
+ }
+
+ // we may be in dictionary.
+ dictO := len(s.dict) - (mo - (len(s.out) + len(hist)))
+ if dictO < 0 || dictO >= len(s.dict) {
+ return fmt.Errorf("match offset (%d) bigger than current history (%d)", mo, len(s.out)+len(hist))
+ }
+ end := dictO + ml
+ if end > len(s.dict) {
+ out = append(out, s.dict[dictO:]...)
+ mo -= len(s.dict) - dictO
+ ml -= len(s.dict) - dictO
+ } else {
+ out = append(out, s.dict[dictO:end]...)
+ mo = 0
+ ml = 0
+ }
+ }
+
+ if mo == 0 && ml > 0 {
+ return fmt.Errorf("zero matchoff and matchlen (%d) > 0", ml)
+ }
+
// Copy from history.
// TODO: Blocks without history could be made to ignore this completely.
- if v := matchOff - len(s.out); v > 0 {
+ if v := mo - len(s.out); v > 0 {
// v is the start position in history from end.
start := len(s.hist) - v
- if matchLen > v {
+ if ml > v {
// Some goes into current block.
// Copy remainder of history
out = append(out, s.hist[start:]...)
- matchOff -= v
- matchLen -= v
+ mo -= v
+ ml -= v
} else {
- out = append(out, s.hist[start:start+matchLen]...)
- matchLen = 0
+ out = append(out, s.hist[start:start+ml]...)
+ ml = 0
}
}
// We must be in current buffer now
- if matchLen > 0 {
- start := len(s.out) - matchOff
- if matchLen <= len(s.out)-start {
+ if ml > 0 {
+ start := len(s.out) - mo
+ if ml <= len(s.out)-start {
// No overlap
- out = append(out, s.out[start:start+matchLen]...)
+ out = append(out, s.out[start:start+ml]...)
} else {
// Overlapping copy
// Extend destination slice and copy one byte at the time.
- out = out[:len(out)+matchLen]
- src := out[start : start+matchLen]
+ out = out[:len(out)+ml]
+ src := out[start : start+ml]
// Destination is the space we just added.
- dst := out[len(out)-matchLen:]
+ dst := out[len(out)-ml:]
dst = dst[:len(src)]
for i := range src {
dst[i] = src[i]
diff --git a/vendor/github.com/seccomp/containers-golang/seccomp.json b/vendor/github.com/seccomp/containers-golang/seccomp.json
index 4c84d981f..06b39024a 100644
--- a/vendor/github.com/seccomp/containers-golang/seccomp.json
+++ b/vendor/github.com/seccomp/containers-golang/seccomp.json
@@ -317,7 +317,6 @@
"signalfd",
"signalfd4",
"sigreturn",
- "socket",
"socketcall",
"socketpair",
"splice",
@@ -769,6 +768,111 @@
]
},
"excludes": {}
+ },
+ {
+ "names": [
+ "socket"
+ ],
+ "action": "SCMP_ACT_ERRNO",
+ "args": [
+ {
+ "index": 0,
+ "value": 16,
+ "valueTwo": 0,
+ "op": "SCMP_CMP_EQ"
+ },
+ {
+ "index": 2,
+ "value": 9,
+ "valueTwo": 0,
+ "op": "SCMP_CMP_EQ"
+ }
+ ],
+ "comment": "",
+ "includes": {},
+ "excludes": {
+ "caps": [
+ "CAP_AUDIT_WRITE"
+ ]
+ },
+ "errnoRet": 22
+ },
+ {
+ "names": [
+ "socket"
+ ],
+ "action": "SCMP_ACT_ALLOW",
+ "args": [
+ {
+ "index": 2,
+ "value": 9,
+ "valueTwo": 0,
+ "op": "SCMP_CMP_NE"
+ }
+ ],
+ "comment": "",
+ "includes": {},
+ "excludes": {
+ "caps": [
+ "CAP_AUDIT_WRITE"
+ ]
+ }
+ },
+ {
+ "names": [
+ "socket"
+ ],
+ "action": "SCMP_ACT_ALLOW",
+ "args": [
+ {
+ "index": 0,
+ "value": 16,
+ "valueTwo": 0,
+ "op": "SCMP_CMP_NE"
+ }
+ ],
+ "comment": "",
+ "includes": {},
+ "excludes": {
+ "caps": [
+ "CAP_AUDIT_WRITE"
+ ]
+ }
+ },
+ {
+ "names": [
+ "socket"
+ ],
+ "action": "SCMP_ACT_ALLOW",
+ "args": [
+ {
+ "index": 2,
+ "value": 9,
+ "valueTwo": 0,
+ "op": "SCMP_CMP_NE"
+ }
+ ],
+ "comment": "",
+ "includes": {},
+ "excludes": {
+ "caps": [
+ "CAP_AUDIT_WRITE"
+ ]
+ }
+ },
+ {
+ "names": [
+ "socket"
+ ],
+ "action": "SCMP_ACT_ALLOW",
+ "args": null,
+ "comment": "",
+ "includes": {
+ "caps": [
+ "CAP_AUDIT_WRITE"
+ ]
+ },
+ "excludes": {}
}
]
} \ No newline at end of file
diff --git a/vendor/github.com/seccomp/containers-golang/seccomp_default_linux.go b/vendor/github.com/seccomp/containers-golang/seccomp_default_linux.go
index e137a5887..2e3e337ac 100644
--- a/vendor/github.com/seccomp/containers-golang/seccomp_default_linux.go
+++ b/vendor/github.com/seccomp/containers-golang/seccomp_default_linux.go
@@ -7,6 +7,8 @@
package seccomp // import "github.com/seccomp/containers-golang"
import (
+ "syscall"
+
"golang.org/x/sys/unix"
)
@@ -45,6 +47,8 @@ func arches() []Architecture {
// DefaultProfile defines the whitelist for the default seccomp profile.
func DefaultProfile() *Seccomp {
+ einval := uint(syscall.EINVAL)
+
syscalls := []*Syscall{
{
Names: []string{
@@ -313,7 +317,6 @@ func DefaultProfile() *Seccomp {
"signalfd",
"signalfd4",
"sigreturn",
- "socket",
"socketcall",
"socketpair",
"splice",
@@ -652,6 +655,85 @@ func DefaultProfile() *Seccomp {
Caps: []string{"CAP_SYS_TTY_CONFIG"},
},
},
+ {
+ Names: []string{
+ "socket",
+ },
+ Action: ActErrno,
+ ErrnoRet: &einval,
+ Args: []*Arg{
+ {
+ Index: 0,
+ Value: syscall.AF_NETLINK,
+ Op: OpEqualTo,
+ },
+ {
+ Index: 2,
+ Value: syscall.NETLINK_AUDIT,
+ Op: OpEqualTo,
+ },
+ },
+ Excludes: Filter{
+ Caps: []string{"CAP_AUDIT_WRITE"},
+ },
+ },
+ {
+ Names: []string{
+ "socket",
+ },
+ Action: ActAllow,
+ Args: []*Arg{
+ {
+ Index: 2,
+ Value: syscall.NETLINK_AUDIT,
+ Op: OpNotEqual,
+ },
+ },
+ Excludes: Filter{
+ Caps: []string{"CAP_AUDIT_WRITE"},
+ },
+ },
+ {
+ Names: []string{
+ "socket",
+ },
+ Action: ActAllow,
+ Args: []*Arg{
+ {
+ Index: 0,
+ Value: syscall.AF_NETLINK,
+ Op: OpNotEqual,
+ },
+ },
+ Excludes: Filter{
+ Caps: []string{"CAP_AUDIT_WRITE"},
+ },
+ },
+ {
+ Names: []string{
+ "socket",
+ },
+ Action: ActAllow,
+ Args: []*Arg{
+ {
+ Index: 2,
+ Value: syscall.NETLINK_AUDIT,
+ Op: OpNotEqual,
+ },
+ },
+ Excludes: Filter{
+ Caps: []string{"CAP_AUDIT_WRITE"},
+ },
+ },
+ {
+ Names: []string{
+ "socket",
+ },
+ Action: ActAllow,
+ Includes: Filter{
+ Caps: []string{"CAP_AUDIT_WRITE"},
+ },
+ },
}
return &Seccomp{
diff --git a/vendor/github.com/stretchr/testify/assert/assertion_format.go b/vendor/github.com/stretchr/testify/assert/assertion_format.go
index b4c46042b..49370eb16 100644
--- a/vendor/github.com/stretchr/testify/assert/assertion_format.go
+++ b/vendor/github.com/stretchr/testify/assert/assertion_format.go
@@ -6,7 +6,6 @@
package assert
import (
- io "io"
http "net/http"
url "net/url"
time "time"
@@ -202,11 +201,11 @@ func GreaterOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, arg
// assert.HTTPBodyContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
-func HTTPBodyContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, body io.Reader, str interface{}, msg string, args ...interface{}) bool {
+func HTTPBodyContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
- return HTTPBodyContains(t, handler, method, url, values, body, str, append([]interface{}{msg}, args...)...)
+ return HTTPBodyContains(t, handler, method, url, values, str, append([]interface{}{msg}, args...)...)
}
// HTTPBodyNotContainsf asserts that a specified handler returns a
@@ -215,11 +214,11 @@ func HTTPBodyContainsf(t TestingT, handler http.HandlerFunc, method string, url
// assert.HTTPBodyNotContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
-func HTTPBodyNotContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, body io.Reader, str interface{}, msg string, args ...interface{}) bool {
+func HTTPBodyNotContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
- return HTTPBodyNotContains(t, handler, method, url, values, body, str, append([]interface{}{msg}, args...)...)
+ return HTTPBodyNotContains(t, handler, method, url, values, str, append([]interface{}{msg}, args...)...)
}
// HTTPErrorf asserts that a specified handler returns an error status code.
diff --git a/vendor/github.com/stretchr/testify/assert/assertion_forward.go b/vendor/github.com/stretchr/testify/assert/assertion_forward.go
index 9bea8d189..9db889427 100644
--- a/vendor/github.com/stretchr/testify/assert/assertion_forward.go
+++ b/vendor/github.com/stretchr/testify/assert/assertion_forward.go
@@ -6,7 +6,6 @@
package assert
import (
- io "io"
http "net/http"
url "net/url"
time "time"
@@ -386,11 +385,11 @@ func (a *Assertions) Greaterf(e1 interface{}, e2 interface{}, msg string, args .
// a.HTTPBodyContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
//
// Returns whether the assertion was successful (true) or not (false).
-func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, url string, values url.Values, body io.Reader, str interface{}, msgAndArgs ...interface{}) bool {
+func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
- return HTTPBodyContains(a.t, handler, method, url, values, body, str, msgAndArgs...)
+ return HTTPBodyContains(a.t, handler, method, url, values, str, msgAndArgs...)
}
// HTTPBodyContainsf asserts that a specified handler returns a
@@ -399,11 +398,11 @@ func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, u
// a.HTTPBodyContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
-func (a *Assertions) HTTPBodyContainsf(handler http.HandlerFunc, method string, url string, values url.Values, body io.Reader, str interface{}, msg string, args ...interface{}) bool {
+func (a *Assertions) HTTPBodyContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
- return HTTPBodyContainsf(a.t, handler, method, url, values, body, str, msg, args...)
+ return HTTPBodyContainsf(a.t, handler, method, url, values, str, msg, args...)
}
// HTTPBodyNotContains asserts that a specified handler returns a
@@ -412,11 +411,11 @@ func (a *Assertions) HTTPBodyContainsf(handler http.HandlerFunc, method string,
// a.HTTPBodyNotContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
//
// Returns whether the assertion was successful (true) or not (false).
-func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string, url string, values url.Values, body io.Reader, str interface{}, msgAndArgs ...interface{}) bool {
+func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
- return HTTPBodyNotContains(a.t, handler, method, url, values, body, str, msgAndArgs...)
+ return HTTPBodyNotContains(a.t, handler, method, url, values, str, msgAndArgs...)
}
// HTTPBodyNotContainsf asserts that a specified handler returns a
@@ -425,11 +424,11 @@ func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string
// a.HTTPBodyNotContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
-func (a *Assertions) HTTPBodyNotContainsf(handler http.HandlerFunc, method string, url string, values url.Values, body io.Reader, str interface{}, msg string, args ...interface{}) bool {
+func (a *Assertions) HTTPBodyNotContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
- return HTTPBodyNotContainsf(a.t, handler, method, url, values, body, str, msg, args...)
+ return HTTPBodyNotContainsf(a.t, handler, method, url, values, str, msg, args...)
}
// HTTPError asserts that a specified handler returns an error status code.
diff --git a/vendor/github.com/stretchr/testify/assert/http_assertions.go b/vendor/github.com/stretchr/testify/assert/http_assertions.go
index 30ef7cc06..4ed341dd2 100644
--- a/vendor/github.com/stretchr/testify/assert/http_assertions.go
+++ b/vendor/github.com/stretchr/testify/assert/http_assertions.go
@@ -2,7 +2,6 @@ package assert
import (
"fmt"
- "io"
"net/http"
"net/http/httptest"
"net/url"
@@ -112,13 +111,9 @@ func HTTPStatusCode(t TestingT, handler http.HandlerFunc, method, url string, va
// HTTPBody is a helper that returns HTTP body of the response. It returns
// empty string if building a new request fails.
-func HTTPBody(handler http.HandlerFunc, method, url string, values url.Values, body io.Reader) string {
+func HTTPBody(handler http.HandlerFunc, method, url string, values url.Values) string {
w := httptest.NewRecorder()
-
- if values != nil {
- url = url + "?" + values.Encode()
- }
- req, err := http.NewRequest(method, url, body)
+ req, err := http.NewRequest(method, url+"?"+values.Encode(), nil)
if err != nil {
return ""
}
@@ -132,13 +127,13 @@ func HTTPBody(handler http.HandlerFunc, method, url string, values url.Values, b
// assert.HTTPBodyContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
//
// Returns whether the assertion was successful (true) or not (false).
-func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, body io.Reader, str interface{}, msgAndArgs ...interface{}) bool {
+func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
- httpBody := HTTPBody(handler, method, url, values, body)
+ body := HTTPBody(handler, method, url, values)
- contains := strings.Contains(httpBody, fmt.Sprint(str))
+ contains := strings.Contains(body, fmt.Sprint(str))
if !contains {
Fail(t, fmt.Sprintf("Expected response body for \"%s\" to contain \"%s\" but found \"%s\"", url+"?"+values.Encode(), str, body))
}
@@ -152,13 +147,13 @@ func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method, url string,
// assert.HTTPBodyNotContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
//
// Returns whether the assertion was successful (true) or not (false).
-func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, body io.Reader, str interface{}, msgAndArgs ...interface{}) bool {
+func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
- httpBody := HTTPBody(handler, method, url, values, body)
+ body := HTTPBody(handler, method, url, values)
- contains := strings.Contains(httpBody, fmt.Sprint(str))
+ contains := strings.Contains(body, fmt.Sprint(str))
if contains {
Fail(t, fmt.Sprintf("Expected response body for \"%s\" to NOT contain \"%s\" but found \"%s\"", url+"?"+values.Encode(), str, body))
}
diff --git a/vendor/github.com/stretchr/testify/require/require.go b/vendor/github.com/stretchr/testify/require/require.go
index 693648f8a..ec4624b28 100644
--- a/vendor/github.com/stretchr/testify/require/require.go
+++ b/vendor/github.com/stretchr/testify/require/require.go
@@ -7,7 +7,6 @@ package require
import (
assert "github.com/stretchr/testify/assert"
- io "io"
http "net/http"
url "net/url"
time "time"
@@ -489,11 +488,11 @@ func Greaterf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...in
// assert.HTTPBodyContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
//
// Returns whether the assertion was successful (true) or not (false).
-func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, body io.Reader, str interface{}, msgAndArgs ...interface{}) {
+func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
- if assert.HTTPBodyContains(t, handler, method, url, values, body, str, msgAndArgs...) {
+ if assert.HTTPBodyContains(t, handler, method, url, values, str, msgAndArgs...) {
return
}
t.FailNow()
@@ -505,11 +504,11 @@ func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method string, url s
// assert.HTTPBodyContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
-func HTTPBodyContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, body io.Reader, str interface{}, msg string, args ...interface{}) {
+func HTTPBodyContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
- if assert.HTTPBodyContainsf(t, handler, method, url, values, body, str, msg, args...) {
+ if assert.HTTPBodyContainsf(t, handler, method, url, values, str, msg, args...) {
return
}
t.FailNow()
@@ -521,11 +520,11 @@ func HTTPBodyContainsf(t TestingT, handler http.HandlerFunc, method string, url
// assert.HTTPBodyNotContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
//
// Returns whether the assertion was successful (true) or not (false).
-func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, body io.Reader, str interface{}, msgAndArgs ...interface{}) {
+func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
- if assert.HTTPBodyNotContains(t, handler, method, url, values, body, str, msgAndArgs...) {
+ if assert.HTTPBodyNotContains(t, handler, method, url, values, str, msgAndArgs...) {
return
}
t.FailNow()
@@ -537,11 +536,11 @@ func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method string, ur
// assert.HTTPBodyNotContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
-func HTTPBodyNotContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, body io.Reader, str interface{}, msg string, args ...interface{}) {
+func HTTPBodyNotContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
- if assert.HTTPBodyNotContainsf(t, handler, method, url, values, body, str, msg, args...) {
+ if assert.HTTPBodyNotContainsf(t, handler, method, url, values, str, msg, args...) {
return
}
t.FailNow()
diff --git a/vendor/github.com/stretchr/testify/require/require_forward.go b/vendor/github.com/stretchr/testify/require/require_forward.go
index 84fc1c88d..103d7dcb6 100644
--- a/vendor/github.com/stretchr/testify/require/require_forward.go
+++ b/vendor/github.com/stretchr/testify/require/require_forward.go
@@ -7,7 +7,6 @@ package require
import (
assert "github.com/stretchr/testify/assert"
- io "io"
http "net/http"
url "net/url"
time "time"
@@ -387,11 +386,11 @@ func (a *Assertions) Greaterf(e1 interface{}, e2 interface{}, msg string, args .
// a.HTTPBodyContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
//
// Returns whether the assertion was successful (true) or not (false).
-func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, url string, values url.Values, body io.Reader, str interface{}, msgAndArgs ...interface{}) {
+func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
- HTTPBodyContains(a.t, handler, method, url, values, body, str, msgAndArgs...)
+ HTTPBodyContains(a.t, handler, method, url, values, str, msgAndArgs...)
}
// HTTPBodyContainsf asserts that a specified handler returns a
@@ -400,11 +399,11 @@ func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, u
// a.HTTPBodyContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
-func (a *Assertions) HTTPBodyContainsf(handler http.HandlerFunc, method string, url string, values url.Values, body io.Reader, str interface{}, msg string, args ...interface{}) {
+func (a *Assertions) HTTPBodyContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
- HTTPBodyContainsf(a.t, handler, method, url, values, body, str, msg, args...)
+ HTTPBodyContainsf(a.t, handler, method, url, values, str, msg, args...)
}
// HTTPBodyNotContains asserts that a specified handler returns a
@@ -413,11 +412,11 @@ func (a *Assertions) HTTPBodyContainsf(handler http.HandlerFunc, method string,
// a.HTTPBodyNotContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
//
// Returns whether the assertion was successful (true) or not (false).
-func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string, url string, values url.Values, body io.Reader, str interface{}, msgAndArgs ...interface{}) {
+func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
- HTTPBodyNotContains(a.t, handler, method, url, values, body, str, msgAndArgs...)
+ HTTPBodyNotContains(a.t, handler, method, url, values, str, msgAndArgs...)
}
// HTTPBodyNotContainsf asserts that a specified handler returns a
@@ -426,11 +425,11 @@ func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string
// a.HTTPBodyNotContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
-func (a *Assertions) HTTPBodyNotContainsf(handler http.HandlerFunc, method string, url string, values url.Values, body io.Reader, str interface{}, msg string, args ...interface{}) {
+func (a *Assertions) HTTPBodyNotContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
- HTTPBodyNotContainsf(a.t, handler, method, url, values, body, str, msg, args...)
+ HTTPBodyNotContainsf(a.t, handler, method, url, values, str, msg, args...)
}
// HTTPError asserts that a specified handler returns an error status code.
diff --git a/vendor/golang.org/x/crypto/ssh/agent/client.go b/vendor/golang.org/x/crypto/ssh/agent/client.go
new file mode 100644
index 000000000..b909471cc
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/agent/client.go
@@ -0,0 +1,813 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package agent implements the ssh-agent protocol, and provides both
+// a client and a server. The client can talk to a standard ssh-agent
+// that uses UNIX sockets, and one could implement an alternative
+// ssh-agent process using the sample server.
+//
+// References:
+// [PROTOCOL.agent]: https://tools.ietf.org/html/draft-miller-ssh-agent-00
+package agent // import "golang.org/x/crypto/ssh/agent"
+
+import (
+ "bytes"
+ "crypto/dsa"
+ "crypto/ecdsa"
+ "crypto/elliptic"
+ "crypto/rsa"
+ "encoding/base64"
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "io"
+ "math/big"
+ "sync"
+
+ "crypto"
+ "golang.org/x/crypto/ed25519"
+ "golang.org/x/crypto/ssh"
+)
+
+// SignatureFlags represent additional flags that can be passed to the signature
+// requests an defined in [PROTOCOL.agent] section 4.5.1.
+type SignatureFlags uint32
+
+// SignatureFlag values as defined in [PROTOCOL.agent] section 5.3.
+const (
+ SignatureFlagReserved SignatureFlags = 1 << iota
+ SignatureFlagRsaSha256
+ SignatureFlagRsaSha512
+)
+
+// Agent represents the capabilities of an ssh-agent.
+type Agent interface {
+ // List returns the identities known to the agent.
+ List() ([]*Key, error)
+
+ // Sign has the agent sign the data using a protocol 2 key as defined
+ // in [PROTOCOL.agent] section 2.6.2.
+ Sign(key ssh.PublicKey, data []byte) (*ssh.Signature, error)
+
+ // Add adds a private key to the agent.
+ Add(key AddedKey) error
+
+ // Remove removes all identities with the given public key.
+ Remove(key ssh.PublicKey) error
+
+ // RemoveAll removes all identities.
+ RemoveAll() error
+
+ // Lock locks the agent. Sign and Remove will fail, and List will empty an empty list.
+ Lock(passphrase []byte) error
+
+ // Unlock undoes the effect of Lock
+ Unlock(passphrase []byte) error
+
+ // Signers returns signers for all the known keys.
+ Signers() ([]ssh.Signer, error)
+}
+
+type ExtendedAgent interface {
+ Agent
+
+ // SignWithFlags signs like Sign, but allows for additional flags to be sent/received
+ SignWithFlags(key ssh.PublicKey, data []byte, flags SignatureFlags) (*ssh.Signature, error)
+
+ // Extension processes a custom extension request. Standard-compliant agents are not
+ // required to support any extensions, but this method allows agents to implement
+ // vendor-specific methods or add experimental features. See [PROTOCOL.agent] section 4.7.
+ // If agent extensions are unsupported entirely this method MUST return an
+ // ErrExtensionUnsupported error. Similarly, if just the specific extensionType in
+ // the request is unsupported by the agent then ErrExtensionUnsupported MUST be
+ // returned.
+ //
+ // In the case of success, since [PROTOCOL.agent] section 4.7 specifies that the contents
+ // of the response are unspecified (including the type of the message), the complete
+ // response will be returned as a []byte slice, including the "type" byte of the message.
+ Extension(extensionType string, contents []byte) ([]byte, error)
+}
+
+// ConstraintExtension describes an optional constraint defined by users.
+type ConstraintExtension struct {
+ // ExtensionName consist of a UTF-8 string suffixed by the
+ // implementation domain following the naming scheme defined
+ // in Section 4.2 of [RFC4251], e.g. "foo@example.com".
+ ExtensionName string
+ // ExtensionDetails contains the actual content of the extended
+ // constraint.
+ ExtensionDetails []byte
+}
+
+// AddedKey describes an SSH key to be added to an Agent.
+type AddedKey struct {
+ // PrivateKey must be a *rsa.PrivateKey, *dsa.PrivateKey,
+ // ed25519.PrivateKey or *ecdsa.PrivateKey, which will be inserted into the
+ // agent.
+ PrivateKey interface{}
+ // Certificate, if not nil, is communicated to the agent and will be
+ // stored with the key.
+ Certificate *ssh.Certificate
+ // Comment is an optional, free-form string.
+ Comment string
+ // LifetimeSecs, if not zero, is the number of seconds that the
+ // agent will store the key for.
+ LifetimeSecs uint32
+ // ConfirmBeforeUse, if true, requests that the agent confirm with the
+ // user before each use of this key.
+ ConfirmBeforeUse bool
+ // ConstraintExtensions are the experimental or private-use constraints
+ // defined by users.
+ ConstraintExtensions []ConstraintExtension
+}
+
+// See [PROTOCOL.agent], section 3.
+const (
+ agentRequestV1Identities = 1
+ agentRemoveAllV1Identities = 9
+
+ // 3.2 Requests from client to agent for protocol 2 key operations
+ agentAddIdentity = 17
+ agentRemoveIdentity = 18
+ agentRemoveAllIdentities = 19
+ agentAddIDConstrained = 25
+
+ // 3.3 Key-type independent requests from client to agent
+ agentAddSmartcardKey = 20
+ agentRemoveSmartcardKey = 21
+ agentLock = 22
+ agentUnlock = 23
+ agentAddSmartcardKeyConstrained = 26
+
+ // 3.7 Key constraint identifiers
+ agentConstrainLifetime = 1
+ agentConstrainConfirm = 2
+ agentConstrainExtension = 3
+)
+
+// maxAgentResponseBytes is the maximum agent reply size that is accepted. This
+// is a sanity check, not a limit in the spec.
+const maxAgentResponseBytes = 16 << 20
+
+// Agent messages:
+// These structures mirror the wire format of the corresponding ssh agent
+// messages found in [PROTOCOL.agent].
+
+// 3.4 Generic replies from agent to client
+const agentFailure = 5
+
+type failureAgentMsg struct{}
+
+const agentSuccess = 6
+
+type successAgentMsg struct{}
+
+// See [PROTOCOL.agent], section 2.5.2.
+const agentRequestIdentities = 11
+
+type requestIdentitiesAgentMsg struct{}
+
+// See [PROTOCOL.agent], section 2.5.2.
+const agentIdentitiesAnswer = 12
+
+type identitiesAnswerAgentMsg struct {
+ NumKeys uint32 `sshtype:"12"`
+ Keys []byte `ssh:"rest"`
+}
+
+// See [PROTOCOL.agent], section 2.6.2.
+const agentSignRequest = 13
+
+type signRequestAgentMsg struct {
+ KeyBlob []byte `sshtype:"13"`
+ Data []byte
+ Flags uint32
+}
+
+// See [PROTOCOL.agent], section 2.6.2.
+
+// 3.6 Replies from agent to client for protocol 2 key operations
+const agentSignResponse = 14
+
+type signResponseAgentMsg struct {
+ SigBlob []byte `sshtype:"14"`
+}
+
+type publicKey struct {
+ Format string
+ Rest []byte `ssh:"rest"`
+}
+
+// 3.7 Key constraint identifiers
+type constrainLifetimeAgentMsg struct {
+ LifetimeSecs uint32 `sshtype:"1"`
+}
+
+type constrainExtensionAgentMsg struct {
+ ExtensionName string `sshtype:"3"`
+ ExtensionDetails []byte
+
+ // Rest is a field used for parsing, not part of message
+ Rest []byte `ssh:"rest"`
+}
+
+// See [PROTOCOL.agent], section 4.7
+const agentExtension = 27
+const agentExtensionFailure = 28
+
+// ErrExtensionUnsupported indicates that an extension defined in
+// [PROTOCOL.agent] section 4.7 is unsupported by the agent. Specifically this
+// error indicates that the agent returned a standard SSH_AGENT_FAILURE message
+// as the result of a SSH_AGENTC_EXTENSION request. Note that the protocol
+// specification (and therefore this error) does not distinguish between a
+// specific extension being unsupported and extensions being unsupported entirely.
+var ErrExtensionUnsupported = errors.New("agent: extension unsupported")
+
+type extensionAgentMsg struct {
+ ExtensionType string `sshtype:"27"`
+ Contents []byte
+}
+
+// Key represents a protocol 2 public key as defined in
+// [PROTOCOL.agent], section 2.5.2.
+type Key struct {
+ Format string
+ Blob []byte
+ Comment string
+}
+
+func clientErr(err error) error {
+ return fmt.Errorf("agent: client error: %v", err)
+}
+
+// String returns the storage form of an agent key with the format, base64
+// encoded serialized key, and the comment if it is not empty.
+func (k *Key) String() string {
+ s := string(k.Format) + " " + base64.StdEncoding.EncodeToString(k.Blob)
+
+ if k.Comment != "" {
+ s += " " + k.Comment
+ }
+
+ return s
+}
+
+// Type returns the public key type.
+func (k *Key) Type() string {
+ return k.Format
+}
+
+// Marshal returns key blob to satisfy the ssh.PublicKey interface.
+func (k *Key) Marshal() []byte {
+ return k.Blob
+}
+
+// Verify satisfies the ssh.PublicKey interface.
+func (k *Key) Verify(data []byte, sig *ssh.Signature) error {
+ pubKey, err := ssh.ParsePublicKey(k.Blob)
+ if err != nil {
+ return fmt.Errorf("agent: bad public key: %v", err)
+ }
+ return pubKey.Verify(data, sig)
+}
+
+type wireKey struct {
+ Format string
+ Rest []byte `ssh:"rest"`
+}
+
+func parseKey(in []byte) (out *Key, rest []byte, err error) {
+ var record struct {
+ Blob []byte
+ Comment string
+ Rest []byte `ssh:"rest"`
+ }
+
+ if err := ssh.Unmarshal(in, &record); err != nil {
+ return nil, nil, err
+ }
+
+ var wk wireKey
+ if err := ssh.Unmarshal(record.Blob, &wk); err != nil {
+ return nil, nil, err
+ }
+
+ return &Key{
+ Format: wk.Format,
+ Blob: record.Blob,
+ Comment: record.Comment,
+ }, record.Rest, nil
+}
+
+// client is a client for an ssh-agent process.
+type client struct {
+ // conn is typically a *net.UnixConn
+ conn io.ReadWriter
+ // mu is used to prevent concurrent access to the agent
+ mu sync.Mutex
+}
+
+// NewClient returns an Agent that talks to an ssh-agent process over
+// the given connection.
+func NewClient(rw io.ReadWriter) ExtendedAgent {
+ return &client{conn: rw}
+}
+
+// call sends an RPC to the agent. On success, the reply is
+// unmarshaled into reply and replyType is set to the first byte of
+// the reply, which contains the type of the message.
+func (c *client) call(req []byte) (reply interface{}, err error) {
+ buf, err := c.callRaw(req)
+ if err != nil {
+ return nil, err
+ }
+ reply, err = unmarshal(buf)
+ if err != nil {
+ return nil, clientErr(err)
+ }
+ return reply, nil
+}
+
+// callRaw sends an RPC to the agent. On success, the raw
+// bytes of the response are returned; no unmarshalling is
+// performed on the response.
+func (c *client) callRaw(req []byte) (reply []byte, err error) {
+ c.mu.Lock()
+ defer c.mu.Unlock()
+
+ msg := make([]byte, 4+len(req))
+ binary.BigEndian.PutUint32(msg, uint32(len(req)))
+ copy(msg[4:], req)
+ if _, err = c.conn.Write(msg); err != nil {
+ return nil, clientErr(err)
+ }
+
+ var respSizeBuf [4]byte
+ if _, err = io.ReadFull(c.conn, respSizeBuf[:]); err != nil {
+ return nil, clientErr(err)
+ }
+ respSize := binary.BigEndian.Uint32(respSizeBuf[:])
+ if respSize > maxAgentResponseBytes {
+ return nil, clientErr(errors.New("response too large"))
+ }
+
+ buf := make([]byte, respSize)
+ if _, err = io.ReadFull(c.conn, buf); err != nil {
+ return nil, clientErr(err)
+ }
+ return buf, nil
+}
+
+func (c *client) simpleCall(req []byte) error {
+ resp, err := c.call(req)
+ if err != nil {
+ return err
+ }
+ if _, ok := resp.(*successAgentMsg); ok {
+ return nil
+ }
+ return errors.New("agent: failure")
+}
+
+func (c *client) RemoveAll() error {
+ return c.simpleCall([]byte{agentRemoveAllIdentities})
+}
+
+func (c *client) Remove(key ssh.PublicKey) error {
+ req := ssh.Marshal(&agentRemoveIdentityMsg{
+ KeyBlob: key.Marshal(),
+ })
+ return c.simpleCall(req)
+}
+
+func (c *client) Lock(passphrase []byte) error {
+ req := ssh.Marshal(&agentLockMsg{
+ Passphrase: passphrase,
+ })
+ return c.simpleCall(req)
+}
+
+func (c *client) Unlock(passphrase []byte) error {
+ req := ssh.Marshal(&agentUnlockMsg{
+ Passphrase: passphrase,
+ })
+ return c.simpleCall(req)
+}
+
+// List returns the identities known to the agent.
+func (c *client) List() ([]*Key, error) {
+ // see [PROTOCOL.agent] section 2.5.2.
+ req := []byte{agentRequestIdentities}
+
+ msg, err := c.call(req)
+ if err != nil {
+ return nil, err
+ }
+
+ switch msg := msg.(type) {
+ case *identitiesAnswerAgentMsg:
+ if msg.NumKeys > maxAgentResponseBytes/8 {
+ return nil, errors.New("agent: too many keys in agent reply")
+ }
+ keys := make([]*Key, msg.NumKeys)
+ data := msg.Keys
+ for i := uint32(0); i < msg.NumKeys; i++ {
+ var key *Key
+ var err error
+ if key, data, err = parseKey(data); err != nil {
+ return nil, err
+ }
+ keys[i] = key
+ }
+ return keys, nil
+ case *failureAgentMsg:
+ return nil, errors.New("agent: failed to list keys")
+ }
+ panic("unreachable")
+}
+
+// Sign has the agent sign the data using a protocol 2 key as defined
+// in [PROTOCOL.agent] section 2.6.2.
+func (c *client) Sign(key ssh.PublicKey, data []byte) (*ssh.Signature, error) {
+ return c.SignWithFlags(key, data, 0)
+}
+
+func (c *client) SignWithFlags(key ssh.PublicKey, data []byte, flags SignatureFlags) (*ssh.Signature, error) {
+ req := ssh.Marshal(signRequestAgentMsg{
+ KeyBlob: key.Marshal(),
+ Data: data,
+ Flags: uint32(flags),
+ })
+
+ msg, err := c.call(req)
+ if err != nil {
+ return nil, err
+ }
+
+ switch msg := msg.(type) {
+ case *signResponseAgentMsg:
+ var sig ssh.Signature
+ if err := ssh.Unmarshal(msg.SigBlob, &sig); err != nil {
+ return nil, err
+ }
+
+ return &sig, nil
+ case *failureAgentMsg:
+ return nil, errors.New("agent: failed to sign challenge")
+ }
+ panic("unreachable")
+}
+
+// unmarshal parses an agent message in packet, returning the parsed
+// form and the message type of packet.
+func unmarshal(packet []byte) (interface{}, error) {
+ if len(packet) < 1 {
+ return nil, errors.New("agent: empty packet")
+ }
+ var msg interface{}
+ switch packet[0] {
+ case agentFailure:
+ return new(failureAgentMsg), nil
+ case agentSuccess:
+ return new(successAgentMsg), nil
+ case agentIdentitiesAnswer:
+ msg = new(identitiesAnswerAgentMsg)
+ case agentSignResponse:
+ msg = new(signResponseAgentMsg)
+ case agentV1IdentitiesAnswer:
+ msg = new(agentV1IdentityMsg)
+ default:
+ return nil, fmt.Errorf("agent: unknown type tag %d", packet[0])
+ }
+ if err := ssh.Unmarshal(packet, msg); err != nil {
+ return nil, err
+ }
+ return msg, nil
+}
+
+type rsaKeyMsg struct {
+ Type string `sshtype:"17|25"`
+ N *big.Int
+ E *big.Int
+ D *big.Int
+ Iqmp *big.Int // IQMP = Inverse Q Mod P
+ P *big.Int
+ Q *big.Int
+ Comments string
+ Constraints []byte `ssh:"rest"`
+}
+
+type dsaKeyMsg struct {
+ Type string `sshtype:"17|25"`
+ P *big.Int
+ Q *big.Int
+ G *big.Int
+ Y *big.Int
+ X *big.Int
+ Comments string
+ Constraints []byte `ssh:"rest"`
+}
+
+type ecdsaKeyMsg struct {
+ Type string `sshtype:"17|25"`
+ Curve string
+ KeyBytes []byte
+ D *big.Int
+ Comments string
+ Constraints []byte `ssh:"rest"`
+}
+
+type ed25519KeyMsg struct {
+ Type string `sshtype:"17|25"`
+ Pub []byte
+ Priv []byte
+ Comments string
+ Constraints []byte `ssh:"rest"`
+}
+
+// Insert adds a private key to the agent.
+func (c *client) insertKey(s interface{}, comment string, constraints []byte) error {
+ var req []byte
+ switch k := s.(type) {
+ case *rsa.PrivateKey:
+ if len(k.Primes) != 2 {
+ return fmt.Errorf("agent: unsupported RSA key with %d primes", len(k.Primes))
+ }
+ k.Precompute()
+ req = ssh.Marshal(rsaKeyMsg{
+ Type: ssh.KeyAlgoRSA,
+ N: k.N,
+ E: big.NewInt(int64(k.E)),
+ D: k.D,
+ Iqmp: k.Precomputed.Qinv,
+ P: k.Primes[0],
+ Q: k.Primes[1],
+ Comments: comment,
+ Constraints: constraints,
+ })
+ case *dsa.PrivateKey:
+ req = ssh.Marshal(dsaKeyMsg{
+ Type: ssh.KeyAlgoDSA,
+ P: k.P,
+ Q: k.Q,
+ G: k.G,
+ Y: k.Y,
+ X: k.X,
+ Comments: comment,
+ Constraints: constraints,
+ })
+ case *ecdsa.PrivateKey:
+ nistID := fmt.Sprintf("nistp%d", k.Params().BitSize)
+ req = ssh.Marshal(ecdsaKeyMsg{
+ Type: "ecdsa-sha2-" + nistID,
+ Curve: nistID,
+ KeyBytes: elliptic.Marshal(k.Curve, k.X, k.Y),
+ D: k.D,
+ Comments: comment,
+ Constraints: constraints,
+ })
+ case ed25519.PrivateKey:
+ req = ssh.Marshal(ed25519KeyMsg{
+ Type: ssh.KeyAlgoED25519,
+ Pub: []byte(k)[32:],
+ Priv: []byte(k),
+ Comments: comment,
+ Constraints: constraints,
+ })
+ // This function originally supported only *ed25519.PrivateKey, however the
+ // general idiom is to pass ed25519.PrivateKey by value, not by pointer.
+ // We still support the pointer variant for backwards compatibility.
+ case *ed25519.PrivateKey:
+ req = ssh.Marshal(ed25519KeyMsg{
+ Type: ssh.KeyAlgoED25519,
+ Pub: []byte(*k)[32:],
+ Priv: []byte(*k),
+ Comments: comment,
+ Constraints: constraints,
+ })
+ default:
+ return fmt.Errorf("agent: unsupported key type %T", s)
+ }
+
+ // if constraints are present then the message type needs to be changed.
+ if len(constraints) != 0 {
+ req[0] = agentAddIDConstrained
+ }
+
+ resp, err := c.call(req)
+ if err != nil {
+ return err
+ }
+ if _, ok := resp.(*successAgentMsg); ok {
+ return nil
+ }
+ return errors.New("agent: failure")
+}
+
+type rsaCertMsg struct {
+ Type string `sshtype:"17|25"`
+ CertBytes []byte
+ D *big.Int
+ Iqmp *big.Int // IQMP = Inverse Q Mod P
+ P *big.Int
+ Q *big.Int
+ Comments string
+ Constraints []byte `ssh:"rest"`
+}
+
+type dsaCertMsg struct {
+ Type string `sshtype:"17|25"`
+ CertBytes []byte
+ X *big.Int
+ Comments string
+ Constraints []byte `ssh:"rest"`
+}
+
+type ecdsaCertMsg struct {
+ Type string `sshtype:"17|25"`
+ CertBytes []byte
+ D *big.Int
+ Comments string
+ Constraints []byte `ssh:"rest"`
+}
+
+type ed25519CertMsg struct {
+ Type string `sshtype:"17|25"`
+ CertBytes []byte
+ Pub []byte
+ Priv []byte
+ Comments string
+ Constraints []byte `ssh:"rest"`
+}
+
+// Add adds a private key to the agent. If a certificate is given,
+// that certificate is added instead as public key.
+func (c *client) Add(key AddedKey) error {
+ var constraints []byte
+
+ if secs := key.LifetimeSecs; secs != 0 {
+ constraints = append(constraints, ssh.Marshal(constrainLifetimeAgentMsg{secs})...)
+ }
+
+ if key.ConfirmBeforeUse {
+ constraints = append(constraints, agentConstrainConfirm)
+ }
+
+ cert := key.Certificate
+ if cert == nil {
+ return c.insertKey(key.PrivateKey, key.Comment, constraints)
+ }
+ return c.insertCert(key.PrivateKey, cert, key.Comment, constraints)
+}
+
+func (c *client) insertCert(s interface{}, cert *ssh.Certificate, comment string, constraints []byte) error {
+ var req []byte
+ switch k := s.(type) {
+ case *rsa.PrivateKey:
+ if len(k.Primes) != 2 {
+ return fmt.Errorf("agent: unsupported RSA key with %d primes", len(k.Primes))
+ }
+ k.Precompute()
+ req = ssh.Marshal(rsaCertMsg{
+ Type: cert.Type(),
+ CertBytes: cert.Marshal(),
+ D: k.D,
+ Iqmp: k.Precomputed.Qinv,
+ P: k.Primes[0],
+ Q: k.Primes[1],
+ Comments: comment,
+ Constraints: constraints,
+ })
+ case *dsa.PrivateKey:
+ req = ssh.Marshal(dsaCertMsg{
+ Type: cert.Type(),
+ CertBytes: cert.Marshal(),
+ X: k.X,
+ Comments: comment,
+ Constraints: constraints,
+ })
+ case *ecdsa.PrivateKey:
+ req = ssh.Marshal(ecdsaCertMsg{
+ Type: cert.Type(),
+ CertBytes: cert.Marshal(),
+ D: k.D,
+ Comments: comment,
+ Constraints: constraints,
+ })
+ case ed25519.PrivateKey:
+ req = ssh.Marshal(ed25519CertMsg{
+ Type: cert.Type(),
+ CertBytes: cert.Marshal(),
+ Pub: []byte(k)[32:],
+ Priv: []byte(k),
+ Comments: comment,
+ Constraints: constraints,
+ })
+ // This function originally supported only *ed25519.PrivateKey, however the
+ // general idiom is to pass ed25519.PrivateKey by value, not by pointer.
+ // We still support the pointer variant for backwards compatibility.
+ case *ed25519.PrivateKey:
+ req = ssh.Marshal(ed25519CertMsg{
+ Type: cert.Type(),
+ CertBytes: cert.Marshal(),
+ Pub: []byte(*k)[32:],
+ Priv: []byte(*k),
+ Comments: comment,
+ Constraints: constraints,
+ })
+ default:
+ return fmt.Errorf("agent: unsupported key type %T", s)
+ }
+
+ // if constraints are present then the message type needs to be changed.
+ if len(constraints) != 0 {
+ req[0] = agentAddIDConstrained
+ }
+
+ signer, err := ssh.NewSignerFromKey(s)
+ if err != nil {
+ return err
+ }
+ if bytes.Compare(cert.Key.Marshal(), signer.PublicKey().Marshal()) != 0 {
+ return errors.New("agent: signer and cert have different public key")
+ }
+
+ resp, err := c.call(req)
+ if err != nil {
+ return err
+ }
+ if _, ok := resp.(*successAgentMsg); ok {
+ return nil
+ }
+ return errors.New("agent: failure")
+}
+
+// Signers provides a callback for client authentication.
+func (c *client) Signers() ([]ssh.Signer, error) {
+ keys, err := c.List()
+ if err != nil {
+ return nil, err
+ }
+
+ var result []ssh.Signer
+ for _, k := range keys {
+ result = append(result, &agentKeyringSigner{c, k})
+ }
+ return result, nil
+}
+
+type agentKeyringSigner struct {
+ agent *client
+ pub ssh.PublicKey
+}
+
+func (s *agentKeyringSigner) PublicKey() ssh.PublicKey {
+ return s.pub
+}
+
+func (s *agentKeyringSigner) Sign(rand io.Reader, data []byte) (*ssh.Signature, error) {
+ // The agent has its own entropy source, so the rand argument is ignored.
+ return s.agent.Sign(s.pub, data)
+}
+
+func (s *agentKeyringSigner) SignWithOpts(rand io.Reader, data []byte, opts crypto.SignerOpts) (*ssh.Signature, error) {
+ var flags SignatureFlags
+ if opts != nil {
+ switch opts.HashFunc() {
+ case crypto.SHA256:
+ flags = SignatureFlagRsaSha256
+ case crypto.SHA512:
+ flags = SignatureFlagRsaSha512
+ }
+ }
+ return s.agent.SignWithFlags(s.pub, data, flags)
+}
+
+// Calls an extension method. It is up to the agent implementation as to whether or not
+// any particular extension is supported and may always return an error. Because the
+// type of the response is up to the implementation, this returns the bytes of the
+// response and does not attempt any type of unmarshalling.
+func (c *client) Extension(extensionType string, contents []byte) ([]byte, error) {
+ req := ssh.Marshal(extensionAgentMsg{
+ ExtensionType: extensionType,
+ Contents: contents,
+ })
+ buf, err := c.callRaw(req)
+ if err != nil {
+ return nil, err
+ }
+ if len(buf) == 0 {
+ return nil, errors.New("agent: failure; empty response")
+ }
+ // [PROTOCOL.agent] section 4.7 indicates that an SSH_AGENT_FAILURE message
+ // represents an agent that does not support the extension
+ if buf[0] == agentFailure {
+ return nil, ErrExtensionUnsupported
+ }
+ if buf[0] == agentExtensionFailure {
+ return nil, errors.New("agent: generic extension failure")
+ }
+
+ return buf, nil
+}
diff --git a/vendor/golang.org/x/crypto/ssh/agent/forward.go b/vendor/golang.org/x/crypto/ssh/agent/forward.go
new file mode 100644
index 000000000..fd24ba900
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/agent/forward.go
@@ -0,0 +1,103 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package agent
+
+import (
+ "errors"
+ "io"
+ "net"
+ "sync"
+
+ "golang.org/x/crypto/ssh"
+)
+
+// RequestAgentForwarding sets up agent forwarding for the session.
+// ForwardToAgent or ForwardToRemote should be called to route
+// the authentication requests.
+func RequestAgentForwarding(session *ssh.Session) error {
+ ok, err := session.SendRequest("auth-agent-req@openssh.com", true, nil)
+ if err != nil {
+ return err
+ }
+ if !ok {
+ return errors.New("forwarding request denied")
+ }
+ return nil
+}
+
+// ForwardToAgent routes authentication requests to the given keyring.
+func ForwardToAgent(client *ssh.Client, keyring Agent) error {
+ channels := client.HandleChannelOpen(channelType)
+ if channels == nil {
+ return errors.New("agent: already have handler for " + channelType)
+ }
+
+ go func() {
+ for ch := range channels {
+ channel, reqs, err := ch.Accept()
+ if err != nil {
+ continue
+ }
+ go ssh.DiscardRequests(reqs)
+ go func() {
+ ServeAgent(keyring, channel)
+ channel.Close()
+ }()
+ }
+ }()
+ return nil
+}
+
+const channelType = "auth-agent@openssh.com"
+
+// ForwardToRemote routes authentication requests to the ssh-agent
+// process serving on the given unix socket.
+func ForwardToRemote(client *ssh.Client, addr string) error {
+ channels := client.HandleChannelOpen(channelType)
+ if channels == nil {
+ return errors.New("agent: already have handler for " + channelType)
+ }
+ conn, err := net.Dial("unix", addr)
+ if err != nil {
+ return err
+ }
+ conn.Close()
+
+ go func() {
+ for ch := range channels {
+ channel, reqs, err := ch.Accept()
+ if err != nil {
+ continue
+ }
+ go ssh.DiscardRequests(reqs)
+ go forwardUnixSocket(channel, addr)
+ }
+ }()
+ return nil
+}
+
+func forwardUnixSocket(channel ssh.Channel, addr string) {
+ conn, err := net.Dial("unix", addr)
+ if err != nil {
+ return
+ }
+
+ var wg sync.WaitGroup
+ wg.Add(2)
+ go func() {
+ io.Copy(conn, channel)
+ conn.(*net.UnixConn).CloseWrite()
+ wg.Done()
+ }()
+ go func() {
+ io.Copy(channel, conn)
+ channel.CloseWrite()
+ wg.Done()
+ }()
+
+ wg.Wait()
+ conn.Close()
+ channel.Close()
+}
diff --git a/vendor/golang.org/x/crypto/ssh/agent/keyring.go b/vendor/golang.org/x/crypto/ssh/agent/keyring.go
new file mode 100644
index 000000000..c9d979430
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/agent/keyring.go
@@ -0,0 +1,241 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package agent
+
+import (
+ "bytes"
+ "crypto/rand"
+ "crypto/subtle"
+ "errors"
+ "fmt"
+ "sync"
+ "time"
+
+ "golang.org/x/crypto/ssh"
+)
+
+type privKey struct {
+ signer ssh.Signer
+ comment string
+ expire *time.Time
+}
+
+type keyring struct {
+ mu sync.Mutex
+ keys []privKey
+
+ locked bool
+ passphrase []byte
+}
+
+var errLocked = errors.New("agent: locked")
+
+// NewKeyring returns an Agent that holds keys in memory. It is safe
+// for concurrent use by multiple goroutines.
+func NewKeyring() Agent {
+ return &keyring{}
+}
+
+// RemoveAll removes all identities.
+func (r *keyring) RemoveAll() error {
+ r.mu.Lock()
+ defer r.mu.Unlock()
+ if r.locked {
+ return errLocked
+ }
+
+ r.keys = nil
+ return nil
+}
+
+// removeLocked does the actual key removal. The caller must already be holding the
+// keyring mutex.
+func (r *keyring) removeLocked(want []byte) error {
+ found := false
+ for i := 0; i < len(r.keys); {
+ if bytes.Equal(r.keys[i].signer.PublicKey().Marshal(), want) {
+ found = true
+ r.keys[i] = r.keys[len(r.keys)-1]
+ r.keys = r.keys[:len(r.keys)-1]
+ continue
+ } else {
+ i++
+ }
+ }
+
+ if !found {
+ return errors.New("agent: key not found")
+ }
+ return nil
+}
+
+// Remove removes all identities with the given public key.
+func (r *keyring) Remove(key ssh.PublicKey) error {
+ r.mu.Lock()
+ defer r.mu.Unlock()
+ if r.locked {
+ return errLocked
+ }
+
+ return r.removeLocked(key.Marshal())
+}
+
+// Lock locks the agent. Sign and Remove will fail, and List will return an empty list.
+func (r *keyring) Lock(passphrase []byte) error {
+ r.mu.Lock()
+ defer r.mu.Unlock()
+ if r.locked {
+ return errLocked
+ }
+
+ r.locked = true
+ r.passphrase = passphrase
+ return nil
+}
+
+// Unlock undoes the effect of Lock
+func (r *keyring) Unlock(passphrase []byte) error {
+ r.mu.Lock()
+ defer r.mu.Unlock()
+ if !r.locked {
+ return errors.New("agent: not locked")
+ }
+ if 1 != subtle.ConstantTimeCompare(passphrase, r.passphrase) {
+ return fmt.Errorf("agent: incorrect passphrase")
+ }
+
+ r.locked = false
+ r.passphrase = nil
+ return nil
+}
+
+// expireKeysLocked removes expired keys from the keyring. If a key was added
+// with a lifetimesecs contraint and seconds >= lifetimesecs seconds have
+// ellapsed, it is removed. The caller *must* be holding the keyring mutex.
+func (r *keyring) expireKeysLocked() {
+ for _, k := range r.keys {
+ if k.expire != nil && time.Now().After(*k.expire) {
+ r.removeLocked(k.signer.PublicKey().Marshal())
+ }
+ }
+}
+
+// List returns the identities known to the agent.
+func (r *keyring) List() ([]*Key, error) {
+ r.mu.Lock()
+ defer r.mu.Unlock()
+ if r.locked {
+ // section 2.7: locked agents return empty.
+ return nil, nil
+ }
+
+ r.expireKeysLocked()
+ var ids []*Key
+ for _, k := range r.keys {
+ pub := k.signer.PublicKey()
+ ids = append(ids, &Key{
+ Format: pub.Type(),
+ Blob: pub.Marshal(),
+ Comment: k.comment})
+ }
+ return ids, nil
+}
+
+// Insert adds a private key to the keyring. If a certificate
+// is given, that certificate is added as public key. Note that
+// any constraints given are ignored.
+func (r *keyring) Add(key AddedKey) error {
+ r.mu.Lock()
+ defer r.mu.Unlock()
+ if r.locked {
+ return errLocked
+ }
+ signer, err := ssh.NewSignerFromKey(key.PrivateKey)
+
+ if err != nil {
+ return err
+ }
+
+ if cert := key.Certificate; cert != nil {
+ signer, err = ssh.NewCertSigner(cert, signer)
+ if err != nil {
+ return err
+ }
+ }
+
+ p := privKey{
+ signer: signer,
+ comment: key.Comment,
+ }
+
+ if key.LifetimeSecs > 0 {
+ t := time.Now().Add(time.Duration(key.LifetimeSecs) * time.Second)
+ p.expire = &t
+ }
+
+ r.keys = append(r.keys, p)
+
+ return nil
+}
+
+// Sign returns a signature for the data.
+func (r *keyring) Sign(key ssh.PublicKey, data []byte) (*ssh.Signature, error) {
+ return r.SignWithFlags(key, data, 0)
+}
+
+func (r *keyring) SignWithFlags(key ssh.PublicKey, data []byte, flags SignatureFlags) (*ssh.Signature, error) {
+ r.mu.Lock()
+ defer r.mu.Unlock()
+ if r.locked {
+ return nil, errLocked
+ }
+
+ r.expireKeysLocked()
+ wanted := key.Marshal()
+ for _, k := range r.keys {
+ if bytes.Equal(k.signer.PublicKey().Marshal(), wanted) {
+ if flags == 0 {
+ return k.signer.Sign(rand.Reader, data)
+ } else {
+ if algorithmSigner, ok := k.signer.(ssh.AlgorithmSigner); !ok {
+ return nil, fmt.Errorf("agent: signature does not support non-default signature algorithm: %T", k.signer)
+ } else {
+ var algorithm string
+ switch flags {
+ case SignatureFlagRsaSha256:
+ algorithm = ssh.SigAlgoRSASHA2256
+ case SignatureFlagRsaSha512:
+ algorithm = ssh.SigAlgoRSASHA2512
+ default:
+ return nil, fmt.Errorf("agent: unsupported signature flags: %d", flags)
+ }
+ return algorithmSigner.SignWithAlgorithm(rand.Reader, data, algorithm)
+ }
+ }
+ }
+ }
+ return nil, errors.New("not found")
+}
+
+// Signers returns signers for all the known keys.
+func (r *keyring) Signers() ([]ssh.Signer, error) {
+ r.mu.Lock()
+ defer r.mu.Unlock()
+ if r.locked {
+ return nil, errLocked
+ }
+
+ r.expireKeysLocked()
+ s := make([]ssh.Signer, 0, len(r.keys))
+ for _, k := range r.keys {
+ s = append(s, k.signer)
+ }
+ return s, nil
+}
+
+// The keyring does not support any extensions
+func (r *keyring) Extension(extensionType string, contents []byte) ([]byte, error) {
+ return nil, ErrExtensionUnsupported
+}
diff --git a/vendor/golang.org/x/crypto/ssh/agent/server.go b/vendor/golang.org/x/crypto/ssh/agent/server.go
new file mode 100644
index 000000000..6e7a1e02f
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/agent/server.go
@@ -0,0 +1,570 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package agent
+
+import (
+ "crypto/dsa"
+ "crypto/ecdsa"
+ "crypto/elliptic"
+ "crypto/rsa"
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "io"
+ "log"
+ "math/big"
+
+ "golang.org/x/crypto/ed25519"
+ "golang.org/x/crypto/ssh"
+)
+
+// Server wraps an Agent and uses it to implement the agent side of
+// the SSH-agent, wire protocol.
+type server struct {
+ agent Agent
+}
+
+func (s *server) processRequestBytes(reqData []byte) []byte {
+ rep, err := s.processRequest(reqData)
+ if err != nil {
+ if err != errLocked {
+ // TODO(hanwen): provide better logging interface?
+ log.Printf("agent %d: %v", reqData[0], err)
+ }
+ return []byte{agentFailure}
+ }
+
+ if err == nil && rep == nil {
+ return []byte{agentSuccess}
+ }
+
+ return ssh.Marshal(rep)
+}
+
+func marshalKey(k *Key) []byte {
+ var record struct {
+ Blob []byte
+ Comment string
+ }
+ record.Blob = k.Marshal()
+ record.Comment = k.Comment
+
+ return ssh.Marshal(&record)
+}
+
+// See [PROTOCOL.agent], section 2.5.1.
+const agentV1IdentitiesAnswer = 2
+
+type agentV1IdentityMsg struct {
+ Numkeys uint32 `sshtype:"2"`
+}
+
+type agentRemoveIdentityMsg struct {
+ KeyBlob []byte `sshtype:"18"`
+}
+
+type agentLockMsg struct {
+ Passphrase []byte `sshtype:"22"`
+}
+
+type agentUnlockMsg struct {
+ Passphrase []byte `sshtype:"23"`
+}
+
+func (s *server) processRequest(data []byte) (interface{}, error) {
+ switch data[0] {
+ case agentRequestV1Identities:
+ return &agentV1IdentityMsg{0}, nil
+
+ case agentRemoveAllV1Identities:
+ return nil, nil
+
+ case agentRemoveIdentity:
+ var req agentRemoveIdentityMsg
+ if err := ssh.Unmarshal(data, &req); err != nil {
+ return nil, err
+ }
+
+ var wk wireKey
+ if err := ssh.Unmarshal(req.KeyBlob, &wk); err != nil {
+ return nil, err
+ }
+
+ return nil, s.agent.Remove(&Key{Format: wk.Format, Blob: req.KeyBlob})
+
+ case agentRemoveAllIdentities:
+ return nil, s.agent.RemoveAll()
+
+ case agentLock:
+ var req agentLockMsg
+ if err := ssh.Unmarshal(data, &req); err != nil {
+ return nil, err
+ }
+
+ return nil, s.agent.Lock(req.Passphrase)
+
+ case agentUnlock:
+ var req agentUnlockMsg
+ if err := ssh.Unmarshal(data, &req); err != nil {
+ return nil, err
+ }
+ return nil, s.agent.Unlock(req.Passphrase)
+
+ case agentSignRequest:
+ var req signRequestAgentMsg
+ if err := ssh.Unmarshal(data, &req); err != nil {
+ return nil, err
+ }
+
+ var wk wireKey
+ if err := ssh.Unmarshal(req.KeyBlob, &wk); err != nil {
+ return nil, err
+ }
+
+ k := &Key{
+ Format: wk.Format,
+ Blob: req.KeyBlob,
+ }
+
+ var sig *ssh.Signature
+ var err error
+ if extendedAgent, ok := s.agent.(ExtendedAgent); ok {
+ sig, err = extendedAgent.SignWithFlags(k, req.Data, SignatureFlags(req.Flags))
+ } else {
+ sig, err = s.agent.Sign(k, req.Data)
+ }
+
+ if err != nil {
+ return nil, err
+ }
+ return &signResponseAgentMsg{SigBlob: ssh.Marshal(sig)}, nil
+
+ case agentRequestIdentities:
+ keys, err := s.agent.List()
+ if err != nil {
+ return nil, err
+ }
+
+ rep := identitiesAnswerAgentMsg{
+ NumKeys: uint32(len(keys)),
+ }
+ for _, k := range keys {
+ rep.Keys = append(rep.Keys, marshalKey(k)...)
+ }
+ return rep, nil
+
+ case agentAddIDConstrained, agentAddIdentity:
+ return nil, s.insertIdentity(data)
+
+ case agentExtension:
+ // Return a stub object where the whole contents of the response gets marshaled.
+ var responseStub struct {
+ Rest []byte `ssh:"rest"`
+ }
+
+ if extendedAgent, ok := s.agent.(ExtendedAgent); !ok {
+ // If this agent doesn't implement extensions, [PROTOCOL.agent] section 4.7
+ // requires that we return a standard SSH_AGENT_FAILURE message.
+ responseStub.Rest = []byte{agentFailure}
+ } else {
+ var req extensionAgentMsg
+ if err := ssh.Unmarshal(data, &req); err != nil {
+ return nil, err
+ }
+ res, err := extendedAgent.Extension(req.ExtensionType, req.Contents)
+ if err != nil {
+ // If agent extensions are unsupported, return a standard SSH_AGENT_FAILURE
+ // message as required by [PROTOCOL.agent] section 4.7.
+ if err == ErrExtensionUnsupported {
+ responseStub.Rest = []byte{agentFailure}
+ } else {
+ // As the result of any other error processing an extension request,
+ // [PROTOCOL.agent] section 4.7 requires that we return a
+ // SSH_AGENT_EXTENSION_FAILURE code.
+ responseStub.Rest = []byte{agentExtensionFailure}
+ }
+ } else {
+ if len(res) == 0 {
+ return nil, nil
+ }
+ responseStub.Rest = res
+ }
+ }
+
+ return responseStub, nil
+ }
+
+ return nil, fmt.Errorf("unknown opcode %d", data[0])
+}
+
+func parseConstraints(constraints []byte) (lifetimeSecs uint32, confirmBeforeUse bool, extensions []ConstraintExtension, err error) {
+ for len(constraints) != 0 {
+ switch constraints[0] {
+ case agentConstrainLifetime:
+ lifetimeSecs = binary.BigEndian.Uint32(constraints[1:5])
+ constraints = constraints[5:]
+ case agentConstrainConfirm:
+ confirmBeforeUse = true
+ constraints = constraints[1:]
+ case agentConstrainExtension:
+ var msg constrainExtensionAgentMsg
+ if err = ssh.Unmarshal(constraints, &msg); err != nil {
+ return 0, false, nil, err
+ }
+ extensions = append(extensions, ConstraintExtension{
+ ExtensionName: msg.ExtensionName,
+ ExtensionDetails: msg.ExtensionDetails,
+ })
+ constraints = msg.Rest
+ default:
+ return 0, false, nil, fmt.Errorf("unknown constraint type: %d", constraints[0])
+ }
+ }
+ return
+}
+
+func setConstraints(key *AddedKey, constraintBytes []byte) error {
+ lifetimeSecs, confirmBeforeUse, constraintExtensions, err := parseConstraints(constraintBytes)
+ if err != nil {
+ return err
+ }
+
+ key.LifetimeSecs = lifetimeSecs
+ key.ConfirmBeforeUse = confirmBeforeUse
+ key.ConstraintExtensions = constraintExtensions
+ return nil
+}
+
+func parseRSAKey(req []byte) (*AddedKey, error) {
+ var k rsaKeyMsg
+ if err := ssh.Unmarshal(req, &k); err != nil {
+ return nil, err
+ }
+ if k.E.BitLen() > 30 {
+ return nil, errors.New("agent: RSA public exponent too large")
+ }
+ priv := &rsa.PrivateKey{
+ PublicKey: rsa.PublicKey{
+ E: int(k.E.Int64()),
+ N: k.N,
+ },
+ D: k.D,
+ Primes: []*big.Int{k.P, k.Q},
+ }
+ priv.Precompute()
+
+ addedKey := &AddedKey{PrivateKey: priv, Comment: k.Comments}
+ if err := setConstraints(addedKey, k.Constraints); err != nil {
+ return nil, err
+ }
+ return addedKey, nil
+}
+
+func parseEd25519Key(req []byte) (*AddedKey, error) {
+ var k ed25519KeyMsg
+ if err := ssh.Unmarshal(req, &k); err != nil {
+ return nil, err
+ }
+ priv := ed25519.PrivateKey(k.Priv)
+
+ addedKey := &AddedKey{PrivateKey: &priv, Comment: k.Comments}
+ if err := setConstraints(addedKey, k.Constraints); err != nil {
+ return nil, err
+ }
+ return addedKey, nil
+}
+
+func parseDSAKey(req []byte) (*AddedKey, error) {
+ var k dsaKeyMsg
+ if err := ssh.Unmarshal(req, &k); err != nil {
+ return nil, err
+ }
+ priv := &dsa.PrivateKey{
+ PublicKey: dsa.PublicKey{
+ Parameters: dsa.Parameters{
+ P: k.P,
+ Q: k.Q,
+ G: k.G,
+ },
+ Y: k.Y,
+ },
+ X: k.X,
+ }
+
+ addedKey := &AddedKey{PrivateKey: priv, Comment: k.Comments}
+ if err := setConstraints(addedKey, k.Constraints); err != nil {
+ return nil, err
+ }
+ return addedKey, nil
+}
+
+func unmarshalECDSA(curveName string, keyBytes []byte, privScalar *big.Int) (priv *ecdsa.PrivateKey, err error) {
+ priv = &ecdsa.PrivateKey{
+ D: privScalar,
+ }
+
+ switch curveName {
+ case "nistp256":
+ priv.Curve = elliptic.P256()
+ case "nistp384":
+ priv.Curve = elliptic.P384()
+ case "nistp521":
+ priv.Curve = elliptic.P521()
+ default:
+ return nil, fmt.Errorf("agent: unknown curve %q", curveName)
+ }
+
+ priv.X, priv.Y = elliptic.Unmarshal(priv.Curve, keyBytes)
+ if priv.X == nil || priv.Y == nil {
+ return nil, errors.New("agent: point not on curve")
+ }
+
+ return priv, nil
+}
+
+func parseEd25519Cert(req []byte) (*AddedKey, error) {
+ var k ed25519CertMsg
+ if err := ssh.Unmarshal(req, &k); err != nil {
+ return nil, err
+ }
+ pubKey, err := ssh.ParsePublicKey(k.CertBytes)
+ if err != nil {
+ return nil, err
+ }
+ priv := ed25519.PrivateKey(k.Priv)
+ cert, ok := pubKey.(*ssh.Certificate)
+ if !ok {
+ return nil, errors.New("agent: bad ED25519 certificate")
+ }
+
+ addedKey := &AddedKey{PrivateKey: &priv, Certificate: cert, Comment: k.Comments}
+ if err := setConstraints(addedKey, k.Constraints); err != nil {
+ return nil, err
+ }
+ return addedKey, nil
+}
+
+func parseECDSAKey(req []byte) (*AddedKey, error) {
+ var k ecdsaKeyMsg
+ if err := ssh.Unmarshal(req, &k); err != nil {
+ return nil, err
+ }
+
+ priv, err := unmarshalECDSA(k.Curve, k.KeyBytes, k.D)
+ if err != nil {
+ return nil, err
+ }
+
+ addedKey := &AddedKey{PrivateKey: priv, Comment: k.Comments}
+ if err := setConstraints(addedKey, k.Constraints); err != nil {
+ return nil, err
+ }
+ return addedKey, nil
+}
+
+func parseRSACert(req []byte) (*AddedKey, error) {
+ var k rsaCertMsg
+ if err := ssh.Unmarshal(req, &k); err != nil {
+ return nil, err
+ }
+
+ pubKey, err := ssh.ParsePublicKey(k.CertBytes)
+ if err != nil {
+ return nil, err
+ }
+
+ cert, ok := pubKey.(*ssh.Certificate)
+ if !ok {
+ return nil, errors.New("agent: bad RSA certificate")
+ }
+
+ // An RSA publickey as marshaled by rsaPublicKey.Marshal() in keys.go
+ var rsaPub struct {
+ Name string
+ E *big.Int
+ N *big.Int
+ }
+ if err := ssh.Unmarshal(cert.Key.Marshal(), &rsaPub); err != nil {
+ return nil, fmt.Errorf("agent: Unmarshal failed to parse public key: %v", err)
+ }
+
+ if rsaPub.E.BitLen() > 30 {
+ return nil, errors.New("agent: RSA public exponent too large")
+ }
+
+ priv := rsa.PrivateKey{
+ PublicKey: rsa.PublicKey{
+ E: int(rsaPub.E.Int64()),
+ N: rsaPub.N,
+ },
+ D: k.D,
+ Primes: []*big.Int{k.Q, k.P},
+ }
+ priv.Precompute()
+
+ addedKey := &AddedKey{PrivateKey: &priv, Certificate: cert, Comment: k.Comments}
+ if err := setConstraints(addedKey, k.Constraints); err != nil {
+ return nil, err
+ }
+ return addedKey, nil
+}
+
+func parseDSACert(req []byte) (*AddedKey, error) {
+ var k dsaCertMsg
+ if err := ssh.Unmarshal(req, &k); err != nil {
+ return nil, err
+ }
+ pubKey, err := ssh.ParsePublicKey(k.CertBytes)
+ if err != nil {
+ return nil, err
+ }
+ cert, ok := pubKey.(*ssh.Certificate)
+ if !ok {
+ return nil, errors.New("agent: bad DSA certificate")
+ }
+
+ // A DSA publickey as marshaled by dsaPublicKey.Marshal() in keys.go
+ var w struct {
+ Name string
+ P, Q, G, Y *big.Int
+ }
+ if err := ssh.Unmarshal(cert.Key.Marshal(), &w); err != nil {
+ return nil, fmt.Errorf("agent: Unmarshal failed to parse public key: %v", err)
+ }
+
+ priv := &dsa.PrivateKey{
+ PublicKey: dsa.PublicKey{
+ Parameters: dsa.Parameters{
+ P: w.P,
+ Q: w.Q,
+ G: w.G,
+ },
+ Y: w.Y,
+ },
+ X: k.X,
+ }
+
+ addedKey := &AddedKey{PrivateKey: priv, Certificate: cert, Comment: k.Comments}
+ if err := setConstraints(addedKey, k.Constraints); err != nil {
+ return nil, err
+ }
+ return addedKey, nil
+}
+
+func parseECDSACert(req []byte) (*AddedKey, error) {
+ var k ecdsaCertMsg
+ if err := ssh.Unmarshal(req, &k); err != nil {
+ return nil, err
+ }
+
+ pubKey, err := ssh.ParsePublicKey(k.CertBytes)
+ if err != nil {
+ return nil, err
+ }
+ cert, ok := pubKey.(*ssh.Certificate)
+ if !ok {
+ return nil, errors.New("agent: bad ECDSA certificate")
+ }
+
+ // An ECDSA publickey as marshaled by ecdsaPublicKey.Marshal() in keys.go
+ var ecdsaPub struct {
+ Name string
+ ID string
+ Key []byte
+ }
+ if err := ssh.Unmarshal(cert.Key.Marshal(), &ecdsaPub); err != nil {
+ return nil, err
+ }
+
+ priv, err := unmarshalECDSA(ecdsaPub.ID, ecdsaPub.Key, k.D)
+ if err != nil {
+ return nil, err
+ }
+
+ addedKey := &AddedKey{PrivateKey: priv, Certificate: cert, Comment: k.Comments}
+ if err := setConstraints(addedKey, k.Constraints); err != nil {
+ return nil, err
+ }
+ return addedKey, nil
+}
+
+func (s *server) insertIdentity(req []byte) error {
+ var record struct {
+ Type string `sshtype:"17|25"`
+ Rest []byte `ssh:"rest"`
+ }
+
+ if err := ssh.Unmarshal(req, &record); err != nil {
+ return err
+ }
+
+ var addedKey *AddedKey
+ var err error
+
+ switch record.Type {
+ case ssh.KeyAlgoRSA:
+ addedKey, err = parseRSAKey(req)
+ case ssh.KeyAlgoDSA:
+ addedKey, err = parseDSAKey(req)
+ case ssh.KeyAlgoECDSA256, ssh.KeyAlgoECDSA384, ssh.KeyAlgoECDSA521:
+ addedKey, err = parseECDSAKey(req)
+ case ssh.KeyAlgoED25519:
+ addedKey, err = parseEd25519Key(req)
+ case ssh.CertAlgoRSAv01:
+ addedKey, err = parseRSACert(req)
+ case ssh.CertAlgoDSAv01:
+ addedKey, err = parseDSACert(req)
+ case ssh.CertAlgoECDSA256v01, ssh.CertAlgoECDSA384v01, ssh.CertAlgoECDSA521v01:
+ addedKey, err = parseECDSACert(req)
+ case ssh.CertAlgoED25519v01:
+ addedKey, err = parseEd25519Cert(req)
+ default:
+ return fmt.Errorf("agent: not implemented: %q", record.Type)
+ }
+
+ if err != nil {
+ return err
+ }
+ return s.agent.Add(*addedKey)
+}
+
+// ServeAgent serves the agent protocol on the given connection. It
+// returns when an I/O error occurs.
+func ServeAgent(agent Agent, c io.ReadWriter) error {
+ s := &server{agent}
+
+ var length [4]byte
+ for {
+ if _, err := io.ReadFull(c, length[:]); err != nil {
+ return err
+ }
+ l := binary.BigEndian.Uint32(length[:])
+ if l == 0 {
+ return fmt.Errorf("agent: request size is 0")
+ }
+ if l > maxAgentResponseBytes {
+ // We also cap requests.
+ return fmt.Errorf("agent: request too large: %d", l)
+ }
+
+ req := make([]byte, l)
+ if _, err := io.ReadFull(c, req); err != nil {
+ return err
+ }
+
+ repData := s.processRequestBytes(req)
+ if len(repData) > maxAgentResponseBytes {
+ return fmt.Errorf("agent: reply too large: %d bytes", len(repData))
+ }
+
+ binary.BigEndian.PutUint32(length[:], uint32(len(repData)))
+ if _, err := c.Write(length[:]); err != nil {
+ return err
+ }
+ if _, err := c.Write(repData); err != nil {
+ return err
+ }
+ }
+}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index e2e83df9b..a44d0e88d 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -84,14 +84,14 @@ github.com/containers/buildah/pkg/secrets
github.com/containers/buildah/pkg/supplemented
github.com/containers/buildah/pkg/umask
github.com/containers/buildah/util
-# github.com/containers/common v0.12.0
+# github.com/containers/common v0.13.0
github.com/containers/common/pkg/apparmor
github.com/containers/common/pkg/auth
github.com/containers/common/pkg/capabilities
github.com/containers/common/pkg/cgroupv2
github.com/containers/common/pkg/config
github.com/containers/common/pkg/sysinfo
-# github.com/containers/conmon v2.0.16+incompatible
+# github.com/containers/conmon v2.0.17+incompatible
github.com/containers/conmon/runner/config
# github.com/containers/image/v5 v5.4.5-0.20200529084758-46b2ee6aebb0
github.com/containers/image/v5/copy
@@ -154,7 +154,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.20.1
+# github.com/containers/storage v1.20.2
github.com/containers/storage
github.com/containers/storage/drivers
github.com/containers/storage/drivers/aufs
@@ -322,9 +322,9 @@ github.com/imdario/mergo
github.com/inconshreveable/mousetrap
# github.com/ishidawataru/sctp v0.0.0-20191218070446-00ab2ac2db07
github.com/ishidawataru/sctp
-# github.com/json-iterator/go v1.1.9
+# github.com/json-iterator/go v1.1.10
github.com/json-iterator/go
-# github.com/klauspost/compress v1.10.6
+# github.com/klauspost/compress v1.10.7
github.com/klauspost/compress/flate
github.com/klauspost/compress/fse
github.com/klauspost/compress/huff0
@@ -480,7 +480,7 @@ github.com/rootless-containers/rootlesskit/pkg/port/builtin/parent/udp/udpproxy
github.com/rootless-containers/rootlesskit/pkg/port/portutil
# github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8
github.com/safchain/ethtool
-# github.com/seccomp/containers-golang v0.4.1
+# github.com/seccomp/containers-golang v0.5.0
github.com/seccomp/containers-golang
# github.com/seccomp/libseccomp-golang v0.9.1
github.com/seccomp/libseccomp-golang
@@ -491,7 +491,7 @@ github.com/sirupsen/logrus/hooks/syslog
github.com/spf13/cobra
# github.com/spf13/pflag v1.0.5
github.com/spf13/pflag
-# github.com/stretchr/testify v1.6.0
+# github.com/stretchr/testify v1.6.1
github.com/stretchr/testify/assert
github.com/stretchr/testify/require
# github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2
@@ -575,6 +575,7 @@ golang.org/x/crypto/openpgp/s2k
golang.org/x/crypto/pbkdf2
golang.org/x/crypto/poly1305
golang.org/x/crypto/ssh
+golang.org/x/crypto/ssh/agent
golang.org/x/crypto/ssh/internal/bcrypt_pbkdf
golang.org/x/crypto/ssh/terminal
# golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7