summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cirrus.yml33
-rw-r--r--Dockerfile143
-rw-r--r--Dockerfile.centos77
-rw-r--r--Dockerfile.fedora73
-rw-r--r--Dockerfile.ubuntu29
-rw-r--r--Makefile20
-rw-r--r--README.md2
-rw-r--r--RELEASE_NOTES.md9
-rw-r--r--cmd/podman/common/create.go28
-rw-r--r--cmd/podman/common/create_opts.go2
-rw-r--r--cmd/podman/common/inspect.go18
-rw-r--r--cmd/podman/common/ports.go6
-rw-r--r--cmd/podman/common/specgen.go61
-rw-r--r--cmd/podman/containers/attach.go18
-rw-r--r--cmd/podman/containers/commit.go1
-rw-r--r--cmd/podman/containers/container.go3
-rw-r--r--cmd/podman/containers/create.go41
-rw-r--r--cmd/podman/containers/diff.go3
-rw-r--r--cmd/podman/containers/exec.go24
-rw-r--r--cmd/podman/containers/exists.go5
-rw-r--r--cmd/podman/containers/export.go1
-rw-r--r--cmd/podman/containers/inspect.go53
-rw-r--r--cmd/podman/containers/kill.go3
-rw-r--r--cmd/podman/containers/list.go3
-rw-r--r--cmd/podman/containers/port.go2
-rw-r--r--cmd/podman/containers/ps.go17
-rw-r--r--cmd/podman/containers/rm.go3
-rw-r--r--cmd/podman/containers/run.go6
-rw-r--r--cmd/podman/containers/start.go2
-rw-r--r--cmd/podman/containers/stop.go3
-rw-r--r--cmd/podman/containers/unmount.go6
-rw-r--r--cmd/podman/containers/wait.go4
-rw-r--r--cmd/podman/diff.go3
-rw-r--r--cmd/podman/generate/generate.go28
-rw-r--r--cmd/podman/generate/systemd.go57
-rw-r--r--cmd/podman/healthcheck/healthcheck.go3
-rw-r--r--cmd/podman/images/exists.go1
-rw-r--r--cmd/podman/images/history.go20
-rw-r--r--cmd/podman/images/image.go3
-rw-r--r--cmd/podman/images/images.go13
-rw-r--r--cmd/podman/images/inspect.go92
-rw-r--r--cmd/podman/images/list.go75
-rw-r--r--cmd/podman/images/prune.go3
-rw-r--r--cmd/podman/images/pull.go12
-rw-r--r--cmd/podman/images/push.go12
-rw-r--r--cmd/podman/images/rm.go5
-rw-r--r--cmd/podman/images/search.go27
-rw-r--r--cmd/podman/inspect.go42
-rw-r--r--cmd/podman/inspect/inspect.go159
-rw-r--r--cmd/podman/login.go2
-rw-r--r--cmd/podman/logout.go2
-rw-r--r--cmd/podman/main.go13
-rw-r--r--cmd/podman/manifest/add.go2
-rw-r--r--cmd/podman/manifest/create.go2
-rw-r--r--cmd/podman/manifest/inspect.go2
-rw-r--r--cmd/podman/manifest/manifest.go3
-rw-r--r--cmd/podman/networks/network.go6
-rw-r--r--cmd/podman/parse/net.go4
-rw-r--r--cmd/podman/parse/net_test.go4
-rw-r--r--cmd/podman/pods/create.go5
-rw-r--r--cmd/podman/pods/exists.go1
-rw-r--r--cmd/podman/pods/pod.go3
-rw-r--r--cmd/podman/pods/ps.go4
-rw-r--r--cmd/podman/pods/rm.go4
-rw-r--r--cmd/podman/registry/registry.go16
-rw-r--r--cmd/podman/root.go18
-rw-r--r--cmd/podman/system/events.go3
-rw-r--r--cmd/podman/system/info.go3
-rw-r--r--cmd/podman/system/system.go3
-rw-r--r--cmd/podman/system/version.go9
-rw-r--r--cmd/podman/utils/alias.go2
-rw-r--r--cmd/podman/validate/args.go32
-rw-r--r--cmd/podman/validate/choice.go46
-rw-r--r--cmd/podman/volumes/list.go20
-rw-r--r--cmd/podman/volumes/prune.go3
-rw-r--r--cmd/podman/volumes/volume.go3
-rw-r--r--contrib/cirrus/lib.sh87
-rw-r--r--contrib/cirrus/packer/fedora_base-setup.sh21
-rw-r--r--contrib/cirrus/packer/fedora_packaging.sh141
-rw-r--r--contrib/cirrus/packer/fedora_setup.sh129
-rw-r--r--contrib/cirrus/packer/libpod_base_images.yml6
-rw-r--r--contrib/cirrus/packer/libpod_images.yml1
-rw-r--r--contrib/cirrus/packer/ubuntu_packaging.sh168
-rw-r--r--contrib/cirrus/packer/ubuntu_setup.sh157
-rwxr-xr-xcontrib/cirrus/setup_environment.sh10
-rw-r--r--contrib/podmanimage/stable/Dockerfile8
-rw-r--r--contrib/podmanimage/stable/manual/Containerfile7
-rw-r--r--contrib/podmanimage/testing/Dockerfile8
-rw-r--r--contrib/podmanimage/upstream/Dockerfile8
-rw-r--r--contrib/spec/podman.spec.in23
-rw-r--r--go.mod2
-rw-r--r--go.sum4
-rw-r--r--libpod/image/image.go27
-rw-r--r--libpod/options.go7
-rw-r--r--libpod/runtime_ctr.go3
-rw-r--r--pkg/api/handlers/compat/containers_prune.go35
-rw-r--r--pkg/api/handlers/libpod/pods.go14
-rw-r--r--pkg/api/handlers/libpod/system.go71
-rw-r--r--pkg/api/handlers/libpod/volumes.go15
-rw-r--r--pkg/api/server/register_system.go17
-rw-r--r--pkg/bindings/images/images.go25
-rw-r--r--pkg/bindings/system/system.go24
-rw-r--r--pkg/bindings/test/system_test.go106
-rw-r--r--pkg/domain/entities/containers.go1
-rw-r--r--pkg/domain/entities/engine_container.go1
-rw-r--r--pkg/domain/entities/engine_image.go2
-rw-r--r--pkg/domain/entities/generate.go22
-rw-r--r--pkg/domain/entities/images.go21
-rw-r--r--pkg/domain/entities/system.go14
-rw-r--r--pkg/domain/entities/types.go10
-rw-r--r--pkg/domain/infra/abi/containers.go31
-rw-r--r--pkg/domain/infra/abi/generate.go174
-rw-r--r--pkg/domain/infra/abi/images.go42
-rw-r--r--pkg/domain/infra/abi/images_list.go9
-rw-r--r--pkg/domain/infra/abi/pods.go2
-rw-r--r--pkg/domain/infra/tunnel/generate.go12
-rw-r--r--pkg/domain/infra/tunnel/images.go14
-rw-r--r--pkg/rootless/rootless_linux.c48
-rw-r--r--pkg/rootlessport/rootlessport_linux.go26
-rw-r--r--pkg/spec/spec.go9
-rw-r--r--pkg/specgen/generate/container.go15
-rw-r--r--pkg/specgen/generate/container_create.go19
-rw-r--r--pkg/specgen/generate/oci.go2
-rw-r--r--pkg/specgen/namespaces.go2
-rw-r--r--test/apiv2/10-images.at6
-rw-r--r--test/e2e/attach_test.go1
-rw-r--r--test/e2e/build_test.go2
-rw-r--r--test/e2e/common_test.go14
-rw-r--r--test/e2e/cp_test.go14
-rw-r--r--test/e2e/create_test.go1
-rw-r--r--test/e2e/exec_test.go1
-rw-r--r--test/e2e/generate_systemd_test.go1
-rw-r--r--test/e2e/images_test.go98
-rw-r--r--test/e2e/inspect_test.go1
-rw-r--r--test/e2e/prune_test.go3
-rw-r--r--test/e2e/push_test.go1
-rw-r--r--test/e2e/rmi_test.go7
-rw-r--r--test/e2e/run_entrypoint_test.go1
-rw-r--r--test/e2e/run_env_test.go138
-rw-r--r--test/e2e/run_test.go91
-rw-r--r--test/e2e/run_volume_test.go7
-rw-r--r--test/e2e/save_test.go12
-rw-r--r--test/e2e/search_test.go1
-rw-r--r--test/e2e/start_test.go6
-rw-r--r--test/e2e/version_test.go28
-rw-r--r--test/e2e/volume_create_test.go1
-rw-r--r--test/e2e/volume_inspect_test.go1
-rw-r--r--test/e2e/volume_ls_test.go2
-rw-r--r--test/e2e/volume_prune_test.go2
-rw-r--r--test/e2e/volume_rm_test.go1
-rw-r--r--test/system/005-info.bats14
-rw-r--r--test/system/015-help.bats21
-rw-r--r--test/system/150-login.bats2
-rw-r--r--test/system/250-generate-systemd.bats2
-rw-r--r--test/utils/utils.go2
-rw-r--r--vendor/github.com/containers/psgo/CODE-OF-CONDUCT.md3
-rw-r--r--vendor/github.com/containers/psgo/Makefile12
-rw-r--r--vendor/github.com/containers/psgo/go.mod2
-rw-r--r--vendor/github.com/containers/psgo/go.sum4
-rw-r--r--vendor/github.com/containers/psgo/internal/proc/stat.go21
-rw-r--r--vendor/github.com/containers/psgo/internal/process/process.go2
-rw-r--r--vendor/github.com/containers/psgo/psgo.go22
-rw-r--r--vendor/modules.txt2
163 files changed, 2209 insertions, 1410 deletions
diff --git a/.cirrus.yml b/.cirrus.yml
index 8ae1bb2f2..2aae343e8 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -39,7 +39,7 @@ env:
UBUNTU_NAME: "ubuntu-19"
PRIOR_UBUNTU_NAME: "ubuntu-18"
- _BUILT_IMAGE_SUFFIX: "libpod-6301182083727360"
+ _BUILT_IMAGE_SUFFIX: "libpod-6224667180531712" # From the packer output of 'build_vm_images_script'
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}"
@@ -156,6 +156,32 @@ gating_task:
failed_branch_script: '$CIRRUS_WORKING_DIR/$SCRIPT_BASE/notice_branch_failure.sh'
+# Ensure these container images can build
+container_image_build_task:
+ alias: 'container_image_build'
+ depends_on:
+ - "gating"
+
+ # Only run for PRs, quay.io will automatically build after bramch-push
+ only_if: $CIRRUS_BRANCH != $DEST_BRANCH
+
+ matrix:
+ - name: "build in_podman image ${FEDORA_NAME} "
+ container:
+ dockerfile: Dockerfile
+ - name: "build in_podman image ${UBUNTU_NAME}"
+ container:
+ dockerfile: Dockerfile.ubuntu
+ - name: "build gate image $DEST_BRANCH branch"
+ container:
+ dockerfile: contrib/gate/Dockerfile
+
+ container:
+ dockerfile: Dockerfile
+
+ script: make install.remote
+
+
# This task checks to make sure that we can still build an rpm from the
# source code using contrib/rpm/podman.spec.in
rpmbuild_task:
@@ -389,8 +415,7 @@ testing_task:
- "varlink_api"
- "build_each_commit"
- "build_without_cgo"
-
- allow_failures: $CI == 'true'
+ - "container_image_build"
# Only test build cache-images, if that's what's requested
only_if: >-
@@ -681,6 +706,7 @@ test_build_cache_images_task:
depends_on:
- "gating"
+ - 'container_image_build'
# VMs created by packer are not cleaned up by cirrus, must allow task to complete
auto_cancellation: $CI != "true"
@@ -782,6 +808,7 @@ success_task:
- "varlink_api"
- "build_each_commit"
- "build_without_cgo"
+ - "container_image_build"
- "meta"
- "image_prune"
- "testing"
diff --git a/Dockerfile b/Dockerfile
index f85c47937..623747295 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,117 +1,26 @@
-FROM golang:1.12
-
-RUN apt-get update && apt-get install -y \
- apparmor \
- autoconf \
- automake \
- bison \
- build-essential \
- curl \
- e2fslibs-dev \
- file \
- gawk \
- gettext \
- go-md2man \
- iptables \
- pkg-config \
- libaio-dev \
- libcap-dev \
- libfuse-dev \
- libnet-dev \
- libnl-3-dev \
- libprotobuf-dev \
- libprotobuf-c-dev \
- libseccomp2 \
- libseccomp-dev \
- libtool \
- libudev-dev \
- protobuf-c-compiler \
- protobuf-compiler \
- libglib2.0-dev \
- libapparmor-dev \
- btrfs-tools \
- libdevmapper1.02.1 \
- libdevmapper-dev \
- libgpgme11-dev \
- liblzma-dev \
- netcat \
- socat \
- lsof \
- xz-utils \
- unzip \
- python3-yaml \
- --no-install-recommends \
- && apt-get clean
-
-# Install runc
-ENV RUNC_COMMIT 029124da7af7360afa781a0234d1b083550f797c
-RUN set -x \
- && export GOPATH="$(mktemp -d)" \
- && git clone https://github.com/opencontainers/runc.git "$GOPATH/src/github.com/opencontainers/runc" \
- && cd "$GOPATH/src/github.com/opencontainers/runc" \
- && git fetch origin --tags \
- && git checkout --detach -q "$RUNC_COMMIT" \
- && make static BUILDTAGS="seccomp selinux" \
- && cp runc /usr/bin/runc \
- && rm -rf "$GOPATH"
-
-# Install conmon
-ENV CONMON_COMMIT 65fe0226d85b69fc9e527e376795c9791199153d
-RUN set -x \
- && export GOPATH="$(mktemp -d)" \
- && git clone https://github.com/containers/conmon.git "$GOPATH/src/github.com/containers/conmon.git" \
- && cd "$GOPATH/src/github.com/containers/conmon.git" \
- && git fetch origin --tags \
- && git checkout --detach -q "$CONMON_COMMIT" \
- && make \
- && install -D -m 755 bin/conmon /usr/libexec/podman/conmon \
- && rm -rf "$GOPATH"
-
-# Install CNI plugins
-ENV CNI_COMMIT 485be65581341430f9106a194a98f0f2412245fb
-RUN set -x \
- && export GOPATH="$(mktemp -d)" GOCACHE="$(mktemp -d)" \
- && git clone https://github.com/containernetworking/plugins.git "$GOPATH/src/github.com/containernetworking/plugins" \
- && cd "$GOPATH/src/github.com/containernetworking/plugins" \
- && git checkout --detach -q "$CNI_COMMIT" \
- && ./build_linux.sh \
- && mkdir -p /usr/libexec/cni \
- && cp bin/* /usr/libexec/cni \
- && rm -rf "$GOPATH"
-
-# Install ginkgo
-RUN set -x \
- && export GOPATH=/go \
- && go get -u github.com/onsi/ginkgo/ginkgo \
- && install -D -m 755 "$GOPATH"/bin/ginkgo /usr/bin/
-
-# Install gomega
-RUN set -x \
- && export GOPATH=/go \
- && go get github.com/onsi/gomega/...
-
-# Install latest stable criu version
-RUN set -x \
- && cd /tmp \
- && git clone https://github.com/checkpoint-restore/criu.git \
- && cd criu \
- && make \
- && install -D -m 755 criu/criu /usr/sbin/ \
- && rm -rf /tmp/criu
-
-# Install cni config
-#RUN make install.cni
-RUN mkdir -p /etc/cni/net.d/
-COPY cni/87-podman-bridge.conflist /etc/cni/net.d/87-podman-bridge.conflist
-
-# Make sure we have some policy for pulling images
-RUN mkdir -p /etc/containers && curl https://raw.githubusercontent.com/projectatomic/registries/master/registries.fedora -o /etc/containers/registries.conf
-
-COPY test/policy.json /etc/containers/policy.json
-COPY test/redhat_sigstore.yaml /etc/containers/registries.d/registry.access.redhat.com.yaml
-
-ADD . /go/src/github.com/containers/libpod
-
-RUN set -x && cd /go/src/github.com/containers/libpod
-
-WORKDIR /go/src/github.com/containers/libpod
+FROM registry.fedoraproject.org/fedora:latest
+
+# This container image is utilized by the containers CI automation system
+# for building and testing libpod inside a container environment.
+# It is assumed that the source to be tested will overwrite $GOSRC (below)
+# at runtime.
+ENV GOPATH=/var/tmp/go
+ENV GOSRC=$GOPATH/src/github.com/containers/libpod
+ENV SCRIPT_BASE=./contrib/cirrus
+ENV PACKER_BASE=$SCRIPT_BASE/packer
+
+# Only add minimal tooling necessary to complete setup.
+ADD /$SCRIPT_BASE $GOSRC/$SCRIPT_BASE
+ADD /hack/install_catatonit.sh $GOSRC/hack/
+ADD /cni/*.conflist $GOSRC/cni/
+ADD /test/*.json $GOSRC/test/
+ADD /test/*.conf $GOSRC/test/
+WORKDIR $GOSRC
+
+# Re-use repositories and package setup as in VMs under CI
+RUN bash $PACKER_BASE/fedora_packaging.sh && \
+ dnf clean all && \
+ rm -rf /var/cache/dnf
+
+# Mirror steps taken under CI
+RUN bash -c 'source $GOSRC/$SCRIPT_BASE/lib.sh && install_test_configs'
diff --git a/Dockerfile.centos b/Dockerfile.centos
deleted file mode 100644
index f5a2b891c..000000000
--- a/Dockerfile.centos
+++ /dev/null
@@ -1,77 +0,0 @@
-FROM registry.centos.org/centos/centos:7
-
-RUN yum -y install btrfs-progs-devel \
- atomic-registries \
- autoconf \
- automake \
- bzip2 \
- device-mapper-devel \
- findutils \
- file \
- git \
- glibc-static \
- glib2-devel \
- gnupg \
- golang \
- golang-github-cpuguy83-go-md2man \
- gpgme-devel \
- libassuan-devel \
- libseccomp-devel \
- libselinux-devel \
- libtool \
- containers-common \
- runc \
- make \
- lsof \
- which\
- golang-github-cpuguy83-go-md2man \
- nmap-ncat \
- xz \
- iptables && yum clean all
-
-# Install CNI plugins
-ENV CNI_COMMIT 485be65581341430f9106a194a98f0f2412245fb
-RUN set -x \
- && export GOPATH="$(mktemp -d)" GOCACHE="$(mktemp -d)" \
- && git clone https://github.com/containernetworking/plugins.git "$GOPATH/src/github.com/containernetworking/plugins" \
- && cd "$GOPATH/src/github.com/containernetworking/plugins" \
- && git checkout --detach -q "$CNI_COMMIT" \
- && ./build_linux.sh \
- && mkdir -p /usr/libexec/cni \
- && cp bin/* /usr/libexec/cni \
- && rm -rf "$GOPATH"
-
-# Install ginkgo
-RUN set -x \
- && export GOPATH=/go \
- && go get -u github.com/onsi/ginkgo/ginkgo \
- && install -D -m 755 "$GOPATH"/bin/ginkgo /usr/bin/
-
-# Install gomega
-RUN set -x \
- && export GOPATH=/go \
- && go get github.com/onsi/gomega/...
-
-# Install conmon
-ENV CONMON_COMMIT 6f3572558b97bc60dd8f8c7f0807748e6ce2c440
-RUN set -x \
- && export GOPATH="$(mktemp -d)" \
- && git clone https://github.com/containers/conmon.git "$GOPATH/src/github.com/containers/conmon.git" \
- && cd "$GOPATH/src/github.com/containers/conmon.git" \
- && git fetch origin --tags \
- && git checkout --detach -q "$CONMON_COMMIT" \
- && make \
- && install -D -m 755 bin/conmon /usr/libexec/podman/conmon \
- && rm -rf "$GOPATH"
-
-# Install cni config
-#RUN make install.cni
-RUN mkdir -p /etc/cni/net.d/
-COPY cni/87-podman-bridge.conflist /etc/cni/net.d/87-podman-bridge.conflist
-
-# Make sure we have some policy for pulling images
-RUN mkdir -p /etc/containers
-COPY test/policy.json /etc/containers/policy.json
-COPY test/redhat_sigstore.yaml /etc/containers/registries.d/registry.access.redhat.com.yaml
-
-WORKDIR /go/src/github.com/containers/libpod
diff --git a/Dockerfile.fedora b/Dockerfile.fedora
deleted file mode 100644
index 45b2c3670..000000000
--- a/Dockerfile.fedora
+++ /dev/null
@@ -1,73 +0,0 @@
-FROM registry.fedoraproject.org/fedora:30
-
-RUN dnf -y install btrfs-progs-devel \
- atomic-registries \
- autoconf \
- automake \
- bzip2 \
- device-mapper-devel \
- file \
- findutils \
- git \
- glib2-devel \
- glibc-static \
- gnupg \
- golang \
- golang-github-cpuguy83-go-md2man \
- gpgme-devel \
- libassuan-devel \
- libseccomp-devel \
- libselinux-devel \
- libtool \
- containers-common \
- runc \
- make \
- lsof \
- which\
- golang-github-cpuguy83-go-md2man \
- procps-ng \
- nmap-ncat \
- xz \
- slirp4netns \
- container-selinux \
- containernetworking-plugins \
- iproute \
- iptables && dnf clean all
-
-# Install ginkgo
-RUN set -x \
- && export GOPATH=/go GOCACHE="$(mktemp -d)" \
- && go get -u github.com/onsi/ginkgo/ginkgo \
- && install -D -m 755 "$GOPATH"/bin/ginkgo /usr/bin/
-
-# Install gomega
-RUN set -x \
- && export GOPATH=/go GOCACHE="$(mktemp -d)" \
- && go get github.com/onsi/gomega/...
-
-# Install conmon
-ENV CONMON_COMMIT 6f3572558b97bc60dd8f8c7f0807748e6ce2c440
-RUN set -x \
- && export GOPATH="$(mktemp -d)" GOCACHE="$(mktemp -d)" \
- && git clone https://github.com/containers/conmon.git "$GOPATH/src/github.com/containers/conmon.git" \
- && cd "$GOPATH/src/github.com/containers/conmon.git" \
- && git fetch origin --tags \
- && git checkout --detach -q "$CONMON_COMMIT" \
- && make \
- && install -D -m 755 bin/conmon /usr/libexec/podman/conmon \
- && rm -rf "$GOPATH"
-
-# Install cni config
-#RUN make install.cni
-RUN mkdir -p /etc/cni/net.d/
-COPY cni/87-podman-bridge.conflist /etc/cni/net.d/87-podman-bridge.conflist
-
-# Make sure we have some policy for pulling images
-RUN mkdir -p /etc/containers
-COPY test/policy.json /etc/containers/policy.json
-COPY test/redhat_sigstore.yaml /etc/containers/registries.d/registry.access.redhat.com.yaml
-
-# Install varlink stuff
-RUN pip3 install varlink
-
-WORKDIR /go/src/github.com/containers/libpod
diff --git a/Dockerfile.ubuntu b/Dockerfile.ubuntu
new file mode 100644
index 000000000..3a8f837b9
--- /dev/null
+++ b/Dockerfile.ubuntu
@@ -0,0 +1,29 @@
+# Must resemble $UBUNTU_BASE_IMAGE in ./contrib/cirrus/lib.sh
+FROM ubuntu:latest
+
+# This container image is intended for building and testing libpod
+# from inside a container environment. It is assumed that the source
+# to be tested will overwrite $GOSRC (below) at runtime.
+ENV GOPATH=/var/tmp/go
+ENV GOSRC=$GOPATH/src/github.com/containers/libpod
+ENV SCRIPT_BASE=./contrib/cirrus
+ENV PACKER_BASE=$SCRIPT_BASE/packer
+
+RUN export DEBIAN_FRONTEND="noninteractive" && \
+ apt-get -qq update --yes && \
+ apt-get -qq upgrade --yes && \
+ apt-get -qq install curl git && \
+ apt-get -qq autoremove --yes && \
+ rm -rf /var/cache/apt
+
+# Only add minimal tooling necessary to complete setup.
+ADD / $GOSRC
+WORKDIR $GOSRC
+
+# Re-use repositories and package setup as in VMs under CI
+RUN bash $PACKER_BASE/ubuntu_packaging.sh && \
+ apt-get -qq autoremove --yes && \
+ rm -rf /var/cache/apt
+
+# Mirror steps taken under CI
+RUN bash -c 'source $GOSRC/$SCRIPT_BASE/lib.sh && install_test_configs'
diff --git a/Makefile b/Makefile
index f389bcb35..bce0f33a1 100644
--- a/Makefile
+++ b/Makefile
@@ -470,25 +470,35 @@ changelog: ## Generate changelog
.PHONY: install
install: .gopathok install.bin install.remote install.man install.cni install.systemd ## Install binaries to system locations
-.PHONY: install.remote
-install.remote: podman-remote
+.PHONY: install.remote-nobuild
+install.remote-nobuild:
install ${SELINUXOPT} -d -m 755 $(DESTDIR)$(BINDIR)
install ${SELINUXOPT} -m 755 bin/podman-remote $(DESTDIR)$(BINDIR)/podman-remote
test -z "${SELINUXOPT}" || chcon --verbose --reference=$(DESTDIR)$(BINDIR)/podman-remote bin/podman-remote
-.PHONY: install.bin
-install.bin: podman
+.PHONY: install.remote
+install.remote: podman-remote install.remote-nobuild
+
+.PHONY: install.bin-nobuild
+install.bin-nobuild:
install ${SELINUXOPT} -d -m 755 $(DESTDIR)$(BINDIR)
install ${SELINUXOPT} -m 755 bin/podman $(DESTDIR)$(BINDIR)/podman
test -z "${SELINUXOPT}" || chcon --verbose --reference=$(DESTDIR)$(BINDIR)/podman bin/podman
-install.man: docs
+.PHONY: install.bin
+install.bin: podman install.bin-nobuild
+
+.PHONY: install.man-nobuild
+install.man-nobuild:
install ${SELINUXOPT} -d -m 755 $(DESTDIR)$(MANDIR)/man1
install ${SELINUXOPT} -d -m 755 $(DESTDIR)$(MANDIR)/man5
install ${SELINUXOPT} -m 644 $(filter %.1,$(MANPAGES_DEST)) -t $(DESTDIR)$(MANDIR)/man1
install ${SELINUXOPT} -m 644 $(filter %.5,$(MANPAGES_DEST)) -t $(DESTDIR)$(MANDIR)/man5
install ${SELINUXOPT} -m 644 docs/source/markdown/links/*1 -t $(DESTDIR)$(MANDIR)/man1
+.PHONY: install.man
+install.man: docs install.man-nobuild
+
.PHONY: install.config
install.config:
install ${SELINUXOPT} -d -m 755 $(DESTDIR)$(SHAREDIR_CONTAINERS)
diff --git a/README.md b/README.md
index 8cc010a45..8d9447e51 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@
Libpod provides a library for applications looking to use the Container Pod concept,
popularized by Kubernetes. Libpod also contains the Pod Manager tool `(Podman)`. Podman manages pods, containers, container images, and container volumes.
-* [Latest Version: 1.9.0](https://github.com/containers/libpod/releases/latest)
+* [Latest Version: 1.9.1](https://github.com/containers/libpod/releases/latest)
* [Continuous Integration:](contrib/cirrus/README.md) [![Build Status](https://api.cirrus-ci.com/github/containers/libpod.svg)](https://cirrus-ci.com/github/containers/libpod/master)
* [GoDoc: ![GoDoc](https://godoc.org/github.com/containers/libpod/libpod?status.svg)](https://godoc.org/github.com/containers/libpod/libpod)
* Automated continuous release downloads (including remote-client):
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index aef66545f..6657529b9 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -1,5 +1,14 @@
# Release Notes
+## 1.9.1
+### Bugfixes
+- Fixed a bug where healthchecks could become nonfunctional if container log paths were manually set with `--log-path` and multiple container logs were placed in the same directory ([#5915](https://github.com/containers/libpod/issues/5915))
+- Fixed a bug where rootless Podman could, when using an older `libpod.conf`, print numerous warning messages about an invalid CGroup manager config
+- Fixed a bug where rootless Podman would sometimes fail to close the rootless user namespace when joining it ([#5873](https://github.com/containers/libpod/issues/5873))
+
+### Misc
+- Updated containers/common to v0.8.2
+
## 1.9.0
### Features
- Experimental support has been added for `podman run --userns=auto`, which automatically allocates a unique UID and GID range for the new container's user namespace
diff --git a/cmd/podman/common/create.go b/cmd/podman/common/create.go
index a0aed984c..0f9476754 100644
--- a/cmd/podman/common/create.go
+++ b/cmd/podman/common/create.go
@@ -49,9 +49,7 @@ func GetCreateFlags(cf *ContainerCLIOpts) *pflag.FlagSet {
"cap-drop", []string{},
"Drop capabilities from the container",
)
- cgroupNS := ""
- createFlags.StringVar(
- &cgroupNS,
+ createFlags.String(
"cgroupns", containerConfig.CgroupNS(),
"cgroup namespace to use",
)
@@ -155,9 +153,7 @@ func GetCreateFlags(cf *ContainerCLIOpts) *pflag.FlagSet {
"device-write-iops", []string{},
"Limit write rate (IO per second) to a device (e.g. --device-write-iops=/dev/sda:1000)",
)
- createFlags.StringVar(
- &cf.Entrypoint,
- "entrypoint", "",
+ createFlags.String("entrypoint", "",
"Overwrite the default ENTRYPOINT of the image",
)
createFlags.StringArrayVarP(
@@ -248,9 +244,7 @@ func GetCreateFlags(cf *ContainerCLIOpts) *pflag.FlagSet {
"interactive", "i", false,
"Keep STDIN open even if not attached",
)
- ipcNS := ""
- createFlags.StringVar(
- &ipcNS,
+ createFlags.String(
"ipc", containerConfig.IPCNS(),
"IPC namespace to use",
)
@@ -331,9 +325,7 @@ func GetCreateFlags(cf *ContainerCLIOpts) *pflag.FlagSet {
"use `OS` instead of the running OS for choosing images",
)
// markFlagHidden(createFlags, "override-os")
- pid := ""
- createFlags.StringVar(
- &pid,
+ createFlags.String(
"pid", containerConfig.PidNS(),
"PID namespace to use",
)
@@ -397,9 +389,7 @@ func GetCreateFlags(cf *ContainerCLIOpts) *pflag.FlagSet {
"security-opt", containerConfig.SecurityOptions(),
"Security Options",
)
- shmSize := ""
- createFlags.StringVar(
- &shmSize,
+ createFlags.String(
"shm-size", containerConfig.ShmSize(),
"Size of /dev/shm "+sizeWithUnitFormat,
)
@@ -464,15 +454,11 @@ func GetCreateFlags(cf *ContainerCLIOpts) *pflag.FlagSet {
"user", "u", "",
"Username or UID (format: <name|uid>[:<group|gid>])",
)
- userNS := ""
- createFlags.StringVar(
- &userNS,
+ createFlags.String(
"userns", containerConfig.Containers.UserNS,
"User namespace to use",
)
- utsNS := ""
- createFlags.StringVar(
- &utsNS,
+ createFlags.String(
"uts", containerConfig.Containers.UTSNS,
"UTS namespace to use",
)
diff --git a/cmd/podman/common/create_opts.go b/cmd/podman/common/create_opts.go
index 2f08bb6a6..c275b1674 100644
--- a/cmd/podman/common/create_opts.go
+++ b/cmd/podman/common/create_opts.go
@@ -31,7 +31,7 @@ type ContainerCLIOpts struct {
DeviceReadIOPs []string
DeviceWriteBPs []string
DeviceWriteIOPs []string
- Entrypoint string
+ Entrypoint *string
env []string
EnvHost bool
EnvFile []string
diff --git a/cmd/podman/common/inspect.go b/cmd/podman/common/inspect.go
deleted file mode 100644
index dfc6fe679..000000000
--- a/cmd/podman/common/inspect.go
+++ /dev/null
@@ -1,18 +0,0 @@
-package common
-
-import (
- "github.com/containers/libpod/pkg/domain/entities"
- "github.com/spf13/cobra"
-)
-
-// AddInspectFlagSet takes a command and adds the inspect flags and returns an InspectOptions object
-// Since this cannot live in `package main` it lives here until a better home is found
-func AddInspectFlagSet(cmd *cobra.Command) *entities.InspectOptions {
- opts := entities.InspectOptions{}
-
- flags := cmd.Flags()
- flags.BoolVarP(&opts.Size, "size", "s", false, "Display total file size")
- flags.StringVarP(&opts.Format, "format", "f", "", "Change the output format to a Go template")
-
- return &opts
-}
diff --git a/cmd/podman/common/ports.go b/cmd/podman/common/ports.go
index a96bafabd..2092bbe53 100644
--- a/cmd/podman/common/ports.go
+++ b/cmd/podman/common/ports.go
@@ -9,10 +9,10 @@ func verifyExpose(expose []string) error {
// add the expose ports from the user (--expose)
// can be single or a range
for _, expose := range expose {
- //support two formats for expose, original format <portnum>/[<proto>] or <startport-endport>/[<proto>]
+ // support two formats for expose, original format <portnum>/[<proto>] or <startport-endport>/[<proto>]
_, port := nat.SplitProtoPort(expose)
- //parse the start and end port and create a sequence of ports to expose
- //if expose a port, the start and end port are the same
+ // parse the start and end port and create a sequence of ports to expose
+ // if expose a port, the start and end port are the same
_, _, err := nat.ParsePortRange(port)
if err != nil {
return errors.Wrapf(err, "invalid range format for --expose: %s", expose)
diff --git a/cmd/podman/common/specgen.go b/cmd/podman/common/specgen.go
index 5d5816ea4..7250f88bb 100644
--- a/cmd/podman/common/specgen.go
+++ b/cmd/podman/common/specgen.go
@@ -192,7 +192,7 @@ func getMemoryLimits(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []strin
func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string) error {
var (
err error
- //namespaces map[string]string
+ // namespaces map[string]string
)
// validate flags as needed
@@ -364,20 +364,20 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string
s.WorkDir = workDir
entrypoint := []string{}
userCommand := []string{}
- if ep := c.Entrypoint; len(ep) > 0 {
- // Check if entrypoint specified is json
- if err := json.Unmarshal([]byte(c.Entrypoint), &entrypoint); err != nil {
- entrypoint = append(entrypoint, ep)
+ if c.Entrypoint != nil {
+ if ep := *c.Entrypoint; len(ep) > 0 {
+ // Check if entrypoint specified is json
+ if err := json.Unmarshal([]byte(*c.Entrypoint), &entrypoint); err != nil {
+ entrypoint = append(entrypoint, ep)
+ }
}
+ s.Entrypoint = entrypoint
}
-
var command []string
- s.Entrypoint = entrypoint
-
// Build the command
// If we have an entry point, it goes first
- if len(entrypoint) > 0 {
+ if c.Entrypoint != nil {
command = entrypoint
}
if len(inputCommand) > 0 {
@@ -386,9 +386,12 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string
userCommand = append(userCommand, inputCommand...)
}
- if len(inputCommand) > 0 {
+ switch {
+ case len(inputCommand) > 0:
s.Command = userCommand
- } else {
+ case c.Entrypoint != nil:
+ s.Command = []string{}
+ default:
s.Command = command
}
@@ -466,24 +469,6 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string
s.CgroupParent = c.CGroupParent
s.CgroupsMode = c.CGroupsMode
s.Groups = c.GroupAdd
- // TODO WTF
- //cgroup := &cc.CgroupConfig{
- // Cgroupns: c.String("cgroupns"),
- //}
- //
- //userns := &cc.UserConfig{
- // GroupAdd: c.StringSlice("group-add"),
- // IDMappings: idmappings,
- // UsernsMode: usernsMode,
- // User: user,
- //}
- //
- //uts := &cc.UtsConfig{
- // UtsMode: utsMode,
- // NoHosts: c.Bool("no-hosts"),
- // HostAdd: c.StringSlice("add-host"),
- // Hostname: c.String("hostname"),
- //}
s.Hostname = c.Hostname
sysctl := map[string]string{}
@@ -503,7 +488,7 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string
// TODO
// ouitside of specgen and oci though
// defaults to true, check spec/storage
- //s.readon = c.ReadOnlyTmpFS
+ // s.readon = c.ReadOnlyTmpFS
// TODO convert to map?
// check if key=value and convert
sysmap := make(map[string]string)
@@ -546,7 +531,7 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string
// Only add read-only tmpfs mounts in case that we are read-only and the
// read-only tmpfs flag has been set.
- mounts, volumes, err := parseVolumes(c.Volume, c.Mount, c.TmpFS, (c.ReadOnlyTmpFS && c.ReadOnly))
+ mounts, volumes, err := parseVolumes(c.Volume, c.Mount, c.TmpFS, c.ReadOnlyTmpFS && c.ReadOnly)
if err != nil {
return err
}
@@ -554,12 +539,12 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string
s.Volumes = volumes
// TODO any idea why this was done
- //devices := rtc.Containers.Devices
+ // devices := rtc.Containers.Devices
// TODO conflict on populate?
//
- //if c.Changed("device") {
+ // if c.Changed("device") {
// devices = append(devices, c.StringSlice("device")...)
- //}
+ // }
for _, dev := range c.Devices {
s.Devices = append(s.Devices, specs.LinuxDevice{Path: dev})
@@ -571,7 +556,7 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string
// initpath
s.Stdin = c.Interactive
// quiet
- //DeviceCgroupRules: c.StringSlice("device-cgroup-rule"),
+ // DeviceCgroupRules: c.StringSlice("device-cgroup-rule"),
// Rlimits/Ulimits
for _, u := range c.Ulimit {
@@ -591,10 +576,10 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string
s.Rlimits = append(s.Rlimits, rl)
}
- //Tmpfs: c.StringArray("tmpfs"),
+ // Tmpfs: c.StringArray("tmpfs"),
// TODO how to handle this?
- //Syslog: c.Bool("syslog"),
+ // Syslog: c.Bool("syslog"),
logOpts := make(map[string]string)
for _, o := range c.LogOptions {
@@ -620,7 +605,7 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string
s.StopTimeout = &c.StopTimeout
// TODO where should we do this?
- //func verifyContainerResources(config *cc.CreateConfig, update bool) ([]string, error) {
+ // func verifyContainerResources(config *cc.CreateConfig, update bool) ([]string, error) {
return nil
}
diff --git a/cmd/podman/containers/attach.go b/cmd/podman/containers/attach.go
index 78b52ad1b..119b47d3f 100644
--- a/cmd/podman/containers/attach.go
+++ b/cmd/podman/containers/attach.go
@@ -4,6 +4,7 @@ import (
"os"
"github.com/containers/libpod/cmd/podman/registry"
+ "github.com/containers/libpod/cmd/podman/validate"
"github.com/containers/libpod/pkg/domain/entities"
"github.com/pkg/errors"
"github.com/spf13/cobra"
@@ -17,12 +18,7 @@ var (
Short: "Attach to a running container",
Long: attachDescription,
RunE: attach,
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) > 1 || (len(args) == 0 && !cmd.Flag("latest").Changed) {
- return errors.Errorf("attach requires the name or id of one running container or the latest flag")
- }
- return nil
- },
+ Args: validate.IdOrLatestArgs,
Example: `podman attach ctrID
podman attach 1234
podman attach --no-stdin foobar`,
@@ -33,6 +29,7 @@ var (
Short: attachCommand.Short,
Long: attachCommand.Long,
RunE: attachCommand.RunE,
+ Args: validate.IdOrLatestArgs,
Example: `podman container attach ctrID
podman container attach 1234
podman container attach --no-stdin foobar`,
@@ -71,11 +68,18 @@ func init() {
}
func attach(cmd *cobra.Command, args []string) error {
+ if len(args) > 1 || (len(args) == 0 && !attachOpts.Latest) {
+ return errors.Errorf("attach requires the name or id of one running container or the latest flag")
+ }
+ var name string
+ if len(args) > 0 {
+ name = args[0]
+ }
attachOpts.Stdin = os.Stdin
if attachOpts.NoStdin {
attachOpts.Stdin = nil
}
attachOpts.Stdout = os.Stdout
attachOpts.Stderr = os.Stderr
- return registry.ContainerEngine().ContainerAttach(registry.GetContext(), args[0], attachOpts)
+ return registry.ContainerEngine().ContainerAttach(registry.GetContext(), name, attachOpts)
}
diff --git a/cmd/podman/containers/commit.go b/cmd/podman/containers/commit.go
index 137e486eb..b3c3d7626 100644
--- a/cmd/podman/containers/commit.go
+++ b/cmd/podman/containers/commit.go
@@ -30,6 +30,7 @@ var (
}
containerCommitCommand = &cobra.Command{
+ Args: cobra.MinimumNArgs(1),
Use: commitCommand.Use,
Short: commitCommand.Short,
Long: commitCommand.Long,
diff --git a/cmd/podman/containers/container.go b/cmd/podman/containers/container.go
index 97b73cdd0..a102318fb 100644
--- a/cmd/podman/containers/container.go
+++ b/cmd/podman/containers/container.go
@@ -2,6 +2,7 @@ package containers
import (
"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/util"
"github.com/spf13/cobra"
@@ -17,7 +18,7 @@ var (
Short: "Manage containers",
Long: "Manage containers",
TraverseChildren: true,
- RunE: registry.SubCommandExists,
+ RunE: validate.SubCommandExists,
}
containerConfig = util.DefaultContainerConfig()
diff --git a/cmd/podman/containers/create.go b/cmd/podman/containers/create.go
index da550b606..7927da04d 100644
--- a/cmd/podman/containers/create.go
+++ b/cmd/podman/containers/create.go
@@ -1,8 +1,10 @@
package containers
import (
+ "context"
"fmt"
"os"
+ "strings"
"github.com/containers/common/pkg/config"
"github.com/containers/libpod/cmd/podman/common"
@@ -33,6 +35,7 @@ var (
}
containerCreateCommand = &cobra.Command{
+ Args: cobra.MinimumNArgs(1),
Use: createCommand.Use,
Short: createCommand.Short,
Long: createCommand.Long,
@@ -59,7 +62,7 @@ func init() {
Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
Command: createCommand,
})
- //common.GetCreateFlags(createCommand)
+ // common.GetCreateFlags(createCommand)
flags := createCommand.Flags()
createFlags(flags)
@@ -105,6 +108,10 @@ func create(cmd *cobra.Command, args []string) error {
return err
}
+ if _, err := createPodIfNecessary(s); err != nil {
+ return err
+ }
+
report, err := registry.ContainerEngine().ContainerCreate(registry.GetContext(), s)
if err != nil {
return err
@@ -159,6 +166,10 @@ func createInit(c *cobra.Command) error {
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
+ }
// Docker-compatibility: the "-h" flag for run/create is reserved for
// the hostname (see https://github.com/containers/libpod/issues/1367).
@@ -180,8 +191,10 @@ func pullImage(imageName string) error {
return errors.New("unable to find a name and tag match for busybox in repotags: no such image")
}
_, pullErr := registry.ImageEngine().Pull(registry.GetContext(), imageName, entities.ImagePullOptions{
- Authfile: cliVals.Authfile,
- Quiet: cliVals.Quiet,
+ Authfile: cliVals.Authfile,
+ Quiet: cliVals.Quiet,
+ OverrideArch: cliVals.OverrideArch,
+ OverrideOS: cliVals.OverrideOS,
})
if pullErr != nil {
return pullErr
@@ -203,3 +216,25 @@ func openCidFile(cidfile string) (*os.File, error) {
}
return cidFile, nil
}
+
+// createPodIfNecessary automatically creates a pod when requested. if the pod name
+// has the form new:ID, the pod ID is created and the name in the spec generator is replaced
+// with ID.
+func createPodIfNecessary(s *specgen.SpecGenerator) (*entities.PodCreateReport, error) {
+ if !strings.HasPrefix(s.Pod, "new:") {
+ return nil, nil
+ }
+ podName := strings.Replace(s.Pod, "new:", "", 1)
+ if len(podName) < 1 {
+ return nil, errors.Errorf("new pod name must be at least one character")
+ }
+ createOptions := entities.PodCreateOptions{
+ Name: podName,
+ Infra: true,
+ Net: &entities.NetOptions{
+ PublishPorts: s.PortMappings,
+ },
+ }
+ s.Pod = podName
+ return registry.ContainerEngine().PodCreate(context.Background(), createOptions)
+}
diff --git a/cmd/podman/containers/diff.go b/cmd/podman/containers/diff.go
index 046dac53e..59b788010 100644
--- a/cmd/podman/containers/diff.go
+++ b/cmd/podman/containers/diff.go
@@ -3,6 +3,7 @@ package containers
import (
"github.com/containers/libpod/cmd/podman/registry"
"github.com/containers/libpod/cmd/podman/report"
+ "github.com/containers/libpod/cmd/podman/validate"
"github.com/containers/libpod/pkg/domain/entities"
"github.com/pkg/errors"
"github.com/spf13/cobra"
@@ -12,7 +13,7 @@ var (
// podman container _diff_
diffCmd = &cobra.Command{
Use: "diff [flags] CONTAINER",
- Args: registry.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 3749c934a..0992b3862 100644
--- a/cmd/podman/containers/exec.go
+++ b/cmd/podman/containers/exec.go
@@ -16,20 +16,22 @@ var (
execDescription = `Execute the specified command inside a running container.
`
execCommand = &cobra.Command{
- Use: "exec [flags] CONTAINER [COMMAND [ARG...]]",
- Short: "Run a process in a running container",
- Long: execDescription,
- RunE: exec,
+ Use: "exec [flags] CONTAINER [COMMAND [ARG...]]",
+ Short: "Run a process in a running container",
+ Long: execDescription,
+ RunE: exec,
+ DisableFlagsInUseLine: true,
Example: `podman exec -it ctrID ls
podman exec -it -w /tmp myCtr pwd
podman exec --user root ctrID ls`,
}
containerExecCommand = &cobra.Command{
- Use: execCommand.Use,
- Short: execCommand.Short,
- Long: execCommand.Long,
- RunE: execCommand.RunE,
+ Use: execCommand.Use,
+ Short: execCommand.Short,
+ Long: execCommand.Long,
+ RunE: execCommand.RunE,
+ DisableFlagsInUseLine: true,
Example: `podman container exec -it ctrID ls
podman container exec -it -w /tmp myCtr pwd
podman container exec --user root ctrID ls`,
@@ -70,7 +72,7 @@ func init() {
registry.Commands = append(registry.Commands, registry.CliCommand{
Mode: []entities.EngineMode{entities.ABIMode},
Command: containerExecCommand,
- Parent: containerCommitCommand,
+ Parent: containerCmd,
})
containerExecFlags := containerExecCommand.Flags()
@@ -79,6 +81,10 @@ func init() {
func exec(cmd *cobra.Command, args []string) error {
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")
+ }
execOpts.Cmd = args
if !execOpts.Latest {
execOpts.Cmd = args[1:]
diff --git a/cmd/podman/containers/exists.go b/cmd/podman/containers/exists.go
index e640ca5e1..81ba8a282 100644
--- a/cmd/podman/containers/exists.go
+++ b/cmd/podman/containers/exists.go
@@ -17,8 +17,9 @@ var (
Long: containerExistsDescription,
Example: `podman container exists containerID
podman container exists myctr || podman run --name myctr [etc...]`,
- RunE: exists,
- Args: cobra.ExactArgs(1),
+ RunE: exists,
+ Args: cobra.ExactArgs(1),
+ DisableFlagsInUseLine: true,
}
)
diff --git a/cmd/podman/containers/export.go b/cmd/podman/containers/export.go
index fb5bd468f..bbb6a6bc9 100644
--- a/cmd/podman/containers/export.go
+++ b/cmd/podman/containers/export.go
@@ -28,6 +28,7 @@ var (
}
containerExportCommand = &cobra.Command{
+ Args: cobra.MinimumNArgs(1),
Use: exportCommand.Use,
Short: exportCommand.Short,
Long: exportCommand.Long,
diff --git a/cmd/podman/containers/inspect.go b/cmd/podman/containers/inspect.go
index f9ef1ddbd..4549a4ef6 100644
--- a/cmd/podman/containers/inspect.go
+++ b/cmd/podman/containers/inspect.go
@@ -1,15 +1,8 @@
package containers
import (
- "context"
- "fmt"
- "os"
- "strings"
- "text/template"
-
- "github.com/containers/libpod/cmd/podman/common"
+ "github.com/containers/libpod/cmd/podman/inspect"
"github.com/containers/libpod/cmd/podman/registry"
-
"github.com/containers/libpod/pkg/domain/entities"
"github.com/spf13/cobra"
)
@@ -20,7 +13,7 @@ var (
Use: "inspect [flags] CONTAINER",
Short: "Display the configuration of a container",
Long: `Displays the low-level information on a container identified by name or ID.`,
- RunE: inspect,
+ RunE: inspectExec,
Example: `podman container inspect myCtr
podman container inspect -l --format '{{.Id}} {{.Config.Labels}}'`,
}
@@ -33,45 +26,9 @@ func init() {
Command: inspectCmd,
Parent: containerCmd,
})
- inspectOpts = common.AddInspectFlagSet(inspectCmd)
- flags := inspectCmd.Flags()
-
- if !registry.IsRemote() {
- flags.BoolVarP(&inspectOpts.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
- }
-
-}
-
-func inspect(cmd *cobra.Command, args []string) error {
- responses, err := registry.ContainerEngine().ContainerInspect(context.Background(), args, *inspectOpts)
- if err != nil {
- return err
- }
- if inspectOpts.Format == "" {
- b, err := json.MarshalIndent(responses, "", " ")
- if err != nil {
- return err
- }
- fmt.Println(string(b))
- return nil
- }
- format := inspectOpts.Format
- if !strings.HasSuffix(format, "\n") {
- format += "\n"
- }
- tmpl, err := template.New("inspect").Parse(format)
- if err != nil {
- return err
- }
- for _, i := range responses {
- if err := tmpl.Execute(os.Stdout, i); err != nil {
- return err
- }
- }
- return nil
+ inspectOpts = inspect.AddInspectFlagSet(inspectCmd)
}
-func Inspect(cmd *cobra.Command, args []string, options *entities.InspectOptions) error {
- inspectOpts = options
- return inspect(cmd, args)
+func inspectExec(cmd *cobra.Command, args []string) error {
+ return inspect.Inspect(args, *inspectOpts)
}
diff --git a/cmd/podman/containers/kill.go b/cmd/podman/containers/kill.go
index 8b4a384fe..ef85aad7d 100644
--- a/cmd/podman/containers/kill.go
+++ b/cmd/podman/containers/kill.go
@@ -30,6 +30,9 @@ var (
}
containerKillCommand = &cobra.Command{
+ Args: func(cmd *cobra.Command, args []string) error {
+ return parse.CheckAllLatestAndCIDFile(cmd, args, false, false)
+ },
Use: killCommand.Use,
Short: killCommand.Short,
Long: killCommand.Long,
diff --git a/cmd/podman/containers/list.go b/cmd/podman/containers/list.go
index b5019ddd2..c200a49aa 100644
--- a/cmd/podman/containers/list.go
+++ b/cmd/podman/containers/list.go
@@ -2,6 +2,7 @@ package containers
import (
"github.com/containers/libpod/cmd/podman/registry"
+ "github.com/containers/libpod/cmd/podman/validate"
"github.com/containers/libpod/pkg/domain/entities"
"github.com/spf13/cobra"
)
@@ -11,7 +12,7 @@ var (
listCmd = &cobra.Command{
Use: "list",
Aliases: []string{"ls"},
- Args: cobra.NoArgs,
+ Args: validate.NoArgs,
Short: "List containers",
Long: "Prints out information about the containers",
RunE: ps,
diff --git a/cmd/podman/containers/port.go b/cmd/podman/containers/port.go
index 0e50140ca..2e3386aa9 100644
--- a/cmd/podman/containers/port.go
+++ b/cmd/podman/containers/port.go
@@ -109,7 +109,7 @@ func port(cmd *cobra.Command, args []string) error {
fmt.Printf("%d/%s -> %s:%d\n", v.ContainerPort, v.Protocol, hostIP, v.HostPort)
continue
}
- if v == userPort {
+ if v.ContainerPort == userPort.ContainerPort {
fmt.Printf("%s:%d\n", hostIP, v.HostPort)
found = true
break
diff --git a/cmd/podman/containers/ps.go b/cmd/podman/containers/ps.go
index 82434e9cc..c5696a158 100644
--- a/cmd/podman/containers/ps.go
+++ b/cmd/podman/containers/ps.go
@@ -13,6 +13,7 @@ import (
tm "github.com/buger/goterm"
"github.com/containers/buildah/pkg/formats"
"github.com/containers/libpod/cmd/podman/registry"
+ "github.com/containers/libpod/cmd/podman/validate"
"github.com/containers/libpod/pkg/domain/entities"
"github.com/cri-o/ocicni/pkg/ocicni"
"github.com/docker/go-units"
@@ -25,7 +26,7 @@ var (
psDescription = "Prints out information about the containers"
psCommand = &cobra.Command{
Use: "ps",
- Args: checkFlags,
+ Args: validate.NoArgs,
Short: "List containers",
Long: psDescription,
RunE: ps,
@@ -40,7 +41,7 @@ var (
}
filters []string
noTrunc bool
- defaultHeaders string = "CONTAINER ID\tIMAGE\tCOMMAND\tCREATED\tSTATUS\tPORTS\tNAMES"
+ defaultHeaders = "CONTAINER ID\tIMAGE\tCOMMAND\tCREATED\tSTATUS\tPORTS\tNAMES"
)
func init() {
@@ -63,9 +64,12 @@ func listFlagSet(flags *pflag.FlagSet) {
flags.BoolVarP(&listOpts.Pod, "pod", "p", false, "Print the ID and name of the pod the containers are associated with")
flags.BoolVarP(&listOpts.Quiet, "quiet", "q", false, "Print the numeric IDs of the containers only")
flags.BoolVarP(&listOpts.Size, "size", "s", false, "Display the total file sizes")
- flags.StringVar(&listOpts.Sort, "sort", "created", "Sort output by command, created, id, image, names, runningfor, size, or status")
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")
+
+ created := validate.ChoiceValue(&listOpts.Sort, "command", "created", "id", "image", "names", "runningfor", "size", "status")
+ flags.Var(created, "sort", "Sort output by: "+created.Choices())
+
if registry.IsRemote() {
_ = flags.MarkHidden("latest")
}
@@ -141,6 +145,9 @@ func getResponses() ([]entities.ListContainer, error) {
func ps(cmd *cobra.Command, args []string) error {
var responses []psReporter
+ if err := checkFlags(cmd, args); err != nil {
+ return err
+ }
for _, f := range filters {
split := strings.SplitN(f, "=", 2)
if len(split) == 1 {
@@ -171,7 +178,7 @@ func ps(cmd *cobra.Command, args []string) error {
headers, format := createPsOut()
if cmd.Flag("format").Changed {
- format = listOpts.Format
+ format = strings.TrimPrefix(listOpts.Format, "table ")
if !strings.HasPrefix(format, "\n") {
format += "\n"
}
@@ -348,7 +355,7 @@ func portsToString(ports []ocicni.PortMapping) string {
if len(ports) == 0 {
return ""
}
- //Sort the ports, so grouping continuous ports become easy.
+ // Sort the ports, so grouping continuous ports become easy.
sort.Slice(ports, func(i, j int) bool {
return comparePorts(ports[i], ports[j])
})
diff --git a/cmd/podman/containers/rm.go b/cmd/podman/containers/rm.go
index 3021853a9..96549cead 100644
--- a/cmd/podman/containers/rm.go
+++ b/cmd/podman/containers/rm.go
@@ -38,6 +38,9 @@ var (
Short: rmCommand.Use,
Long: rmCommand.Long,
RunE: rmCommand.RunE,
+ Args: func(cmd *cobra.Command, args []string) error {
+ return parse.CheckAllLatestAndCIDFile(cmd, args, false, true)
+ },
Example: `podman container rm imageID
podman container rm mywebserver myflaskserver 860a4b23
podman container rm --force --all
diff --git a/cmd/podman/containers/run.go b/cmd/podman/containers/run.go
index e3fe4cd0b..b13983e37 100644
--- a/cmd/podman/containers/run.go
+++ b/cmd/podman/containers/run.go
@@ -20,6 +20,7 @@ import (
var (
runDescription = "Runs a command in a new container from the given image"
runCommand = &cobra.Command{
+ Args: cobra.MinimumNArgs(1),
Use: "run [flags] IMAGE [COMMAND [ARG...]]",
Short: "Run a command in a new container",
Long: runDescription,
@@ -30,6 +31,7 @@ var (
}
containerRunCommand = &cobra.Command{
+ Args: cobra.MinimumNArgs(1),
Use: runCommand.Use,
Short: runCommand.Short,
Long: runCommand.Long,
@@ -144,6 +146,10 @@ func run(cmd *cobra.Command, args []string) error {
}
runOpts.Spec = s
+ if _, err := createPodIfNecessary(s); err != nil {
+ return err
+ }
+
report, err := registry.ContainerEngine().ContainerRun(registry.GetContext(), runOpts)
// report.ExitCode is set by ContainerRun even it it returns an error
if report != nil {
diff --git a/cmd/podman/containers/start.go b/cmd/podman/containers/start.go
index 381bf8e26..ce78d24ed 100644
--- a/cmd/podman/containers/start.go
+++ b/cmd/podman/containers/start.go
@@ -99,7 +99,7 @@ func start(cmd *cobra.Command, args []string) error {
for _, r := range responses {
if r.Err == nil {
- fmt.Println(r.Id)
+ fmt.Println(r.RawInput)
} else {
errs = append(errs, r.Err)
}
diff --git a/cmd/podman/containers/stop.go b/cmd/podman/containers/stop.go
index 4a451134a..22c487961 100644
--- a/cmd/podman/containers/stop.go
+++ b/cmd/podman/containers/stop.go
@@ -34,6 +34,9 @@ var (
Short: stopCommand.Short,
Long: stopCommand.Long,
RunE: stopCommand.RunE,
+ Args: func(cmd *cobra.Command, args []string) error {
+ return parse.CheckAllLatestAndCIDFile(cmd, args, false, true)
+ },
Example: `podman container stop ctrID
podman container stop --latest
podman container stop --time 2 mywebserver 6e534f14da9d`,
diff --git a/cmd/podman/containers/unmount.go b/cmd/podman/containers/unmount.go
index a4550abbd..d0ca202fe 100644
--- a/cmd/podman/containers/unmount.go
+++ b/cmd/podman/containers/unmount.go
@@ -27,6 +27,9 @@ var (
Args: func(cmd *cobra.Command, args []string) error {
return parse.CheckAllLatestAndCIDFile(cmd, args, false, false)
},
+ Annotations: map[string]string{
+ registry.ParentNSRequired: "",
+ },
Example: `podman umount ctrID
podman umount ctrID1 ctrID2 ctrID3
podman umount --all`,
@@ -37,6 +40,9 @@ var (
Short: umountCommand.Short,
Long: umountCommand.Long,
RunE: umountCommand.RunE,
+ Args: func(cmd *cobra.Command, args []string) error {
+ return parse.CheckAllLatestAndCIDFile(cmd, args, false, false)
+ },
Example: `podman container umount ctrID
podman container umount ctrID1 ctrID2 ctrID3
podman container umount --all`,
diff --git a/cmd/podman/containers/wait.go b/cmd/podman/containers/wait.go
index da746361d..1f4d4159b 100644
--- a/cmd/podman/containers/wait.go
+++ b/cmd/podman/containers/wait.go
@@ -7,6 +7,7 @@ import (
"github.com/containers/libpod/cmd/podman/registry"
"github.com/containers/libpod/cmd/podman/utils"
+ "github.com/containers/libpod/cmd/podman/validate"
"github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/pkg/domain/entities"
"github.com/pkg/errors"
@@ -22,7 +23,7 @@ var (
Short: "Block on one or more containers",
Long: waitDescription,
RunE: wait,
- Args: registry.IdOrLatestArgs,
+ Args: validate.IdOrLatestArgs,
Example: `podman wait --latest
podman wait --interval 5000 ctrID
podman wait ctrID1 ctrID2`,
@@ -33,6 +34,7 @@ var (
Short: waitCommand.Short,
Long: waitCommand.Long,
RunE: waitCommand.RunE,
+ Args: validate.IdOrLatestArgs,
Example: `podman container wait --latest
podman container wait --interval 5000 ctrID
podman container wait ctrID1 ctrID2`,
diff --git a/cmd/podman/diff.go b/cmd/podman/diff.go
index ec94c0918..1ff2fce40 100644
--- a/cmd/podman/diff.go
+++ b/cmd/podman/diff.go
@@ -6,6 +6,7 @@ import (
"github.com/containers/libpod/cmd/podman/containers"
"github.com/containers/libpod/cmd/podman/images"
"github.com/containers/libpod/cmd/podman/registry"
+ "github.com/containers/libpod/cmd/podman/validate"
"github.com/containers/libpod/pkg/domain/entities"
"github.com/spf13/cobra"
)
@@ -17,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: registry.IdOrLatestArgs,
+ Args: validate.IdOrLatestArgs,
Short: "Display the changes of object's file system",
Long: diffDescription,
TraverseChildren: true,
diff --git a/cmd/podman/generate/generate.go b/cmd/podman/generate/generate.go
new file mode 100644
index 000000000..b112e666a
--- /dev/null
+++ b/cmd/podman/generate/generate.go
@@ -0,0 +1,28 @@
+package pods
+
+import (
+ "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/util"
+ "github.com/spf13/cobra"
+)
+
+var (
+ // Command: podman _generate_
+ generateCmd = &cobra.Command{
+ Use: "generate",
+ Short: "Generate structured data based on containers and pods.",
+ Long: "Generate structured data (e.g., Kubernetes yaml or systemd units) based on containers and pods.",
+ TraverseChildren: true,
+ RunE: validate.SubCommandExists,
+ }
+ containerConfig = util.DefaultContainerConfig()
+)
+
+func init() {
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Mode: []entities.EngineMode{entities.ABIMode},
+ Command: generateCmd,
+ })
+}
diff --git a/cmd/podman/generate/systemd.go b/cmd/podman/generate/systemd.go
new file mode 100644
index 000000000..55d770249
--- /dev/null
+++ b/cmd/podman/generate/systemd.go
@@ -0,0 +1,57 @@
+package pods
+
+import (
+ "fmt"
+
+ "github.com/containers/libpod/cmd/podman/registry"
+ "github.com/containers/libpod/cmd/podman/utils"
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/spf13/cobra"
+)
+
+var (
+ systemdTimeout uint
+ systemdOptions = entities.GenerateSystemdOptions{}
+ systemdDescription = `Generate systemd units for a pod or container.
+ The generated units can later be controlled via systemctl(1).`
+
+ systemdCmd = &cobra.Command{
+ Use: "systemd [flags] CTR|POD",
+ Short: "Generate systemd units.",
+ Long: systemdDescription,
+ RunE: systemd,
+ Args: cobra.MinimumNArgs(1),
+ Example: `podman generate systemd CTR
+ podman generate systemd --new --time 10 CTR
+ podman generate systemd --files --name POD`,
+ }
+)
+
+func init() {
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
+ Command: systemdCmd,
+ Parent: generateCmd,
+ })
+ flags := systemdCmd.Flags()
+ flags.BoolVarP(&systemdOptions.Name, "name", "n", false, "Use container/pod names instead of IDs")
+ flags.BoolVarP(&systemdOptions.Files, "files", "f", false, "Generate .service files instead of printing to stdout")
+ flags.UintVarP(&systemdTimeout, "time", "t", containerConfig.Engine.StopTimeout, "Stop timeout override")
+ flags.StringVar(&systemdOptions.RestartPolicy, "restart-policy", "on-failure", "Systemd restart-policy")
+ flags.BoolVarP(&systemdOptions.New, "new", "", false, "Create a new container instead of starting an existing one")
+ flags.SetNormalizeFunc(utils.AliasFlags)
+}
+
+func systemd(cmd *cobra.Command, args []string) error {
+ if cmd.Flags().Changed("time") {
+ systemdOptions.StopTimeout = &systemdTimeout
+ }
+
+ report, err := registry.ContainerEngine().GenerateSystemd(registry.GetContext(), args[0], systemdOptions)
+ if err != nil {
+ return err
+ }
+
+ fmt.Println(report.Output)
+ return nil
+}
diff --git a/cmd/podman/healthcheck/healthcheck.go b/cmd/podman/healthcheck/healthcheck.go
index 794a94615..ce90dba31 100644
--- a/cmd/podman/healthcheck/healthcheck.go
+++ b/cmd/podman/healthcheck/healthcheck.go
@@ -2,6 +2,7 @@ package healthcheck
import (
"github.com/containers/libpod/cmd/podman/registry"
+ "github.com/containers/libpod/cmd/podman/validate"
"github.com/containers/libpod/pkg/domain/entities"
"github.com/spf13/cobra"
)
@@ -13,7 +14,7 @@ var (
Short: "Manage Healthcheck",
Long: "Manage Healthcheck",
TraverseChildren: true,
- RunE: registry.SubCommandExists,
+ RunE: validate.SubCommandExists,
}
)
diff --git a/cmd/podman/images/exists.go b/cmd/podman/images/exists.go
index 6464e6cd8..13191113f 100644
--- a/cmd/podman/images/exists.go
+++ b/cmd/podman/images/exists.go
@@ -15,6 +15,7 @@ var (
RunE: exists,
Example: `podman image exists ID
podman image exists IMAGE && podman pull IMAGE`,
+ DisableFlagsInUseLine: true,
}
)
diff --git a/cmd/podman/images/history.go b/cmd/podman/images/history.go
index b8d216cc1..ce153aa46 100644
--- a/cmd/podman/images/history.go
+++ b/cmd/podman/images/history.go
@@ -89,22 +89,20 @@ func history(cmd *cobra.Command, args []string) error {
hdr := "ID\tCREATED\tCREATED BY\tSIZE\tCOMMENT\n"
row := "{{.ID}}\t{{.Created}}\t{{.CreatedBy}}\t{{.Size}}\t{{.Comment}}\n"
- if len(opts.format) > 0 {
+ switch {
+ case len(opts.format) > 0:
hdr = ""
row = opts.format
if !strings.HasSuffix(opts.format, "\n") {
row += "\n"
}
- } else {
- switch {
- case opts.human:
- row = "{{.ID}}\t{{.Created}}\t{{.CreatedBy}}\t{{.Size}}\t{{.Comment}}\n"
- case opts.noTrunc:
- row = "{{.ID}}\t{{.Created}}\t{{.CreatedBy}}\t{{.Size}}\t{{.Comment}}\n"
- case opts.quiet:
- hdr = ""
- row = "{{.ID}}\n"
- }
+ case opts.quiet:
+ hdr = ""
+ row = "{{.ID}}\n"
+ case opts.human:
+ row = "{{.ID}}\t{{.Created}}\t{{.CreatedBy}}\t{{.Size}}\t{{.Comment}}\n"
+ case opts.noTrunc:
+ row = "{{.ID}}\t{{.Created}}\t{{.CreatedBy}}\t{{.Size}}\t{{.Comment}}\n"
}
format := hdr + "{{range . }}" + row + "{{end}}"
diff --git a/cmd/podman/images/image.go b/cmd/podman/images/image.go
index 604f49251..790c16c05 100644
--- a/cmd/podman/images/image.go
+++ b/cmd/podman/images/image.go
@@ -2,6 +2,7 @@ package images
import (
"github.com/containers/libpod/cmd/podman/registry"
+ "github.com/containers/libpod/cmd/podman/validate"
"github.com/containers/libpod/pkg/domain/entities"
"github.com/spf13/cobra"
)
@@ -16,7 +17,7 @@ var (
Short: "Manage images",
Long: "Manage images",
TraverseChildren: true,
- RunE: registry.SubCommandExists,
+ RunE: validate.SubCommandExists,
}
)
diff --git a/cmd/podman/images/images.go b/cmd/podman/images/images.go
index fd3ede26a..96ef344bf 100644
--- a/cmd/podman/images/images.go
+++ b/cmd/podman/images/images.go
@@ -11,12 +11,13 @@ import (
var (
// podman _images_ Alias for podman image _list_
imagesCmd = &cobra.Command{
- Use: strings.Replace(listCmd.Use, "list", "images", 1),
- Args: listCmd.Args,
- Short: listCmd.Short,
- Long: listCmd.Long,
- RunE: listCmd.RunE,
- Example: strings.Replace(listCmd.Example, "podman image list", "podman images", -1),
+ Use: strings.Replace(listCmd.Use, "list", "images", 1),
+ Args: listCmd.Args,
+ Short: listCmd.Short,
+ Long: listCmd.Long,
+ RunE: listCmd.RunE,
+ Example: strings.Replace(listCmd.Example, "podman image list", "podman images", -1),
+ DisableFlagsInUseLine: true,
}
)
diff --git a/cmd/podman/images/inspect.go b/cmd/podman/images/inspect.go
index 91c9445eb..8c727eb07 100644
--- a/cmd/podman/images/inspect.go
+++ b/cmd/podman/images/inspect.go
@@ -1,18 +1,9 @@
package images
import (
- "context"
- "fmt"
- "os"
- "strings"
- "text/tabwriter"
- "text/template"
-
- "github.com/containers/buildah/pkg/formats"
- "github.com/containers/libpod/cmd/podman/common"
+ "github.com/containers/libpod/cmd/podman/inspect"
"github.com/containers/libpod/cmd/podman/registry"
"github.com/containers/libpod/pkg/domain/entities"
- "github.com/pkg/errors"
"github.com/spf13/cobra"
)
@@ -21,8 +12,8 @@ var (
inspectCmd = &cobra.Command{
Use: "inspect [flags] IMAGE",
Short: "Display the configuration of an image",
- Long: `Displays the low-level information on an image identified by name or ID.`,
- RunE: inspect,
+ Long: `Displays the low-level information of an image identified by name or ID.`,
+ RunE: inspectExec,
Example: `podman inspect alpine
podman inspect --format "imageId: {{.Id}} size: {{.Size}}" alpine
podman inspect --format "image: {{.ImageName}} driver: {{.Driver}}" myctr`,
@@ -36,78 +27,11 @@ func init() {
Command: inspectCmd,
Parent: imageCmd,
})
- inspectOpts = common.AddInspectFlagSet(inspectCmd)
-}
-
-func inspect(cmd *cobra.Command, args []string) error {
- if inspectOpts.Size {
- return fmt.Errorf("--size can only be used for containers")
- }
- if inspectOpts.Latest {
- return fmt.Errorf("--latest can only be used for containers")
- }
- if len(args) == 0 {
- return errors.Errorf("image name must be specified: podman image inspect [options [...]] name")
- }
-
- results, err := registry.ImageEngine().Inspect(context.Background(), args, *inspectOpts)
- if err != nil {
- return err
- }
-
- if len(results.Images) > 0 {
- if inspectOpts.Format == "" {
- buf, err := json.MarshalIndent(results.Images, "", " ")
- if err != nil {
- return err
- }
- fmt.Println(string(buf))
-
- for id, e := range results.Errors {
- fmt.Fprintf(os.Stderr, "%s: %s\n", id, e.Error())
- }
- return nil
- }
- row := inspectFormat(inspectOpts.Format)
- format := "{{range . }}" + row + "{{end}}"
- tmpl, err := template.New("inspect").Parse(format)
- if err != nil {
- return err
- }
-
- w := tabwriter.NewWriter(os.Stdout, 8, 2, 2, ' ', 0)
- defer func() { _ = w.Flush() }()
- err = tmpl.Execute(w, results.Images)
- if err != nil {
- return err
- }
- }
-
- var lastErr error
- for id, e := range results.Errors {
- if lastErr != nil {
- fmt.Fprintf(os.Stderr, "%s: %s\n", id, lastErr.Error())
- }
- lastErr = e
- }
- return lastErr
-}
-
-func inspectFormat(row string) string {
- r := strings.NewReplacer("{{.Id}}", formats.IDString,
- ".Src", ".Source",
- ".Dst", ".Destination",
- ".ImageID", ".Image",
- )
- row = r.Replace(row)
-
- if !strings.HasSuffix(row, "\n") {
- row += "\n"
- }
- return row
+ inspectOpts = inspect.AddInspectFlagSet(inspectCmd)
+ flags := inspectCmd.Flags()
+ _ = flags.MarkHidden("latest") // Shared with container-inspect but not wanted here.
}
-func Inspect(cmd *cobra.Command, args []string, options *entities.InspectOptions) error {
- inspectOpts = options
- return inspect(cmd, args)
+func inspectExec(cmd *cobra.Command, args []string) error {
+ return inspect.Inspect(args, *inspectOpts)
}
diff --git a/cmd/podman/images/list.go b/cmd/podman/images/list.go
index b979cb6af..83c039ed3 100644
--- a/cmd/podman/images/list.go
+++ b/cmd/podman/images/list.go
@@ -32,7 +32,7 @@ type listFlagType struct {
var (
// Command: podman image _list_
listCmd = &cobra.Command{
- Use: "list [flag] [IMAGE]",
+ Use: "list [FLAGS] [IMAGE]",
Aliases: []string{"ls"},
Args: cobra.MaximumNArgs(1),
Short: "List images in local storage",
@@ -41,6 +41,7 @@ var (
Example: `podman image list --format json
podman image list --sort repository --format "table {{.ID}} {{.Repository}} {{.Tag}}"
podman image list --filter dangling=true`,
+ DisableFlagsInUseLine: true,
}
// Options to pull data
@@ -98,14 +99,29 @@ func images(cmd *cobra.Command, args []string) error {
return err
}
- imageS := summaries
- sort.Slice(imageS, sortFunc(listFlag.sort, imageS))
+ switch {
+ case listFlag.quiet:
+ return writeId(summaries)
+ case cmd.Flag("format").Changed && listFlag.format == "json":
+ return writeJSON(summaries)
+ default:
+ return writeTemplate(summaries)
+ }
+}
- if cmd.Flag("format").Changed && listFlag.format == "json" {
- return writeJSON(imageS)
- } else {
- return writeTemplate(imageS, err)
+func writeId(imageS []*entities.ImageSummary) error {
+ var ids = map[string]struct{}{}
+ for _, e := range imageS {
+ i := "sha256:" + e.ID
+ if !listFlag.noTrunc {
+ i = fmt.Sprintf("%12.12s", e.ID)
+ }
+ ids[i] = struct{}{}
}
+ for k := range ids {
+ fmt.Fprint(os.Stdout, k+"\n")
+ }
+ return nil
}
func writeJSON(imageS []*entities.ImageSummary) error {
@@ -130,7 +146,7 @@ func writeJSON(imageS []*entities.ImageSummary) error {
return enc.Encode(imgs)
}
-func writeTemplate(imageS []*entities.ImageSummary, err error) error {
+func writeTemplate(imageS []*entities.ImageSummary) error {
var (
hdr, row string
)
@@ -142,10 +158,11 @@ func writeTemplate(imageS []*entities.ImageSummary, err error) error {
h.Repository, h.Tag = tokenRepoTag(tag)
imgs = append(imgs, h)
}
- if e.IsReadOnly() {
- listFlag.readOnly = true
- }
+ listFlag.readOnly = e.IsReadOnly()
}
+
+ sort.Slice(imgs, sortFunc(listFlag.sort, imgs))
+
if len(listFlag.format) < 1 {
hdr, row = imageListFormat(listFlag)
} else {
@@ -175,37 +192,33 @@ func tokenRepoTag(tag string) (string, string) {
}
}
-func sortFunc(key string, data []*entities.ImageSummary) func(i, j int) bool {
+func sortFunc(key string, data []imageReporter) func(i, j int) bool {
switch key {
case "id":
return func(i, j int) bool {
- return data[i].ID < data[j].ID
+ return data[i].ID() < data[j].ID()
}
case "repository":
return func(i, j int) bool {
- return data[i].RepoTags[0] < data[j].RepoTags[0]
+ return data[i].Repository < data[j].Repository
}
case "size":
return func(i, j int) bool {
- return data[i].Size < data[j].Size
+ return data[i].size() < data[j].size()
}
case "tag":
return func(i, j int) bool {
- return data[i].RepoTags[0] < data[j].RepoTags[0]
+ return data[i].Tag < data[j].Tag
}
default:
// case "created":
return func(i, j int) bool {
- return data[i].Created.After(data[j].Created)
+ return data[i].created().After(data[j].created())
}
}
}
func imageListFormat(flags listFlagType) (string, string) {
- if flags.quiet {
- return "", "{{.ID}}\n"
- }
-
// Defaults
hdr := "REPOSITORY\tTAG"
row := "{{.Repository}}\t{{if .Tag}}{{.Tag}}{{else}}<none>{{end}}"
@@ -262,6 +275,10 @@ func (i imageReporter) Created() string {
return units.HumanDuration(time.Since(i.ImageSummary.Created)) + " ago"
}
+func (i imageReporter) created() time.Time {
+ return i.ImageSummary.Created
+}
+
func (i imageReporter) Size() string {
s := units.HumanSizeWithPrecision(float64(i.ImageSummary.Size), 3)
j := strings.LastIndexFunc(s, unicode.IsNumber)
@@ -271,3 +288,19 @@ func (i imageReporter) Size() string {
func (i imageReporter) History() string {
return strings.Join(i.ImageSummary.History, ", ")
}
+
+func (i imageReporter) CreatedAt() string {
+ return i.ImageSummary.Created.String()
+}
+
+func (i imageReporter) CreatedSince() string {
+ return i.Created()
+}
+
+func (i imageReporter) CreatedTime() string {
+ return i.CreatedAt()
+}
+
+func (i imageReporter) size() int64 {
+ return i.ImageSummary.Size
+}
diff --git a/cmd/podman/images/prune.go b/cmd/podman/images/prune.go
index b90d889be..53a1966c1 100644
--- a/cmd/podman/images/prune.go
+++ b/cmd/podman/images/prune.go
@@ -7,6 +7,7 @@ import (
"strings"
"github.com/containers/libpod/cmd/podman/registry"
+ "github.com/containers/libpod/cmd/podman/validate"
"github.com/containers/libpod/pkg/domain/entities"
"github.com/pkg/errors"
"github.com/spf13/cobra"
@@ -18,7 +19,7 @@ var (
If an image is not being used by a container, it will be removed from the system.`
pruneCmd = &cobra.Command{
Use: "prune",
- Args: cobra.NoArgs,
+ Args: validate.NoArgs,
Short: "Remove unused images",
Long: pruneDescription,
RunE: prune,
diff --git a/cmd/podman/images/pull.go b/cmd/podman/images/pull.go
index f996d0681..9f4cbc50e 100644
--- a/cmd/podman/images/pull.go
+++ b/cmd/podman/images/pull.go
@@ -45,6 +45,7 @@ var (
Short: pullCmd.Short,
Long: pullCmd.Long,
RunE: pullCmd.RunE,
+ Args: cobra.ExactArgs(1),
Example: `podman image pull imageName
podman image pull fedora:latest`,
}
@@ -93,23 +94,22 @@ func pullFlags(flags *pflag.FlagSet) {
// imagePull is implement the command for pulling images.
func imagePull(cmd *cobra.Command, args []string) error {
- pullOptsAPI := pullOptions.ImagePullOptions
// TLS verification in c/image is controlled via a `types.OptionalBool`
// which allows for distinguishing among set-true, set-false, unspecified
// which is important to implement a sane way of dealing with defaults of
// boolean CLI flags.
if cmd.Flags().Changed("tls-verify") {
- pullOptsAPI.TLSVerify = types.NewOptionalBool(pullOptions.TLSVerifyCLI)
+ pullOptions.SkipTLSVerify = types.NewOptionalBool(!pullOptions.TLSVerifyCLI)
}
- if pullOptsAPI.Authfile != "" {
- if _, err := os.Stat(pullOptsAPI.Authfile); err != nil {
- return errors.Wrapf(err, "error getting authfile %s", pullOptsAPI.Authfile)
+ if pullOptions.Authfile != "" {
+ if _, err := os.Stat(pullOptions.Authfile); err != nil {
+ return errors.Wrapf(err, "error getting authfile %s", pullOptions.Authfile)
}
}
// Let's do all the remaining Yoga in the API to prevent us from
// scattering logic across (too) many parts of the code.
- pullReport, err := registry.ImageEngine().Pull(registry.GetContext(), args[0], pullOptsAPI)
+ pullReport, err := registry.ImageEngine().Pull(registry.GetContext(), args[0], pullOptions.ImagePullOptions)
if err != nil {
return err
}
diff --git a/cmd/podman/images/push.go b/cmd/podman/images/push.go
index ef2ffd0d7..0b3502d61 100644
--- a/cmd/podman/images/push.go
+++ b/cmd/podman/images/push.go
@@ -98,6 +98,7 @@ func imagePush(cmd *cobra.Command, args []string) error {
switch len(args) {
case 1:
source = args[0]
+ destination = args[0]
case 2:
source = args[0]
destination = args[1]
@@ -107,22 +108,21 @@ func imagePush(cmd *cobra.Command, args []string) error {
return errors.New("push requires at least one image name, or optionally a second to specify a different destination")
}
- pushOptsAPI := pushOptions.ImagePushOptions
// TLS verification in c/image is controlled via a `types.OptionalBool`
// which allows for distinguishing among set-true, set-false, unspecified
// which is important to implement a sane way of dealing with defaults of
// boolean CLI flags.
if cmd.Flags().Changed("tls-verify") {
- pushOptsAPI.TLSVerify = types.NewOptionalBool(pushOptions.TLSVerifyCLI)
+ pushOptions.SkipTLSVerify = types.NewOptionalBool(!pushOptions.TLSVerifyCLI)
}
- if pushOptsAPI.Authfile != "" {
- if _, err := os.Stat(pushOptsAPI.Authfile); err != nil {
- return errors.Wrapf(err, "error getting authfile %s", pushOptsAPI.Authfile)
+ if pushOptions.Authfile != "" {
+ if _, err := os.Stat(pushOptions.Authfile); err != nil {
+ return errors.Wrapf(err, "error getting authfile %s", pushOptions.Authfile)
}
}
// Let's do all the remaining Yoga in the API to prevent us from scattering
// logic across (too) many parts of the code.
- return registry.ImageEngine().Push(registry.GetContext(), source, destination, pushOptsAPI)
+ return registry.ImageEngine().Push(registry.GetContext(), source, destination, pushOptions.ImagePushOptions)
}
diff --git a/cmd/podman/images/rm.go b/cmd/podman/images/rm.go
index da6a90d2b..1cf5fa365 100644
--- a/cmd/podman/images/rm.go
+++ b/cmd/podman/images/rm.go
@@ -54,7 +54,10 @@ func rm(cmd *cobra.Command, args []string) error {
fmt.Println("Untagged: " + u)
}
for _, d := range report.Deleted {
- fmt.Println("Deleted: " + d)
+ // Make sure an image was deleted (and not just untagged); else print it
+ if len(d) > 0 {
+ fmt.Println("Deleted: " + d)
+ }
}
registry.SetExitCode(report.ExitCode)
}
diff --git a/cmd/podman/images/search.go b/cmd/podman/images/search.go
index fdad94d45..a8abfb339 100644
--- a/cmd/podman/images/search.go
+++ b/cmd/podman/images/search.go
@@ -1,6 +1,7 @@
package images
import (
+ "os"
"reflect"
"strings"
@@ -47,14 +48,15 @@ var (
// Command: podman image search
imageSearchCmd = &cobra.Command{
- Use: searchCmd.Use,
- Short: searchCmd.Short,
- Long: searchCmd.Long,
- RunE: searchCmd.RunE,
- Args: searchCmd.Args,
+ Use: searchCmd.Use,
+ Short: searchCmd.Short,
+ Long: searchCmd.Long,
+ RunE: searchCmd.RunE,
+ Args: searchCmd.Args,
+ Annotations: searchCmd.Annotations,
Example: `podman image search --filter=is-official --limit 3 alpine
- podman image search registry.fedoraproject.org/ # only works with v2 registries
- podman image search --format "table {{.Index}} {{.Name}}" registry.fedoraproject.org/fedora`,
+ podman image search registry.fedoraproject.org/ # only works with v2 registries
+ podman image search --format "table {{.Index}} {{.Name}}" registry.fedoraproject.org/fedora`,
}
)
@@ -103,16 +105,21 @@ func imageSearch(cmd *cobra.Command, args []string) error {
return errors.Errorf("search requires exactly one argument")
}
- sarchOptsAPI := searchOptions.ImageSearchOptions
// TLS verification in c/image is controlled via a `types.OptionalBool`
// which allows for distinguishing among set-true, set-false, unspecified
// which is important to implement a sane way of dealing with defaults of
// boolean CLI flags.
if cmd.Flags().Changed("tls-verify") {
- sarchOptsAPI.TLSVerify = types.NewOptionalBool(pullOptions.TLSVerifyCLI)
+ searchOptions.SkipTLSVerify = types.NewOptionalBool(!searchOptions.TLSVerifyCLI)
}
- searchReport, err := registry.ImageEngine().Search(registry.GetContext(), searchTerm, sarchOptsAPI)
+ if searchOptions.Authfile != "" {
+ if _, err := os.Stat(searchOptions.Authfile); err != nil {
+ return errors.Wrapf(err, "error getting authfile %s", searchOptions.Authfile)
+ }
+ }
+
+ searchReport, err := registry.ImageEngine().Search(registry.GetContext(), searchTerm, searchOptions.ImageSearchOptions)
if err != nil {
return err
}
diff --git a/cmd/podman/inspect.go b/cmd/podman/inspect.go
index 93bf58bdd..a5fdaedc2 100644
--- a/cmd/podman/inspect.go
+++ b/cmd/podman/inspect.go
@@ -1,31 +1,26 @@
package main
import (
- "fmt"
-
- "github.com/containers/libpod/cmd/podman/common"
- "github.com/containers/libpod/cmd/podman/containers"
- "github.com/containers/libpod/cmd/podman/images"
+ "github.com/containers/libpod/cmd/podman/inspect"
"github.com/containers/libpod/cmd/podman/registry"
"github.com/containers/libpod/pkg/domain/entities"
"github.com/spf13/cobra"
)
-// Inspect is one of the outlier commands in that it operates on images/containers/...
-
var (
- inspectOpts *entities.InspectOptions
-
// Command: podman _inspect_ Object_ID
inspectCmd = &cobra.Command{
Use: "inspect [flags] {CONTAINER_ID | IMAGE_ID}",
Short: "Display the configuration of object denoted by ID",
Long: "Displays the low-level information on an object identified by name or ID",
TraverseChildren: true,
- RunE: inspect,
- Example: `podman inspect alpine
- podman inspect --format "imageId: {{.Id}} size: {{.Size}}" alpine`,
+ RunE: inspectExec,
+ Example: `podman inspect fedora
+ podman inspect --type image fedora
+ podman inspect CtrID ImgID
+ podman inspect --format "imageId: {{.Id}} size: {{.Size}}" fedora`,
}
+ inspectOpts *entities.InspectOptions
)
func init() {
@@ -33,26 +28,9 @@ func init() {
Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
Command: inspectCmd,
})
- inspectOpts = common.AddInspectFlagSet(inspectCmd)
- flags := inspectCmd.Flags()
- flags.StringVarP(&inspectOpts.Type, "type", "t", "", "Return JSON for specified type, (image or container) (default \"all\")")
- if !registry.IsRemote() {
- flags.BoolVarP(&inspectOpts.Latest, "latest", "l", false, "Act on the latest container podman is aware of (containers only)")
- }
+ inspectOpts = inspect.AddInspectFlagSet(inspectCmd)
}
-func inspect(cmd *cobra.Command, args []string) error {
- switch inspectOpts.Type {
- case "image":
- return images.Inspect(cmd, args, inspectOpts)
- case "container":
- return containers.Inspect(cmd, args, inspectOpts)
- case "":
- if err := images.Inspect(cmd, args, inspectOpts); err == nil {
- return nil
- }
- return containers.Inspect(cmd, args, inspectOpts)
- default:
- return fmt.Errorf("invalid type %q is must be 'container' or 'image'", inspectOpts.Type)
- }
+func inspectExec(cmd *cobra.Command, args []string) error {
+ return inspect.Inspect(args, *inspectOpts)
}
diff --git a/cmd/podman/inspect/inspect.go b/cmd/podman/inspect/inspect.go
new file mode 100644
index 000000000..223ce00f0
--- /dev/null
+++ b/cmd/podman/inspect/inspect.go
@@ -0,0 +1,159 @@
+package inspect
+
+import (
+ "context"
+ "fmt"
+ "strings"
+
+ "github.com/containers/buildah/pkg/formats"
+ "github.com/containers/libpod/cmd/podman/registry"
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/pkg/errors"
+ "github.com/spf13/cobra"
+)
+
+const (
+ // ImageType is the image type.
+ ImageType = "image"
+ // ContainerType is the container type.
+ ContainerType = "container"
+ // AllType can be of type ImageType or ContainerType.
+ AllType = "all"
+)
+
+// AddInspectFlagSet takes a command and adds the inspect flags and returns an
+// InspectOptions object.
+func AddInspectFlagSet(cmd *cobra.Command) *entities.InspectOptions {
+ opts := entities.InspectOptions{}
+
+ flags := cmd.Flags()
+ flags.BoolVarP(&opts.Size, "size", "s", false, "Display total file size")
+ flags.StringVarP(&opts.Format, "format", "f", "json", "Format the output to a Go template or json")
+ flags.StringVarP(&opts.Type, "type", "t", AllType, fmt.Sprintf("Specify inspect-oject type (%q, %q or %q)", ImageType, ContainerType, AllType))
+ flags.BoolVarP(&opts.Latest, "latest", "l", false, "Act on the latest container Podman is aware of")
+
+ return &opts
+}
+
+// Inspect inspects the specified container/image names or IDs.
+func Inspect(namesOrIDs []string, options entities.InspectOptions) error {
+ inspector, err := newInspector(options)
+ if err != nil {
+ return err
+ }
+ return inspector.inspect(namesOrIDs)
+}
+
+// inspector allows for inspecting images and containers.
+type inspector struct {
+ containerEngine entities.ContainerEngine
+ imageEngine entities.ImageEngine
+ options entities.InspectOptions
+}
+
+// newInspector creates a new inspector based on the specified options.
+func newInspector(options entities.InspectOptions) (*inspector, error) {
+ switch options.Type {
+ case ImageType, ContainerType, AllType:
+ // Valid types.
+ default:
+ return nil, errors.Errorf("invalid type %q: must be %q, %q or %q", options.Type, ImageType, ContainerType, AllType)
+ }
+ if options.Type == ImageType {
+ if options.Latest {
+ return nil, errors.Errorf("latest is not supported for type %q", ImageType)
+ }
+ if options.Size {
+ return nil, errors.Errorf("size is not supported for type %q", ImageType)
+ }
+ }
+ return &inspector{
+ containerEngine: registry.ContainerEngine(),
+ imageEngine: registry.ImageEngine(),
+ options: options,
+ }, nil
+}
+
+// inspect inspects the specified container/image names or IDs.
+func (i *inspector) inspect(namesOrIDs []string) error {
+ // data - dumping place for inspection results.
+ var data []interface{}
+ ctx := context.Background()
+
+ if len(namesOrIDs) == 0 {
+ if !i.options.Latest {
+ return errors.New("no containers or images specified")
+ }
+ }
+
+ tmpType := i.options.Type
+ if i.options.Latest {
+ if len(namesOrIDs) > 0 {
+ return errors.New("latest and containers are not allowed")
+ }
+ tmpType = ContainerType // -l works with --type=all
+ }
+
+ // Inspect - note that AllType requires us to expensively query one-by-one.
+ switch tmpType {
+ case AllType:
+ all, err := i.inspectAll(ctx, namesOrIDs)
+ if err != nil {
+ return err
+ }
+ data = all
+ case ImageType:
+ imgData, err := i.imageEngine.Inspect(ctx, namesOrIDs, i.options)
+ if err != nil {
+ return err
+ }
+ for i := range imgData {
+ data = append(data, imgData[i])
+ }
+ case ContainerType:
+ ctrData, err := i.containerEngine.ContainerInspect(ctx, namesOrIDs, i.options)
+ if err != nil {
+ return err
+ }
+ for i := range ctrData {
+ data = append(data, ctrData[i])
+ }
+ default:
+ return errors.Errorf("invalid type %q: must be %q, %q or %q", i.options.Type, ImageType, ContainerType, AllType)
+ }
+
+ var out formats.Writer
+ if i.options.Format == "json" || i.options.Format == "" { // "" for backwards compat
+ out = formats.JSONStructArray{Output: data}
+ } else {
+ out = formats.StdoutTemplateArray{Output: data, Template: inspectFormat(i.options.Format)}
+ }
+ return out.Out()
+}
+
+func (i *inspector) inspectAll(ctx context.Context, namesOrIDs []string) ([]interface{}, error) {
+ var data []interface{}
+ for _, name := range namesOrIDs {
+ imgData, err := i.imageEngine.Inspect(ctx, []string{name}, i.options)
+ if err == nil {
+ data = append(data, imgData[0])
+ continue
+ }
+ ctrData, err := i.containerEngine.ContainerInspect(ctx, []string{name}, i.options)
+ if err != nil {
+ return nil, err
+ }
+ data = append(data, ctrData[0])
+ }
+ return data, nil
+}
+
+func inspectFormat(row string) string {
+ r := strings.NewReplacer(
+ "{{.Id}}", formats.IDString,
+ ".Src", ".Source",
+ ".Dst", ".Destination",
+ ".ImageID", ".Image",
+ )
+ return r.Replace(row)
+}
diff --git a/cmd/podman/login.go b/cmd/podman/login.go
index 1843a764d..9de805d15 100644
--- a/cmd/podman/login.go
+++ b/cmd/podman/login.go
@@ -19,7 +19,7 @@ type loginOptionsWrapper struct {
var (
loginOptions = loginOptionsWrapper{}
loginCommand = &cobra.Command{
- Use: "login [flags] REGISTRY",
+ Use: "login [flags] [REGISTRY]",
Short: "Login to a container registry",
Long: "Login to a container registry on a specified server.",
RunE: login,
diff --git a/cmd/podman/logout.go b/cmd/podman/logout.go
index 77bdc92b4..c21711fc0 100644
--- a/cmd/podman/logout.go
+++ b/cmd/podman/logout.go
@@ -14,7 +14,7 @@ import (
var (
logoutOptions = auth.LogoutOptions{}
logoutCommand = &cobra.Command{
- Use: "logout [flags] REGISTRY",
+ Use: "logout [flags] [REGISTRY]",
Short: "Logout of a container registry",
Long: "Remove the cached username and password for the registry.",
RunE: logout,
diff --git a/cmd/podman/main.go b/cmd/podman/main.go
index 8109eca2f..3a8958b6d 100644
--- a/cmd/podman/main.go
+++ b/cmd/podman/main.go
@@ -1,18 +1,21 @@
package main
import (
+ "fmt"
"os"
_ "github.com/containers/libpod/cmd/podman/containers"
+ _ "github.com/containers/libpod/cmd/podman/generate"
_ "github.com/containers/libpod/cmd/podman/healthcheck"
_ "github.com/containers/libpod/cmd/podman/images"
_ "github.com/containers/libpod/cmd/podman/manifest"
- _ "github.com/containers/libpod/cmd/podman/networks"
_ "github.com/containers/libpod/cmd/podman/pods"
"github.com/containers/libpod/cmd/podman/registry"
_ "github.com/containers/libpod/cmd/podman/system"
_ "github.com/containers/libpod/cmd/podman/volumes"
+ "github.com/containers/libpod/pkg/rootless"
"github.com/containers/storage/pkg/reexec"
+ "github.com/spf13/cobra"
)
func main() {
@@ -26,6 +29,14 @@ func main() {
for _, c := range registry.Commands {
for _, m := range c.Mode {
if cfg.EngineMode == m {
+ // Command cannot be run rootless
+ _, found := c.Command.Annotations[registry.ParentNSRequired]
+ if rootless.IsRootless() && found {
+ c.Command.RunE = func(cmd *cobra.Command, args []string) error {
+ return fmt.Errorf("cannot `%s` in rootless mode", cmd.CommandPath())
+ }
+ }
+
parent := rootCmd
if c.Parent != nil {
parent = c.Parent
diff --git a/cmd/podman/manifest/add.go b/cmd/podman/manifest/add.go
index c83beff7a..38f832fad 100644
--- a/cmd/podman/manifest/add.go
+++ b/cmd/podman/manifest/add.go
@@ -13,7 +13,7 @@ import (
var (
manifestAddOpts = entities.ManifestAddOptions{}
addCmd = &cobra.Command{
- Use: "add",
+ Use: "add [flags] LIST LIST",
Short: "Add images to a manifest list or image index",
Long: "Adds an image to a manifest list or image index.",
RunE: add,
diff --git a/cmd/podman/manifest/create.go b/cmd/podman/manifest/create.go
index 4f3e27774..9c0097b90 100644
--- a/cmd/podman/manifest/create.go
+++ b/cmd/podman/manifest/create.go
@@ -13,7 +13,7 @@ import (
var (
manifestCreateOpts = entities.ManifestCreateOptions{}
createCmd = &cobra.Command{
- Use: "create",
+ Use: "create [flags] LIST [IMAGE]",
Short: "Create manifest list or image index",
Long: "Creates manifest lists or image indexes.",
RunE: create,
diff --git a/cmd/podman/manifest/inspect.go b/cmd/podman/manifest/inspect.go
index 36ecdc87b..5112aa5b2 100644
--- a/cmd/podman/manifest/inspect.go
+++ b/cmd/podman/manifest/inspect.go
@@ -12,7 +12,7 @@ import (
var (
inspectCmd = &cobra.Command{
- Use: "inspect IMAGE",
+ Use: "inspect [flags] IMAGE",
Short: "Display the contents of a manifest list or image index",
Long: "Display the contents of a manifest list or image index.",
RunE: inspect,
diff --git a/cmd/podman/manifest/manifest.go b/cmd/podman/manifest/manifest.go
index b9ac7ea68..b78879b34 100644
--- a/cmd/podman/manifest/manifest.go
+++ b/cmd/podman/manifest/manifest.go
@@ -2,6 +2,7 @@ package manifest
import (
"github.com/containers/libpod/cmd/podman/registry"
+ "github.com/containers/libpod/cmd/podman/validate"
"github.com/containers/libpod/pkg/domain/entities"
"github.com/spf13/cobra"
)
@@ -13,7 +14,7 @@ var (
Short: "Manipulate manifest lists and image indexes",
Long: manifestDescription,
TraverseChildren: true,
- RunE: registry.SubCommandExists,
+ RunE: validate.SubCommandExists,
Example: `podman manifest create localhost/list
podman manifest inspect localhost/list`,
}
diff --git a/cmd/podman/networks/network.go b/cmd/podman/networks/network.go
index 3cee86bcc..e2a928312 100644
--- a/cmd/podman/networks/network.go
+++ b/cmd/podman/networks/network.go
@@ -2,6 +2,7 @@ package images
import (
"github.com/containers/libpod/cmd/podman/registry"
+ "github.com/containers/libpod/cmd/podman/validate"
"github.com/containers/libpod/pkg/domain/entities"
"github.com/spf13/cobra"
)
@@ -13,10 +14,13 @@ var (
Short: "Manage networks",
Long: "Manage networks",
TraverseChildren: true,
- RunE: registry.SubCommandExists,
+ RunE: validate.SubCommandExists,
}
)
+// TODO add the following to main.go to get networks back onto the
+// command list.
+// _ "github.com/containers/libpod/cmd/podman/networks"
func init() {
registry.Commands = append(registry.Commands, registry.CliCommand{
Mode: []entities.EngineMode{entities.ABIMode},
diff --git a/cmd/podman/parse/net.go b/cmd/podman/parse/net.go
index 03cda268c..f93c4ab1e 100644
--- a/cmd/podman/parse/net.go
+++ b/cmd/podman/parse/net.go
@@ -1,4 +1,4 @@
-//nolint
+// nolint
// most of these validate and parse functions have been taken from projectatomic/docker
// and modified for cri-o
package parse
@@ -46,7 +46,7 @@ var (
// validateExtraHost validates that the specified string is a valid extrahost and returns it.
// ExtraHost is in the form of name:ip where the ip has to be a valid ip (ipv4 or ipv6).
// for add-host flag
-func ValidateExtraHost(val string) (string, error) { //nolint
+func ValidateExtraHost(val string) (string, error) { // nolint
// allow for IPv6 addresses in extra hosts by only splitting on first ":"
arr := strings.SplitN(val, ":", 2)
if len(arr) != 2 || len(arr[0]) == 0 {
diff --git a/cmd/podman/parse/net_test.go b/cmd/podman/parse/net_test.go
index a6ddc2be9..51c8509df 100644
--- a/cmd/podman/parse/net_test.go
+++ b/cmd/podman/parse/net_test.go
@@ -1,4 +1,4 @@
-//nolint
+// nolint
// most of these validate and parse functions have been taken from projectatomic/docker
// and modified for cri-o
package parse
@@ -41,7 +41,7 @@ func TestValidateExtraHost(t *testing.T) {
want string
wantErr bool
}{
- //2001:0db8:85a3:0000:0000:8a2e:0370:7334
+ // 2001:0db8:85a3:0000:0000:8a2e:0370:7334
{name: "good-ipv4", args: args{val: "foobar:192.168.1.1"}, want: "foobar:192.168.1.1", wantErr: false},
{name: "bad-ipv4", args: args{val: "foobar:999.999.999.99"}, want: "", wantErr: true},
{name: "bad-ipv4", args: args{val: "foobar:999.999.999"}, want: "", wantErr: true},
diff --git a/cmd/podman/pods/create.go b/cmd/podman/pods/create.go
index ff21166f3..85b96d37b 100644
--- a/cmd/podman/pods/create.go
+++ b/cmd/podman/pods/create.go
@@ -9,6 +9,7 @@ import (
"github.com/containers/libpod/cmd/podman/common"
"github.com/containers/libpod/cmd/podman/parse"
"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/errorhandling"
"github.com/containers/libpod/pkg/specgen"
@@ -24,7 +25,7 @@ var (
createCommand = &cobra.Command{
Use: "create",
- Args: cobra.NoArgs,
+ Args: validate.NoArgs,
Short: "Create a new empty pod",
Long: podCreateDescription,
RunE: create,
@@ -116,7 +117,7 @@ func create(cmd *cobra.Command, args []string) error {
case "slip4netns":
n.NSMode = specgen.Slirp
default:
- if strings.HasPrefix(netInput, "container:") { //nolint
+ if strings.HasPrefix(netInput, "container:") { // nolint
split := strings.Split(netInput, ":")
if len(split) != 2 {
return errors.Errorf("invalid network paramater: %q", netInput)
diff --git a/cmd/podman/pods/exists.go b/cmd/podman/pods/exists.go
index 5a94bf150..cf3e3eae5 100644
--- a/cmd/podman/pods/exists.go
+++ b/cmd/podman/pods/exists.go
@@ -19,6 +19,7 @@ var (
Args: cobra.ExactArgs(1),
Example: `podman pod exists podID
podman pod exists mypod || podman pod create --name mypod`,
+ DisableFlagsInUseLine: true,
}
)
diff --git a/cmd/podman/pods/pod.go b/cmd/podman/pods/pod.go
index e86b8aba4..edca08202 100644
--- a/cmd/podman/pods/pod.go
+++ b/cmd/podman/pods/pod.go
@@ -2,6 +2,7 @@ package pods
import (
"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/util"
"github.com/spf13/cobra"
@@ -17,7 +18,7 @@ var (
Short: "Manage pods",
Long: "Manage pods",
TraverseChildren: true,
- RunE: registry.SubCommandExists,
+ RunE: validate.SubCommandExists,
}
containerConfig = util.DefaultContainerConfig()
)
diff --git a/cmd/podman/pods/ps.go b/cmd/podman/pods/ps.go
index 6d0d9cf7f..b97dfeb66 100644
--- a/cmd/podman/pods/ps.go
+++ b/cmd/podman/pods/ps.go
@@ -12,6 +12,7 @@ import (
"time"
"github.com/containers/libpod/cmd/podman/registry"
+ "github.com/containers/libpod/cmd/podman/validate"
"github.com/containers/libpod/pkg/domain/entities"
"github.com/docker/go-units"
"github.com/pkg/errors"
@@ -28,11 +29,12 @@ var (
Short: "list pods",
Long: psDescription,
RunE: pods,
+ Args: validate.NoArgs,
}
)
var (
- defaultHeaders string = "POD ID\tNAME\tSTATUS\tCREATED"
+ defaultHeaders = "POD ID\tNAME\tSTATUS\tCREATED"
inputFilters []string
noTrunc bool
psInput entities.PodPSOptions
diff --git a/cmd/podman/pods/rm.go b/cmd/podman/pods/rm.go
index ea3a6476a..4b9882f8a 100644
--- a/cmd/podman/pods/rm.go
+++ b/cmd/podman/pods/rm.go
@@ -41,10 +41,10 @@ func init() {
})
flags := rmCommand.Flags()
- flags.BoolVarP(&rmOptions.All, "all", "a", false, "Restart all running pods")
+ flags.BoolVarP(&rmOptions.All, "all", "a", false, "Remove all running pods")
flags.BoolVarP(&rmOptions.Force, "force", "f", false, "Force removal of a running pod by first stopping all containers, then removing all containers in the pod. The default is false")
flags.BoolVarP(&rmOptions.Ignore, "ignore", "i", false, "Ignore errors when a specified pod is missing")
- flags.BoolVarP(&rmOptions.Latest, "latest", "l", false, "Restart the latest pod podman is aware of")
+ flags.BoolVarP(&rmOptions.Latest, "latest", "l", false, "Remove the latest pod podman is aware of")
if registry.IsRemote() {
_ = flags.MarkHidden("latest")
_ = flags.MarkHidden("ignore")
diff --git a/cmd/podman/registry/registry.go b/cmd/podman/registry/registry.go
index 2e9d59d10..69e2babfc 100644
--- a/cmd/podman/registry/registry.go
+++ b/cmd/podman/registry/registry.go
@@ -5,7 +5,6 @@ import (
"github.com/containers/libpod/pkg/domain/entities"
"github.com/containers/libpod/pkg/domain/infra"
- "github.com/pkg/errors"
"github.com/spf13/cobra"
)
@@ -76,21 +75,6 @@ func NewContainerEngine(cmd *cobra.Command, args []string) (entities.ContainerEn
return containerEngine, nil
}
-func SubCommandExists(cmd *cobra.Command, args []string) error {
- if len(args) > 0 {
- return errors.Errorf("unrecognized command `%[1]s %[2]s`\nTry '%[1]s --help' for more information.", cmd.CommandPath(), args[0])
- }
- 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 {
- if len(args) > 1 || (len(args) == 0 && !cmd.Flag("latest").Changed) {
- return errors.New(`command requires a name, id or the "--latest" flag`)
- }
- return nil
-}
-
type PodmanOptionsKey struct{}
func Context() context.Context {
diff --git a/cmd/podman/root.go b/cmd/podman/root.go
index 84c3867f2..375faf8b1 100644
--- a/cmd/podman/root.go
+++ b/cmd/podman/root.go
@@ -9,6 +9,7 @@ import (
"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/rootless"
"github.com/containers/libpod/pkg/tracing"
@@ -34,7 +35,7 @@ Description:
// UsageTemplate is the usage template for podman commands
// This blocks the displaying of the global options. The main podman
// command should not use this.
-const usageTemplate = `Usage(v2):{{if (and .Runnable (not .HasAvailableSubCommands))}}
+const usageTemplate = `Usage:{{if (and .Runnable (not .HasAvailableSubCommands))}}
{{.UseLine}}{{end}}{{if .HasAvailableSubCommands}}
{{.CommandPath}} [command]{{end}}{{if gt (len .Aliases) 0}}
@@ -60,7 +61,7 @@ var (
SilenceErrors: true,
TraverseChildren: true,
PersistentPreRunE: persistentPreRunE,
- RunE: registry.SubCommandExists,
+ RunE: validate.SubCommandExists,
PersistentPostRunE: persistentPostRunE,
Version: version.Version,
}
@@ -78,6 +79,10 @@ func init() {
)
rootFlags(registry.PodmanConfig(), rootCmd.PersistentFlags())
+
+ // "version" is a local flag to avoid collisions with sub-commands that use "-v"
+ var dummyVersion bool
+ rootCmd.Flags().BoolVarP(&dummyVersion, "version", "v", false, "Version of Podman")
}
func Execute() {
@@ -96,7 +101,7 @@ func Execute() {
func persistentPreRunE(cmd *cobra.Command, args []string) error {
// TODO: Remove trace statement in podman V2.1
- logrus.Debugf("Called %s.PersistentPreRunE()", cmd.Name())
+ logrus.Debugf("Called %s.PersistentPreRunE(%s)", cmd.Name(), strings.Join(os.Args, " "))
cfg := registry.PodmanConfig()
@@ -145,7 +150,7 @@ func persistentPreRunE(cmd *cobra.Command, args []string) error {
func persistentPostRunE(cmd *cobra.Command, args []string) error {
// TODO: Remove trace statement in podman V2.1
- logrus.Debugf("Called %s.PersistentPostRunE()", cmd.Name())
+ logrus.Debugf("Called %s.PersistentPostRunE(%s)", cmd.Name(), strings.Join(os.Args, " "))
cfg := registry.PodmanConfig()
if cmd.Flag("cpu-profile").Changed {
@@ -206,11 +211,6 @@ func rootFlags(opts *entities.PodmanConfig, flags *pflag.FlagSet) {
flags.StringVarP(&opts.Uri, "remote", "r", "", "URL to access Podman service")
flags.StringSliceVar(&opts.Identities, "identity", []string{}, "path to SSH identity file")
- // Override default --help information of `--version` global flag
- // TODO: restore -v option for version without breaking -v for volumes
- var dummyVersion bool
- flags.BoolVar(&dummyVersion, "version", false, "Version of Podman")
-
cfg := opts.Config
flags.StringVar(&cfg.Engine.CgroupManager, "cgroup-manager", cfg.Engine.CgroupManager, opts.CGroupUsage)
flags.StringVar(&opts.CpuProfile, "cpu-profile", "", "Path for the cpu profiling results")
diff --git a/cmd/podman/system/events.go b/cmd/podman/system/events.go
index 3c1943b55..6aae62dc0 100644
--- a/cmd/podman/system/events.go
+++ b/cmd/podman/system/events.go
@@ -8,6 +8,7 @@ import (
"github.com/containers/buildah/pkg/formats"
"github.com/containers/libpod/cmd/podman/registry"
+ "github.com/containers/libpod/cmd/podman/validate"
"github.com/containers/libpod/libpod/events"
"github.com/containers/libpod/pkg/domain/entities"
"github.com/pkg/errors"
@@ -18,7 +19,7 @@ var (
eventsDescription = "Monitor podman events"
eventsCommand = &cobra.Command{
Use: "events",
- Args: cobra.NoArgs,
+ Args: validate.NoArgs,
Short: "Show podman events",
Long: eventsDescription,
RunE: eventsCmd,
diff --git a/cmd/podman/system/info.go b/cmd/podman/system/info.go
index 8b36ef549..26be794c5 100644
--- a/cmd/podman/system/info.go
+++ b/cmd/podman/system/info.go
@@ -6,6 +6,7 @@ import (
"text/template"
"github.com/containers/libpod/cmd/podman/registry"
+ "github.com/containers/libpod/cmd/podman/validate"
"github.com/containers/libpod/pkg/domain/entities"
"github.com/ghodss/yaml"
"github.com/spf13/cobra"
@@ -18,7 +19,7 @@ var (
`
infoCommand = &cobra.Command{
Use: "info",
- Args: cobra.NoArgs,
+ Args: validate.NoArgs,
Long: infoDescription,
Short: "Display podman system information",
RunE: info,
diff --git a/cmd/podman/system/system.go b/cmd/podman/system/system.go
index 2d55e8c13..d9691ad2a 100644
--- a/cmd/podman/system/system.go
+++ b/cmd/podman/system/system.go
@@ -2,6 +2,7 @@ package system
import (
"github.com/containers/libpod/cmd/podman/registry"
+ "github.com/containers/libpod/cmd/podman/validate"
"github.com/containers/libpod/pkg/domain/entities"
"github.com/spf13/cobra"
)
@@ -16,7 +17,7 @@ var (
Short: "Manage podman",
Long: "Manage podman",
TraverseChildren: true,
- RunE: registry.SubCommandExists,
+ RunE: validate.SubCommandExists,
}
)
diff --git a/cmd/podman/system/version.go b/cmd/podman/system/version.go
index 5d3874de3..065eef309 100644
--- a/cmd/podman/system/version.go
+++ b/cmd/podman/system/version.go
@@ -10,6 +10,7 @@ import (
"github.com/containers/buildah/pkg/formats"
"github.com/containers/libpod/cmd/podman/registry"
+ "github.com/containers/libpod/cmd/podman/validate"
"github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/pkg/domain/entities"
"github.com/pkg/errors"
@@ -19,7 +20,7 @@ import (
var (
versionCommand = &cobra.Command{
Use: "version",
- Args: cobra.NoArgs,
+ Args: validate.NoArgs,
Short: "Display the Podman Version Information",
RunE: version,
Annotations: map[string]string{
@@ -55,14 +56,14 @@ func version(cmd *cobra.Command, args []string) error {
// TODO we need to discuss how to implement
// this more. current endpoints dont have a
// version endpoint. maybe we use info?
- //if remote {
+ // if remote {
// v.Server, err = getRemoteVersion(c)
// if err != nil {
// return err
// }
- //} else {
+ // } else {
v.Server = v.Client
- //}
+ // }
versionOutputFormat := versionFormat
if versionOutputFormat != "" {
diff --git a/cmd/podman/utils/alias.go b/cmd/podman/utils/alias.go
index 54b3c5e89..e484461c5 100644
--- a/cmd/podman/utils/alias.go
+++ b/cmd/podman/utils/alias.go
@@ -2,7 +2,7 @@ package utils
import "github.com/spf13/pflag"
-// AliasFlags is a function to handle backwards compatability with old flags
+// AliasFlags is a function to handle backwards compatibility with old flags
func AliasFlags(f *pflag.FlagSet, name string) pflag.NormalizedName {
switch name {
case "healthcheck-command":
diff --git a/cmd/podman/validate/args.go b/cmd/podman/validate/args.go
new file mode 100644
index 000000000..14b4d7897
--- /dev/null
+++ b/cmd/podman/validate/args.go
@@ -0,0 +1,32 @@
+package validate
+
+import (
+ "fmt"
+
+ "github.com/pkg/errors"
+ "github.com/spf13/cobra"
+)
+
+// NoArgs returns an error if any args are included.
+func NoArgs(cmd *cobra.Command, args []string) error {
+ if len(args) > 0 {
+ return fmt.Errorf("`%s` takes no arguments", cmd.CommandPath())
+ }
+ return nil
+}
+
+// SubCommandExists returns an error if no sub command is provided
+func SubCommandExists(cmd *cobra.Command, args []string) error {
+ if len(args) > 0 {
+ return errors.Errorf("unrecognized command `%[1]s %[2]s`\nTry '%[1]s --help' for more information.", cmd.CommandPath(), args[0])
+ }
+ 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 {
+ 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())
+ }
+ return nil
+}
diff --git a/cmd/podman/validate/choice.go b/cmd/podman/validate/choice.go
new file mode 100644
index 000000000..572c5f4a5
--- /dev/null
+++ b/cmd/podman/validate/choice.go
@@ -0,0 +1,46 @@
+package validate
+
+import (
+ "fmt"
+ "strings"
+)
+
+// Honors cobra.Value interface
+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
+//
+// 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{
+ value: p,
+ choices: choices,
+ }
+}
+
+func (c *choiceValue) String() string {
+ return *c.value
+}
+
+func (c *choiceValue) Set(value string) error {
+ for _, v := range c.choices {
+ if v == value {
+ *c.value = value
+ return nil
+ }
+ }
+ return fmt.Errorf("%q is not a valid value. Choose from: %q", value, c.Choices())
+}
+
+func (c *choiceValue) Choices() string {
+ return strings.Join(c.choices, ", ")
+}
+
+func (c *choiceValue) Type() string {
+ return "choice"
+}
diff --git a/cmd/podman/volumes/list.go b/cmd/podman/volumes/list.go
index f75de6b4b..72bf9f25b 100644
--- a/cmd/podman/volumes/list.go
+++ b/cmd/podman/volumes/list.go
@@ -2,6 +2,7 @@ package volumes
import (
"context"
+ "fmt"
"html/template"
"io"
"os"
@@ -9,6 +10,7 @@ import (
"text/tabwriter"
"github.com/containers/libpod/cmd/podman/registry"
+ "github.com/containers/libpod/cmd/podman/validate"
"github.com/containers/libpod/pkg/domain/entities"
"github.com/pkg/errors"
"github.com/spf13/cobra"
@@ -23,7 +25,7 @@ and the output format can be changed to JSON or a user specified Go template.`
lsCommand = &cobra.Command{
Use: "ls",
Aliases: []string{"list"},
- Args: cobra.NoArgs,
+ Args: validate.NoArgs,
Short: "List volumes",
Long: volumeLsDescription,
RunE: list,
@@ -57,6 +59,9 @@ func list(cmd *cobra.Command, args []string) error {
if cliOpts.Quiet && cmd.Flag("format").Changed {
return errors.New("quiet and format flags cannot be used together")
}
+ if len(cliOpts.Filter) > 0 {
+ lsOpts.Filter = make(map[string][]string)
+ }
for _, f := range cliOpts.Filter {
filterSplit := strings.Split(f, "=")
if len(filterSplit) < 2 {
@@ -68,6 +73,10 @@ func list(cmd *cobra.Command, args []string) error {
if err != nil {
return err
}
+ if cliOpts.Format == "json" {
+ return outputJSON(responses)
+ }
+
if len(responses) < 1 {
return nil
}
@@ -99,3 +108,12 @@ func list(cmd *cobra.Command, args []string) error {
}
return nil
}
+
+func outputJSON(vols []*entities.VolumeListReport) error {
+ b, err := json.MarshalIndent(vols, "", " ")
+ if err != nil {
+ return err
+ }
+ fmt.Println(string(b))
+ return nil
+}
diff --git a/cmd/podman/volumes/prune.go b/cmd/podman/volumes/prune.go
index 197a9da9b..2c3ed88f3 100644
--- a/cmd/podman/volumes/prune.go
+++ b/cmd/podman/volumes/prune.go
@@ -9,6 +9,7 @@ import (
"github.com/containers/libpod/cmd/podman/registry"
"github.com/containers/libpod/cmd/podman/utils"
+ "github.com/containers/libpod/cmd/podman/validate"
"github.com/containers/libpod/pkg/domain/entities"
"github.com/pkg/errors"
"github.com/spf13/cobra"
@@ -21,7 +22,7 @@ var (
Note all data will be destroyed.`
pruneCommand = &cobra.Command{
Use: "prune",
- Args: cobra.NoArgs,
+ Args: validate.NoArgs,
Short: "Remove all unused volumes",
Long: volumePruneDescription,
RunE: prune,
diff --git a/cmd/podman/volumes/volume.go b/cmd/podman/volumes/volume.go
index 4d74ff084..3e90d178c 100644
--- a/cmd/podman/volumes/volume.go
+++ b/cmd/podman/volumes/volume.go
@@ -2,6 +2,7 @@ package volumes
import (
"github.com/containers/libpod/cmd/podman/registry"
+ "github.com/containers/libpod/cmd/podman/validate"
"github.com/containers/libpod/pkg/domain/entities"
"github.com/spf13/cobra"
)
@@ -16,7 +17,7 @@ var (
Short: "Manage volumes",
Long: "Volumes are created in and can be shared between containers",
TraverseChildren: true,
- RunE: registry.SubCommandExists,
+ RunE: validate.SubCommandExists,
}
)
diff --git a/contrib/cirrus/lib.sh b/contrib/cirrus/lib.sh
index 04f14eeb3..750aec3b6 100644
--- a/contrib/cirrus/lib.sh
+++ b/contrib/cirrus/lib.sh
@@ -6,6 +6,11 @@
# Global details persist here
source /etc/environment # not always loaded under all circumstances
+# Automation environment doesn't automatically load for Ubuntu 18
+if [[ -r '/usr/share/automation/environment' ]]; then
+ source '/usr/share/automation/environment'
+fi
+
# Under some contexts these values are not set, make sure they are.
export USER="$(whoami)"
export HOME="$(getent passwd $USER | cut -d : -f 6)"
@@ -64,18 +69,23 @@ export PACKER_BUILDS="${PACKER_BUILDS:-ubuntu-18,ubuntu-19,fedora-32,fedora-31}"
export UBUNTU_BASE_IMAGE="ubuntu-1910-eoan-v20200211"
export PRIOR_UBUNTU_BASE_IMAGE="ubuntu-1804-bionic-v20200218"
# Manually produced base-image names (see $SCRIPT_BASE/README.md)
-export FEDORA_BASE_IMAGE="fedora-cloud-base-32-n-0-1586202964"
-export PRIOR_FEDORA_BASE_IMAGE="fedora-cloud-base-31-1-9-1586202964"
+export FEDORA_BASE_IMAGE="fedora-cloud-base-32-1-6-1588257430"
+export PRIOR_FEDORA_BASE_IMAGE="fedora-cloud-base-31-1-9-1588257430"
export BUILT_IMAGE_SUFFIX="${BUILT_IMAGE_SUFFIX:--$CIRRUS_REPO_NAME-${CIRRUS_BUILD_ID}}"
# IN_PODMAN container image
IN_PODMAN_IMAGE="quay.io/libpod/in_podman:$DEST_BRANCH"
# Image for uploading releases
UPLDREL_IMAGE="quay.io/libpod/upldrel:master"
+# This is needed under some environments/contexts
+SUDO=''
+[[ "$UID" -eq 0 ]] || \
+ SUDO='sudo -E'
+
# Avoid getting stuck waiting for user input
export DEBIAN_FRONTEND="noninteractive"
-SUDOAPTGET="ooe.sh sudo -E apt-get -qq --yes"
-SUDOAPTADD="ooe.sh sudo -E add-apt-repository --yes"
+SUDOAPTGET="$SUDO apt-get -qq --yes"
+SUDOAPTADD="$SUDO add-apt-repository --yes"
# Regex that finds enabled periodic apt configuration items
PERIODIC_APT_RE='^(APT::Periodic::.+")1"\;'
# Short-cuts for retrying/timeout calls
@@ -109,6 +119,9 @@ OS_REL_VER="${OS_RELEASE_ID}-${OS_RELEASE_VER}"
# Type of filesystem used for cgroups
CG_FS_TYPE="$(stat -f -c %T /sys/fs/cgroup)"
+# When building images, the version of automation tooling to install
+INSTALL_AUTOMATION_VERSION=1.1.3
+
# Installed into cache-images, supports overrides
# by user-data in case of breakage or for debugging.
CUSTOM_CLOUD_CONFIG_DEFAULTS="$GOSRC/$PACKER_BASE/cloud-init/$OS_RELEASE_ID/cloud.cfg.d"
@@ -354,25 +367,18 @@ setup_rootless() {
die 11 "Timeout exceeded waiting for localhost ssh capability"
}
-# Helper/wrapper script to only show stderr/stdout on non-zero exit
-install_ooe() {
- req_env_var SCRIPT_BASE
- echo "Installing script to mask stdout/stderr unless non-zero exit."
- sudo install -D -m 755 "$GOSRC/$SCRIPT_BASE/ooe.sh" /usr/local/bin/ooe.sh
-}
-
# Grab a newer version of git from software collections
# https://www.softwarecollections.org/en/
# and use it with a wrapper
install_scl_git() {
echo "Installing SoftwareCollections updated 'git' version."
- ooe.sh sudo yum -y install rh-git29
- cat << "EOF" | sudo tee /usr/bin/git
+ ooe.sh $SUDO yum -y install rh-git29
+ cat << "EOF" | $SUDO tee /usr/bin/git
#!/bin/bash
scl enable rh-git29 -- git $@
EOF
- sudo chmod 755 /usr/bin/git
+ $SUDO chmod 755 /usr/bin/git
}
install_test_configs() {
@@ -414,9 +420,9 @@ remove_packaged_podman_files() {
if [[ "$OS_RELEASE_ID" =~ "ubuntu" ]]
then
- LISTING_CMD="sudo -E dpkg-query -L podman"
+ 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
@@ -424,7 +430,7 @@ remove_packaged_podman_files() {
do
# Sub-directories may contain unrelated/valuable stuff
if [[ -d "$fullpath" ]]; then continue; fi
- ooe.sh sudo rm -vf "$fullpath"
+ ooe.sh $SUDO rm -vf "$fullpath"
done
# Be super extra sure and careful vs performant and completely safe
@@ -447,43 +453,60 @@ systemd_banish() {
$GOSRC/$PACKER_BASE/systemd_banish.sh
}
+# This can be removed when the kernel bug fix is included in Fedora
+workaround_bfq_bug() {
+ if [[ "$OS_RELEASE_ID" == "fedora" ]] && [[ $OS_RELEASE_VER -le 32 ]]; then
+ warn "Switching io scheduler to 'deadline' to avoid RHBZ 1767539"
+ warn "aka https://bugzilla.kernel.org/show_bug.cgi?id=205447"
+ echo "mq-deadline" | sudo tee /sys/block/sda/queue/scheduler > /dev/null
+ echo -n "IO Scheduler set to: "
+ $SUDO cat /sys/block/sda/queue/scheduler
+ fi
+}
+
+# Warning: DO NOT USE.
+# This is called by other functions as the very last step during the VM Image build
+# process. It's purpose is to "reset" the image, so all the first-boot operations
+# happen at test runtime (like generating new ssh host keys, resizing partitions, etc.)
_finalize() {
set +e # Don't fail at the very end
if [[ -d "$CUSTOM_CLOUD_CONFIG_DEFAULTS" ]]
then
echo "Installing custom cloud-init defaults"
- sudo cp -v "$CUSTOM_CLOUD_CONFIG_DEFAULTS"/* /etc/cloud/cloud.cfg.d/
+ $SUDO cp -v "$CUSTOM_CLOUD_CONFIG_DEFAULTS"/* /etc/cloud/cloud.cfg.d/
else
echo "Could not find any files in $CUSTOM_CLOUD_CONFIG_DEFAULTS"
fi
echo "Re-initializing so next boot does 'first-boot' setup again."
cd /
- sudo rm -rf /var/lib/cloud/instanc*
- sudo rm -rf /root/.ssh/*
- sudo rm -rf /etc/ssh/*key*
- sudo rm -rf /etc/ssh/moduli
- sudo rm -rf /home/*
- sudo rm -rf /tmp/*
- sudo rm -rf /tmp/.??*
- sudo sync
- sudo fstrim -av
+ $SUDO rm -rf /var/lib/cloud/instanc*
+ $SUDO rm -rf /root/.ssh/*
+ $SUDO rm -rf /etc/ssh/*key*
+ $SUDO rm -rf /etc/ssh/moduli
+ $SUDO rm -rf /home/*
+ $SUDO rm -rf /tmp/*
+ $SUDO rm -rf /tmp/.??*
+ $SUDO sync
+ $SUDO fstrim -av
}
+# Called during VM Image setup, not intended for general use.
rh_finalize() {
set +e # Don't fail at the very end
echo "Resetting to fresh-state for usage as cloud-image."
PKG=$(type -P dnf || type -P yum || echo "")
- sudo $PKG clean all
- sudo rm -rf /var/cache/{yum,dnf}
- sudo rm -f /etc/udev/rules.d/*-persistent-*.rules
- sudo touch /.unconfigured # force firstboot to run
+ $SUDO $PKG clean all
+ $SUDO rm -rf /var/cache/{yum,dnf}
+ $SUDO rm -f /etc/udev/rules.d/*-persistent-*.rules
+ $SUDO touch /.unconfigured # force firstboot to run
_finalize
}
+# Called during VM Image setup, not intended for general use.
ubuntu_finalize() {
set +e # Don't fail at the very end
echo "Resetting to fresh-state for usage as cloud-image."
$LILTO $SUDOAPTGET autoremove
- sudo rm -rf /var/cache/apt
+ $SUDO rm -rf /var/cache/apt
_finalize
}
diff --git a/contrib/cirrus/packer/fedora_base-setup.sh b/contrib/cirrus/packer/fedora_base-setup.sh
index 29c23117f..f271abee0 100644
--- a/contrib/cirrus/packer/fedora_base-setup.sh
+++ b/contrib/cirrus/packer/fedora_base-setup.sh
@@ -8,16 +8,14 @@ set -e
# Load in library (copied by packer, before this script was run)
source $GOSRC/$SCRIPT_BASE/lib.sh
-install_ooe
-
echo "Updating packages"
-ooe.sh dnf -y update
+dnf -y update
echo "Installing necessary packages and google services"
-ooe.sh dnf -y install rng-tools google-compute-engine-tools google-compute-engine-oslogin ethtool
+dnf -y install rng-tools google-compute-engine-tools google-compute-engine-oslogin ethtool
echo "Enabling services"
-ooe.sh systemctl enable rngd
+systemctl enable rngd
# There is a race that can happen on boot between the GCE services configuring
# the VM, and cloud-init trying to do similar activities. Use a customized
@@ -25,6 +23,19 @@ ooe.sh systemctl enable rngd
echo "Setting cloud-init service to start after google-network-daemon.service"
cp -v $GOSRC/$PACKER_BASE/cloud-init/fedora/cloud-init.service /etc/systemd/system/
+# ref: https://cloud.google.com/compute/docs/startupscript
+# The mechanism used by Cirrus-CI to execute tasks on the system is through an
+# "agent" process launched as a GCP startup-script (from the metadata service).
+# This agent is responsible for cloning the repository and executing all task
+# scripts and other operations. Therefor, on SELinux-enforcing systems, the
+# service must be labeled properly to ensure it's child processes can
+# run with the proper contexts.
+METADATA_SERVICE_CTX=unconfined_u:unconfined_r:unconfined_t:s0
+METADATA_SERVICE_PATH=systemd/system/google-startup-scripts.service
+sed -r -e \
+ "s/Type=oneshot/Type=oneshot\nSELinuxContext=$METADATA_SERVICE_CTX/" \
+ /lib/$METADATA_SERVICE_PATH > /etc/$METADATA_SERVICE_PATH
+
# Ensure there are no disruptive periodic services enabled by default in image
systemd_banish
diff --git a/contrib/cirrus/packer/fedora_packaging.sh b/contrib/cirrus/packer/fedora_packaging.sh
new file mode 100644
index 000000000..e80d48bc8
--- /dev/null
+++ b/contrib/cirrus/packer/fedora_packaging.sh
@@ -0,0 +1,141 @@
+#!/bin/bash
+
+# This script is called from fedora_setup.sh and various Dockerfiles.
+# It's not intended to be used outside of those contexts. It assumes the lib.sh
+# library has already been sourced, and that all "ground-up" package-related activity
+# needs to be done, including repository setup and initial update.
+
+set -e
+
+echo "Updating/Installing repos and packages for $OS_REL_VER"
+
+source $GOSRC/$SCRIPT_BASE/lib.sh
+
+# Pre-req. to install automation tooing
+$LILTO $SUDO dnf install -y git
+
+# Install common automation tooling (i.e. ooe.sh)
+curl --silent --show-error --location \
+ --url "https://raw.githubusercontent.com/containers/automation/master/bin/install_automation.sh" | \
+ $SUDO env INSTALL_PREFIX=/usr/share /bin/bash -s - "$INSTALL_AUTOMATION_VERSION"
+# Reload installed environment right now (happens automatically in a new process)
+source /usr/share/automation/environment
+
+# Set this to 1 to NOT enable updates-testing repository
+DISABLE_UPDATES_TESTING=${DISABLE_UPDATES_TESTING:0}
+
+# Do not enable update-stesting on the previous Fedora release
+if ((DISABLE_UPDATES_TESTING!=0)); then
+ warn "Enabling updates-testing repository for image based on $FEDORA_BASE_IMAGE"
+ $LILTO $SUDO ooe.sh dnf install -y 'dnf-command(config-manager)'
+ $LILTO $SUDO ooe.sh dnf config-manager --set-enabled updates-testing
+else
+ warn "NOT enabling updates-testing repository for image based on $PRIOR_FEDORA_BASE_IMAGE"
+fi
+
+$BIGTO ooe.sh $SUDO dnf update -y
+
+REMOVE_PACKAGES=()
+INSTALL_PACKAGES=(\
+ autoconf
+ automake
+ bash-completion
+ bats
+ bridge-utils
+ btrfs-progs-devel
+ buildah
+ bzip2
+ conmon
+ container-selinux
+ containernetworking-plugins
+ containers-common
+ criu
+ device-mapper-devel
+ dnsmasq
+ emacs-nox
+ file
+ findutils
+ fuse3
+ fuse3-devel
+ gcc
+ git
+ glib2-devel
+ glibc-static
+ gnupg
+ go-md2man
+ golang
+ gpgme-devel
+ iproute
+ iptables
+ jq
+ libassuan-devel
+ libcap-devel
+ libmsi1
+ libnet
+ libnet-devel
+ libnl3-devel
+ libseccomp
+ libseccomp-devel
+ libselinux-devel
+ libtool
+ libvarlink-util
+ lsof
+ make
+ msitools
+ nmap-ncat
+ ostree-devel
+ pandoc
+ podman
+ procps-ng
+ protobuf
+ protobuf-c
+ protobuf-c-devel
+ protobuf-devel
+ python
+ python3-dateutil
+ python3-psutil
+ python3-pytoml
+ rsync
+ selinux-policy-devel
+ skopeo
+ skopeo-containers
+ slirp4netns
+ unzip
+ vim
+ wget
+ which
+ xz
+ zip
+)
+
+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[@]}
+
+[[ ${#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
diff --git a/contrib/cirrus/packer/fedora_setup.sh b/contrib/cirrus/packer/fedora_setup.sh
index fcef7360b..3830b3bc4 100644
--- a/contrib/cirrus/packer/fedora_setup.sh
+++ b/contrib/cirrus/packer/fedora_setup.sh
@@ -6,139 +6,26 @@
set -e
# Load in library (copied by packer, before this script was run)
-source /tmp/libpod/$SCRIPT_BASE/lib.sh
+source $GOSRC/$SCRIPT_BASE/lib.sh
-req_env_var SCRIPT_BASE PACKER_BUILDER_NAME GOSRC FEDORA_BASE_IMAGE OS_RELEASE_ID OS_RELEASE_VER
+req_env_var SCRIPT_BASE PACKER_BASE INSTALL_AUTOMATION_VERSION PACKER_BUILDER_NAME GOSRC FEDORA_BASE_IMAGE OS_RELEASE_ID OS_RELEASE_VER
-install_ooe
-
-if [[ $OS_RELEASE_VER -le 31 ]]; then
- warn "Switching io scheduler to 'deadline' to avoid RHBZ 1767539"
- warn "aka https://bugzilla.kernel.org/show_bug.cgi?id=205447"
- echo "mq-deadline" | sudo tee /sys/block/sda/queue/scheduler > /dev/null
- sudo cat /sys/block/sda/queue/scheduler
-fi
-
-export GOPATH="$(mktemp -d)"
-trap "sudo rm -rf $GOPATH" EXIT
-
-$BIGTO ooe.sh sudo dnf update -y
+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
- warn "Enabling updates-testing repository for image based on $FEDORA_BASE_IMAGE"
- $LILTO ooe.sh sudo dnf install -y 'dnf-command(config-manager)'
- $LILTO ooe.sh sudo dnf config-manager --set-enabled updates-testing
+ DISABLE_UPDATES_TESTING=0
else
- warn "NOT enabling updates-testing repository for image based on $PRIOR_FEDORA_BASE_IMAGE"
+ DISABLE_UPDATES_TESTING=1
fi
-REMOVE_PACKAGES=()
-INSTALL_PACKAGES=(\
- autoconf
- automake
- bash-completion
- bats
- bridge-utils
- btrfs-progs-devel
- buildah
- bzip2
- conmon
- container-selinux
- containernetworking-plugins
- containers-common
- criu
- device-mapper-devel
- dnsmasq
- emacs-nox
- file
- findutils
- fuse3
- fuse3-devel
- gcc
- git
- glib2-devel
- glibc-static
- gnupg
- go-md2man
- golang
- gpgme-devel
- iproute
- iptables
- jq
- libassuan-devel
- libcap-devel
- libmsi1
- libnet
- libnet-devel
- libnl3-devel
- libseccomp
- libseccomp-devel
- libselinux-devel
- libtool
- libvarlink-util
- lsof
- make
- msitools
- nmap-ncat
- ostree-devel
- pandoc
- podman
- procps-ng
- protobuf
- protobuf-c
- protobuf-c-devel
- protobuf-devel
- python
- python3-dateutil
- python3-psutil
- python3-pytoml
- rsync
- selinux-policy-devel
- skopeo
- skopeo-containers
- slirp4netns
- unzip
- vim
- wget
- which
- xz
- zip
-)
-
-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[@]}
-
-[[ "${#REMOVE_PACKAGES[@]}" -eq "0" ]] || \
- $LILTO ooe.sh sudo dnf erase -y ${REMOVE_PACKAGES[@]}
+bash $PACKER_BASE/fedora_packaging.sh
+# Load installed environment right now (happens automatically in a new process)
+source /usr/share/automation/environment
echo "Enabling cgroup management from containers"
ooe.sh sudo setsebool container_manage_cgroup true
-ooe.sh sudo /tmp/libpod/hack/install_catatonit.sh
-
# Ensure there are no disruptive periodic services enabled by default in image
systemd_banish
diff --git a/contrib/cirrus/packer/libpod_base_images.yml b/contrib/cirrus/packer/libpod_base_images.yml
index a66fac31c..f53bfafc5 100644
--- a/contrib/cirrus/packer/libpod_base_images.yml
+++ b/contrib/cirrus/packer/libpod_base_images.yml
@@ -17,9 +17,9 @@ variables:
PRIOR_UBUNTU_BASE_IMAGE:
# Latest Fedora release
- FEDORA_IMAGE_URL: "https://dl.fedoraproject.org/pub/fedora/linux/development/32/Cloud/x86_64/images/Fedora-Cloud-Base-32-20200406.n.0.x86_64.qcow2"
- FEDORA_CSUM_URL: "https://dl.fedoraproject.org/pub/fedora/linux/development/32/Cloud/x86_64/images/Fedora-Cloud-32-x86_64-20200406.n.0-CHECKSUM"
- FEDORA_BASE_IMAGE_NAME: 'fedora-cloud-base-32-n-0'
+ FEDORA_IMAGE_URL: "https://dl.fedoraproject.org/pub/fedora/linux/releases/32/Cloud/x86_64/images/Fedora-Cloud-Base-32-1.6.x86_64.qcow2"
+ FEDORA_CSUM_URL: "https://dl.fedoraproject.org/pub/fedora/linux/releases/32/Cloud/x86_64/images/Fedora-Cloud-32-1.6-x86_64-CHECKSUM"
+ FEDORA_BASE_IMAGE_NAME: 'fedora-cloud-base-32-1-6'
# Prior Fedora release
PRIOR_FEDORA_IMAGE_URL: "https://dl.fedoraproject.org/pub/fedora/linux/releases/31/Cloud/x86_64/images/Fedora-Cloud-Base-31-1.9.x86_64.qcow2"
diff --git a/contrib/cirrus/packer/libpod_images.yml b/contrib/cirrus/packer/libpod_images.yml
index c23439201..e33ad775e 100644
--- a/contrib/cirrus/packer/libpod_images.yml
+++ b/contrib/cirrus/packer/libpod_images.yml
@@ -71,6 +71,7 @@ provisioners:
environment_vars:
- 'PACKER_BUILDER_NAME={{build_name}}'
- 'GOSRC=/tmp/libpod'
+ - 'PACKER_BASE={{user `PACKER_BASE`}}'
- 'SCRIPT_BASE={{user `SCRIPT_BASE`}}'
post-processors:
diff --git a/contrib/cirrus/packer/ubuntu_packaging.sh b/contrib/cirrus/packer/ubuntu_packaging.sh
new file mode 100644
index 000000000..b57bc95e9
--- /dev/null
+++ b/contrib/cirrus/packer/ubuntu_packaging.sh
@@ -0,0 +1,168 @@
+#!/bin/bash
+
+# This script is called from ubuntu_setup.sh and various Dockerfiles.
+# It's not intended to be used outside of those contexts. It assumes the lib.sh
+# library has already been sourced, and that all "ground-up" package-related activity
+# needs to be done, including repository setup and initial update.
+
+set -e
+
+echo "Updating/Installing repos and packages for $OS_REL_VER"
+
+source $GOSRC/$SCRIPT_BASE/lib.sh
+
+echo "Updating/configuring package repositories."
+$BIGTO $SUDOAPTGET update
+
+echo "Installing deps to add third-party repositories and automation tooling"
+$LILTO $SUDOAPTGET install software-properties-common git curl
+
+# Install common automation tooling (i.e. ooe.sh)
+curl --silent --show-error --location \
+ --url "https://raw.githubusercontent.com/containers/automation/master/bin/install_automation.sh" | \
+ $SUDO env INSTALL_PREFIX=/usr/share /bin/bash -s - "$INSTALL_AUTOMATION_VERSION"
+# Reload installed environment right now (happens automatically in a new process)
+source /usr/share/automation/environment
+
+$LILTO ooe.sh $SUDOAPTADD ppa:criu/ppa
+
+# Install newer version of golang
+if [[ "$OS_RELEASE_VER" -eq "18" ]]
+then
+ $LILTO ooe.sh $SUDOAPTADD ppa:longsleep/golang-backports
+fi
+
+echo "Configuring/Instaling deps from Open build server"
+VERSION_ID=$(source /etc/os-release; echo $VERSION_ID)
+echo "deb http://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/xUbuntu_$VERSION_ID/ /" \
+ | ooe.sh $SUDO tee /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list
+ooe.sh curl -L -o /tmp/Release.key "https://download.opensuse.org/repositories/devel:kubic:libcontainers:stable/xUbuntu_${VERSION_ID}/Release.key"
+ooe.sh $SUDO apt-key add - < /tmp/Release.key
+
+INSTALL_PACKAGES=(\
+ apparmor
+ aufs-tools
+ autoconf
+ automake
+ bash-completion
+ bison
+ build-essential
+ buildah
+ bzip2
+ conmon
+ containernetworking-plugins
+ containers-common
+ coreutils
+ cri-o-runc
+ criu
+ curl
+ dnsmasq
+ e2fslibs-dev
+ emacs-nox
+ file
+ gawk
+ gcc
+ gettext
+ git
+ go-md2man
+ golang
+ iproute2
+ iptables
+ jq
+ libaio-dev
+ libapparmor-dev
+ libcap-dev
+ libdevmapper-dev
+ libdevmapper1.02.1
+ libfuse-dev
+ libfuse2
+ libglib2.0-dev
+ libgpgme11-dev
+ liblzma-dev
+ libnet1
+ libnet1-dev
+ libnl-3-dev
+ libprotobuf-c-dev
+ libprotobuf-dev
+ libseccomp-dev
+ libseccomp2
+ libselinux-dev
+ libsystemd-dev
+ libtool
+ libudev-dev
+ libvarlink
+ lsof
+ make
+ netcat
+ openssl
+ pkg-config
+ podman
+ protobuf-c-compiler
+ protobuf-compiler
+ python-future
+ python-minimal
+ python-protobuf
+ python3-dateutil
+ python3-pip
+ python3-psutil
+ python3-pytoml
+ python3-setuptools
+ rsync
+ runc
+ scons
+ skopeo
+ slirp4netns
+ socat
+ sudo
+ unzip
+ vim
+ wget
+ xz-utils
+ yum-utils
+ zip
+ zlib1g-dev
+)
+
+if [[ $OS_RELEASE_VER -ge 19 ]]
+then
+ INSTALL_PACKAGES+=(\
+ bats
+ btrfs-progs
+ fuse3
+ libbtrfs-dev
+ libfuse3-dev
+ )
+else
+ echo "Downloading version of bats with fix for a \$IFS related bug in 'run' command"
+ cd /tmp
+ BATS_URL='http://launchpadlibrarian.net/438140887/bats_1.1.0+git104-g1c83a1b-1_all.deb'
+ curl -L -O "$BATS_URL"
+ cd -
+ INSTALL_PACKAGES+=(\
+ /tmp/$(basename $BATS_URL)
+ btrfs-tools
+ )
+fi
+
+# Do this at the last possible moment to avoid dpkg lock conflicts
+echo "Upgrading all packages"
+$BIGTO ooe.sh $SUDOAPTGET upgrade
+
+echo "Installing general testing and system dependencies"
+# Necessary to update cache of newly added repos
+$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"
+fi
diff --git a/contrib/cirrus/packer/ubuntu_setup.sh b/contrib/cirrus/packer/ubuntu_setup.sh
index 4b6e99358..2febbd265 100644
--- a/contrib/cirrus/packer/ubuntu_setup.sh
+++ b/contrib/cirrus/packer/ubuntu_setup.sh
@@ -8,164 +8,21 @@ set -e
# Load in library (copied by packer, before this script was run)
source $GOSRC/$SCRIPT_BASE/lib.sh
-req_env_var SCRIPT_BASE
+req_env_var SCRIPT_BASE PACKER_BASE INSTALL_AUTOMATION_VERSION PACKER_BUILDER_NAME GOSRC UBUNTU_BASE_IMAGE OS_RELEASE_ID OS_RELEASE_VER
-install_ooe
-
-export GOPATH="$(mktemp -d)"
-trap "sudo rm -rf $GOPATH" EXIT
+# Ensure there are no disruptive periodic services enabled by default in image
+systemd_banish
# Stop disruption upon boot ASAP after booting
echo "Disabling all packaging activity on boot"
-# Don't let sed process sed's temporary files
-_FILEPATHS=$(sudo ls -1 /etc/apt/apt.conf.d)
-for filename in $_FILEPATHS; do \
+for filename in $(sudo ls -1 /etc/apt/apt.conf.d); do \
echo "Checking/Patching $filename"
sudo sed -i -r -e "s/$PERIODIC_APT_RE/"'\10"\;/' "/etc/apt/apt.conf.d/$filename"; done
-echo "Updating/configuring package repositories."
-$BIGTO $SUDOAPTGET update
-
-echo "Upgrading all packages"
-$BIGTO $SUDOAPTGET upgrade
-
-echo "Adding third-party repositories and PPAs"
-$LILTO $SUDOAPTGET install software-properties-common
-$LILTO $SUDOAPTADD ppa:criu/ppa
-if [[ "$OS_RELEASE_VER" -eq "18" ]]
-then
- $LILTO $SUDOAPTADD ppa:longsleep/golang-backports
-fi
-
-echo "Configuring/Instaling deps from Open build server"
-VERSION_ID=$(source /etc/os-release; echo $VERSION_ID)
-echo "deb http://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/xUbuntu_$VERSION_ID/ /" \
- | ooe.sh sudo tee /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list
-ooe.sh curl -L -o /tmp/Release.key "https://download.opensuse.org/repositories/devel:kubic:libcontainers:stable/xUbuntu_${VERSION_ID}/Release.key"
-ooe.sh sudo apt-key add - < /tmp/Release.key
-
-INSTALL_PACKAGES=(\
- apparmor
- aufs-tools
- autoconf
- automake
- bash-completion
- bison
- build-essential
- buildah
- bzip2
- conmon
- containernetworking-plugins
- containers-common
- coreutils
- cri-o-runc
- criu
- curl
- dnsmasq
- e2fslibs-dev
- emacs-nox
- file
- gawk
- gcc
- gettext
- git
- go-md2man
- golang
- iproute2
- iptables
- jq
- libaio-dev
- libapparmor-dev
- libcap-dev
- libdevmapper-dev
- libdevmapper1.02.1
- libfuse-dev
- libfuse2
- libglib2.0-dev
- libgpgme11-dev
- liblzma-dev
- libnet1
- libnet1-dev
- libnl-3-dev
- libprotobuf-c-dev
- libprotobuf-dev
- libseccomp-dev
- libseccomp2
- libselinux-dev
- libsystemd-dev
- libtool
- libudev-dev
- libvarlink
- lsof
- make
- netcat
- openssl
- pkg-config
- podman
- protobuf-c-compiler
- protobuf-compiler
- python-future
- python-minimal
- python-protobuf
- python3-dateutil
- python3-pip
- python3-psutil
- python3-pytoml
- python3-setuptools
- rsync
- runc
- scons
- skopeo
- slirp4netns
- socat
- unzip
- vim
- wget
- xz-utils
- yum-utils
- zip
- zlib1g-dev
-)
-
-if [[ "$OS_RELEASE_VER" -ge "19" ]]
-then
- INSTALL_PACKAGES+=(\
- bats
- btrfs-progs
- fuse3
- libbtrfs-dev
- libfuse3-dev
- )
-else
- echo "Downloading version of bats with fix for a \$IFS related bug in 'run' command"
- cd /tmp
- BATS_URL='http://launchpadlibrarian.net/438140887/bats_1.1.0+git104-g1c83a1b-1_all.deb'
- curl -L -O "$BATS_URL"
- cd -
- INSTALL_PACKAGES+=(\
- /tmp/$(basename $BATS_URL)
- btrfs-tools
- )
-fi
-
-echo "Installing general testing and system dependencies"
-# Necessary to update cache of newly added repos
-$LILTO $SUDOAPTGET update
-$BIGTO $SUDOAPTGET install ${INSTALL_PACKAGES[@]}
-
-echo "Installing cataonit and libseccomp.sudo"
-ooe.sh sudo /tmp/libpod/hack/install_catatonit.sh
-ooe.sh sudo make -C /tmp/libpod install.libseccomp.sudo
-
-# Ensure there are no disruptive periodic services enabled by default in image
-systemd_banish
+bash $PACKER_BASE/ubuntu_packaging.sh
-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"
-fi
+# Load installed environment right now (happens automatically in a new process)
+source /usr/share/automation/environment
echo "Making Ubuntu kernel to enable cgroup swap accounting as it is not the default."
SEDCMD='s/^GRUB_CMDLINE_LINUX="(.*)"/GRUB_CMDLINE_LINUX="\1 cgroup_enable=memory swapaccount=1"/g'
diff --git a/contrib/cirrus/setup_environment.sh b/contrib/cirrus/setup_environment.sh
index 57c9ec52a..6bec9625e 100755
--- a/contrib/cirrus/setup_environment.sh
+++ b/contrib/cirrus/setup_environment.sh
@@ -43,16 +43,8 @@ case "${OS_RELEASE_ID}" in
fedora)
# All SELinux distros need this for systemd-in-a-container
setsebool container_manage_cgroup true
- if [[ "$ADD_SECOND_PARTITION" == "true" ]]; then
- bash "$SCRIPT_BASE/add_second_partition.sh"
- fi
- if [[ $OS_RELEASE_VER -le 31 ]]; then
- warn "Switching io scheduler to 'deadline' to avoid RHBZ 1767539"
- warn "aka https://bugzilla.kernel.org/show_bug.cgi?id=205447"
- echo "mq-deadline" > /sys/block/sda/queue/scheduler
- cat /sys/block/sda/queue/scheduler
- fi
+ workaround_bfq_bug
if [[ "$ADD_SECOND_PARTITION" == "true" ]]; then
bash "$SCRIPT_BASE/add_second_partition.sh"
diff --git a/contrib/podmanimage/stable/Dockerfile b/contrib/podmanimage/stable/Dockerfile
index 7aeb5bbdc..912d16e1c 100644
--- a/contrib/podmanimage/stable/Dockerfile
+++ b/contrib/podmanimage/stable/Dockerfile
@@ -13,10 +13,10 @@ FROM fedora:latest
# up space.
RUN useradd podman; yum -y update; yum -y reinstall shadow-utils; yum -y install podman fuse-overlayfs --exclude container-selinux; rm -rf /var/cache /var/log/dnf* /var/log/yum.*
-# Adjust storage.conf to enable Fuse storage.
-RUN sed -i -e 's|^#mount_program|mount_program|g' -e '/additionalimage.*/a "/var/lib/shared",' /etc/containers/storage.conf
-RUN mkdir -p /var/lib/shared/overlay-images /var/lib/shared/overlay-layers; touch /var/lib/shared/overlay-images/images.lock; touch /var/lib/shared/overlay-layers/layers.lock
-
ADD https://raw.githubusercontent.com/containers/libpod/master/contrib/podmanimage/stable/containers.conf /etc/containers/
+# chmod containers.conf and adjust storage.conf to enable Fuse storage.
+RUN chmod 644 /etc/containers/containers.conf; sed -i -e 's|^#mount_program|mount_program|g' -e '/additionalimage.*/a "/var/lib/shared",' /etc/containers/storage.conf
+RUN mkdir -p /var/lib/shared/overlay-images /var/lib/shared/overlay-layers; touch /var/lib/shared/overlay-images/images.lock; touch /var/lib/shared/overlay-layers/layers.lock
+
ENV _CONTAINERS_USERNS_CONFIGURED=""
diff --git a/contrib/podmanimage/stable/manual/Containerfile b/contrib/podmanimage/stable/manual/Containerfile
index afc4f5ffd..4375ea4f4 100644
--- a/contrib/podmanimage/stable/manual/Containerfile
+++ b/contrib/podmanimage/stable/manual/Containerfile
@@ -26,10 +26,11 @@ FROM fedora:latest
COPY /tmp/podman-1.7.0-3.fc30.x86_64.rpm /tmp
RUN yum -y install /tmp/podman-1.7.0-3.fc30.x86_64.rpm fuse-overlayfs --exclude container-selinux; rm -rf /var/cache /var/log/dnf* /var/log/yum.* /tmp/podman*.rpm
-# Adjust storage.conf to enable Fuse storage.
-RUN sed -i -e 's|^#mount_program|mount_program|g' -e '/additionalimage.*/a "/var/lib/shared",' /etc/containers/storage.conf
+ADD https://raw.githubusercontent.com/containers/libpod/master/contrib/podmanimage/stable/containers.conf /etc/containers/
+
+# chmod containers.conf and adjust storage.conf to enable Fuse storage.
+RUN chmod 644 /etc/containers/containers.conf; sed -i -e 's|^#mount_program|mount_program|g' -e '/additionalimage.*/a "/var/lib/shared",' /etc/containers/storage.conf
RUN mkdir -p /var/lib/shared/overlay-images /var/lib/shared/overlay-layers; touch /var/lib/shared/overlay-images/images.lock; touch /var/lib/shared/overlay-layers/layers.lock
-ADD https://raw.githubusercontent.com/containers/libpod/master/contrib/podmanimage/stable/containers.conf /etc/containers/
ENV _CONTAINERS_USERNS_CONFIGURED=""
diff --git a/contrib/podmanimage/testing/Dockerfile b/contrib/podmanimage/testing/Dockerfile
index 3a7a0b7f8..31265a0ea 100644
--- a/contrib/podmanimage/testing/Dockerfile
+++ b/contrib/podmanimage/testing/Dockerfile
@@ -15,10 +15,10 @@ FROM fedora:latest
# up space.
RUN useradd podman; yum -y update; yum -y reinstall shadow-utils; yum -y install podman fuse-overlayfs --exclude container-selinux --enablerepo updates-testing; rm -rf /var/cache /var/log/dnf* /var/log/yum.*
-# Adjust storage.conf to enable Fuse storage.
-RUN sed -i -e 's|^#mount_program|mount_program|g' -e '/additionalimage.*/a "/var/lib/shared",' /etc/containers/storage.conf
-RUN mkdir -p /var/lib/shared/overlay-images /var/lib/shared/overlay-layers; touch /var/lib/shared/overlay-images/images.lock; touch /var/lib/shared/overlay-layers/layers.lock
-
ADD https://raw.githubusercontent.com/containers/libpod/master/contrib/podmanimage/stable/containers.conf /etc/containers/
+# chmod containers.conf and adjust storage.conf to enable Fuse storage.
+RUN chmod 644 /etc/containers/containers.conf; sed -i -e 's|^#mount_program|mount_program|g' -e '/additionalimage.*/a "/var/lib/shared",' /etc/containers/storage.conf
+RUN mkdir -p /var/lib/shared/overlay-images /var/lib/shared/overlay-layers; touch /var/lib/shared/overlay-images/images.lock; touch /var/lib/shared/overlay-layers/layers.lock
+
ENV _CONTAINERS_USERNS_CONFIGURED=""
diff --git a/contrib/podmanimage/upstream/Dockerfile b/contrib/podmanimage/upstream/Dockerfile
index 3b2f49094..541670aa2 100644
--- a/contrib/podmanimage/upstream/Dockerfile
+++ b/contrib/podmanimage/upstream/Dockerfile
@@ -63,10 +63,10 @@ RUN useradd podman; yum -y update; yum -y reinstall shadow-utils; yum -y install
yum -y remove git golang go-md2man make; \
yum clean all;
-# Adjust storage.conf to enable Fuse storage.
-RUN sed -i -e 's|^#mount_program|mount_program|g' -e '/additionalimage.*/a "/var/lib/shared",' /etc/containers/storage.conf
-RUN mkdir -p /var/lib/shared/overlay-images /var/lib/shared/overlay-layers; touch /var/lib/shared/overlay-images/images.lock; touch /var/lib/shared/overlay-layers/layers.lock
-
ADD https://raw.githubusercontent.com/containers/libpod/master/contrib/podmanimage/stable/containers.conf /etc/containers/
+# chmod containers.conf and adjust storage.conf to enable Fuse storage.
+RUN chmod 644 /etc/containers/containers.conf; sed -i -e 's|^#mount_program|mount_program|g' -e '/additionalimage.*/a "/var/lib/shared",' /etc/containers/storage.conf
+RUN mkdir -p /var/lib/shared/overlay-images /var/lib/shared/overlay-layers; touch /var/lib/shared/overlay-images/images.lock; touch /var/lib/shared/overlay-layers/layers.lock
+
ENV _CONTAINERS_USERNS_CONFIGURED=""
diff --git a/contrib/spec/podman.spec.in b/contrib/spec/podman.spec.in
index afc50f854..1dfbdf208 100644
--- a/contrib/spec/podman.spec.in
+++ b/contrib/spec/podman.spec.in
@@ -377,12 +377,6 @@ Man pages for the %{name} commands
# untar conmon
tar zxf %{SOURCE1}
-sed -i 's/install.remote: podman-remote/install.remote:/' Makefile
-sed -i 's/install.bin: podman/install.bin:/' Makefile
-%if %{with doc}
-sed -i 's/install.man: docs/install.man:/' Makefile
-%endif
-
%build
mkdir _build
pushd _build
@@ -417,22 +411,15 @@ popd
%install
install -dp %{buildroot}%{_unitdir}
install -dp %{buildroot}%{_usr}/lib/systemd/user
-%if %{with doc}
-PODMAN_VERSION=%{version} %{__make} PREFIX=%{buildroot}%{_prefix} ETCDIR=%{buildroot}%{_sysconfdir} \
- install.bin \
- install.remote \
- install.man \
- install.cni \
- install.systemd \
- install.completions
-%else
PODMAN_VERSION=%{version} %{__make} PREFIX=%{buildroot}%{_prefix} ETCDIR=%{buildroot}%{_sysconfdir} \
- install.bin \
- install.remote \
+ install.bin-nobuild \
+ install.remote-nobuild \
+%if %{with doc}
+ install.man-nobuild \
+%endif
install.cni \
install.systemd \
install.completions
-%endif
mv pkg/hooks/README.md pkg/hooks/README-hooks.md
diff --git a/go.mod b/go.mod
index 576166df0..14b80e216 100644
--- a/go.mod
+++ b/go.mod
@@ -13,7 +13,7 @@ require (
github.com/containers/common v0.9.5
github.com/containers/conmon v2.0.14+incompatible
github.com/containers/image/v5 v5.4.3
- github.com/containers/psgo v1.4.0
+ github.com/containers/psgo v1.5.0
github.com/containers/storage v1.18.2
github.com/coreos/go-systemd/v22 v22.0.0
github.com/cri-o/ocicni v0.1.1-0.20190920040751-deac903fd99b
diff --git a/go.sum b/go.sum
index 167d52e0a..acd345144 100644
--- a/go.sum
+++ b/go.sum
@@ -76,8 +76,8 @@ github.com/containers/libtrust v0.0.0-20190913040956-14b96171aa3b h1:Q8ePgVfHDpl
github.com/containers/libtrust v0.0.0-20190913040956-14b96171aa3b/go.mod h1:9rfv8iPl1ZP7aqh9YA68wnZv2NUDbXdcdPHVz0pFbPY=
github.com/containers/ocicrypt v1.0.2 h1:Q0/IPs8ohfbXNxEfyJ2pFVmvJu5BhqJUAmc6ES9NKbo=
github.com/containers/ocicrypt v1.0.2/go.mod h1:nsOhbP19flrX6rE7ieGFvBlr7modwmNjsqWarIUce4M=
-github.com/containers/psgo v1.4.0 h1:D8B4fZCCZhYgc8hDyMPCiShOinmOB1TP1qe46sSC19k=
-github.com/containers/psgo v1.4.0/go.mod h1:ENXXLQ5E1At4K0EUsGogXBJi/C28gwqkONWeLPI9fJ8=
+github.com/containers/psgo v1.5.0 h1:uofUREsrm0Ls5K4tkEIFPqWSHKyg3Bvoqo/Q2eDmj8g=
+github.com/containers/psgo v1.5.0/go.mod h1:2ubh0SsreMZjSXW1Hif58JrEcFudQyIy9EzPUWfawVU=
github.com/containers/storage v1.18.2 h1:4cgFbrrgr9nR9xCeOmfpyxk1MtXYZGr7XGPJfAVkGmc=
github.com/containers/storage v1.18.2/go.mod h1:WTBMf+a9ZZ/LbmEVeLHH2TX4CikWbO1Bt+/m58ZHVPg=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
diff --git a/libpod/image/image.go b/libpod/image/image.go
index bbf803056..60787b826 100644
--- a/libpod/image/image.go
+++ b/libpod/image/image.go
@@ -1487,14 +1487,14 @@ func (i *Image) Save(ctx context.Context, source, format, output string, moreTag
}
manifestType = manifest.DockerV2Schema2MediaType
case "docker-archive", "":
- dst := output
destImageName := imageNameForSaveDestination(i, source)
- if destImageName != "" {
- dst = fmt.Sprintf("%s:%s", dst, destImageName)
+ ref, err := dockerArchiveDstReference(destImageName)
+ if err != nil {
+ return err
}
- destRef, err = dockerarchive.ParseReference(dst) // FIXME? Add dockerarchive.NewReference
+ destRef, err = dockerarchive.NewReference(output, ref)
if err != nil {
- return errors.Wrapf(err, "error getting Docker archive ImageReference for %q", dst)
+ return errors.Wrapf(err, "error getting Docker archive ImageReference for %s:%v", output, ref)
}
default:
return errors.Errorf("unknown format option %q", format)
@@ -1514,6 +1514,23 @@ func (i *Image) Save(ctx context.Context, source, format, output string, moreTag
return nil
}
+// dockerArchiveDestReference returns a NamedTagged reference for a tagged image and nil for untagged image.
+func dockerArchiveDstReference(normalizedInput string) (reference.NamedTagged, error) {
+ if normalizedInput == "" {
+ return nil, nil
+ }
+ ref, err := reference.ParseNormalizedNamed(normalizedInput)
+ if err != nil {
+ return nil, errors.Wrapf(err, "docker-archive parsing reference %s", normalizedInput)
+ }
+ ref = reference.TagNameOnly(ref)
+ namedTagged, isTagged := ref.(reference.NamedTagged)
+ if !isTagged {
+ namedTagged = nil
+ }
+ return namedTagged, nil
+}
+
// GetConfigBlob returns a schema2image. If the image is not a schema2, then
// it will return an error
func (i *Image) GetConfigBlob(ctx context.Context) (*manifest.Schema2Image, error) {
diff --git a/libpod/options.go b/libpod/options.go
index b4e436b63..33b423bce 100644
--- a/libpod/options.go
+++ b/libpod/options.go
@@ -1400,8 +1400,13 @@ func WithVolumeDriver(driver string) VolumeCreateOption {
if volume.valid {
return define.ErrVolumeFinalized
}
+ // only local driver is possible rn
+ if driver != define.VolumeDriverLocal {
+ return define.ErrNotImplemented
- return define.ErrNotImplemented
+ }
+ volume.config.Driver = define.VolumeDriverLocal
+ return nil
}
}
diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go
index 3dc8d3d0f..1d880531e 100644
--- a/libpod/runtime_ctr.go
+++ b/libpod/runtime_ctr.go
@@ -869,7 +869,8 @@ func (r *Runtime) PruneContainers(filterFuncs []ContainerFilter) (map[string]int
logrus.Error(err)
return false
}
- if state == define.ContainerStateStopped || state == define.ContainerStateExited {
+ if state == define.ContainerStateStopped || state == define.ContainerStateExited ||
+ state == define.ContainerStateCreated || state == define.ContainerStateConfigured {
return true
}
return false
diff --git a/pkg/api/handlers/compat/containers_prune.go b/pkg/api/handlers/compat/containers_prune.go
index b4e98ac1f..9d77f612b 100644
--- a/pkg/api/handlers/compat/containers_prune.go
+++ b/pkg/api/handlers/compat/containers_prune.go
@@ -38,21 +38,24 @@ func PruneContainers(w http.ResponseWriter, r *http.Request) {
filterFuncs = append(filterFuncs, generatedFunc)
}
}
- prunedContainers, pruneErrors, err := runtime.PruneContainers(filterFuncs)
- if err != nil {
- utils.InternalServerError(w, err)
- return
- }
// Libpod response differs
if utils.IsLibpodRequest(r) {
- report := &entities.ContainerPruneReport{
- Err: pruneErrors,
- ID: prunedContainers,
+ report, err := PruneContainersHelper(w, r, filterFuncs)
+ if err != nil {
+ utils.InternalServerError(w, err)
+ return
}
+
utils.WriteResponse(w, http.StatusOK, report)
return
}
+
+ prunedContainers, pruneErrors, err := runtime.PruneContainers(filterFuncs)
+ if err != nil {
+ utils.InternalServerError(w, err)
+ return
+ }
for ctrID, size := range prunedContainers {
if pruneErrors[ctrID] == nil {
space += size
@@ -65,3 +68,19 @@ func PruneContainers(w http.ResponseWriter, r *http.Request) {
}
utils.WriteResponse(w, http.StatusOK, report)
}
+
+func PruneContainersHelper(w http.ResponseWriter, r *http.Request, filterFuncs []libpod.ContainerFilter) (
+ *entities.ContainerPruneReport, error) {
+ runtime := r.Context().Value("runtime").(*libpod.Runtime)
+ prunedContainers, pruneErrors, err := runtime.PruneContainers(filterFuncs)
+ if err != nil {
+ utils.InternalServerError(w, err)
+ return nil, err
+ }
+
+ report := &entities.ContainerPruneReport{
+ Err: pruneErrors,
+ ID: prunedContainers,
+ }
+ return report, nil
+}
diff --git a/pkg/api/handlers/libpod/pods.go b/pkg/api/handlers/libpod/pods.go
index 0b15ab0d6..c3f8d5d66 100644
--- a/pkg/api/handlers/libpod/pods.go
+++ b/pkg/api/handlers/libpod/pods.go
@@ -231,14 +231,22 @@ func PodRestart(w http.ResponseWriter, r *http.Request) {
}
func PodPrune(w http.ResponseWriter, r *http.Request) {
+ reports, err := PodPruneHelper(w, r)
+ if err != nil {
+ utils.InternalServerError(w, err)
+ return
+ }
+ utils.WriteResponse(w, http.StatusOK, reports)
+}
+
+func PodPruneHelper(w http.ResponseWriter, r *http.Request) ([]*entities.PodPruneReport, error) {
var (
runtime = r.Context().Value("runtime").(*libpod.Runtime)
reports []*entities.PodPruneReport
)
responses, err := runtime.PrunePods(r.Context())
if err != nil {
- utils.InternalServerError(w, err)
- return
+ return nil, err
}
for k, v := range responses {
reports = append(reports, &entities.PodPruneReport{
@@ -246,7 +254,7 @@ func PodPrune(w http.ResponseWriter, r *http.Request) {
Id: k,
})
}
- utils.WriteResponse(w, http.StatusOK, reports)
+ return reports, nil
}
func PodPause(w http.ResponseWriter, r *http.Request) {
diff --git a/pkg/api/handlers/libpod/system.go b/pkg/api/handlers/libpod/system.go
new file mode 100644
index 000000000..98e33bf10
--- /dev/null
+++ b/pkg/api/handlers/libpod/system.go
@@ -0,0 +1,71 @@
+package libpod
+
+import (
+ "net/http"
+
+ "github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/pkg/api/handlers/compat"
+ "github.com/containers/libpod/pkg/api/handlers/utils"
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/gorilla/schema"
+ "github.com/pkg/errors"
+)
+
+// SystemPrune removes unused data
+func SystemPrune(w http.ResponseWriter, r *http.Request) {
+ var (
+ decoder = r.Context().Value("decoder").(*schema.Decoder)
+ runtime = r.Context().Value("runtime").(*libpod.Runtime)
+ systemPruneReport = new(entities.SystemPruneReport)
+ )
+ query := struct {
+ All bool `schema:"all"`
+ Volumes bool `schema:"volumes"`
+ }{}
+
+ if err := decoder.Decode(&query, r.URL.Query()); err != nil {
+ utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
+ errors.Wrapf(err, "Failed to parse parameters for %s", r.URL.String()))
+ return
+ }
+
+ podPruneReport, err := PodPruneHelper(w, r)
+ if err != nil {
+ utils.InternalServerError(w, err)
+ return
+ }
+ systemPruneReport.PodPruneReport = podPruneReport
+
+ // We could parallelize this, should we?
+ containerPruneReport, err := compat.PruneContainersHelper(w, r, nil)
+ if err != nil {
+ utils.InternalServerError(w, err)
+ return
+ }
+ systemPruneReport.ContainerPruneReport = containerPruneReport
+
+ results, err := runtime.ImageRuntime().PruneImages(r.Context(), query.All, nil)
+ if err != nil {
+ utils.InternalServerError(w, err)
+ return
+ }
+
+ report := entities.ImagePruneReport{
+ Report: entities.Report{
+ Id: results,
+ Err: nil,
+ },
+ }
+
+ systemPruneReport.ImagePruneReport = &report
+
+ if query.Volumes {
+ volumePruneReport, err := pruneVolumesHelper(w, r)
+ if err != nil {
+ utils.InternalServerError(w, err)
+ return
+ }
+ systemPruneReport.VolumePruneReport = volumePruneReport
+ }
+ utils.WriteResponse(w, http.StatusOK, systemPruneReport)
+}
diff --git a/pkg/api/handlers/libpod/volumes.go b/pkg/api/handlers/libpod/volumes.go
index 18c561a0d..c42ca407b 100644
--- a/pkg/api/handlers/libpod/volumes.go
+++ b/pkg/api/handlers/libpod/volumes.go
@@ -147,14 +147,22 @@ func ListVolumes(w http.ResponseWriter, r *http.Request) {
}
func PruneVolumes(w http.ResponseWriter, r *http.Request) {
+ reports, err := pruneVolumesHelper(w, r)
+ if err != nil {
+ utils.InternalServerError(w, err)
+ return
+ }
+ utils.WriteResponse(w, http.StatusOK, reports)
+}
+
+func pruneVolumesHelper(w http.ResponseWriter, r *http.Request) ([]*entities.VolumePruneReport, error) {
var (
runtime = r.Context().Value("runtime").(*libpod.Runtime)
reports []*entities.VolumePruneReport
)
pruned, err := runtime.PruneVolumes(r.Context())
if err != nil {
- utils.InternalServerError(w, err)
- return
+ return nil, err
}
for k, v := range pruned {
reports = append(reports, &entities.VolumePruneReport{
@@ -162,9 +170,8 @@ func PruneVolumes(w http.ResponseWriter, r *http.Request) {
Id: k,
})
}
- utils.WriteResponse(w, http.StatusOK, reports)
+ return reports, nil
}
-
func RemoveVolume(w http.ResponseWriter, r *http.Request) {
var (
runtime = r.Context().Value("runtime").(*libpod.Runtime)
diff --git a/pkg/api/server/register_system.go b/pkg/api/server/register_system.go
index 708ccd39b..7375a75c1 100644
--- a/pkg/api/server/register_system.go
+++ b/pkg/api/server/register_system.go
@@ -4,6 +4,7 @@ import (
"net/http"
"github.com/containers/libpod/pkg/api/handlers/compat"
+ "github.com/containers/libpod/pkg/api/handlers/libpod"
"github.com/gorilla/mux"
)
@@ -11,5 +12,21 @@ func (s *APIServer) registerSystemHandlers(r *mux.Router) error {
r.Handle(VersionedPath("/system/df"), s.APIHandler(compat.GetDiskUsage)).Methods(http.MethodGet)
// Added non version path to URI to support docker non versioned paths
r.Handle("/system/df", s.APIHandler(compat.GetDiskUsage)).Methods(http.MethodGet)
+ // Swagger:operation POST /libpod/system/prune libpod pruneSystem
+ // ---
+ // tags:
+ // - system
+ // summary: Prune unused data
+ // produces:
+ // - application/json
+ // responses:
+ // 200:
+ // $ref: '#/responses/SystemPruneReport'
+ // 400:
+ // $ref: "#/responses/BadParamError"
+ // 500:
+ // $ref: "#/responses/InternalError"
+ r.Handle(VersionedPath("/libpod/system/prune"), s.APIHandler(libpod.SystemPrune)).Methods(http.MethodPost)
+
return nil
}
diff --git a/pkg/bindings/images/images.go b/pkg/bindings/images/images.go
index 06f01c7a0..4d8ae6a6e 100644
--- a/pkg/bindings/images/images.go
+++ b/pkg/bindings/images/images.go
@@ -57,7 +57,7 @@ func List(ctx context.Context, all *bool, filters map[string][]string) ([]*entit
// Get performs an image inspect. To have the on-disk size of the image calculated, you can
// use the optional size parameter.
-func GetImage(ctx context.Context, nameOrID string, size *bool) (*entities.ImageData, error) {
+func GetImage(ctx context.Context, nameOrID string, size *bool) (*entities.ImageInspectReport, error) {
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
@@ -66,7 +66,7 @@ func GetImage(ctx context.Context, nameOrID string, size *bool) (*entities.Image
if size != nil {
params.Set("size", strconv.FormatBool(*size))
}
- inspectedData := entities.ImageData{}
+ inspectedData := entities.ImageInspectReport{}
response, err := conn.DoRequest(nil, http.MethodGet, "/images/%s/json", params, nameOrID)
if err != nil {
return &inspectedData, err
@@ -273,9 +273,10 @@ func Pull(ctx context.Context, rawImage string, options entities.ImagePullOption
params.Set("credentials", options.Credentials)
params.Set("overrideArch", options.OverrideArch)
params.Set("overrideOS", options.OverrideOS)
- if options.TLSVerify != types.OptionalBoolUndefined {
- val := bool(options.TLSVerify == types.OptionalBoolTrue)
- params.Set("tlsVerify", strconv.FormatBool(val))
+ if options.SkipTLSVerify != types.OptionalBoolUndefined {
+ // Note: we have to verify if skipped is false.
+ verifyTLS := bool(options.SkipTLSVerify == types.OptionalBoolFalse)
+ params.Set("tlsVerify", strconv.FormatBool(verifyTLS))
}
params.Set("allTags", strconv.FormatBool(options.AllTags))
@@ -310,9 +311,10 @@ func Push(ctx context.Context, source string, destination string, options entiti
params := url.Values{}
params.Set("credentials", options.Credentials)
params.Set("destination", destination)
- if options.TLSVerify != types.OptionalBoolUndefined {
- val := bool(options.TLSVerify == types.OptionalBoolTrue)
- params.Set("tlsVerify", strconv.FormatBool(val))
+ if options.SkipTLSVerify != types.OptionalBoolUndefined {
+ // Note: we have to verify if skipped is false.
+ verifyTLS := bool(options.SkipTLSVerify == types.OptionalBoolFalse)
+ params.Set("tlsVerify", strconv.FormatBool(verifyTLS))
}
path := fmt.Sprintf("/images/%s/push", source)
@@ -333,9 +335,10 @@ func Search(ctx context.Context, term string, opts entities.ImageSearchOptions)
params.Set("filters", f)
}
- if opts.TLSVerify != types.OptionalBoolUndefined {
- val := bool(opts.TLSVerify == types.OptionalBoolTrue)
- params.Set("tlsVerify", strconv.FormatBool(val))
+ if opts.SkipTLSVerify != types.OptionalBoolUndefined {
+ // Note: we have to verify if skipped is false.
+ verifyTLS := bool(opts.SkipTLSVerify == types.OptionalBoolFalse)
+ params.Set("tlsVerify", strconv.FormatBool(verifyTLS))
}
response, err := conn.DoRequest(nil, http.MethodGet, "/images/search", params)
diff --git a/pkg/bindings/system/system.go b/pkg/bindings/system/system.go
index e2f264139..df6b529de 100644
--- a/pkg/bindings/system/system.go
+++ b/pkg/bindings/system/system.go
@@ -6,6 +6,7 @@ import (
"io"
"net/http"
"net/url"
+ "strconv"
"github.com/containers/libpod/pkg/bindings"
"github.com/containers/libpod/pkg/domain/entities"
@@ -59,3 +60,26 @@ func Events(ctx context.Context, eventChan chan (entities.Event), cancelChan cha
}
return nil
}
+
+// Prune removes all unused system data.
+func Prune(ctx context.Context, all, volumes *bool) (*entities.SystemPruneReport, error) {
+ var (
+ report entities.SystemPruneReport
+ )
+ conn, err := bindings.GetClient(ctx)
+ if err != nil {
+ return nil, err
+ }
+ params := url.Values{}
+ if all != nil {
+ params.Set("All", strconv.FormatBool(*all))
+ }
+ if volumes != nil {
+ params.Set("Volumes", strconv.FormatBool(*volumes))
+ }
+ response, err := conn.DoRequest(nil, http.MethodPost, "/system/prune", params)
+ if err != nil {
+ return nil, err
+ }
+ return &report, response.Process(&report)
+}
diff --git a/pkg/bindings/test/system_test.go b/pkg/bindings/test/system_test.go
index 3abc26b34..87e6d56dc 100644
--- a/pkg/bindings/test/system_test.go
+++ b/pkg/bindings/test/system_test.go
@@ -4,7 +4,12 @@ import (
"time"
"github.com/containers/libpod/pkg/api/handlers"
+ "github.com/containers/libpod/pkg/bindings"
+ "github.com/containers/libpod/pkg/bindings/containers"
+ "github.com/containers/libpod/pkg/bindings/pods"
"github.com/containers/libpod/pkg/bindings/system"
+ "github.com/containers/libpod/pkg/bindings/volumes"
+ "github.com/containers/libpod/pkg/domain/entities"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/onsi/gomega/gexec"
@@ -12,13 +17,16 @@ import (
var _ = Describe("Podman system", func() {
var (
- bt *bindingTest
- s *gexec.Session
+ bt *bindingTest
+ s *gexec.Session
+ newpod string
)
BeforeEach(func() {
bt = newBindingTest()
bt.RestoreImagesFromCache()
+ newpod = "newpod"
+ bt.Podcreate(&newpod)
s = bt.startAPIService()
time.Sleep(1 * time.Second)
err := bt.NewConnection()
@@ -48,4 +56,98 @@ var _ = Describe("Podman system", func() {
cancelChan <- true
Expect(len(messages)).To(BeNumerically("==", 3))
})
+
+ It("podman system prune - pod,container stopped", func() {
+ // Start and stop a pod to enter in exited state.
+ _, err := pods.Start(bt.conn, newpod)
+ Expect(err).To(BeNil())
+ _, err = pods.Stop(bt.conn, newpod, nil)
+ Expect(err).To(BeNil())
+ // Start and stop a container to enter in exited state.
+ var name = "top"
+ _, err = bt.RunTopContainer(&name, &bindings.PFalse, nil)
+ Expect(err).To(BeNil())
+ err = containers.Stop(bt.conn, name, nil)
+ Expect(err).To(BeNil())
+
+ systemPruneResponse, err := system.Prune(bt.conn, &bindings.PTrue, &bindings.PFalse)
+ Expect(err).To(BeNil())
+ Expect(len(systemPruneResponse.PodPruneReport)).To(Equal(1))
+ Expect(len(systemPruneResponse.ContainerPruneReport.ID)).To(Equal(1))
+ Expect(len(systemPruneResponse.ImagePruneReport.Report.Id)).
+ To(BeNumerically(">", 0))
+ Expect(systemPruneResponse.ImagePruneReport.Report.Id).
+ To(ContainElement("docker.io/library/alpine:latest"))
+ Expect(len(systemPruneResponse.VolumePruneReport)).To(Equal(0))
+ })
+
+ It("podman system prune running alpine container", func() {
+ // Start and stop a pod to enter in exited state.
+ _, err := pods.Start(bt.conn, newpod)
+ Expect(err).To(BeNil())
+ _, err = pods.Stop(bt.conn, newpod, nil)
+ Expect(err).To(BeNil())
+
+ // Start and stop a container to enter in exited state.
+ var name = "top"
+ _, err = bt.RunTopContainer(&name, &bindings.PFalse, nil)
+ Expect(err).To(BeNil())
+ err = containers.Stop(bt.conn, name, nil)
+ Expect(err).To(BeNil())
+
+ // Start container and leave in running
+ var name2 = "top2"
+ _, err = bt.RunTopContainer(&name2, &bindings.PFalse, nil)
+ Expect(err).To(BeNil())
+
+ // Adding an unused volume
+ _, err = volumes.Create(bt.conn, entities.VolumeCreateOptions{})
+ Expect(err).To(BeNil())
+
+ systemPruneResponse, err := system.Prune(bt.conn, &bindings.PTrue, &bindings.PFalse)
+ Expect(err).To(BeNil())
+ Expect(len(systemPruneResponse.PodPruneReport)).To(Equal(1))
+ Expect(len(systemPruneResponse.ContainerPruneReport.ID)).To(Equal(1))
+ Expect(len(systemPruneResponse.ImagePruneReport.Report.Id)).
+ To(BeNumerically(">", 0))
+ // Alpine image should not be pruned as used by running container
+ Expect(systemPruneResponse.ImagePruneReport.Report.Id).
+ ToNot(ContainElement("docker.io/library/alpine:latest"))
+ // Though unsed volume is available it should not be pruned as flag set to false.
+ Expect(len(systemPruneResponse.VolumePruneReport)).To(Equal(0))
+ })
+
+ It("podman system prune running alpine container volume prune", func() {
+ // Start a pod and leave it running
+ _, err := pods.Start(bt.conn, newpod)
+ Expect(err).To(BeNil())
+
+ // Start and stop a container to enter in exited state.
+ var name = "top"
+ _, err = bt.RunTopContainer(&name, &bindings.PFalse, nil)
+ Expect(err).To(BeNil())
+ err = containers.Stop(bt.conn, name, nil)
+ Expect(err).To(BeNil())
+
+ // Start second container and leave in running
+ var name2 = "top2"
+ _, err = bt.RunTopContainer(&name2, &bindings.PFalse, nil)
+ Expect(err).To(BeNil())
+
+ // Adding an unused volume should work
+ _, err = volumes.Create(bt.conn, entities.VolumeCreateOptions{})
+ Expect(err).To(BeNil())
+
+ systemPruneResponse, err := system.Prune(bt.conn, &bindings.PTrue, &bindings.PTrue)
+ Expect(err).To(BeNil())
+ Expect(len(systemPruneResponse.PodPruneReport)).To(Equal(0))
+ Expect(len(systemPruneResponse.ContainerPruneReport.ID)).To(Equal(1))
+ Expect(len(systemPruneResponse.ImagePruneReport.Report.Id)).
+ To(BeNumerically(">", 0))
+ // Alpine image should not be pruned as used by running container
+ Expect(systemPruneResponse.ImagePruneReport.Report.Id).
+ ToNot(ContainElement("docker.io/library/alpine:latest"))
+ // Volume should be pruned now as flag set true
+ Expect(len(systemPruneResponse.VolumePruneReport)).To(Equal(1))
+ })
})
diff --git a/pkg/domain/entities/containers.go b/pkg/domain/entities/containers.go
index e58258b75..622e8eb5b 100644
--- a/pkg/domain/entities/containers.go
+++ b/pkg/domain/entities/containers.go
@@ -227,6 +227,7 @@ type ContainerStartOptions struct {
// containers from the cli
type ContainerStartReport struct {
Id string
+ RawInput string
Err error
ExitCode int
}
diff --git a/pkg/domain/entities/engine_container.go b/pkg/domain/entities/engine_container.go
index 502279bcf..eebf4c033 100644
--- a/pkg/domain/entities/engine_container.go
+++ b/pkg/domain/entities/engine_container.go
@@ -41,6 +41,7 @@ type ContainerEngine interface {
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)
HealthCheckRun(ctx context.Context, nameOrId string, options HealthCheckOptions) (*define.HealthCheckResults, error)
Info(ctx context.Context) (*define.Info, error)
PodCreate(ctx context.Context, opts PodCreateOptions) (*PodCreateReport, error)
diff --git a/pkg/domain/entities/engine_image.go b/pkg/domain/entities/engine_image.go
index b118a4104..46a96ca20 100644
--- a/pkg/domain/entities/engine_image.go
+++ b/pkg/domain/entities/engine_image.go
@@ -13,7 +13,7 @@ type ImageEngine interface {
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, names []string, opts InspectOptions) (*ImageInspectReport, error)
+ Inspect(ctx context.Context, namesOrIDs []string, opts InspectOptions) ([]*ImageInspectReport, error)
List(ctx context.Context, opts ImageListOptions) ([]*ImageSummary, error)
Load(ctx context.Context, opts ImageLoadOptions) (*ImageLoadReport, error)
Prune(ctx context.Context, opts ImagePruneOptions) (*ImagePruneReport, error)
diff --git a/pkg/domain/entities/generate.go b/pkg/domain/entities/generate.go
new file mode 100644
index 000000000..6d65b52f8
--- /dev/null
+++ b/pkg/domain/entities/generate.go
@@ -0,0 +1,22 @@
+package entities
+
+// GenerateSystemdOptions control the generation of systemd unit files.
+type GenerateSystemdOptions struct {
+ // Files - generate files instead of printing to stdout.
+ Files bool
+ // Name - use container/pod name instead of its ID.
+ Name bool
+ // New - create a new container instead of starting a new one.
+ New bool
+ // RestartPolicy - systemd restart policy.
+ RestartPolicy string
+ // StopTimeout - time when stopping the container.
+ StopTimeout *uint
+}
+
+// GenerateSystemdReport
+type GenerateSystemdReport struct {
+ // Output of the generate process. Either the generated files or their
+ // entire content.
+ Output string
+}
diff --git a/pkg/domain/entities/images.go b/pkg/domain/entities/images.go
index 460965b34..74f27e25f 100644
--- a/pkg/domain/entities/images.go
+++ b/pkg/domain/entities/images.go
@@ -141,8 +141,8 @@ type ImagePullOptions struct {
Quiet bool
// SignaturePolicy to use when pulling. Ignored for remote calls.
SignaturePolicy string
- // TLSVerify to enable/disable HTTPS and certificate verification.
- TLSVerify types.OptionalBool
+ // SkipTLSVerify to skip HTTPS and certificate verification.
+ SkipTLSVerify types.OptionalBool
}
// ImagePullReport is the response from pulling one or more images.
@@ -183,8 +183,8 @@ type ImagePushOptions struct {
// SignBy adds a signature at the destination using the specified key.
// Ignored for remote calls.
SignBy string
- // TLSVerify to enable/disable HTTPS and certificate verification.
- TLSVerify types.OptionalBool
+ // SkipTLSVerify to skip HTTPS and certificate verification.
+ SkipTLSVerify types.OptionalBool
}
// ImageSearchOptions are the arguments for searching images.
@@ -198,8 +198,8 @@ type ImageSearchOptions struct {
Limit int
// NoTrunc will not truncate the output.
NoTrunc bool
- // TLSVerify to enable/disable HTTPS and certificate verification.
- TLSVerify types.OptionalBool
+ // SkipTLSVerify to skip HTTPS and certificate verification.
+ SkipTLSVerify types.OptionalBool
}
// ImageSearchReport is the response from searching images.
@@ -218,6 +218,7 @@ type ImageSearchReport struct {
Automated string
}
+// Image List Options
type ImageListOptions struct {
All bool `json:"all" schema:"all"`
Filter []string `json:"Filter,omitempty"`
@@ -238,13 +239,9 @@ type ImagePruneReport struct {
type ImageTagOptions struct{}
type ImageUntagOptions struct{}
-type ImageData struct {
- *inspect.ImageData
-}
-
+// ImageInspectReport is the data when inspecting an image.
type ImageInspectReport struct {
- Images []*ImageData
- Errors map[string]error
+ *inspect.ImageData
}
type ImageLoadOptions struct {
diff --git a/pkg/domain/entities/system.go b/pkg/domain/entities/system.go
index 3ddc04293..de93a382f 100644
--- a/pkg/domain/entities/system.go
+++ b/pkg/domain/entities/system.go
@@ -12,3 +12,17 @@ type ServiceOptions struct {
Timeout time.Duration // duration of inactivity the service should wait before shutting down
Command *cobra.Command // CLI command provided. Used in V1 code
}
+
+// SystemPruneOptions provides options to prune system.
+type SystemPruneOptions struct {
+ All bool
+ Volume bool
+}
+
+// SystemPruneReport provides report after system prune is executed.
+type SystemPruneReport struct {
+ PodPruneReport []*PodPruneReport
+ *ContainerPruneReport
+ *ImagePruneReport
+ VolumePruneReport []*VolumePruneReport
+}
diff --git a/pkg/domain/entities/types.go b/pkg/domain/entities/types.go
index d742cc53d..9fbe04c9a 100644
--- a/pkg/domain/entities/types.go
+++ b/pkg/domain/entities/types.go
@@ -47,10 +47,14 @@ type NetOptions struct {
// All CLI inspect commands and inspect sub-commands use the same options
type InspectOptions struct {
+ // Format - change the output to JSON or a Go template.
Format string `json:",omitempty"`
- Latest bool `json:",omitempty"`
- Size bool `json:",omitempty"`
- Type string `json:",omitempty"`
+ // Latest - inspect the latest container Podman is aware of.
+ Latest bool `json:",omitempty"`
+ // Size (containers only) - display total file size.
+ Size bool `json:",omitempty"`
+ // Type -- return JSON for specified type.
+ Type string `json:",omitempty"`
}
// All API and CLI diff commands and diff sub-commands use the same options
diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go
index 286d37c34..f4996583a 100644
--- a/pkg/domain/infra/abi/containers.go
+++ b/pkg/domain/infra/abi/containers.go
@@ -32,9 +32,9 @@ import (
"github.com/sirupsen/logrus"
)
-// getContainersByContext gets pods whether all, latest, or a slice of names/ids
-// is specified.
-func getContainersByContext(all, latest bool, names []string, runtime *libpod.Runtime) (ctrs []*libpod.Container, err error) {
+// getContainersAndInputByContext gets containers whether all, latest, or a slice of names/ids
+// is specified. It also returns a list of the corresponding input name used to lookup each container.
+func getContainersAndInputByContext(all, latest bool, names []string, runtime *libpod.Runtime) (ctrs []*libpod.Container, rawInput []string, err error) {
var ctr *libpod.Container
ctrs = []*libpod.Container{}
@@ -43,6 +43,7 @@ func getContainersByContext(all, latest bool, names []string, runtime *libpod.Ru
ctrs, err = runtime.GetAllContainers()
case latest:
ctr, err = runtime.GetLatestContainer()
+ rawInput = append(rawInput, ctr.ID())
ctrs = append(ctrs, ctr)
default:
for _, n := range names {
@@ -54,6 +55,7 @@ func getContainersByContext(all, latest bool, names []string, runtime *libpod.Ru
err = e
}
} else {
+ rawInput = append(rawInput, n)
ctrs = append(ctrs, ctr)
}
}
@@ -61,6 +63,13 @@ func getContainersByContext(all, latest bool, names []string, runtime *libpod.Ru
return
}
+// getContainersByContext gets containers whether all, latest, or a slice of names/ids
+// is specified.
+func getContainersByContext(all, latest bool, names []string, runtime *libpod.Runtime) (ctrs []*libpod.Container, err error) {
+ ctrs, _, err = getContainersAndInputByContext(all, latest, names, runtime)
+ return
+}
+
// TODO: Should return *entities.ContainerExistsReport, error
func (ic *ContainerEngine) ContainerExists(ctx context.Context, nameOrId string) (*entities.BoolReport, error) {
_, err := ic.Libpod.LookupContainer(nameOrId)
@@ -514,7 +523,7 @@ func (ic *ContainerEngine) ContainerAttach(ctx context.Context, nameOrId string,
}
// If the container is in a pod, also set to recursively start dependencies
- if err := terminal.StartAttachCtr(ctx, ctr, options.Stdin, options.Stderr, options.Stdin, options.DetachKeys, options.SigProxy, false, ctr.PodID() != ""); err != nil && errors.Cause(err) != define.ErrDetach {
+ if err := terminal.StartAttachCtr(ctx, ctr, options.Stdout, options.Stderr, options.Stdin, options.DetachKeys, options.SigProxy, false, ctr.PodID() != ""); err != nil && errors.Cause(err) != define.ErrDetach {
return errors.Wrapf(err, "error attaching to container %s", ctr.ID())
}
return nil
@@ -555,12 +564,14 @@ func (ic *ContainerEngine) ContainerExec(ctx context.Context, nameOrId string, o
func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []string, options entities.ContainerStartOptions) ([]*entities.ContainerStartReport, error) {
var reports []*entities.ContainerStartReport
var exitCode = define.ExecErrorCodeGeneric
- ctrs, err := getContainersByContext(false, options.Latest, namesOrIds, ic.Libpod)
+ ctrs, rawInputs, err := getContainersAndInputByContext(false, options.Latest, namesOrIds, ic.Libpod)
if err != nil {
return nil, err
}
// There can only be one container if attach was used
- for _, ctr := range ctrs {
+ for i := range ctrs {
+ ctr := ctrs[i]
+ rawInput := rawInputs[i]
ctrState, err := ctr.State()
if err != nil {
return nil, err
@@ -574,6 +585,7 @@ func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []stri
// Exit cleanly immediately
reports = append(reports, &entities.ContainerStartReport{
Id: ctr.ID(),
+ RawInput: rawInput,
Err: nil,
ExitCode: 0,
})
@@ -584,6 +596,7 @@ func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []stri
logrus.Debugf("Deadlock error: %v", err)
reports = append(reports, &entities.ContainerStartReport{
Id: ctr.ID(),
+ RawInput: rawInput,
Err: err,
ExitCode: define.ExitCode(err),
})
@@ -593,6 +606,7 @@ func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []stri
if ctrRunning {
reports = append(reports, &entities.ContainerStartReport{
Id: ctr.ID(),
+ RawInput: rawInput,
Err: nil,
ExitCode: 0,
})
@@ -602,6 +616,7 @@ func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []stri
if err != nil {
reports = append(reports, &entities.ContainerStartReport{
Id: ctr.ID(),
+ RawInput: rawInput,
Err: err,
ExitCode: exitCode,
})
@@ -624,6 +639,7 @@ func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []stri
}
reports = append(reports, &entities.ContainerStartReport{
Id: ctr.ID(),
+ RawInput: rawInput,
Err: err,
ExitCode: exitCode,
})
@@ -636,6 +652,7 @@ func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []stri
// If the container is in a pod, also set to recursively start dependencies
report := &entities.ContainerStartReport{
Id: ctr.ID(),
+ RawInput: rawInput,
ExitCode: 125,
}
if err := ctr.Start(ctx, ctr.PodID() != ""); err != nil {
@@ -949,7 +966,7 @@ func (ic *ContainerEngine) Config(_ context.Context) (*config.Config, 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, false, []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/generate.go b/pkg/domain/infra/abi/generate.go
new file mode 100644
index 000000000..f69ba560e
--- /dev/null
+++ b/pkg/domain/infra/abi/generate.go
@@ -0,0 +1,174 @@
+package abi
+
+import (
+ "context"
+ "fmt"
+ "strings"
+
+ "github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/containers/libpod/pkg/systemd/generate"
+ "github.com/pkg/errors"
+)
+
+func (ic *ContainerEngine) GenerateSystemd(ctx context.Context, nameOrID string, options entities.GenerateSystemdOptions) (*entities.GenerateSystemdReport, error) {
+ opts := generate.Options{
+ Files: options.Files,
+ New: options.New,
+ }
+
+ // First assume it's a container.
+ if info, found, err := ic.generateSystemdgenContainerInfo(nameOrID, nil, options); found && err != nil {
+ return nil, err
+ } else if found && err == nil {
+ output, err := generate.CreateContainerSystemdUnit(info, opts)
+ if err != nil {
+ return nil, err
+ }
+ return &entities.GenerateSystemdReport{Output: output}, nil
+ }
+
+ // --new does not support pods.
+ if options.New {
+ return nil, errors.Errorf("error generating systemd unit files: cannot generate generic files for a pod")
+ }
+
+ // We're either having a pod or garbage.
+ pod, err := ic.Libpod.LookupPod(nameOrID)
+ if err != nil {
+ return nil, err
+ }
+
+ // Error out if the pod has no infra container, which we require to be the
+ // main service.
+ if !pod.HasInfraContainer() {
+ return nil, fmt.Errorf("error generating systemd unit files: Pod %q has no infra container", pod.Name())
+ }
+
+ // Generate a systemdgen.ContainerInfo for the infra container. This
+ // ContainerInfo acts as the main service of the pod.
+ infraID, err := pod.InfraContainerID()
+ if err != nil {
+ return nil, nil
+ }
+ podInfo, _, err := ic.generateSystemdgenContainerInfo(infraID, pod, options)
+ if err != nil {
+ return nil, err
+ }
+
+ // Compute the container-dependency graph for the Pod.
+ containers, err := pod.AllContainers()
+ if err != nil {
+ return nil, err
+ }
+ if len(containers) == 0 {
+ return nil, fmt.Errorf("error generating systemd unit files: Pod %q has no containers", pod.Name())
+ }
+ graph, err := libpod.BuildContainerGraph(containers)
+ if err != nil {
+ return nil, err
+ }
+
+ // Traverse the dependency graph and create systemdgen.ContainerInfo's for
+ // each container.
+ containerInfos := []*generate.ContainerInfo{podInfo}
+ for ctr, dependencies := range graph.DependencyMap() {
+ // Skip the infra container as we already generated it.
+ if ctr.ID() == infraID {
+ continue
+ }
+ ctrInfo, _, err := ic.generateSystemdgenContainerInfo(ctr.ID(), nil, options)
+ if err != nil {
+ return nil, err
+ }
+ // Now add the container's dependencies and at the container as a
+ // required service of the infra container.
+ for _, dep := range dependencies {
+ if dep.ID() == infraID {
+ ctrInfo.BoundToServices = append(ctrInfo.BoundToServices, podInfo.ServiceName)
+ } else {
+ _, serviceName := generateServiceName(dep, nil, options)
+ ctrInfo.BoundToServices = append(ctrInfo.BoundToServices, serviceName)
+ }
+ }
+ podInfo.RequiredServices = append(podInfo.RequiredServices, ctrInfo.ServiceName)
+ containerInfos = append(containerInfos, ctrInfo)
+ }
+
+ // Now generate the systemd service for all containers.
+ builder := strings.Builder{}
+ for i, info := range containerInfos {
+ if i > 0 {
+ builder.WriteByte('\n')
+ }
+ out, err := generate.CreateContainerSystemdUnit(info, opts)
+ if err != nil {
+ return nil, err
+ }
+ builder.WriteString(out)
+ }
+
+ return &entities.GenerateSystemdReport{Output: builder.String()}, nil
+}
+
+// generateSystemdgenContainerInfo is a helper to generate a
+// systemdgen.ContainerInfo for `GenerateSystemd`.
+func (ic *ContainerEngine) generateSystemdgenContainerInfo(nameOrID string, pod *libpod.Pod, options entities.GenerateSystemdOptions) (*generate.ContainerInfo, bool, error) {
+ ctr, err := ic.Libpod.LookupContainer(nameOrID)
+ if err != nil {
+ return nil, false, err
+ }
+
+ timeout := ctr.StopTimeout()
+ if options.StopTimeout != nil {
+ timeout = *options.StopTimeout
+ }
+
+ config := ctr.Config()
+ conmonPidFile := config.ConmonPidFile
+ if conmonPidFile == "" {
+ return nil, true, errors.Errorf("conmon PID file path is empty, try to recreate the container with --conmon-pidfile flag")
+ }
+
+ createCommand := []string{}
+ if config.CreateCommand != nil {
+ createCommand = config.CreateCommand
+ } else if options.New {
+ return nil, true, errors.Errorf("cannot use --new on container %q: no create command found", nameOrID)
+ }
+
+ name, serviceName := generateServiceName(ctr, pod, options)
+ info := &generate.ContainerInfo{
+ ServiceName: serviceName,
+ ContainerName: name,
+ RestartPolicy: options.RestartPolicy,
+ PIDFile: conmonPidFile,
+ StopTimeout: timeout,
+ GenerateTimestamp: true,
+ CreateCommand: createCommand,
+ }
+
+ return info, true, nil
+}
+
+// generateServiceName generates the container name and the service name for systemd service.
+func generateServiceName(ctr *libpod.Container, pod *libpod.Pod, options entities.GenerateSystemdOptions) (string, string) {
+ var kind, name, ctrName string
+ if pod == nil {
+ kind = "container"
+ name = ctr.ID()
+ if options.Name {
+ name = ctr.Name()
+ }
+ ctrName = name
+ } else {
+ kind = "pod"
+ name = pod.ID()
+ ctrName = ctr.ID()
+ if options.Name {
+ name = pod.Name()
+ ctrName = ctr.Name()
+ }
+ }
+ return ctrName, fmt.Sprintf("%s-%s", kind, name)
+}
diff --git a/pkg/domain/infra/abi/images.go b/pkg/domain/infra/abi/images.go
index 724bc5343..be788b2bf 100644
--- a/pkg/domain/infra/abi/images.go
+++ b/pkg/domain/infra/abi/images.go
@@ -46,7 +46,6 @@ func (ir *ImageEngine) Prune(ctx context.Context, opts entities.ImagePruneOption
Id: results,
Err: nil,
},
- Size: 0,
}
return &report, nil
}
@@ -119,7 +118,7 @@ func (ir *ImageEngine) Pull(ctx context.Context, rawImage string, options entiti
DockerCertPath: options.CertDir,
OSChoice: options.OverrideOS,
ArchitectureChoice: options.OverrideArch,
- DockerInsecureSkipTLSVerify: options.TLSVerify,
+ DockerInsecureSkipTLSVerify: options.SkipTLSVerify,
}
if !options.AllTags {
@@ -171,29 +170,24 @@ func (ir *ImageEngine) Pull(ctx context.Context, rawImage string, options entiti
return &entities.ImagePullReport{Images: foundIDs}, nil
}
-func (ir *ImageEngine) Inspect(ctx context.Context, names []string, opts entities.InspectOptions) (*entities.ImageInspectReport, error) {
- report := entities.ImageInspectReport{
- Errors: make(map[string]error),
- }
-
- for _, id := range names {
- img, err := ir.Libpod.ImageRuntime().NewFromLocal(id)
+func (ir *ImageEngine) Inspect(ctx context.Context, namesOrIDs []string, opts entities.InspectOptions) ([]*entities.ImageInspectReport, error) {
+ reports := []*entities.ImageInspectReport{}
+ for _, i := range namesOrIDs {
+ img, err := ir.Libpod.ImageRuntime().NewFromLocal(i)
if err != nil {
- report.Errors[id] = err
- continue
+ return nil, err
}
-
- results, err := img.Inspect(ctx)
+ result, err := img.Inspect(ctx)
if err != nil {
- report.Errors[id] = err
- continue
+ return nil, err
}
-
- cookedResults := entities.ImageData{}
- _ = domainUtils.DeepCopy(&cookedResults, results)
- report.Images = append(report.Images, &cookedResults)
+ report := entities.ImageInspectReport{}
+ if err := domainUtils.DeepCopy(&report, result); err != nil {
+ return nil, err
+ }
+ reports = append(reports, &report)
}
- return &report, nil
+ return reports, nil
}
func (ir *ImageEngine) Push(ctx context.Context, source string, destination string, options entities.ImagePushOptions) error {
@@ -227,7 +221,7 @@ func (ir *ImageEngine) Push(ctx context.Context, source string, destination stri
dockerRegistryOptions := image.DockerRegistryOptions{
DockerRegistryCreds: registryCreds,
DockerCertPath: options.CertDir,
- DockerInsecureSkipTLSVerify: options.TLSVerify,
+ DockerInsecureSkipTLSVerify: options.SkipTLSVerify,
}
signOptions := image.SigningOptions{
@@ -376,7 +370,7 @@ func (ir *ImageEngine) Search(ctx context.Context, term string, opts entities.Im
Filter: *filter,
Limit: opts.Limit,
NoTrunc: opts.NoTrunc,
- InsecureSkipTLSVerify: opts.TLSVerify,
+ InsecureSkipTLSVerify: opts.SkipTLSVerify,
}
searchResults, err := image.SearchImages(term, searchOpts)
@@ -475,6 +469,8 @@ func (ir *ImageEngine) Remove(ctx context.Context, images []string, opts entitie
switch errors.Cause(err) {
case nil:
break
+ case define.ErrNoSuchImage:
+ inUseErrors = true // ExitCode is expected
case storage.ErrImageUsedByContainer:
inUseErrors = true // Important for exit codes in Podman.
return errors.New(
@@ -546,7 +542,7 @@ func (ir *ImageEngine) Remove(ctx context.Context, images []string, opts entitie
noSuchImageErrors = true // Important for exit codes in Podman.
fallthrough
default:
- deleteError = multierror.Append(deleteError, err)
+ deleteError = multierror.Append(deleteError, errors.Wrapf(err, "failed to remove image '%s'", id))
continue
}
diff --git a/pkg/domain/infra/abi/images_list.go b/pkg/domain/infra/abi/images_list.go
index 9add915ea..c559e250c 100644
--- a/pkg/domain/infra/abi/images_list.go
+++ b/pkg/domain/infra/abi/images_list.go
@@ -25,8 +25,8 @@ func (ir *ImageEngine) List(ctx context.Context, opts entities.ImageListOptions)
return nil, err
}
- summaries := make([]*entities.ImageSummary, len(images))
- for i, img := range images {
+ var summaries []*entities.ImageSummary
+ for _, img := range images {
var repoTags []string
if opts.All {
pairs, err := libpodImage.ReposToMap(img.Names())
@@ -41,6 +41,9 @@ func (ir *ImageEngine) List(ctx context.Context, opts entities.ImageListOptions)
}
} else {
repoTags, _ = img.RepoTags()
+ if len(repoTags) == 0 {
+ continue
+ }
}
digests := make([]string, len(img.Digests()))
@@ -72,7 +75,7 @@ func (ir *ImageEngine) List(ctx context.Context, opts entities.ImageListOptions)
sz, _ := img.Size(context.TODO())
e.Size = int64(*sz)
- summaries[i] = &e
+ summaries = append(summaries, &e)
}
return summaries, nil
}
diff --git a/pkg/domain/infra/abi/pods.go b/pkg/domain/infra/abi/pods.go
index 7c06f9a4e..b286bcf0d 100644
--- a/pkg/domain/infra/abi/pods.go
+++ b/pkg/domain/infra/abi/pods.go
@@ -236,8 +236,6 @@ func (ic *ContainerEngine) PodRm(ctx context.Context, namesOrIds []string, optio
err := ic.Libpod.RemovePod(ctx, p, true, options.Force)
if err != nil {
report.Err = err
- reports = append(reports, &report)
- continue
}
reports = append(reports, &report)
}
diff --git a/pkg/domain/infra/tunnel/generate.go b/pkg/domain/infra/tunnel/generate.go
new file mode 100644
index 000000000..3cd483053
--- /dev/null
+++ b/pkg/domain/infra/tunnel/generate.go
@@ -0,0 +1,12 @@
+package tunnel
+
+import (
+ "context"
+
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/pkg/errors"
+)
+
+func (ic *ContainerEngine) GenerateSystemd(ctx context.Context, nameOrID string, options entities.GenerateSystemdOptions) (*entities.GenerateSystemdReport, error) {
+ return nil, errors.New("not implemented for tunnel")
+}
diff --git a/pkg/domain/infra/tunnel/images.go b/pkg/domain/infra/tunnel/images.go
index 66e4e6e3f..dcc5fc3e7 100644
--- a/pkg/domain/infra/tunnel/images.go
+++ b/pkg/domain/infra/tunnel/images.go
@@ -143,16 +143,16 @@ func (ir *ImageEngine) Untag(ctx context.Context, nameOrId string, tags []string
return nil
}
-func (ir *ImageEngine) Inspect(_ context.Context, names []string, opts entities.InspectOptions) (*entities.ImageInspectReport, error) {
- report := entities.ImageInspectReport{}
- for _, id := range names {
- r, err := images.GetImage(ir.ClientCxt, id, &opts.Size)
+func (ir *ImageEngine) Inspect(ctx context.Context, namesOrIDs []string, opts entities.InspectOptions) ([]*entities.ImageInspectReport, error) {
+ reports := []*entities.ImageInspectReport{}
+ for _, i := range namesOrIDs {
+ r, err := images.GetImage(ir.ClientCxt, i, &opts.Size)
if err != nil {
- report.Errors[id] = err
+ return nil, err
}
- report.Images = append(report.Images, r)
+ reports = append(reports, r)
}
- return &report, nil
+ return reports, nil
}
func (ir *ImageEngine) Load(ctx context.Context, opts entities.ImageLoadOptions) (*entities.ImageLoadReport, error) {
diff --git a/pkg/rootless/rootless_linux.c b/pkg/rootless/rootless_linux.c
index 72d461cdc..716db81dc 100644
--- a/pkg/rootless/rootless_linux.c
+++ b/pkg/rootless/rootless_linux.c
@@ -535,32 +535,30 @@ create_pause_process (const char *pause_pid_file_path, char **argv)
}
}
-static void
-join_namespace_or_die (int pid_to_join, const char *ns_file)
+static int
+open_namespace (int pid_to_join, const char *ns_file)
{
char ns_path[PATH_MAX];
int ret;
- int fd;
ret = snprintf (ns_path, PATH_MAX, "/proc/%d/ns/%s", pid_to_join, ns_file);
if (ret == PATH_MAX)
{
fprintf (stderr, "internal error: namespace path too long\n");
- _exit (EXIT_FAILURE);
+ return -1;
}
- fd = open (ns_path, O_CLOEXEC | O_RDONLY);
- if (fd < 0)
- {
- fprintf (stderr, "cannot open: %s\n", ns_path);
- _exit (EXIT_FAILURE);
- }
- if (setns (fd, 0) < 0)
+ return open (ns_path, O_CLOEXEC | O_RDONLY);
+}
+
+static void
+join_namespace_or_die (const char *name, int ns_fd)
+{
+ if (setns (ns_fd, 0) < 0)
{
- fprintf (stderr, "cannot set namespace to %s: %s\n", ns_path, strerror (errno));
+ fprintf (stderr, "cannot set %s namespace\n", name);
_exit (EXIT_FAILURE);
}
- close (fd);
}
int
@@ -570,6 +568,8 @@ reexec_userns_join (int pid_to_join, char *pause_pid_file_path)
char gid[16];
char **argv;
int pid;
+ int mnt_ns = -1;
+ int user_ns = -1;
char *cwd = getcwd (NULL, 0);
sigset_t sigset, oldsigset;
@@ -589,14 +589,28 @@ reexec_userns_join (int pid_to_join, char *pause_pid_file_path)
_exit (EXIT_FAILURE);
}
+ user_ns = open_namespace (pid_to_join, "user");
+ if (user_ns < 0)
+ return user_ns;
+ mnt_ns = open_namespace (pid_to_join, "mnt");
+ if (mnt_ns < 0)
+ {
+ close (user_ns);
+ return mnt_ns;
+ }
+
pid = fork ();
if (pid < 0)
fprintf (stderr, "cannot fork: %s\n", strerror (errno));
if (pid)
{
- /* We passed down these fds, close them. */
int f;
+
+ /* We passed down these fds, close them. */
+ close (user_ns);
+ close (mnt_ns);
+
for (f = 3; f < open_files_max_fd; f++)
if (open_files_set == NULL || FD_ISSET (f % FD_SETSIZE, &(open_files_set[f / FD_SETSIZE])))
close (f);
@@ -634,8 +648,10 @@ reexec_userns_join (int pid_to_join, char *pause_pid_file_path)
_exit (EXIT_FAILURE);
}
- join_namespace_or_die (pid_to_join, "user");
- join_namespace_or_die (pid_to_join, "mnt");
+ join_namespace_or_die ("user", user_ns);
+ join_namespace_or_die ("mnt", mnt_ns);
+ close (user_ns);
+ close (mnt_ns);
if (syscall_setresgid (0, 0, 0) < 0)
{
diff --git a/pkg/rootlessport/rootlessport_linux.go b/pkg/rootlessport/rootlessport_linux.go
index 1c1ed39df..c686d80fc 100644
--- a/pkg/rootlessport/rootlessport_linux.go
+++ b/pkg/rootlessport/rootlessport_linux.go
@@ -102,25 +102,27 @@ func parent() error {
return err
}
- sigC := make(chan os.Signal, 1)
- signal.Notify(sigC, unix.SIGPIPE)
- defer func() {
- // dummy signal to terminate the goroutine
- sigC <- unix.SIGKILL
- }()
+ exitC := make(chan os.Signal, 1)
+ defer close(exitC)
+
go func() {
+ sigC := make(chan os.Signal, 1)
+ signal.Notify(sigC, unix.SIGPIPE)
defer func() {
signal.Stop(sigC)
close(sigC)
}()
- s := <-sigC
- if s == unix.SIGPIPE {
- if f, err := os.OpenFile("/dev/null", os.O_WRONLY, 0755); err == nil {
- unix.Dup2(int(f.Fd()), 1) // nolint:errcheck
- unix.Dup2(int(f.Fd()), 2) // nolint:errcheck
- f.Close()
+ select {
+ case s := <-sigC:
+ if s == unix.SIGPIPE {
+ if f, err := os.OpenFile("/dev/null", os.O_WRONLY, 0755); err == nil {
+ unix.Dup2(int(f.Fd()), 1) // nolint:errcheck
+ unix.Dup2(int(f.Fd()), 2) // nolint:errcheck
+ f.Close()
+ }
}
+ case <-exitC:
}
}()
diff --git a/pkg/spec/spec.go b/pkg/spec/spec.go
index cb2403dec..41ed5f1f0 100644
--- a/pkg/spec/spec.go
+++ b/pkg/spec/spec.go
@@ -328,10 +328,6 @@ func (config *CreateConfig) createConfigToOCISpec(runtime *libpod.Runtime, userM
}
defaultEnv = env.Join(env.DefaultEnvVariables, defaultEnv)
}
- config.Env = env.Join(defaultEnv, config.Env)
- for name, val := range config.Env {
- g.AddProcessEnv(name, val)
- }
if err := addRlimits(config, &g); err != nil {
return nil, err
@@ -362,6 +358,11 @@ func (config *CreateConfig) createConfigToOCISpec(runtime *libpod.Runtime, userM
if err := config.Cgroup.ConfigureGenerator(&g); err != nil {
return nil, err
}
+
+ config.Env = env.Join(defaultEnv, config.Env)
+ for name, val := range config.Env {
+ g.AddProcessEnv(name, val)
+ }
configSpec := g.Config
// If the container image specifies an label with a
diff --git a/pkg/specgen/generate/container.go b/pkg/specgen/generate/container.go
index b27dd1cc2..92a2b4d35 100644
--- a/pkg/specgen/generate/container.go
+++ b/pkg/specgen/generate/container.go
@@ -3,6 +3,7 @@ package generate
import (
"context"
+ "github.com/containers/image/v5/manifest"
"github.com/containers/libpod/libpod"
ann "github.com/containers/libpod/pkg/annotations"
envLib "github.com/containers/libpod/pkg/env"
@@ -22,7 +23,12 @@ func CompleteSpec(ctx context.Context, r *libpod.Runtime, s *specgen.SpecGenerat
return err
}
- if s.HealthConfig == nil {
+ _, mediaType, err := newImage.Manifest(ctx)
+ if err != nil {
+ return err
+ }
+
+ if s.HealthConfig == nil && mediaType == manifest.DockerV2Schema2MediaType {
s.HealthConfig, err = newImage.GetHealthCheck(ctx)
if err != nil {
return err
@@ -126,13 +132,6 @@ func CompleteSpec(ctx context.Context, r *libpod.Runtime, s *specgen.SpecGenerat
if err != nil {
return err
}
-
- // TODO This should be enabled when namespaces actually work
- //case usernsMode.IsKeepID():
- // user = fmt.Sprintf("%d:%d", rootless.GetRootlessUID(), rootless.GetRootlessGID())
- if len(s.User) == 0 {
- s.User = "0"
- }
}
if err := finishThrottleDevices(s); err != nil {
return err
diff --git a/pkg/specgen/generate/container_create.go b/pkg/specgen/generate/container_create.go
index bb84f0618..14836035d 100644
--- a/pkg/specgen/generate/container_create.go
+++ b/pkg/specgen/generate/container_create.go
@@ -24,11 +24,10 @@ func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGener
// If joining a pod, retrieve the pod for use.
var pod *libpod.Pod
if s.Pod != "" {
- foundPod, err := rt.LookupPod(s.Pod)
+ pod, err = rt.LookupPod(s.Pod)
if err != nil {
return nil, errors.Wrapf(err, "error retrieving pod %s", s.Pod)
}
- pod = foundPod
}
// Set defaults for unset namespaces
@@ -76,6 +75,7 @@ func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGener
}
options := []libpod.CtrCreateOption{}
+ options = append(options, libpod.WithCreateCommand())
var newImage *image.Image
if s.Rootfs != "" {
@@ -129,12 +129,8 @@ func createContainerOptions(rt *libpod.Runtime, s *specgen.SpecGenerator, pod *l
logrus.Debugf("setting container name %s", s.Name)
options = append(options, libpod.WithName(s.Name))
}
- if s.Pod != "" {
- pod, err := rt.LookupPod(s.Pod)
- if err != nil {
- return nil, err
- }
- logrus.Debugf("adding container to pod %s", s.Pod)
+ if pod != nil {
+ logrus.Debugf("adding container to pod %s", pod.Name())
options = append(options, rt.WithPod(pod))
}
destinations := []string{}
@@ -159,11 +155,12 @@ func createContainerOptions(rt *libpod.Runtime, s *specgen.SpecGenerator, pod *l
options = append(options, libpod.WithNamedVolumes(vols))
}
- if len(s.Command) != 0 {
+ if s.Command != nil {
options = append(options, libpod.WithCommand(s.Command))
}
-
- options = append(options, libpod.WithEntrypoint(s.Entrypoint))
+ if s.Entrypoint != nil {
+ options = append(options, libpod.WithEntrypoint(s.Entrypoint))
+ }
if s.StopSignal != nil {
options = append(options, libpod.WithStopSignal(*s.StopSignal))
}
diff --git a/pkg/specgen/generate/oci.go b/pkg/specgen/generate/oci.go
index f2292f500..7993777fb 100644
--- a/pkg/specgen/generate/oci.go
+++ b/pkg/specgen/generate/oci.go
@@ -89,7 +89,7 @@ func makeCommand(ctx context.Context, s *specgen.SpecGenerator, img *image.Image
finalCommand = append(finalCommand, entrypoint...)
command := s.Command
- if len(command) == 0 && img != nil {
+ if command == nil && img != nil {
newCmd, err := img.Cmd(ctx)
if err != nil {
return nil, err
diff --git a/pkg/specgen/namespaces.go b/pkg/specgen/namespaces.go
index f0161a793..396563267 100644
--- a/pkg/specgen/namespaces.go
+++ b/pkg/specgen/namespaces.go
@@ -216,6 +216,8 @@ func ParseNetworkNamespace(ns string) (Namespace, []string, error) {
toReturn := Namespace{}
var cniNetworks []string
switch {
+ case ns == "slirp4netns":
+ toReturn.NSMode = Slirp
case ns == "pod":
toReturn.NSMode = FromPod
case ns == "bridge":
diff --git a/test/apiv2/10-images.at b/test/apiv2/10-images.at
index 42ec028d0..1c8da0c2f 100644
--- a/test/apiv2/10-images.at
+++ b/test/apiv2/10-images.at
@@ -7,15 +7,15 @@
podman pull -q $IMAGE
t GET libpod/images/json 200 \
- .[0].Id~[0-9a-f]\\{64\\}
-iid=$(jq -r '.[0].Id' <<<"$output")
+ .[0].ID~[0-9a-f]\\{64\\}
+iid=$(jq -r '.[0].ID' <<<"$output")
t GET libpod/images/$iid/exists 204
t GET libpod/images/$PODMAN_TEST_IMAGE_NAME/exists 204
# FIXME: compare to actual podman info
t GET libpod/images/json 200 \
- .[0].Id=${iid}
+ .[0].ID=${iid}
t GET libpod/images/$iid/json 200 \
.Id=$iid \
diff --git a/test/e2e/attach_test.go b/test/e2e/attach_test.go
index 6ca8a537c..7233d169c 100644
--- a/test/e2e/attach_test.go
+++ b/test/e2e/attach_test.go
@@ -20,7 +20,6 @@ var _ = Describe("Podman attach", func() {
)
BeforeEach(func() {
- Skip(v2fail)
tempdir, err = CreateTempDirInTempDir()
if err != nil {
os.Exit(1)
diff --git a/test/e2e/build_test.go b/test/e2e/build_test.go
index 3ccee3575..76651283a 100644
--- a/test/e2e/build_test.go
+++ b/test/e2e/build_test.go
@@ -22,7 +22,6 @@ var _ = Describe("Podman build", func() {
)
BeforeEach(func() {
- Skip(v2fail)
tempdir, err = CreateTempDirInTempDir()
if err != nil {
os.Exit(1)
@@ -178,6 +177,7 @@ var _ = Describe("Podman build", func() {
})
It("podman Test PATH in built image", func() {
+ Skip(v2fail) // Run error - we don't set data from the image (i.e., PATH) yet
path := "/tmp:/bin:/usr/bin:/usr/sbin"
session := podmanTest.PodmanNoCache([]string{
"build", "-f", "build/basicalpine/Containerfile.path", "-t", "test-path",
diff --git a/test/e2e/common_test.go b/test/e2e/common_test.go
index 160af1bd5..68f733b41 100644
--- a/test/e2e/common_test.go
+++ b/test/e2e/common_test.go
@@ -1,7 +1,6 @@
package integration
import (
- "encoding/json"
"fmt"
"io/ioutil"
"math/rand"
@@ -21,9 +20,10 @@ import (
"github.com/containers/storage"
"github.com/containers/storage/pkg/reexec"
"github.com/containers/storage/pkg/stringid"
+ jsoniter "github.com/json-iterator/go"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
- "github.com/onsi/gomega/gexec"
+ . "github.com/onsi/gomega/gexec"
"github.com/pkg/errors"
)
@@ -314,7 +314,7 @@ func (p *PodmanTestIntegration) createArtifact(image string) {
// image and returns json
func (s *PodmanSessionIntegration) InspectImageJSON() []inspect.ImageData {
var i []inspect.ImageData
- err := json.Unmarshal(s.Out.Contents(), &i)
+ err := jsoniter.Unmarshal(s.Out.Contents(), &i)
Expect(err).To(BeNil())
return i
}
@@ -324,7 +324,7 @@ func (p *PodmanTestIntegration) InspectContainer(name string) []define.InspectCo
cmd := []string{"inspect", name}
session := p.Podman(cmd)
session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
+ Expect(session).Should(Exit(0))
return session.InspectContainerToJSON()
}
@@ -419,7 +419,7 @@ func (p *PodmanTestIntegration) PodmanPID(args []string) (*PodmanSessionIntegrat
podmanOptions := p.MakeOptions(args, false, false)
fmt.Printf("Running: %s %s\n", p.PodmanBinary, strings.Join(podmanOptions, " "))
command := exec.Command(p.PodmanBinary, podmanOptions...)
- session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter)
+ session, err := Start(command, GinkgoWriter, GinkgoWriter)
if err != nil {
Fail(fmt.Sprintf("unable to run podman command: %s", strings.Join(podmanOptions, " ")))
}
@@ -494,7 +494,7 @@ func (p *PodmanTestIntegration) PullImage(image string) error {
// container and returns json
func (s *PodmanSessionIntegration) InspectContainerToJSON() []define.InspectContainerData {
var i []define.InspectContainerData
- err := json.Unmarshal(s.Out.Contents(), &i)
+ err := jsoniter.Unmarshal(s.Out.Contents(), &i)
Expect(err).To(BeNil())
return i
}
@@ -502,7 +502,7 @@ func (s *PodmanSessionIntegration) InspectContainerToJSON() []define.InspectCont
// InspectPodToJSON takes the sessions output from a pod inspect and returns json
func (s *PodmanSessionIntegration) InspectPodToJSON() define.InspectPodData {
var i define.InspectPodData
- err := json.Unmarshal(s.Out.Contents(), &i)
+ err := jsoniter.Unmarshal(s.Out.Contents(), &i)
Expect(err).To(BeNil())
return i
}
diff --git a/test/e2e/cp_test.go b/test/e2e/cp_test.go
index 2ff6fe65e..f95f8646c 100644
--- a/test/e2e/cp_test.go
+++ b/test/e2e/cp_test.go
@@ -22,7 +22,6 @@ var _ = Describe("Podman cp", func() {
)
BeforeEach(func() {
- Skip(v2fail)
tempdir, err = CreateTempDirInTempDir()
if err != nil {
os.Exit(1)
@@ -96,7 +95,7 @@ var _ = Describe("Podman cp", func() {
})
It("podman cp dir to dir", func() {
- testDirPath := filepath.Join(podmanTest.RunRoot, "TestDir")
+ testDirPath := filepath.Join(podmanTest.RunRoot, "TestDir1")
session := podmanTest.Podman([]string{"create", ALPINE, "ls", "/foodir"})
session.WaitWithDefaultTimeout()
@@ -105,6 +104,7 @@ var _ = Describe("Podman cp", func() {
err := os.Mkdir(testDirPath, 0755)
Expect(err).To(BeNil())
+ defer os.RemoveAll(testDirPath)
session = podmanTest.Podman([]string{"cp", testDirPath, name + ":/foodir"})
session.WaitWithDefaultTimeout()
@@ -138,8 +138,6 @@ var _ = Describe("Podman cp", func() {
res, err := cmd.Output()
Expect(err).To(BeNil())
Expect(len(res)).To(Equal(0))
-
- os.RemoveAll(testDirPath)
})
It("podman cp stdin/stdout", func() {
@@ -148,9 +146,10 @@ var _ = Describe("Podman cp", func() {
Expect(session.ExitCode()).To(Equal(0))
name := session.OutputToString()
- testDirPath := filepath.Join(podmanTest.RunRoot, "TestDir")
+ testDirPath := filepath.Join(podmanTest.RunRoot, "TestDir2")
err := os.Mkdir(testDirPath, 0755)
Expect(err).To(BeNil())
+ defer os.RemoveAll(testDirPath)
cmd := exec.Command("tar", "-zcvf", "file.tar.gz", testDirPath)
_, err = cmd.Output()
Expect(err).To(BeNil())
@@ -169,7 +168,6 @@ var _ = Describe("Podman cp", func() {
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- os.RemoveAll(testDirPath)
os.Remove("file.tar.gz")
})
@@ -185,9 +183,10 @@ var _ = Describe("Podman cp", func() {
path, err := os.Getwd()
Expect(err).To(BeNil())
- testDirPath := filepath.Join(path, "TestDir")
+ testDirPath := filepath.Join(path, "TestDir3")
err = os.Mkdir(testDirPath, 0777)
Expect(err).To(BeNil())
+ defer os.RemoveAll(testDirPath)
cmd := exec.Command("tar", "-cvf", "file.tar", testDirPath)
_, err = cmd.Output()
Expect(err).To(BeNil())
@@ -202,7 +201,6 @@ var _ = Describe("Podman cp", func() {
Expect(session.OutputToString()).To(ContainSubstring("file.tar"))
os.Remove("file.tar")
- os.RemoveAll(testDirPath)
})
It("podman cp symlink", func() {
diff --git a/test/e2e/create_test.go b/test/e2e/create_test.go
index 82346823a..10742a0e8 100644
--- a/test/e2e/create_test.go
+++ b/test/e2e/create_test.go
@@ -18,7 +18,6 @@ var _ = Describe("Podman create", func() {
)
BeforeEach(func() {
- Skip(v2fail)
tempdir, err = CreateTempDirInTempDir()
if err != nil {
os.Exit(1)
diff --git a/test/e2e/exec_test.go b/test/e2e/exec_test.go
index 3aac4b35b..8b95794d2 100644
--- a/test/e2e/exec_test.go
+++ b/test/e2e/exec_test.go
@@ -18,7 +18,6 @@ var _ = Describe("Podman exec", func() {
)
BeforeEach(func() {
- Skip(v2fail)
tempdir, err = CreateTempDirInTempDir()
if err != nil {
os.Exit(1)
diff --git a/test/e2e/generate_systemd_test.go b/test/e2e/generate_systemd_test.go
index 2901e7ac6..abfca4db9 100644
--- a/test/e2e/generate_systemd_test.go
+++ b/test/e2e/generate_systemd_test.go
@@ -18,7 +18,6 @@ var _ = Describe("Podman generate systemd", func() {
)
BeforeEach(func() {
- Skip(v2fail)
tempdir, err = CreateTempDirInTempDir()
if err != nil {
os.Exit(1)
diff --git a/test/e2e/images_test.go b/test/e2e/images_test.go
index c0165e060..d7295b67a 100644
--- a/test/e2e/images_test.go
+++ b/test/e2e/images_test.go
@@ -10,6 +10,7 @@ import (
"github.com/docker/go-units"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
+ . "github.com/onsi/gomega/gexec"
)
var _ = Describe("Podman images", func() {
@@ -20,7 +21,6 @@ var _ = Describe("Podman images", func() {
)
BeforeEach(func() {
- Skip(v2fail)
tempdir, err = CreateTempDirInTempDir()
if err != nil {
os.Exit(1)
@@ -39,7 +39,7 @@ var _ = Describe("Podman images", func() {
It("podman images", func() {
session := podmanTest.Podman([]string{"images"})
session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
+ Expect(session).Should(Exit(0))
Expect(len(session.OutputToStringArray())).To(BeNumerically(">", 2))
Expect(session.LineInOuputStartsWith("docker.io/library/alpine")).To(BeTrue())
Expect(session.LineInOuputStartsWith("docker.io/library/busybox")).To(BeTrue())
@@ -48,11 +48,11 @@ var _ = Describe("Podman images", func() {
It("podman images with no images prints header", func() {
rmi := podmanTest.PodmanNoCache([]string{"rmi", "-a"})
rmi.WaitWithDefaultTimeout()
- Expect(rmi.ExitCode()).To(Equal(0))
+ Expect(rmi).Should(Exit(0))
session := podmanTest.PodmanNoCache([]string{"images"})
session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
+ Expect(session).Should(Exit(0))
Expect(len(session.OutputToStringArray())).To(Equal(1))
Expect(session.LineInOutputContains("REPOSITORY")).To(BeTrue())
})
@@ -60,7 +60,7 @@ var _ = Describe("Podman images", func() {
It("podman image List", func() {
session := podmanTest.Podman([]string{"image", "list"})
session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
+ Expect(session).Should(Exit(0))
Expect(len(session.OutputToStringArray())).To(BeNumerically(">", 2))
Expect(session.LineInOuputStartsWith("docker.io/library/alpine")).To(BeTrue())
Expect(session.LineInOuputStartsWith("docker.io/library/busybox")).To(BeTrue())
@@ -71,15 +71,15 @@ var _ = Describe("Podman images", func() {
podmanTest.RestoreAllArtifacts()
session := podmanTest.PodmanNoCache([]string{"tag", ALPINE, "foo:a", "foo:b", "foo:c"})
session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
+ Expect(session).Should(Exit(0))
// tag "foo:c" to "bar:{a,b}"
session = podmanTest.PodmanNoCache([]string{"tag", "foo:c", "bar:a", "bar:b"})
session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
+ Expect(session).Should(Exit(0))
// check all previous and the newly tagged images
session = podmanTest.PodmanNoCache([]string{"images"})
session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
+ Expect(session).Should(Exit(0))
session.LineInOutputContainsTag("docker.io/library/alpine", "latest")
session.LineInOutputContainsTag("docker.io/library/busybox", "glibc")
session.LineInOutputContainsTag("foo", "a")
@@ -89,14 +89,14 @@ var _ = Describe("Podman images", func() {
session.LineInOutputContainsTag("bar", "b")
session = podmanTest.PodmanNoCache([]string{"images", "-qn"})
session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
+ Expect(session).Should(Exit(0))
Expect(len(session.OutputToStringArray())).To(BeNumerically("==", 2))
})
It("podman images with digests", func() {
session := podmanTest.Podman([]string{"images", "--digests"})
session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
+ Expect(session).Should(Exit(0))
Expect(len(session.OutputToStringArray())).To(BeNumerically(">", 2))
Expect(session.LineInOuputStartsWith("docker.io/library/alpine")).To(BeTrue())
Expect(session.LineInOuputStartsWith("docker.io/library/busybox")).To(BeTrue())
@@ -105,14 +105,14 @@ var _ = Describe("Podman images", func() {
It("podman empty images list in JSON format", func() {
session := podmanTest.Podman([]string{"images", "--format=json", "not-existing-image"})
session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
+ Expect(session).Should(Exit(0))
Expect(session.IsJSONOutputValid()).To(BeTrue())
})
It("podman images in JSON format", func() {
session := podmanTest.Podman([]string{"images", "--format=json"})
session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
+ Expect(session).Should(Exit(0))
Expect(session.IsJSONOutputValid()).To(BeTrue())
})
@@ -120,13 +120,13 @@ var _ = Describe("Podman images", func() {
formatStr := "{{.ID}}\t{{.Created}}\t{{.CreatedAt}}\t{{.CreatedSince}}\t{{.CreatedTime}}"
session := podmanTest.Podman([]string{"images", fmt.Sprintf("--format=%s", formatStr)})
session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
+ Expect(session).Should(Exit(0))
})
It("podman images with short options", func() {
session := podmanTest.Podman([]string{"images", "-qn"})
session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
+ Expect(session).Should(Exit(0))
Expect(len(session.OutputToStringArray())).To(BeNumerically(">", 1))
})
@@ -134,19 +134,19 @@ var _ = Describe("Podman images", func() {
podmanTest.RestoreAllArtifacts()
session := podmanTest.PodmanNoCache([]string{"images", "-q", ALPINE})
session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
+ Expect(session).Should(Exit(0))
Expect(len(session.OutputToStringArray())).To(Equal(1))
session = podmanTest.PodmanNoCache([]string{"tag", ALPINE, "foo:a"})
session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
+ Expect(session).Should(Exit(0))
session = podmanTest.PodmanNoCache([]string{"tag", BB, "foo:b"})
session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
+ Expect(session).Should(Exit(0))
session = podmanTest.PodmanNoCache([]string{"images", "-q", "foo"})
session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
+ Expect(session).Should(Exit(0))
Expect(len(session.OutputToStringArray())).To(Equal(2))
})
@@ -157,24 +157,24 @@ var _ = Describe("Podman images", func() {
podmanTest.RestoreAllArtifacts()
result := podmanTest.PodmanNoCache([]string{"images", "-q", "-f", "reference=docker.io*"})
result.WaitWithDefaultTimeout()
- Expect(result.ExitCode()).To(Equal(0))
+ Expect(result).Should(Exit(0))
Expect(len(result.OutputToStringArray())).To(Equal(2))
retapline := podmanTest.PodmanNoCache([]string{"images", "-f", "reference=a*pine"})
retapline.WaitWithDefaultTimeout()
- Expect(retapline.ExitCode()).To(Equal(0))
+ Expect(retapline).Should(Exit(0))
Expect(len(retapline.OutputToStringArray())).To(Equal(2))
Expect(retapline.LineInOutputContains("alpine")).To(BeTrue())
retapline = podmanTest.PodmanNoCache([]string{"images", "-f", "reference=alpine"})
retapline.WaitWithDefaultTimeout()
- Expect(retapline.ExitCode()).To(Equal(0))
+ Expect(retapline).Should(Exit(0))
Expect(len(retapline.OutputToStringArray())).To(Equal(2))
Expect(retapline.LineInOutputContains("alpine")).To(BeTrue())
retnone := podmanTest.PodmanNoCache([]string{"images", "-q", "-f", "reference=bogus"})
retnone.WaitWithDefaultTimeout()
- Expect(retnone.ExitCode()).To(Equal(0))
+ Expect(retnone).Should(Exit(0))
Expect(len(retnone.OutputToStringArray())).To(Equal(0))
})
@@ -188,7 +188,7 @@ RUN apk update && apk add man
podmanTest.BuildImage(dockerfile, "foobar.com/before:latest", "false")
result := podmanTest.Podman([]string{"images", "-q", "-f", "before=foobar.com/before:latest"})
result.WaitWithDefaultTimeout()
- Expect(result.ExitCode()).To(Equal(0))
+ Expect(result).Should(Exit(0))
Expect(len(result.OutputToStringArray()) >= 1).To(BeTrue())
})
@@ -199,14 +199,14 @@ RUN apk update && apk add man
podmanTest.RestoreAllArtifacts()
rmi := podmanTest.PodmanNoCache([]string{"rmi", "busybox"})
rmi.WaitWithDefaultTimeout()
- Expect(rmi.ExitCode()).To(Equal(0))
+ Expect(rmi).Should(Exit(0))
dockerfile := `FROM docker.io/library/alpine:latest
`
podmanTest.BuildImage(dockerfile, "foobar.com/before:latest", "false")
result := podmanTest.PodmanNoCache([]string{"images", "-q", "-f", "after=docker.io/library/alpine:latest"})
result.WaitWithDefaultTimeout()
- Expect(result.ExitCode()).To(Equal(0))
+ Expect(result).Should(Exit(0))
Expect(len(result.OutputToStringArray())).To(Equal(0))
})
@@ -217,14 +217,14 @@ RUN apk update && apk add man
podmanTest.RestoreAllArtifacts()
rmi := podmanTest.PodmanNoCache([]string{"image", "rm", "busybox"})
rmi.WaitWithDefaultTimeout()
- Expect(rmi.ExitCode()).To(Equal(0))
+ Expect(rmi).Should(Exit(0))
dockerfile := `FROM docker.io/library/alpine:latest
`
podmanTest.BuildImage(dockerfile, "foobar.com/before:latest", "false")
result := podmanTest.PodmanNoCache([]string{"image", "list", "-q", "-f", "after=docker.io/library/alpine:latest"})
result.WaitWithDefaultTimeout()
- Expect(result.ExitCode()).To(Equal(0))
+ Expect(result).Should(Exit(0))
Expect(len(result.OutputToStringArray())).To(Equal(0))
})
@@ -238,7 +238,7 @@ RUN apk update && apk add man
podmanTest.BuildImage(dockerfile, "foobar.com/before:latest", "false")
result := podmanTest.Podman([]string{"images", "-q", "-f", "dangling=true"})
result.WaitWithDefaultTimeout()
- Expect(result.ExitCode()).To(Equal(0))
+ Expect(result).Should(Exit(0))
Expect(len(result.OutputToStringArray())).To(Equal(0))
})
@@ -248,13 +248,13 @@ RUN apk update && apk add man
}
session := podmanTest.Podman([]string{"inspect", "--format=json", ALPINE})
session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
+ Expect(session).Should(Exit(0))
Expect(session.IsJSONOutputValid()).To(BeTrue())
imageData := session.InspectImageJSON()
- result := podmanTest.Podman([]string{"images", fmt.Sprintf("sha256:%s", imageData[0].ID)})
+ result := podmanTest.Podman([]string{"images", "sha256:" + imageData[0].ID})
result.WaitWithDefaultTimeout()
- Expect(result.ExitCode()).To(Equal(0))
+ Expect(result).Should(Exit(0))
})
It("podman check for image with sha256: prefix", func() {
@@ -263,13 +263,13 @@ RUN apk update && apk add man
}
session := podmanTest.Podman([]string{"image", "inspect", "--format=json", ALPINE})
session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
+ Expect(session).Should(Exit(0))
Expect(session.IsJSONOutputValid()).To(BeTrue())
imageData := session.InspectImageJSON()
result := podmanTest.Podman([]string{"image", "ls", fmt.Sprintf("sha256:%s", imageData[0].ID)})
result.WaitWithDefaultTimeout()
- Expect(result.ExitCode()).To(Equal(0))
+ Expect(result).Should(Exit(0))
})
It("podman images sort by values", func() {
@@ -277,7 +277,7 @@ RUN apk update && apk add man
f := fmt.Sprintf("{{.%s}}", format)
session := podmanTest.Podman([]string{"images", "--sort", value, "--format", f})
session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(result))
+ Expect(session).Should(Exit(result))
return session.OutputToStringArray()
}
@@ -298,7 +298,9 @@ RUN apk update && apk add man
return size1 < size2
})).To(BeTrue())
sortedArr = sortValueTest("tag", 0, "Tag")
- Expect(sort.SliceIsSorted(sortedArr, func(i, j int) bool { return sortedArr[i] < sortedArr[j] })).To(BeTrue())
+ Expect(sort.SliceIsSorted(sortedArr,
+ func(i, j int) bool { return sortedArr[i] < sortedArr[j] })).
+ To(BeTrue())
sortValueTest("badvalue", 125, "Tag")
sortValueTest("id", 125, "badvalue")
@@ -317,12 +319,12 @@ ENV foo=bar
podmanTest.BuildImage(dockerfile, "test", "true")
session := podmanTest.PodmanNoCache([]string{"images"})
session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
+ Expect(session).Should(Exit(0))
Expect(len(session.OutputToStringArray())).To(Equal(4))
session2 := podmanTest.PodmanNoCache([]string{"images", "--all"})
session2.WaitWithDefaultTimeout()
- Expect(session2.ExitCode()).To(Equal(0))
+ Expect(session2).Should(Exit(0))
Expect(len(session2.OutputToStringArray())).To(Equal(6))
})
@@ -335,7 +337,7 @@ LABEL "com.example.vendor"="Example Vendor"
podmanTest.BuildImage(dockerfile, "test", "true")
session := podmanTest.Podman([]string{"images", "-f", "label=version=1.0"})
session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
+ Expect(session).Should(Exit(0))
Expect(len(session.OutputToStringArray())).To(Equal(2))
})
@@ -357,52 +359,52 @@ LABEL "com.example.vendor"="Example Vendor"
session := podmanTest.Podman([]string{"images", "foo"})
session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
+ Expect(session).Should(Exit(0))
output := session.OutputToString()
Expect(output).To(Not(MatchRegexp("<missing>")))
Expect(output).To(Not(MatchRegexp("error")))
session = podmanTest.Podman([]string{"image", "tree", "foo"})
session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
+ Expect(session).Should(Exit(0))
output = session.OutputToString()
Expect(output).To(MatchRegexp("No Image Layers"))
session = podmanTest.Podman([]string{"history", "foo"})
session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
+ Expect(session).Should(Exit(0))
output = session.OutputToString()
Expect(output).To(Not(MatchRegexp("error")))
session = podmanTest.Podman([]string{"history", "--quiet", "foo"})
session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
+ Expect(session).Should(Exit(0))
Expect(len(session.OutputToStringArray())).To(Equal(6))
session = podmanTest.Podman([]string{"image", "list", "foo"})
session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
+ Expect(session).Should(Exit(0))
output = session.OutputToString()
Expect(output).To(Not(MatchRegexp("<missing>")))
Expect(output).To(Not(MatchRegexp("error")))
session = podmanTest.Podman([]string{"image", "list"})
session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
+ Expect(session).Should(Exit(0))
output = session.OutputToString()
Expect(output).To(Not(MatchRegexp("<missing>")))
Expect(output).To(Not(MatchRegexp("error")))
session = podmanTest.Podman([]string{"inspect", "foo"})
session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
+ Expect(session).Should(Exit(0))
output = session.OutputToString()
Expect(output).To(Not(MatchRegexp("<missing>")))
Expect(output).To(Not(MatchRegexp("error")))
session = podmanTest.Podman([]string{"inspect", "--format", "{{.RootFS.Layers}}", "foo"})
session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
+ Expect(session).Should(Exit(0))
output = session.OutputToString()
Expect(output).To(Equal("[]"))
})
@@ -414,11 +416,11 @@ LABEL "com.example.vendor"="Example Vendor"
podmanTest.BuildImage(dockerfile, "foobar.com/before:latest", "false")
result := podmanTest.Podman([]string{"images", "-f", "readonly=true"})
result.WaitWithDefaultTimeout()
- Expect(result.ExitCode()).To(Equal(0))
+ Expect(result).Should(Exit(0))
result1 := podmanTest.Podman([]string{"images", "--filter", "readonly=false"})
result1.WaitWithDefaultTimeout()
- Expect(result1.ExitCode()).To(Equal(0))
+ Expect(result1).Should(Exit(0))
Expect(result.OutputToStringArray()).To(Not(Equal(result1.OutputToStringArray())))
})
diff --git a/test/e2e/inspect_test.go b/test/e2e/inspect_test.go
index 5ec1b51bb..ebac087ac 100644
--- a/test/e2e/inspect_test.go
+++ b/test/e2e/inspect_test.go
@@ -17,7 +17,6 @@ var _ = Describe("Podman inspect", func() {
)
BeforeEach(func() {
- Skip(v2fail)
tempdir, err = CreateTempDirInTempDir()
if err != nil {
os.Exit(1)
diff --git a/test/e2e/prune_test.go b/test/e2e/prune_test.go
index e8a208c3c..466a4f739 100644
--- a/test/e2e/prune_test.go
+++ b/test/e2e/prune_test.go
@@ -22,7 +22,6 @@ var _ = Describe("Podman prune", func() {
)
BeforeEach(func() {
- Skip(v2fail)
tempdir, err = CreateTempDirInTempDir()
if err != nil {
os.Exit(1)
@@ -149,6 +148,7 @@ var _ = Describe("Podman prune", func() {
It("podman system image prune unused images", func() {
SkipIfRemote()
+ Skip(v2fail)
podmanTest.RestoreAllArtifacts()
podmanTest.BuildImage(pruneImage, "alpine_bash:latest", "true")
prune := podmanTest.PodmanNoCache([]string{"system", "prune", "-a", "--force"})
@@ -162,6 +162,7 @@ var _ = Describe("Podman prune", func() {
})
It("podman system prune pods", func() {
+ Skip(v2fail)
session := podmanTest.Podman([]string{"pod", "create"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
diff --git a/test/e2e/push_test.go b/test/e2e/push_test.go
index 0991da867..0747257be 100644
--- a/test/e2e/push_test.go
+++ b/test/e2e/push_test.go
@@ -22,7 +22,6 @@ var _ = Describe("Podman push", func() {
)
BeforeEach(func() {
- Skip(v2fail)
tempdir, err = CreateTempDirInTempDir()
if err != nil {
os.Exit(1)
diff --git a/test/e2e/rmi_test.go b/test/e2e/rmi_test.go
index d556cbc72..6c0b01bd5 100644
--- a/test/e2e/rmi_test.go
+++ b/test/e2e/rmi_test.go
@@ -141,12 +141,13 @@ var _ = Describe("Podman rmi", func() {
session = podmanTest.PodmanNoCache([]string{"images", "-q", "-a"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
- Expect(len(session.OutputToStringArray())).To(Equal(2))
- untaggedImg := session.OutputToStringArray()[1]
+ Expect(len(session.OutputToStringArray())).To(Equal(2),
+ "Output from 'podman images -q -a':'%s'", session.Out.Contents())
+ untaggedImg := session.OutputToStringArray()[0]
session = podmanTest.PodmanNoCache([]string{"rmi", "-f", untaggedImg})
session.WaitWithDefaultTimeout()
- Expect(session).Should(Exit(2))
+ Expect(session).Should(Exit(2), "UntaggedImg is '%s'", untaggedImg)
})
It("podman rmi image that is created from another named imaged", func() {
diff --git a/test/e2e/run_entrypoint_test.go b/test/e2e/run_entrypoint_test.go
index ebc06b36c..b1344a371 100644
--- a/test/e2e/run_entrypoint_test.go
+++ b/test/e2e/run_entrypoint_test.go
@@ -18,7 +18,6 @@ var _ = Describe("Podman run entrypoint", func() {
)
BeforeEach(func() {
- Skip(v2fail)
tempdir, err = CreateTempDirInTempDir()
if err != nil {
os.Exit(1)
diff --git a/test/e2e/run_env_test.go b/test/e2e/run_env_test.go
new file mode 100644
index 000000000..867913a08
--- /dev/null
+++ b/test/e2e/run_env_test.go
@@ -0,0 +1,138 @@
+// +build !remoteclient
+
+package integration
+
+import (
+ "os"
+
+ . "github.com/containers/libpod/test/utils"
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+)
+
+var _ = Describe("Podman run", func() {
+ var (
+ tempdir string
+ err error
+ podmanTest *PodmanTestIntegration
+ )
+
+ BeforeEach(func() {
+ tempdir, err = CreateTempDirInTempDir()
+ if err != nil {
+ os.Exit(1)
+ }
+ podmanTest = PodmanTestCreate(tempdir)
+ podmanTest.Setup()
+ podmanTest.SeedImages()
+ })
+
+ AfterEach(func() {
+ podmanTest.Cleanup()
+ f := CurrentGinkgoTestDescription()
+ processTestResult(f)
+
+ })
+
+ It("podman run environment test", func() {
+ session := podmanTest.Podman([]string{"run", "--rm", ALPINE, "printenv", "HOME"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ match, _ := session.GrepString("/root")
+ Expect(match).Should(BeTrue())
+
+ session = podmanTest.Podman([]string{"run", "--rm", "--user", "2", ALPINE, "printenv", "HOME"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ match, _ = session.GrepString("/sbin")
+ Expect(match).Should(BeTrue())
+
+ session = podmanTest.Podman([]string{"run", "--rm", "--env", "HOME=/foo", ALPINE, "printenv", "HOME"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ match, _ = session.GrepString("/foo")
+ Expect(match).Should(BeTrue())
+
+ session = podmanTest.Podman([]string{"run", "--rm", "--env", "FOO=BAR,BAZ", ALPINE, "printenv", "FOO"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ match, _ = session.GrepString("BAR,BAZ")
+ Expect(match).Should(BeTrue())
+
+ session = podmanTest.Podman([]string{"run", "--rm", "--env", "PATH=/bin", ALPINE, "printenv", "PATH"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ match, _ = session.GrepString("/bin")
+ Expect(match).Should(BeTrue())
+
+ os.Setenv("FOO", "BAR")
+ session = podmanTest.Podman([]string{"run", "--rm", "--env", "FOO", ALPINE, "printenv", "FOO"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ match, _ = session.GrepString("BAR")
+ Expect(match).Should(BeTrue())
+ os.Unsetenv("FOO")
+
+ session = podmanTest.Podman([]string{"run", "--rm", "--env", "FOO", ALPINE, "printenv", "FOO"})
+ session.WaitWithDefaultTimeout()
+ Expect(len(session.OutputToString())).To(Equal(0))
+ Expect(session.ExitCode()).To(Equal(1))
+
+ session = podmanTest.Podman([]string{"run", "--rm", ALPINE, "printenv"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ // This currently does not work
+ // Re-enable when hostname is an env variable
+ session = podmanTest.Podman([]string{"run", "--rm", ALPINE, "sh", "-c", "printenv"})
+ session.Wait(10)
+ Expect(session.ExitCode()).To(Equal(0))
+ match, _ = session.GrepString("HOSTNAME")
+ Expect(match).Should(BeTrue())
+ })
+
+ It("podman run --host-env environment test", func() {
+ env := append(os.Environ(), "FOO=BAR")
+ session := podmanTest.PodmanAsUser([]string{"run", "--rm", "--env-host", ALPINE, "/bin/printenv", "FOO"}, 0, 0, "", env)
+
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ match, _ := session.GrepString("BAR")
+ Expect(match).Should(BeTrue())
+
+ session = podmanTest.PodmanAsUser([]string{"run", "--rm", "--env", "FOO=BAR1", "--env-host", ALPINE, "/bin/printenv", "FOO"}, 0, 0, "", env)
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ match, _ = session.GrepString("BAR1")
+ Expect(match).Should(BeTrue())
+ os.Unsetenv("FOO")
+ })
+
+ It("podman run --http-proxy test", func() {
+ os.Setenv("http_proxy", "1.2.3.4")
+ session := podmanTest.Podman([]string{"run", "--rm", ALPINE, "printenv", "http_proxy"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ match, _ := session.GrepString("1.2.3.4")
+ Expect(match).Should(BeTrue())
+
+ session = podmanTest.Podman([]string{"run", "--http-proxy=false", ALPINE, "printenv", "http_proxy"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(1))
+ Expect(session.OutputToString()).To(Equal(""))
+
+ session = podmanTest.Podman([]string{"run", "--env", "http_proxy=5.6.7.8", ALPINE, "printenv", "http_proxy"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ match, _ = session.GrepString("5.6.7.8")
+ Expect(match).Should(BeTrue())
+ os.Unsetenv("http_proxy")
+
+ session = podmanTest.Podman([]string{"run", "--http-proxy=false", "--env", "http_proxy=5.6.7.8", ALPINE, "printenv", "http_proxy"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ match, _ = session.GrepString("5.6.7.8")
+ Expect(match).Should(BeTrue())
+ os.Unsetenv("http_proxy")
+ })
+})
diff --git a/test/e2e/run_test.go b/test/e2e/run_test.go
index 7d4039819..59215c7e5 100644
--- a/test/e2e/run_test.go
+++ b/test/e2e/run_test.go
@@ -193,80 +193,6 @@ var _ = Describe("Podman run", func() {
Expect(session.ExitCode()).To(Equal(0))
})
- It("podman run environment test", func() {
- session := podmanTest.Podman([]string{"run", "--rm", ALPINE, "printenv", "HOME"})
- session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
- match, _ := session.GrepString("/root")
- Expect(match).Should(BeTrue())
-
- session = podmanTest.Podman([]string{"run", "--rm", "--user", "2", ALPINE, "printenv", "HOME"})
- session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
- match, _ = session.GrepString("/sbin")
- Expect(match).Should(BeTrue())
-
- session = podmanTest.Podman([]string{"run", "--rm", "--env", "HOME=/foo", ALPINE, "printenv", "HOME"})
- session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
- match, _ = session.GrepString("/foo")
- Expect(match).Should(BeTrue())
-
- session = podmanTest.Podman([]string{"run", "--rm", "--env", "FOO=BAR,BAZ", ALPINE, "printenv", "FOO"})
- session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
- match, _ = session.GrepString("BAR,BAZ")
- Expect(match).Should(BeTrue())
-
- session = podmanTest.Podman([]string{"run", "--rm", "--env", "PATH=/bin", ALPINE, "printenv", "PATH"})
- session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
- match, _ = session.GrepString("/bin")
- Expect(match).Should(BeTrue())
-
- os.Setenv("FOO", "BAR")
- session = podmanTest.Podman([]string{"run", "--rm", "--env", "FOO", ALPINE, "printenv", "FOO"})
- session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
- match, _ = session.GrepString("BAR")
- Expect(match).Should(BeTrue())
- os.Unsetenv("FOO")
-
- session = podmanTest.Podman([]string{"run", "--rm", "--env", "FOO", ALPINE, "printenv", "FOO"})
- session.WaitWithDefaultTimeout()
- Expect(len(session.OutputToString())).To(Equal(0))
- Expect(session.ExitCode()).To(Equal(1))
-
- session = podmanTest.Podman([]string{"run", "--rm", ALPINE, "printenv"})
- session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
-
- // This currently does not work
- // Re-enable when hostname is an env variable
- session = podmanTest.Podman([]string{"run", "--rm", ALPINE, "sh", "-c", "printenv"})
- session.Wait(10)
- Expect(session.ExitCode()).To(Equal(0))
- match, _ = session.GrepString("HOSTNAME")
- Expect(match).Should(BeTrue())
- })
-
- It("podman run --host-env environment test", func() {
- env := append(os.Environ(), "FOO=BAR")
- session := podmanTest.PodmanAsUser([]string{"run", "--rm", "--env-host", ALPINE, "/bin/printenv", "FOO"}, 0, 0, "", env)
-
- session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
- match, _ := session.GrepString("BAR")
- Expect(match).Should(BeTrue())
-
- session = podmanTest.PodmanAsUser([]string{"run", "--rm", "--env", "FOO=BAR1", "--env-host", ALPINE, "/bin/printenv", "FOO"}, 0, 0, "", env)
- session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
- match, _ = session.GrepString("BAR1")
- Expect(match).Should(BeTrue())
- os.Unsetenv("FOO")
- })
-
It("podman run limits test", func() {
SkipIfRootless()
session := podmanTest.Podman([]string{"run", "--rm", "--ulimit", "rtprio=99", "--cap-add=sys_nice", fedoraMinimal, "cat", "/proc/self/sched"})
@@ -708,7 +634,6 @@ USER mail`
})
It("podman run --volumes-from flag with built-in volumes", func() {
- Skip(v2fail)
session := podmanTest.Podman([]string{"create", redis, "sh"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
@@ -803,7 +728,6 @@ USER mail`
})
It("podman run --pod automatically", func() {
- Skip(v2fail)
session := podmanTest.Podman([]string{"run", "--pod", "new:foobar", ALPINE, "ls"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
@@ -875,21 +799,6 @@ USER mail`
Expect(session).To(ExitWithError())
})
- It("podman run --http-proxy test", func() {
- os.Setenv("http_proxy", "1.2.3.4")
- session := podmanTest.Podman([]string{"run", "--rm", ALPINE, "printenv", "http_proxy"})
- session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
- match, _ := session.GrepString("1.2.3.4")
- Expect(match).Should(BeTrue())
-
- session = podmanTest.Podman([]string{"run", "--http-proxy=false", ALPINE, "printenv", "http_proxy"})
- session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(1))
- Expect(session.OutputToString()).To(Equal(""))
- os.Unsetenv("http_proxy")
- })
-
It("podman run with restart-policy always restarts containers", func() {
testDir := filepath.Join(podmanTest.RunRoot, "restart-test")
diff --git a/test/e2e/run_volume_test.go b/test/e2e/run_volume_test.go
index 1d9538912..1f892d9f8 100644
--- a/test/e2e/run_volume_test.go
+++ b/test/e2e/run_volume_test.go
@@ -222,7 +222,6 @@ var _ = Describe("Podman run with volumes", func() {
})
It("podman run with tmpfs named volume mounts and unmounts", func() {
- Skip(v2fail)
SkipIfRootless()
volName := "testvol"
mkVolume := podmanTest.Podman([]string{"volume", "create", "--opt", "type=tmpfs", "--opt", "device=tmpfs", "--opt", "o=nodev", "testvol"})
@@ -279,7 +278,6 @@ var _ = Describe("Podman run with volumes", func() {
})
It("podman named volume copyup", func() {
- Skip(v2fail)
baselineSession := podmanTest.Podman([]string{"run", "--rm", "-t", "-i", ALPINE, "ls", "/etc/apk/"})
baselineSession.WaitWithDefaultTimeout()
Expect(baselineSession.ExitCode()).To(Equal(0))
@@ -311,7 +309,6 @@ var _ = Describe("Podman run with volumes", func() {
})
It("podman run with anonymous volume", func() {
- Skip(v2fail)
list1 := podmanTest.Podman([]string{"volume", "list", "--quiet"})
list1.WaitWithDefaultTimeout()
Expect(list1.ExitCode()).To(Equal(0))
@@ -330,7 +327,6 @@ var _ = Describe("Podman run with volumes", func() {
})
It("podman rm -v removes anonymous volume", func() {
- Skip(v2fail)
list1 := podmanTest.Podman([]string{"volume", "list", "--quiet"})
list1.WaitWithDefaultTimeout()
Expect(list1.ExitCode()).To(Equal(0))
@@ -359,7 +355,6 @@ var _ = Describe("Podman run with volumes", func() {
})
It("podman rm -v retains named volume", func() {
- Skip(v2fail)
list1 := podmanTest.Podman([]string{"volume", "list", "--quiet"})
list1.WaitWithDefaultTimeout()
Expect(list1.ExitCode()).To(Equal(0))
@@ -398,7 +393,6 @@ var _ = Describe("Podman run with volumes", func() {
})
It("podman mount with invalid option fails", func() {
- Skip(v2fail)
volName := "testVol"
volCreate := podmanTest.Podman([]string{"volume", "create", "--opt", "type=tmpfs", "--opt", "device=tmpfs", "--opt", "o=invalid", volName})
volCreate.WaitWithDefaultTimeout()
@@ -410,7 +404,6 @@ var _ = Describe("Podman run with volumes", func() {
})
It("Podman fix for CVE-2020-1726", func() {
- Skip(v2fail)
volName := "testVol"
volCreate := podmanTest.Podman([]string{"volume", "create", volName})
volCreate.WaitWithDefaultTimeout()
diff --git a/test/e2e/save_test.go b/test/e2e/save_test.go
index 60825f975..aaa5ae180 100644
--- a/test/e2e/save_test.go
+++ b/test/e2e/save_test.go
@@ -116,4 +116,16 @@ var _ = Describe("Podman save", func() {
Expect(save).To(ExitWithError())
})
+ It("podman save image with digest reference", func() {
+ // pull a digest reference
+ session := podmanTest.PodmanNoCache([]string{"pull", ALPINELISTDIGEST})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ // save a digest reference should exit without error.
+ outfile := filepath.Join(podmanTest.TempDir, "temp.tar")
+ save := podmanTest.PodmanNoCache([]string{"save", "-o", outfile, ALPINELISTDIGEST})
+ save.WaitWithDefaultTimeout()
+ Expect(save.ExitCode()).To(Equal(0))
+ })
})
diff --git a/test/e2e/search_test.go b/test/e2e/search_test.go
index 3c64fa05f..9ba0241fe 100644
--- a/test/e2e/search_test.go
+++ b/test/e2e/search_test.go
@@ -68,7 +68,6 @@ registries = ['{{.Host}}:{{.Port}}']`
registryFileTwoTmpl := template.Must(template.New("registryFileTwo").Parse(regFileContents2))
BeforeEach(func() {
- Skip(v2fail)
tempdir, err = CreateTempDirInTempDir()
if err != nil {
os.Exit(1)
diff --git a/test/e2e/start_test.go b/test/e2e/start_test.go
index 5f6f5a8cf..6af0b7068 100644
--- a/test/e2e/start_test.go
+++ b/test/e2e/start_test.go
@@ -17,7 +17,6 @@ var _ = Describe("Podman start", func() {
)
BeforeEach(func() {
- Skip(v2fail)
tempdir, err = CreateTempDirInTempDir()
if err != nil {
os.Exit(1)
@@ -66,10 +65,11 @@ var _ = Describe("Podman start", func() {
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
cid := session.OutputToString()
- session = podmanTest.Podman([]string{"container", "start", cid[0:10]})
+ shortID := cid[0:10]
+ session = podmanTest.Podman([]string{"container", "start", shortID})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- Expect(session.OutputToString()).To(Equal(cid))
+ Expect(session.OutputToString()).To(Equal(shortID))
})
It("podman start single container by name", func() {
diff --git a/test/e2e/version_test.go b/test/e2e/version_test.go
index 4d2e14589..e353b9f97 100644
--- a/test/e2e/version_test.go
+++ b/test/e2e/version_test.go
@@ -7,6 +7,7 @@ import (
"github.com/containers/libpod/version"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
+ . "github.com/onsi/gomega/gexec"
)
var _ = Describe("Podman version", func() {
@@ -35,54 +36,49 @@ var _ = Describe("Podman version", func() {
It("podman version", func() {
session := podmanTest.Podman([]string{"version"})
session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
- Expect(len(session.OutputToStringArray())).To(BeNumerically(">", 2))
- ok, _ := session.GrepString(version.Version)
- Expect(ok).To(BeTrue())
+ Expect(session).Should(Exit(0))
+ Expect(session.Out.Contents()).Should(ContainSubstring(version.Version))
})
It("podman -v", func() {
- Skip(v2fail)
session := podmanTest.Podman([]string{"-v"})
session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
- ok, _ := session.GrepString(version.Version)
- Expect(ok).To(BeTrue())
+ Expect(session).Should(Exit(0))
+ Expect(session.Out.Contents()).Should(ContainSubstring(version.Version))
})
It("podman --version", func() {
session := podmanTest.Podman([]string{"--version"})
session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
- ok, _ := session.GrepString(version.Version)
- Expect(ok).To(BeTrue())
+ Expect(session).Should(Exit(0))
+ Expect(session.Out.Contents()).Should(ContainSubstring(version.Version))
})
It("podman version --format json", func() {
session := podmanTest.Podman([]string{"version", "--format", "json"})
session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
+ Expect(session).Should(Exit(0))
Expect(session.IsJSONOutputValid()).To(BeTrue())
})
It("podman version --format json", func() {
session := podmanTest.Podman([]string{"version", "--format", "{{ json .}}"})
session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
+ Expect(session).Should(Exit(0))
Expect(session.IsJSONOutputValid()).To(BeTrue())
})
It("podman version --format GO template", func() {
session := podmanTest.Podman([]string{"version", "--format", "{{ .Client.Version }}"})
session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
+ Expect(session).Should(Exit(0))
session = podmanTest.Podman([]string{"version", "--format", "{{ .Server.Version }}"})
session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
+ Expect(session).Should(Exit(0))
session = podmanTest.Podman([]string{"version", "--format", "{{ .Version }}"})
session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
+ Expect(session).Should(Exit(0))
})
})
diff --git a/test/e2e/volume_create_test.go b/test/e2e/volume_create_test.go
index 4cfc5bfc9..71023f9e2 100644
--- a/test/e2e/volume_create_test.go
+++ b/test/e2e/volume_create_test.go
@@ -17,7 +17,6 @@ var _ = Describe("Podman volume create", func() {
)
BeforeEach(func() {
- Skip(v2fail)
tempdir, err = CreateTempDirInTempDir()
if err != nil {
os.Exit(1)
diff --git a/test/e2e/volume_inspect_test.go b/test/e2e/volume_inspect_test.go
index 1197fa552..5015e0535 100644
--- a/test/e2e/volume_inspect_test.go
+++ b/test/e2e/volume_inspect_test.go
@@ -17,7 +17,6 @@ var _ = Describe("Podman volume inspect", func() {
)
BeforeEach(func() {
- Skip(v2fail)
tempdir, err = CreateTempDirInTempDir()
if err != nil {
os.Exit(1)
diff --git a/test/e2e/volume_ls_test.go b/test/e2e/volume_ls_test.go
index 4073df59d..7664e64bb 100644
--- a/test/e2e/volume_ls_test.go
+++ b/test/e2e/volume_ls_test.go
@@ -16,7 +16,6 @@ var _ = Describe("Podman volume ls", func() {
)
BeforeEach(func() {
- Skip(v2fail)
tempdir, err = CreateTempDirInTempDir()
if err != nil {
os.Exit(1)
@@ -56,6 +55,7 @@ var _ = Describe("Podman volume ls", func() {
})
It("podman ls volume with Go template", func() {
+ Skip(v2fail)
session := podmanTest.Podman([]string{"volume", "create", "myvol"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
diff --git a/test/e2e/volume_prune_test.go b/test/e2e/volume_prune_test.go
index 137a2c41b..b9ea90568 100644
--- a/test/e2e/volume_prune_test.go
+++ b/test/e2e/volume_prune_test.go
@@ -18,7 +18,6 @@ var _ = Describe("Podman volume prune", func() {
)
BeforeEach(func() {
- Skip(v2fail)
tempdir, err = CreateTempDirInTempDir()
if err != nil {
os.Exit(1)
@@ -66,6 +65,7 @@ var _ = Describe("Podman volume prune", func() {
})
It("podman system prune --volume", func() {
+ Skip(v2fail)
session := podmanTest.Podman([]string{"volume", "create"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
diff --git a/test/e2e/volume_rm_test.go b/test/e2e/volume_rm_test.go
index e67cfcd11..6f2020828 100644
--- a/test/e2e/volume_rm_test.go
+++ b/test/e2e/volume_rm_test.go
@@ -16,7 +16,6 @@ var _ = Describe("Podman volume rm", func() {
)
BeforeEach(func() {
- Skip(v2fail)
tempdir, err = CreateTempDirInTempDir()
if err != nil {
os.Exit(1)
diff --git a/test/system/005-info.bats b/test/system/005-info.bats
index 3c06103e8..c53ba8125 100644
--- a/test/system/005-info.bats
+++ b/test/system/005-info.bats
@@ -8,19 +8,19 @@ load helpers
run_podman info
expected_keys="
-buildahversion: *[0-9.]\\\+
+buildahVersion: *[0-9.]\\\+
conmon:\\\s\\\+package:
distribution:
-ociruntime:\\\s\\\+name:
+ociRuntime:\\\s\\\+name:
os:
rootless:
registries:
store:
-graphdrivername:
-graphroot:
-graphstatus:
-imagestore:\\\s\\\+number: 1
-runroot:
+graphDriverName:
+graphRoot:
+graphStatus:
+imageStore:\\\s\\\+number: 1
+runRoot:
"
while read expect; do
is "$output" ".*$expect" "output includes '$expect'"
diff --git a/test/system/015-help.bats b/test/system/015-help.bats
index fd4be87b2..6c3d617dc 100644
--- a/test/system/015-help.bats
+++ b/test/system/015-help.bats
@@ -55,11 +55,24 @@ function check_help() {
# If usage has required arguments, try running without them
if expr "$usage" : '.*\[flags\] [A-Z]' >/dev/null; then
- if [ "$cmd" != "stats"]; then
- dprint "podman $@ $cmd (without required args)"
- run_podman 125 "$@" $cmd
- is "$output" "Error:"
+ # Exceptions: these commands don't work rootless
+ if is_rootless; then
+ # "pause is not supported for rootless containers"
+ if [ "$cmd" = "pause" -o "$cmd" = "unpause" ]; then
+ continue
+ fi
+ # "network rm" too
+ if [ "$@" = "network" -a "$cmd" = "rm" ]; then
+ continue
+ fi
fi
+
+ # The </dev/null protects us from 'podman login' which will
+ # try to read username/password from stdin.
+ dprint "podman $@ $cmd (without required args)"
+ run_podman 125 "$@" $cmd </dev/null
+ is "$output" "Error:.* \(require\|specif\|must\|provide\|need\|choose\|accepts\)" \
+ "'podman $@ $cmd' without required arg"
fi
count=$(expr $count + 1)
diff --git a/test/system/150-login.bats b/test/system/150-login.bats
index e33217e14..e3e2b7aca 100644
--- a/test/system/150-login.bats
+++ b/test/system/150-login.bats
@@ -165,6 +165,7 @@ function setup() {
# Some push tests
@test "podman push fail" {
+
# Create an invalid authfile
authfile=${PODMAN_LOGIN_WORKDIR}/auth-$(random_string 10).json
rm -f $authfile
@@ -197,6 +198,7 @@ EOF
#
# https://github.com/containers/skopeo/issues/651
#
+
run_podman pull busybox
# Preserve its ID for later comparison against push/pulled image
diff --git a/test/system/250-generate-systemd.bats b/test/system/250-generate-systemd.bats
index 80199af5f..6155d6ace 100644
--- a/test/system/250-generate-systemd.bats
+++ b/test/system/250-generate-systemd.bats
@@ -10,6 +10,8 @@ SERVICE_NAME="podman_test_$(random_string)"
UNIT_DIR="$HOME/.config/systemd/user"
UNIT_FILE="$UNIT_DIR/$SERVICE_NAME.service"
+# FIXME: the must run as root (because of CI). It's also broken...
+
function setup() {
skip_if_not_systemd
skip_if_remote
diff --git a/test/utils/utils.go b/test/utils/utils.go
index 6ab8604a4..0131e023d 100644
--- a/test/utils/utils.go
+++ b/test/utils/utils.go
@@ -206,7 +206,7 @@ func WaitContainerReady(p PodmanTestCommon, id string, expStr string, timeout in
// OutputToString formats session output to string
func (s *PodmanSession) OutputToString() string {
- fields := strings.Fields(fmt.Sprintf("%s", s.Out.Contents()))
+ fields := strings.Fields(string(s.Out.Contents()))
return strings.Join(fields, " ")
}
diff --git a/vendor/github.com/containers/psgo/CODE-OF-CONDUCT.md b/vendor/github.com/containers/psgo/CODE-OF-CONDUCT.md
new file mode 100644
index 000000000..1081553f8
--- /dev/null
+++ b/vendor/github.com/containers/psgo/CODE-OF-CONDUCT.md
@@ -0,0 +1,3 @@
+## The psgo Project Community Code of Conduct
+
+The psgo project follows the [Containers Community Code of Conduct](https://github.com/containers/common/blob/master/CODE-OF-CONDUCT.md).
diff --git a/vendor/github.com/containers/psgo/Makefile b/vendor/github.com/containers/psgo/Makefile
index 361820784..831dfa31f 100644
--- a/vendor/github.com/containers/psgo/Makefile
+++ b/vendor/github.com/containers/psgo/Makefile
@@ -16,6 +16,8 @@ ifeq ($(shell go help mod >/dev/null 2>&1 && echo true), true)
GO_BUILD=GO111MODULE=on $(GO) build -mod=vendor
endif
+GOBIN ?= $(GO)/bin
+
all: validate build
.PHONY: build
@@ -34,12 +36,7 @@ vendor:
.PHONY: validate
validate: .install.lint
- @which gofmt >/dev/null 2>/dev/null || (echo "ERROR: gofmt not found." && false)
- test -z "$$(gofmt -s -l . | grep -vE 'vendor/' | tee /dev/stderr)"
- @which golangci-lint >/dev/null 2>/dev/null|| (echo "ERROR: golangci-lint not found." && false)
- test -z "$$(golangci-lint run)"
- @go doc cmd/vet >/dev/null 2>/dev/null|| (echo "ERROR: go vet not found." && false)
- test -z "$$($(GO) vet $$($(GO) list $(PROJECT)/...) 2>&1 | tee /dev/stderr)"
+ $(GOBIN)/golangci-lint run
.PHONY: test
test: test-unit test-integration
@@ -59,8 +56,7 @@ install:
.PHONY: .install.lint
.install.lint:
- # Workaround for https://github.com/golangci/golangci-lint/issues/523
- go get -u github.com/golangci/golangci-lint/cmd/golangci-lint
+ VERSION=1.24.0 GOBIN=$(GOBIN) sh ./hack/install_golangci.sh
.PHONY: uninstall
uninstall:
diff --git a/vendor/github.com/containers/psgo/go.mod b/vendor/github.com/containers/psgo/go.mod
index d9d54c5f7..5f3341aa9 100644
--- a/vendor/github.com/containers/psgo/go.mod
+++ b/vendor/github.com/containers/psgo/go.mod
@@ -6,6 +6,6 @@ require (
github.com/opencontainers/runc v0.0.0-20190425234816-dae70e8efea4
github.com/pkg/errors v0.0.0-20190227000051-27936f6d90f9
github.com/sirupsen/logrus v0.0.0-20190403091019-9b3cdde74fbe
- github.com/stretchr/testify v1.4.0
+ github.com/stretchr/testify v1.5.1
golang.org/x/sys v0.0.0-20190425145619-16072639606e
)
diff --git a/vendor/github.com/containers/psgo/go.sum b/vendor/github.com/containers/psgo/go.sum
index bbdd99730..781b26f2b 100644
--- a/vendor/github.com/containers/psgo/go.sum
+++ b/vendor/github.com/containers/psgo/go.sum
@@ -16,8 +16,8 @@ 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 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
-github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
-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=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190425145619-16072639606e h1:4ktJgTV34+N3qOZUc5fAaG3Pb11qzMm3PkAoTAgUZ2I=
golang.org/x/sys v0.0.0-20190425145619-16072639606e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
diff --git a/vendor/github.com/containers/psgo/internal/proc/stat.go b/vendor/github.com/containers/psgo/internal/proc/stat.go
index 866a5cdda..e3286704c 100644
--- a/vendor/github.com/containers/psgo/internal/proc/stat.go
+++ b/vendor/github.com/containers/psgo/internal/proc/stat.go
@@ -15,6 +15,7 @@
package proc
import (
+ "errors"
"fmt"
"io/ioutil"
"strings"
@@ -112,21 +113,31 @@ type Stat struct {
}
// readStat is used for mocking in unit tests.
-var readStat = func(path string) ([]string, error) {
- data, err := ioutil.ReadFile(path)
+var readStat = func(path string) (string, error) {
+ rawData, err := ioutil.ReadFile(path)
if err != nil {
- return nil, err
+ return "", err
}
- return strings.Fields(string(data)), nil
+ return string(rawData), nil
}
// ParseStat parses the /proc/$pid/stat file and returns a Stat.
func ParseStat(pid string) (*Stat, error) {
- fields, err := readStat(fmt.Sprintf("/proc/%s/stat", pid))
+ data, err := readStat(fmt.Sprintf("/proc/%s/stat", pid))
if err != nil {
return nil, err
}
+ firstParen := strings.IndexByte(data, '(')
+ lastParen := strings.LastIndexByte(data, ')')
+ if firstParen == -1 || lastParen == -1 {
+ return nil, errors.New("invalid format in stat")
+ }
+ pidstr := data[0 : firstParen-1]
+ comm := data[firstParen+1 : lastParen]
+ rest := strings.Fields(data[lastParen+1:])
+ fields := append([]string{pidstr, comm}, rest...)
+
fieldAt := func(i int) string {
return fields[i-1]
}
diff --git a/vendor/github.com/containers/psgo/internal/process/process.go b/vendor/github.com/containers/psgo/internal/process/process.go
index a936cc4ef..b46a39f46 100644
--- a/vendor/github.com/containers/psgo/internal/process/process.go
+++ b/vendor/github.com/containers/psgo/internal/process/process.go
@@ -192,7 +192,7 @@ func (p *Process) ElapsedTime() (time.Duration, error) {
if err != nil {
return 0, err
}
- return (time.Now()).Sub(startTime), nil
+ return time.Since(startTime), nil
}
// StarTime returns the time.Time when process p was started.
diff --git a/vendor/github.com/containers/psgo/psgo.go b/vendor/github.com/containers/psgo/psgo.go
index 30b8b74ce..57132c94e 100644
--- a/vendor/github.com/containers/psgo/psgo.go
+++ b/vendor/github.com/containers/psgo/psgo.go
@@ -306,6 +306,11 @@ var (
procFn: processHGROUP,
},
{
+ normal: "rss",
+ header: "RSS",
+ procFn: processRSS,
+ },
+ {
normal: "state",
header: "STATE",
procFn: processState,
@@ -663,12 +668,7 @@ func processARGS(p *process.Process, ctx *psContext) (string, error) {
// processCOMM returns the command name (i.e., executable name) of process p.
func processCOMM(p *process.Process, ctx *psContext) (string, error) {
- // ps (1) returns "[$name]" if command/args are empty
- if p.CmdLine[0] == "" {
- return processName(p, ctx)
- }
- spl := strings.Split(p.CmdLine[0], "/")
- return spl[len(spl)-1], nil
+ return p.Stat.Comm, nil
}
// processNICE returns the nice value of process p.
@@ -867,6 +867,16 @@ func processHGROUP(p *process.Process, ctx *psContext) (string, error) {
return "?", nil
}
+// processRSS returns the resident set size of process p in KiB (1024-byte
+// units).
+func processRSS(p *process.Process, ctx *psContext) (string, error) {
+ if p.Status.VMRSS == "" {
+ // probably a kernel thread
+ return "0", nil
+ }
+ return p.Status.VMRSS, nil
+}
+
// processState returns the process state of process p.
func processState(p *process.Process, ctx *psContext) (string, error) {
return p.Status.State, nil
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 0a6d8ccd5..c1d803f84 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -143,7 +143,7 @@ github.com/containers/ocicrypt/keywrap/pgp
github.com/containers/ocicrypt/keywrap/pkcs7
github.com/containers/ocicrypt/spec
github.com/containers/ocicrypt/utils
-# github.com/containers/psgo v1.4.0
+# github.com/containers/psgo v1.5.0
github.com/containers/psgo
github.com/containers/psgo/internal/capabilities
github.com/containers/psgo/internal/cgroups