summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cirrus.yml5
-rw-r--r--API.md13
-rw-r--r--Makefile9
-rw-r--r--cmd/podman/images.go38
-rw-r--r--cmd/podman/varlink/io.podman.varlink7
-rwxr-xr-xcontrib/cirrus/upload_release_archive.sh39
-rw-r--r--contrib/spec/podman.spec.in4
-rwxr-xr-xdocs/dckrman.sh5
-rw-r--r--docs/tutorials/README.md4
-rw-r--r--docs/tutorials/image_signing.md194
-rw-r--r--go.mod2
-rw-r--r--go.sum2
-rw-r--r--libpod/container_internal.go70
-rw-r--r--libpod/container_internal_linux.go7
-rw-r--r--libpod/container_internal_unsupported.go4
-rw-r--r--libpod/networking_linux.go7
-rw-r--r--libpod/networking_unsupported.go4
-rw-r--r--pkg/adapter/containers.go3
-rw-r--r--pkg/adapter/runtime_remote.go10
-rw-r--r--pkg/api/handlers/libpod/images.go84
-rw-r--r--pkg/api/server/register_images.go11
-rw-r--r--pkg/bindings/containers/commit.go49
-rw-r--r--pkg/bindings/containers/types.go13
-rw-r--r--pkg/bindings/test/pods_test.go4
-rw-r--r--pkg/rootlessport/rootlessport_linux.go23
-rw-r--r--pkg/varlinkapi/images.go10
-rw-r--r--test/e2e/prune_test.go28
-rw-r--r--test/e2e/volume_prune_test.go2
-rw-r--r--test/system/010-images.bats10
-rw-r--r--vendor/github.com/containers/common/pkg/config/config.go13
-rw-r--r--vendor/github.com/containers/common/pkg/config/default.go36
-rw-r--r--vendor/github.com/containers/common/pkg/config/default_linux.go2
-rw-r--r--vendor/github.com/containers/common/pkg/config/libpodConfig.go10
-rw-r--r--vendor/modules.txt2
34 files changed, 599 insertions, 125 deletions
diff --git a/.cirrus.yml b/.cirrus.yml
index c44277b05..3f3ab2ff4 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -420,9 +420,6 @@ testing_task:
integration_test_script: '$SCRIPT_BASE/integration_test.sh |& ${TIMESTAMP} | ${LOGFORMAT} integration_test'
system_test_script: '$SCRIPT_BASE/system_test.sh |& ${TIMESTAMP} | ${LOGFORMAT} system_test'
apiv2_test_script: '$SCRIPT_BASE/apiv2_test.sh |& ${TIMESTAMP} | ${LOGFORMAT} apiv2_test'
- build_release_script: '$SCRIPT_BASE/build_release.sh |& ${TIMESTAMP}'
- # For PRs this confirms uploading releases after merge, is functional.
- upload_release_archive_script: '$SCRIPT_BASE/upload_release_archive.sh |& ${TIMESTAMP}'
# When examining a particular run, provide convenient access to release files.
tar_artifacts:
@@ -552,7 +549,6 @@ special_testing_cross_task:
networking_script: '${CIRRUS_WORKING_DIR}/${SCRIPT_BASE}/networking.sh'
setup_environment_script: '$SCRIPT_BASE/setup_environment.sh |& ${TIMESTAMP}'
build_release_script: '$SCRIPT_BASE/build_release.sh |& ${TIMESTAMP}'
- upload_release_archive_script: '$SCRIPT_BASE/upload_release_archive.sh |& ${TIMESTAMP}'
on_failure:
failed_branch_script: '$CIRRUS_WORKING_DIR/$SCRIPT_BASE/notice_branch_failure.sh'
@@ -697,7 +693,6 @@ verify_test_built_images_task:
# "probably" work. A full round of testing will happen again after $*_CACHE_IMAGE_NAME
# are updated in this or another PR (w/o '***CIRRUS: TEST IMAGES***').
integration_test_script: '$SCRIPT_BASE/integration_test.sh |& ${TIMESTAMP}'
- build_release_script: '$SCRIPT_BASE/build_release.sh |& ${TIMESTAMP}'
system_test_script: '$SCRIPT_BASE/system_test.sh |& ${TIMESTAMP}'
always:
diff --git a/API.md b/API.md
index 2460de09f..e1255ebd9 100644
--- a/API.md
+++ b/API.md
@@ -141,7 +141,7 @@ in the [API.md](https://github.com/containers/libpod/blob/master/API.md) file in
[func Ps(opts: PsOpts) PsContainer](#Ps)
-[func PullImage(name: string) MoreResponse](#PullImage)
+[func PullImage(name: string, creds: AuthConfig) MoreResponse](#PullImage)
[func PushImage(name: string, tag: string, compress: bool, format: string, removeSignatures: bool, signBy: string) MoreResponse](#PushImage)
@@ -197,6 +197,8 @@ in the [API.md](https://github.com/containers/libpod/blob/master/API.md) file in
[func WaitContainer(name: string, interval: int) int](#WaitContainer)
+[type AuthConfig](#AuthConfig)
+
[type BuildInfo](#BuildInfo)
[type BuildOptions](#BuildOptions)
@@ -1027,7 +1029,7 @@ method Ps(opts: [PsOpts](#PsOpts)) [PsContainer](#PsContainer)</div>
### <a name="PullImage"></a>func PullImage
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
-method PullImage(name: [string](https://godoc.org/builtin#string)) [MoreResponse](#MoreResponse)</div>
+method PullImage(name: [string](https://godoc.org/builtin#string), creds: [AuthConfig](#AuthConfig)) [MoreResponse](#MoreResponse)</div>
PullImage pulls an image from a repository to local storage. After a successful pull, the image id and logs
are returned as a [MoreResponse](#MoreResponse). This connection also will handle a WantsMores request to send
status as it occurs.
@@ -1283,6 +1285,13 @@ WaitContainer takes the name or ID of a container and waits the given interval i
stops. Upon stopping, the return code of the container is returned. If the container container cannot be found by ID
or name, a [ContainerNotFound](#ContainerNotFound) error is returned.
## Types
+### <a name="AuthConfig"></a>type AuthConfig
+
+
+
+username [string](https://godoc.org/builtin#string)
+
+password [string](https://godoc.org/builtin#string)
### <a name="BuildInfo"></a>type BuildInfo
BuildInfo is used to describe user input for building images
diff --git a/Makefile b/Makefile
index d0f7d9382..7e5a564a0 100644
--- a/Makefile
+++ b/Makefile
@@ -527,6 +527,11 @@ install.systemd:
# For user units the default.target that's the default is fine.
sed -e 's,^WantedBy=.*,WantedBy=default.target,' < contrib/varlink/io.podman.service > ${DESTDIR}${USERSYSTEMDDIR}/io.podman.service
install ${SELINUXOPT} -m 644 contrib/varlink/podman.conf ${DESTDIR}${TMPFILESDIR}/podman.conf
+ # Install APIV2 services
+ install ${SELINUXOPT} -m 644 contrib/systemd/user/podman.socket ${DESTDIR}${USERSYSTEMDDIR}/podman.socket
+ install ${SELINUXOPT} -m 644 contrib/systemd/user/podman.service ${DESTDIR}${USERSYSTEMDDIR}/podman.service
+ install ${SELINUXOPT} -m 644 contrib/systemd/system/podman.socket ${DESTDIR}${SYSTEMDDIR}/podman.socket
+ install ${SELINUXOPT} -m 644 contrib/systemd/system/podman.service ${DESTDIR}${SYSTEMDDIR}/podman.service
.PHONY: uninstall
uninstall:
@@ -545,6 +550,10 @@ uninstall:
rm -f ${DESTDIR}${SYSTEMDDIR}/io.podman.socket
rm -f ${DESTDIR}${USERSYSTEMDDIR}/io.podman.socket
rm -f ${DESTDIR}${SYSTEMDDIR}/io.podman.service
+ rm -f ${DESTDIR}${SYSTEMDDIR}/podman.service
+ rm -f ${DESTDIR}${SYSTEMDDIR}/podman.socket
+ rm -f ${DESTDIR}${USERSYSTEMDDIR}/podman.socket
+ rm -f ${DESTDIR}${USERSYSTEMDDIR}/podman.service
.PHONY: .gitvalidation
.gitvalidation: .gopathok
diff --git a/cmd/podman/images.go b/cmd/podman/images.go
index 41790a5aa..ed33402ab 100644
--- a/cmd/podman/images.go
+++ b/cmd/podman/images.go
@@ -13,8 +13,8 @@ import (
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/libpod/image"
"github.com/containers/libpod/pkg/adapter"
- "github.com/docker/go-units"
- "github.com/opencontainers/go-digest"
+ units "github.com/docker/go-units"
+ digest "github.com/opencontainers/go-digest"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
@@ -34,14 +34,15 @@ type imagesTemplateParams struct {
}
type imagesJSONParams struct {
- ID string `json:"id"`
- Name []string `json:"names"`
- Digest digest.Digest `json:"digest"`
- Digests []digest.Digest `json:"digests"`
- Created time.Time `json:"created"`
- Size *uint64 `json:"size"`
- ReadOnly bool `json:"readonly"`
- History []string `json:"history"`
+ ID string `json:"ID"`
+ Name []string `json:"Names"`
+ Created string `json:"Created"`
+ Digest digest.Digest `json:"Digest"`
+ Digests []digest.Digest `json:"Digests"`
+ CreatedAt time.Time `json:"CreatedAt"`
+ Size *uint64 `json:"Size"`
+ ReadOnly bool `json:"ReadOnly"`
+ History []string `json:"History"`
}
type imagesOptions struct {
@@ -344,14 +345,15 @@ func getImagesJSONOutput(ctx context.Context, images []*adapter.ContainerImage)
size = nil
}
params := imagesJSONParams{
- ID: img.ID(),
- Name: img.Names(),
- Digest: img.Digest(),
- Digests: img.Digests(),
- Created: img.Created(),
- Size: size,
- ReadOnly: img.IsReadOnly(),
- History: img.NamesHistory(),
+ ID: img.ID(),
+ Name: img.Names(),
+ Digest: img.Digest(),
+ Digests: img.Digests(),
+ Created: units.HumanDuration(time.Since(img.Created())) + " ago",
+ CreatedAt: img.Created(),
+ Size: size,
+ ReadOnly: img.IsReadOnly(),
+ History: img.NamesHistory(),
}
imagesOutput = append(imagesOutput, params)
}
diff --git a/cmd/podman/varlink/io.podman.varlink b/cmd/podman/varlink/io.podman.varlink
index e9792fa8f..0ef350fc2 100644
--- a/cmd/podman/varlink/io.podman.varlink
+++ b/cmd/podman/varlink/io.podman.varlink
@@ -105,6 +105,11 @@ type ImageSearchFilter (
star_count: int
)
+type AuthConfig (
+ username: string,
+ password: string
+)
+
type KubePodService (
pod: string,
service: string
@@ -932,7 +937,7 @@ method ExportImage(name: string, destination: string, compress: bool, tags: []st
# PullImage pulls an image from a repository to local storage. After a successful pull, the image id and logs
# are returned as a [MoreResponse](#MoreResponse). This connection also will handle a WantsMores request to send
# status as it occurs.
-method PullImage(name: string) -> (reply: MoreResponse)
+method PullImage(name: string, creds: AuthConfig) -> (reply: MoreResponse)
# CreatePod creates a new empty pod. It uses a [PodCreate](#PodCreate) type for input.
# On success, the ID of the newly created pod will be returned.
diff --git a/contrib/cirrus/upload_release_archive.sh b/contrib/cirrus/upload_release_archive.sh
index a94a5cc82..e1b8937b7 100755
--- a/contrib/cirrus/upload_release_archive.sh
+++ b/contrib/cirrus/upload_release_archive.sh
@@ -19,36 +19,19 @@ then
BUCKET="libpod-pr-releases"
elif [[ -n "$CIRRUS_BRANCH" ]]
then
- # Only release binaries for tagged commit ranges, unless working on docs
- if is_release || [[ $CIRRUS_TASK_NAME =~ "docs" ]]
+ # Only release binaries for docs
+ if [[ $CIRRUS_TASK_NAME =~ "docs" ]]
then
PR_OR_BRANCH="$CIRRUS_BRANCH"
BUCKET="libpod-$CIRRUS_BRANCH-releases"
else
- warn "" "Skipping release processing: Commit range|CIRRUS_TAG is development tagged."
+ warn "" "Skipping release processing for non-docs task."
exit 0
fi
else
die 1 "Expecting either \$CIRRUS_PR or \$CIRRUS_BRANCH to be non-empty."
fi
-echo "Parsing actual_release.txt contents: $(< actual_release.txt)"
-cd $GOSRC
-RELEASETXT=$(<actual_release.txt) # see build_release.sh
-[[ -n "$RELEASETXT" ]] || \
- die 3 "Could not obtain metadata from actual_release.txt"
-RELEASE_INFO=$(echo "$RELEASETXT" | grep -m 1 'X-RELEASE-INFO:' | sed -r -e 's/X-RELEASE-INFO:\s*(.+)/\1/')
-if [[ "$?" -ne "0" ]] || [[ -z "$RELEASE_INFO" ]]
-then
- die 4 "Metadata is empty or invalid: '$RELEASETXT'"
-fi
-# Format specified in Makefile
-# e.g. libpod v1.3.1-166-g60df124e fedora 29 amd64
-# or libpod-remote v1.3.1-166-g60df124e windows - amd64
-FIELDS="RELEASE_BASENAME RELEASE_VERSION RELEASE_DIST RELEASE_DIST_VER RELEASE_ARCH"
-read $FIELDS <<< $RELEASE_INFO
-req_env_var $FIELDS
-
# Functional local podman required for uploading
echo "Verifying a local, functional podman, building one if necessary."
[[ -n "$(type -P podman)" ]] || \
@@ -64,7 +47,7 @@ echo "$RELEASE_GCPJSON" > "$TMPF"
unset RELEASE_GCPJSON
cd $GOSRC
-for filename in $(ls -1 *.tar.gz *.zip *.msi $SWAGGER_FILEPATH)
+for filename in $(ls -1 $SWAGGER_FILEPATH)
do
unset EXT
EXT=$(echo "$filename" | sed -r -e 's/.+\.(.+$)/\1/g')
@@ -85,19 +68,7 @@ do
# For doc. ref. this must always be a static filename, e.g. swagger-latest-master.yaml
ALSO_FILENAME="swagger-latest-${PR_OR_BRANCH}.yaml"
else
- # Form the generic "latest" file for this branch or pr
- TO_PREFIX="${RELEASE_BASENAME}-latest-${PR_OR_BRANCH}-${RELEASE_DIST}"
- # Form the fully-versioned filename for historical sake
- ALSO_PREFIX="${RELEASE_BASENAME}-${RELEASE_VERSION}-${PR_OR_BRANCH}-${RELEASE_DIST}"
- TO_SUFFIX="${RELEASE_ARCH}.${EXT}"
- if [[ "$RELEASE_DIST" == "windows" ]] || [[ "$RELEASE_DIST" == "darwin" ]]
- then
- TO_FILENAME="${TO_PREFIX}-${TO_SUFFIX}"
- ALSO_FILENAME="${ALSO_PREFIX}-${TO_SUFFIX}"
- else
- TO_FILENAME="${TO_PREFIX}-${RELEASE_DIST_VER}-${TO_SUFFIX}"
- ALSO_FILENAME="${ALSO_PREFIX}-${TO_SUFFIX}"
- fi
+ die "Uploading non-docs files has been disabled"
fi
[[ "$OS_RELEASE_ID" == "ubuntu" ]] || \
diff --git a/contrib/spec/podman.spec.in b/contrib/spec/podman.spec.in
index 635de0c7e..817be31b7 100644
--- a/contrib/spec/podman.spec.in
+++ b/contrib/spec/podman.spec.in
@@ -524,6 +524,10 @@ export GOPATH=%{buildroot}/%{gopath}:$(pwd)/vendor:%{gopath}
%{_unitdir}/io.podman.socket
%{_usr}/lib/systemd/user/io.podman.service
%{_usr}/lib/systemd/user/io.podman.socket
+%{_unitdir}/podman.service
+%{_unitdir}/podman.socket
+%{_usr}/lib/systemd/user/podman.service
+%{_usr}/lib/systemd/user/podman.socket
%{_usr}/lib/tmpfiles.d/%{name}.conf
%if 0%{?with_devel}
diff --git a/docs/dckrman.sh b/docs/dckrman.sh
index 8ae7fd40d..c69524a7e 100755
--- a/docs/dckrman.sh
+++ b/docs/dckrman.sh
@@ -1,5 +1,6 @@
#!/bin/sh
for i in $@; do
- filename=$(echo $i | sed 's/podman/docker/g')
- echo .so man1/$i > $filename
+ b=$(basename $i)
+ filename=$(echo $i | sed 's/podman/docker/g')
+ echo .so man1/$b > $filename
done
diff --git a/docs/tutorials/README.md b/docs/tutorials/README.md
index bcd1b01d9..191d7a4b5 100644
--- a/docs/tutorials/README.md
+++ b/docs/tutorials/README.md
@@ -23,3 +23,7 @@ A brief how-to on using the Podman remote-client.
**[How to use libpod for custom/derivative projects](podman-derivative-api.md)**
How the libpod API can be used within your own project.
+
+**[Image Signing](image_signing.md)**
+
+Learn how to setup and use image signing with Podman.
diff --git a/docs/tutorials/image_signing.md b/docs/tutorials/image_signing.md
new file mode 100644
index 000000000..f0adca9af
--- /dev/null
+++ b/docs/tutorials/image_signing.md
@@ -0,0 +1,194 @@
+# How to sign and distribute container images using Podman
+
+Signing container images originates from the motivation of trusting only
+dedicated image providers to mitigate man-in-the-middle (MITM) attacks or
+attacks on container registries. One way to sign images is to utilize a GNU
+Privacy Guard ([GPG][0]) key. This technique is generally compatible with any
+OCI compliant container registry like [Quay.io][1]. It is worth mentioning that
+the OpenShift integrated container registry supports this signing mechanism out
+of the box, which makes separate signature storage unnecessary.
+
+[0]: https://gnupg.org
+[1]: https://quay.io
+
+From a technical perspective, we can utilize Podman to sign the image before
+pushing it into a remote registry. After that, all systems running Podman have
+to be configured to retrieve the signatures from a remote server, which can
+be any simple web server. This means that every unsigned image will be rejected
+during an image pull operation. But how does this work?
+
+First of all, we have to create a GPG key pair or select an already locally
+available one. To generate a new GPG key, just run `gpg --full-gen-key` and
+follow the interactive dialog. Now we should be able to verify that the key
+exists locally:
+
+```bash
+> gpg --list-keys sgrunert@suse.com
+pub rsa2048 2018-11-26 [SC] [expires: 2020-11-25]
+ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+uid [ultimate] Sascha Grunert <sgrunert@suse.com>
+sub rsa2048 2018-11-26 [E] [expires: 2020-11-25]
+```
+
+Now let’s assume that we run a container registry. For example we could simply
+start one on our local machine:
+
+```bash
+> sudo podman run -d -p 5000:5000 docker.io/registry
+```
+
+The registry does not know anything about image signing, it just provides the remote
+storage for the container images. This means if we want to sign an image, we
+have to take care of how to distribute the signatures.
+
+Let’s choose a standard `alpine` image for our signing experiment:
+
+```bash
+> sudo podman pull docker://docker.io/alpine:latest
+```
+
+```bash
+> sudo podman images alpine
+REPOSITORY TAG IMAGE ID CREATED SIZE
+docker.io/library/alpine latest e7d92cdc71fe 6 weeks ago 5.86 MB
+```
+
+Now we can re-tag the image to point it to our local registry:
+
+```bash
+> sudo podman tag alpine localhost:5000/alpine
+```
+
+```bash
+> sudo podman images alpine
+REPOSITORY TAG IMAGE ID CREATED SIZE
+localhost:5000/alpine latest e7d92cdc71fe 6 weeks ago 5.86 MB
+docker.io/library/alpine latest e7d92cdc71fe 6 weeks ago 5.86 MB
+```
+
+Podman would now be able to push the image and sign it in one command. But to
+let this work, we have to modify our system-wide registries configuration at
+`/etc/containers/registries.d/default.yaml`:
+
+```yaml
+default-docker:
+ sigstore: http://localhost:8000 # Added by us
+ sigstore-staging: file:///var/lib/containers/sigstore
+```
+
+We can see that we have two signature stores configured:
+
+- `sigstore`: referencing a web server for signature reading
+- `sigstore-staging`: referencing a file path for signature writing
+
+Now, let’s push and sign the image:
+
+```bash
+> sudo -E GNUPGHOME=$HOME/.gnupg \
+ podman push \
+ --tls-verify=false \
+ --sign-by sgrunert@suse.com \
+ localhost:5000/alpine
+…
+Storing signatures
+```
+
+If we now take a look at the systems signature storage, then we see that there
+is a new signature available, which was caused by the image push:
+
+```bash
+> sudo ls /var/lib/containers/sigstore
+'alpine@sha256=e9b65ef660a3ff91d28cc50eba84f21798a6c5c39b4dd165047db49e84ae1fb9'
+```
+
+The default signature store in our edited version of
+`/etc/containers/registries.d/default.yaml` references a web server listening at
+`http://localhost:8000`. For our experiment, we simply start a new server inside
+the local staging signature store:
+
+```bash
+> sudo bash -c 'cd /var/lib/containers/sigstore && python3 -m http.server'
+Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
+```
+
+Let’s remove the local images for our verification test:
+
+```
+> sudo podman rmi docker.io/alpine localhost:5000/alpine
+```
+
+We have to write a policy to enforce that the signature has to be valid. This
+can be done by adding a new rule in `/etc/containers/policy.json`. From the
+below example, copy the `"docker"` entry into the `"transports"` section of your
+`policy.json`.
+
+```json
+{
+ "default": [{ "type": "insecureAcceptAnything" }],
+ "transports": {
+ "docker": {
+ "localhost:5000": [
+ {
+ "type": "signedBy",
+ "keyType": "GPGKeys",
+ "keyPath": "/tmp/key.gpg"
+ }
+ ]
+ }
+ }
+}
+```
+
+The `keyPath` does not exist yet, so we have to put the GPG key there:
+
+```bash
+> gpg --output /tmp/key.gpg --armor --export sgrunert@suse.com
+```
+
+If we now pull the image:
+
+```bash
+> sudo podman pull --tls-verify=false localhost:5000/alpine
+…
+Storing signatures
+e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a
+```
+
+Then we can see in the logs of the web server that the signature has been
+accessed:
+
+```
+127.0.0.1 - - [04/Mar/2020 11:18:21] "GET /alpine@sha256=e9b65ef660a3ff91d28cc50eba84f21798a6c5c39b4dd165047db49e84ae1fb9/signature-1 HTTP/1.1" 200 -
+```
+
+As an counterpart example, if we specify the wrong key at `/tmp/key.gpg`:
+
+```bash
+> gpg --output /tmp/key.gpg --armor --export mail@saschagrunert.de
+File '/tmp/key.gpg' exists. Overwrite? (y/N) y
+```
+
+Then a pull is not possible any more:
+
+```bash
+> sudo podman pull --tls-verify=false localhost:5000/alpine
+Trying to pull localhost:5000/alpine...
+Error: error pulling image "localhost:5000/alpine": unable to pull localhost:5000/alpine: unable to pull image: Source image rejected: Invalid GPG signature: …
+```
+
+So in general there are four main things to be taken into consideration when
+signing container images with Podman and GPG:
+
+1. We need a valid private GPG key on the signing machine and corresponding
+ public keys on every system which would pull the image
+2. A web server has to run somewhere which has access to the signature storage
+3. The web server has to be configured in any
+ `/etc/containers/registries.d/*.yaml` file
+4. Every image pulling system has to be configured to contain the enforcing
+ policy configuration via `policy.conf`
+
+That’s it for image signing and GPG. The cool thing is that this setup works out
+of the box with [CRI-O][2] as well and can be used to sign container images in
+Kubernetes environments.
+
+[2]: https://cri-o.io
diff --git a/go.mod b/go.mod
index b079fbf65..7cac1f3b9 100644
--- a/go.mod
+++ b/go.mod
@@ -10,7 +10,7 @@ require (
github.com/containernetworking/cni v0.7.2-0.20200304161608-4fae32b84921
github.com/containernetworking/plugins v0.8.5
github.com/containers/buildah v1.14.3
- github.com/containers/common v0.5.0
+ github.com/containers/common v0.6.1
github.com/containers/conmon v2.0.10+incompatible
github.com/containers/image/v5 v5.2.1
github.com/containers/psgo v1.4.0
diff --git a/go.sum b/go.sum
index 08d321a9f..8e725dc4d 100644
--- a/go.sum
+++ b/go.sum
@@ -77,6 +77,8 @@ github.com/containers/common v0.4.2 h1:O5d1gj/xdpQdZi0MEivRQ/7AeRaVeHdbSP/bvShw4
github.com/containers/common v0.4.2/go.mod h1:m62kenckrWi5rZx32kaLje2Og0hpf6NsaTBn6+b+Oys=
github.com/containers/common v0.5.0 h1:ZAef7h3oO46PcbTyfooZf8XLHrYad+GkhSu3EhH6P24=
github.com/containers/common v0.5.0/go.mod h1:m62kenckrWi5rZx32kaLje2Og0hpf6NsaTBn6+b+Oys=
+github.com/containers/common v0.6.1 h1:z9VeVXYeOnNV99uNLp7zoE5KO1n0hqz1mdm5a6AiIrA=
+github.com/containers/common v0.6.1/go.mod h1:m62kenckrWi5rZx32kaLje2Og0hpf6NsaTBn6+b+Oys=
github.com/containers/conmon v2.0.10+incompatible h1:EiwL41r5vx8SxG+dyUmbJ3baV9GUWjijPOdCkzM6gWU=
github.com/containers/conmon v2.0.10+incompatible/go.mod h1:hgwZ2mtuDrppv78a/cOBNiCm6O0UMWGx1mu7P00nu5I=
github.com/containers/image/v5 v5.2.1 h1:rQR6QSUneWBoW1bTFpP9EJJTevQFv27YsKYQVJIzg+s=
diff --git a/libpod/container_internal.go b/libpod/container_internal.go
index 12a13a0ce..7a85c1f04 100644
--- a/libpod/container_internal.go
+++ b/libpod/container_internal.go
@@ -470,9 +470,9 @@ func (c *Container) teardownStorage() error {
return nil
}
-// Reset resets state fields to default values
-// It is performed before a refresh and clears the state after a reboot
-// It does not save the results - assumes the database will do that for us
+// Reset resets state fields to default values.
+// It is performed before a refresh and clears the state after a reboot.
+// It does not save the results - assumes the database will do that for us.
func resetState(state *ContainerState) error {
state.PID = 0
state.ConmonPID = 0
@@ -483,7 +483,6 @@ func resetState(state *ContainerState) error {
}
state.ExecSessions = make(map[string]*ExecSession)
state.LegacyExecSessions = nil
- state.NetworkStatus = nil
state.BindMounts = make(map[string]string)
state.StoppedByUser = false
state.RestartPolicyMatch = false
@@ -539,6 +538,18 @@ func (c *Container) refresh() error {
}
c.lock = lock
+ // Try to delete any lingering IP allocations.
+ // If this fails, just log and ignore.
+ // I'm a little concerned that this is so far down in refresh() and we
+ // could fail before getting to it - but the worst that would happen is
+ // that Inspect() would return info on IPs we no longer own.
+ if len(c.state.NetworkStatus) > 0 {
+ if err := c.removeIPv4Allocations(); err != nil {
+ logrus.Errorf("Error removing IP allocations for container %s: %v", c.ID(), err)
+ }
+ }
+ c.state.NetworkStatus = nil
+
if err := c.save(); err != nil {
return errors.Wrapf(err, "error refreshing state for container %s", c.ID())
}
@@ -548,11 +559,58 @@ func (c *Container) refresh() error {
return err
}
- if rootless.IsRootless() {
+ return nil
+}
+
+// Try and remove IP address allocations. Presently IPv4 only.
+// Should be safe as rootless because NetworkStatus should only be populated if
+// CNI is running.
+func (c *Container) removeIPv4Allocations() error {
+ cniNetworksDir, err := getCNINetworksDir()
+ if err != nil {
+ return err
+ }
+
+ if len(c.state.NetworkStatus) == 0 {
return nil
}
- return c.refreshCNI()
+ cniDefaultNetwork := ""
+ if c.runtime.netPlugin != nil {
+ cniDefaultNetwork = c.runtime.netPlugin.GetDefaultNetworkName()
+ }
+
+ switch {
+ case len(c.config.Networks) > 0 && len(c.config.Networks) != len(c.state.NetworkStatus):
+ return errors.Wrapf(define.ErrInternal, "network mismatch: asked to join %d CNI networks but got %d CNI results", len(c.config.Networks), len(c.state.NetworkStatus))
+ case len(c.config.Networks) == 0 && len(c.state.NetworkStatus) != 1:
+ return errors.Wrapf(define.ErrInternal, "network mismatch: did not specify CNI networks but joined more than one (%d)", len(c.state.NetworkStatus))
+ case len(c.config.Networks) == 0 && cniDefaultNetwork == "":
+ return errors.Wrapf(define.ErrInternal, "could not retrieve name of CNI default network")
+ }
+
+ for index, result := range c.state.NetworkStatus {
+ for _, ctrIP := range result.IPs {
+ if ctrIP.Version != "4" {
+ continue
+ }
+ candidate := ""
+ if len(c.config.Networks) > 0 {
+ // CNI returns networks in order we passed them.
+ // So our index into results should be our index
+ // into networks.
+ candidate = filepath.Join(cniNetworksDir, c.config.Networks[index], ctrIP.Address.IP.String())
+ } else {
+ candidate = filepath.Join(cniNetworksDir, cniDefaultNetwork, ctrIP.Address.IP.String())
+ }
+ logrus.Debugf("Going to try removing IP address reservation file %q for container %s", candidate, c.ID())
+ if err := os.Remove(candidate); err != nil && !os.IsNotExist(err) {
+ return errors.Wrapf(err, "error removing CNI IP reservation file %q for container %s", candidate, c.ID())
+ }
+ }
+ }
+
+ return nil
}
// Remove conmon attach socket and terminal resize FIFO
diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go
index 63968918c..2f0f59c24 100644
--- a/libpod/container_internal_linux.go
+++ b/libpod/container_internal_linux.go
@@ -1436,13 +1436,6 @@ func (c *Container) copyOwnerAndPerms(source, dest string) error {
return nil
}
-// Teardown CNI config on refresh
-func (c *Container) refreshCNI() error {
- // Let's try and delete any lingering network config...
- podNetwork := c.runtime.getPodNetwork(c.ID(), c.config.Name, "", c.config.Networks, c.config.PortMappings, c.config.StaticIP, c.config.StaticMAC)
- return c.runtime.netPlugin.TearDownPod(podNetwork)
-}
-
// Get cgroup path in a format suitable for the OCI spec
func (c *Container) getOCICgroupPath() (string, error) {
unified, err := cgroups.IsCgroup2UnifiedMode()
diff --git a/libpod/container_internal_unsupported.go b/libpod/container_internal_unsupported.go
index 4abaa6362..395271b2a 100644
--- a/libpod/container_internal_unsupported.go
+++ b/libpod/container_internal_unsupported.go
@@ -41,10 +41,6 @@ func (c *Container) copyOwnerAndPerms(source, dest string) error {
return nil
}
-func (c *Container) refreshCNI() error {
- return define.ErrNotImplemented
-}
-
func (c *Container) getOCICgroupPath() (string, error) {
return "", define.ErrNotImplemented
}
diff --git a/libpod/networking_linux.go b/libpod/networking_linux.go
index 5a27a2abb..f1bf79ce7 100644
--- a/libpod/networking_linux.go
+++ b/libpod/networking_linux.go
@@ -657,6 +657,13 @@ func resultToBasicNetworkConfig(result *cnitypes.Result) (InspectBasicNetworkCon
return config, nil
}
+// This is a horrible hack, necessary because CNI does not properly clean up
+// after itself on an unclean reboot. Return what we're pretty sure is the path
+// to CNI's internal files (it's not really exposed to us).
+func getCNINetworksDir() (string, error) {
+ return "/var/lib/cni/networks", nil
+}
+
type logrusDebugWriter struct {
prefix string
}
diff --git a/libpod/networking_unsupported.go b/libpod/networking_unsupported.go
index 7f343cf35..32b354a44 100644
--- a/libpod/networking_unsupported.go
+++ b/libpod/networking_unsupported.go
@@ -23,3 +23,7 @@ func (r *Runtime) createNetNS(ctr *Container) (err error) {
func (c *Container) getContainerNetworkInfo() (*InspectNetworkSettings, error) {
return nil, define.ErrNotImplemented
}
+
+func getCNINetworksDir() (string, error) {
+ return "", define.ErrNotImplemented
+}
diff --git a/pkg/adapter/containers.go b/pkg/adapter/containers.go
index a5242270e..0d2ca1a64 100644
--- a/pkg/adapter/containers.go
+++ b/pkg/adapter/containers.go
@@ -1057,7 +1057,8 @@ func (r *LocalRuntime) Prune(ctx context.Context, maxWorkers int, filters []stri
if c.PodID() != "" {
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/adapter/runtime_remote.go b/pkg/adapter/runtime_remote.go
index d87de481c..fc396eddb 100644
--- a/pkg/adapter/runtime_remote.go
+++ b/pkg/adapter/runtime_remote.go
@@ -291,7 +291,8 @@ func (r *LocalRuntime) NewImageFromLocal(name string) (*ContainerImage, error) {
// LoadFromArchiveReference creates an image from a local archive
func (r *LocalRuntime) LoadFromArchiveReference(ctx context.Context, srcRef types.ImageReference, signaturePolicyPath string, writer io.Writer) ([]*ContainerImage, error) {
var iid string
- reply, err := iopodman.PullImage().Send(r.Conn, varlink.More, srcRef.DockerReference().String())
+ creds := iopodman.AuthConfig{}
+ reply, err := iopodman.PullImage().Send(r.Conn, varlink.More, srcRef.DockerReference().String(), creds)
if err != nil {
return nil, err
}
@@ -323,7 +324,12 @@ func (r *LocalRuntime) New(ctx context.Context, name, signaturePolicyPath, authf
if label != nil {
return nil, errors.New("the remote client function does not support checking a remote image for a label")
}
- reply, err := iopodman.PullImage().Send(r.Conn, varlink.More, name)
+ creds := iopodman.AuthConfig{}
+ if dockeroptions.DockerRegistryCreds != nil {
+ creds.Username = dockeroptions.DockerRegistryCreds.Username
+ creds.Password = dockeroptions.DockerRegistryCreds.Password
+ }
+ reply, err := iopodman.PullImage().Send(r.Conn, varlink.More, name, creds)
if err != nil {
return nil, err
}
diff --git a/pkg/api/handlers/libpod/images.go b/pkg/api/handlers/libpod/images.go
index cfd3b993e..b6f2f58e8 100644
--- a/pkg/api/handlers/libpod/images.go
+++ b/pkg/api/handlers/libpod/images.go
@@ -10,12 +10,15 @@ import (
"strconv"
"strings"
+ "github.com/containers/buildah"
"github.com/containers/image/v5/docker"
"github.com/containers/image/v5/docker/reference"
+ "github.com/containers/image/v5/manifest"
"github.com/containers/image/v5/transports/alltransports"
"github.com/containers/image/v5/types"
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/libpod/image"
+ image2 "github.com/containers/libpod/libpod/image"
"github.com/containers/libpod/pkg/api/handlers"
"github.com/containers/libpod/pkg/api/handlers/utils"
"github.com/containers/libpod/pkg/util"
@@ -416,3 +419,84 @@ func ImagesPull(w http.ResponseWriter, r *http.Request) {
utils.WriteResponse(w, http.StatusOK, res)
}
+
+func CommitContainer(w http.ResponseWriter, r *http.Request) {
+ var (
+ destImage string
+ mimeType string
+ )
+ decoder := r.Context().Value("decoder").(*schema.Decoder)
+ runtime := r.Context().Value("runtime").(*libpod.Runtime)
+
+ query := struct {
+ Author string `schema:"author"`
+ Changes []string `schema:"changes"`
+ Comment string `schema:"comment"`
+ Container string `schema:"container"`
+ Format string `schema:"format"`
+ Pause bool `schema:"pause"`
+ Repo string `schema:"repo"`
+ Tag string `schema:"tag"`
+ }{
+ Format: "oci",
+ }
+
+ if err := decoder.Decode(&query, r.URL.Query()); err != nil {
+ utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "Failed to parse parameters for %s", r.URL.String()))
+ return
+ }
+ rtc, err := runtime.GetConfig()
+ if err != nil {
+ utils.Error(w, "failed to get runtime config", http.StatusInternalServerError, errors.Wrap(err, "failed to get runtime config"))
+ return
+ }
+ sc := image2.GetSystemContext(rtc.SignaturePolicyPath, "", false)
+ tag := "latest"
+ options := libpod.ContainerCommitOptions{
+ Pause: true,
+ }
+ switch query.Format {
+ case "oci":
+ mimeType = buildah.OCIv1ImageManifest
+ if len(query.Comment) > 0 {
+ utils.InternalServerError(w, errors.New("messages are only compatible with the docker image format (-f docker)"))
+ return
+ }
+ case "docker":
+ mimeType = manifest.DockerV2Schema2MediaType
+ default:
+ utils.InternalServerError(w, errors.Errorf("unrecognized image format %q", query.Format))
+ return
+ }
+ options.CommitOptions = buildah.CommitOptions{
+ SignaturePolicyPath: rtc.SignaturePolicyPath,
+ ReportWriter: os.Stderr,
+ SystemContext: sc,
+ PreferredManifestType: mimeType,
+ }
+
+ if len(query.Tag) > 0 {
+ tag = query.Tag
+ }
+ options.Message = query.Comment
+ options.Author = query.Author
+ options.Pause = query.Pause
+ options.Changes = query.Changes
+ ctr, err := runtime.LookupContainer(query.Container)
+ if err != nil {
+ utils.Error(w, "failed to lookup container", http.StatusNotFound, err)
+ return
+ }
+
+ // I know mitr hates this ... but doing for now
+ if len(query.Repo) > 1 {
+ destImage = fmt.Sprintf("%s:%s", query.Repo, tag)
+ }
+
+ commitImage, err := ctr.Commit(r.Context(), destImage, options)
+ if err != nil && !strings.Contains(err.Error(), "is not running") {
+ utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrapf(err, "CommitFailure"))
+ return
+ }
+ utils.WriteResponse(w, http.StatusOK, handlers.IDResponse{ID: commitImage.ID()}) // nolint
+}
diff --git a/pkg/api/server/register_images.go b/pkg/api/server/register_images.go
index e6ad045a2..87ddf5add 100644
--- a/pkg/api/server/register_images.go
+++ b/pkg/api/server/register_images.go
@@ -978,6 +978,7 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// name: container
// type: string
// description: the name or ID of a container
+ // required: true
// - in: query
// name: repo
// type: string
@@ -1000,8 +1001,14 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// description: pause the container before committing it
// - in: query
// name: changes
+ // description: instructions to apply while committing in Dockerfile format (i.e. "CMD=/bin/foo")
+ // type: array
+ // items:
+ // type: string
+ // - in: query
+ // name: format
// type: string
- // description: instructions to apply while committing in Dockerfile format
+ // description: format of the image manifest and metadata (default "oci")
// produces:
// - application/json
// responses:
@@ -1011,6 +1018,6 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// $ref: '#/responses/NoSuchImage'
// 500:
// $ref: '#/responses/InternalError'
- r.Handle(VersionedPath("/commit"), s.APIHandler(compat.CommitContainer)).Methods(http.MethodPost)
+ r.Handle(VersionedPath("/libpod/commit"), s.APIHandler(libpod.CommitContainer)).Methods(http.MethodPost)
return nil
}
diff --git a/pkg/bindings/containers/commit.go b/pkg/bindings/containers/commit.go
new file mode 100644
index 000000000..12c25f842
--- /dev/null
+++ b/pkg/bindings/containers/commit.go
@@ -0,0 +1,49 @@
+package containers
+
+import (
+ "context"
+ "net/http"
+ "net/url"
+ "strconv"
+
+ "github.com/containers/libpod/pkg/api/handlers"
+ "github.com/containers/libpod/pkg/bindings"
+)
+
+// Commit creates a container image from a container. The container is defined by nameOrId. Use
+// the CommitOptions for finer grain control on characteristics of the resulting image.
+func Commit(ctx context.Context, nameOrId string, options CommitOptions) (handlers.IDResponse, error) {
+ id := handlers.IDResponse{}
+ conn, err := bindings.GetClient(ctx)
+ if err != nil {
+ return id, err
+ }
+ params := url.Values{}
+ params.Set("container", nameOrId)
+ if options.Author != nil {
+ params.Set("author", *options.Author)
+ }
+ for _, change := range options.Changes {
+ params.Set("changes", change)
+ }
+ if options.Comment != nil {
+ params.Set("comment", *options.Comment)
+ }
+ if options.Format != nil {
+ params.Set("format", *options.Format)
+ }
+ if options.Pause != nil {
+ params.Set("pause", strconv.FormatBool(*options.Pause))
+ }
+ if options.Repo != nil {
+ params.Set("repo", *options.Repo)
+ }
+ if options.Tag != nil {
+ params.Set("tag", *options.Tag)
+ }
+ response, err := conn.DoRequest(nil, http.MethodPost, "/commit", params)
+ if err != nil {
+ return id, err
+ }
+ return id, response.Process(&id)
+}
diff --git a/pkg/bindings/containers/types.go b/pkg/bindings/containers/types.go
index 87342f7ea..31daaf565 100644
--- a/pkg/bindings/containers/types.go
+++ b/pkg/bindings/containers/types.go
@@ -11,3 +11,16 @@ type LogOptions struct {
Timestamps *bool
Until *string
}
+
+// CommitOptions describe details about the resulting commited
+// image as defined by repo and tag. None of these options
+// are required.
+type CommitOptions struct {
+ Author *string
+ Changes []string
+ Comment *string
+ Format *string
+ Pause *bool
+ Repo *string
+ Tag *string
+}
diff --git a/pkg/bindings/test/pods_test.go b/pkg/bindings/test/pods_test.go
index bcf8e69b8..e94048a9c 100644
--- a/pkg/bindings/test/pods_test.go
+++ b/pkg/bindings/test/pods_test.go
@@ -79,7 +79,9 @@ var _ = Describe("Podman pods", func() {
// The test validates the list pod endpoint with passing filters as the params.
It("List pods with filters", func() {
- var newpod2 string = "newpod2"
+ var (
+ newpod2 string = "newpod2"
+ )
bt.Podcreate(&newpod2)
_, err = bt.RunTopContainer(nil, &bindings.PTrue, &newpod)
Expect(err).To(BeNil())
diff --git a/pkg/rootlessport/rootlessport_linux.go b/pkg/rootlessport/rootlessport_linux.go
index febfc2268..6ecd3cf98 100644
--- a/pkg/rootlessport/rootlessport_linux.go
+++ b/pkg/rootlessport/rootlessport_linux.go
@@ -19,6 +19,7 @@ import (
"io/ioutil"
"os"
"os/exec"
+ "os/signal"
"syscall"
"github.com/containernetworking/plugins/pkg/ns"
@@ -101,6 +102,28 @@ func parent() error {
return err
}
+ sigC := make(chan os.Signal, 1)
+ signal.Notify(sigC, syscall.SIGPIPE)
+ defer func() {
+ // dummy signal to terminate the goroutine
+ sigC <- syscall.SIGKILL
+ }()
+ go func() {
+ defer func() {
+ signal.Stop(sigC)
+ close(sigC)
+ }()
+
+ s := <-sigC
+ if s == syscall.SIGPIPE {
+ if f, err := os.OpenFile("/dev/null", os.O_WRONLY, 0755); err == nil {
+ syscall.Dup2(int(f.Fd()), 1) // nolint:errcheck
+ syscall.Dup2(int(f.Fd()), 2) // nolint:errcheck
+ f.Close()
+ }
+ }
+ }()
+
// create the parent driver
stateDir, err := ioutil.TempDir(cfg.TmpDir, "rootlessport")
if err != nil {
diff --git a/pkg/varlinkapi/images.go b/pkg/varlinkapi/images.go
index c4809f16b..2dfb84e58 100644
--- a/pkg/varlinkapi/images.go
+++ b/pkg/varlinkapi/images.go
@@ -688,12 +688,18 @@ func (i *LibpodAPI) ExportImage(call iopodman.VarlinkCall, name, destination str
}
// PullImage pulls an image from a registry to the image store.
-func (i *LibpodAPI) PullImage(call iopodman.VarlinkCall, name string) error {
+func (i *LibpodAPI) PullImage(call iopodman.VarlinkCall, name string, creds iopodman.AuthConfig) error {
var (
imageID string
err error
)
- dockerRegistryOptions := image.DockerRegistryOptions{}
+ dockerRegistryOptions := image.DockerRegistryOptions{
+ DockerRegistryCreds: &types.DockerAuthConfig{
+ Username: creds.Username,
+ Password: creds.Password,
+ },
+ }
+
so := image.SigningOptions{}
if call.WantsMore() {
diff --git a/test/e2e/prune_test.go b/test/e2e/prune_test.go
index c9b01ad4a..672b0e103 100644
--- a/test/e2e/prune_test.go
+++ b/test/e2e/prune_test.go
@@ -59,6 +59,34 @@ var _ = Describe("Podman prune", func() {
Expect(podmanTest.NumberOfContainers()).To(Equal(1))
})
+ It("podman container prune after create containers", func() {
+ create := podmanTest.Podman([]string{"create", "--name", "test", BB})
+ create.WaitWithDefaultTimeout()
+ Expect(create.ExitCode()).To(Equal(0))
+
+ prune := podmanTest.Podman([]string{"container", "prune", "-f"})
+ prune.WaitWithDefaultTimeout()
+ Expect(prune.ExitCode()).To(Equal(0))
+
+ Expect(podmanTest.NumberOfContainers()).To(Equal(0))
+ })
+
+ It("podman container prune after create & init containers", func() {
+ create := podmanTest.Podman([]string{"create", "--name", "test", BB})
+ create.WaitWithDefaultTimeout()
+ Expect(create.ExitCode()).To(Equal(0))
+
+ init := podmanTest.Podman([]string{"init", "test"})
+ init.WaitWithDefaultTimeout()
+ Expect(init.ExitCode()).To(Equal(0))
+
+ prune := podmanTest.Podman([]string{"container", "prune", "-f"})
+ prune.WaitWithDefaultTimeout()
+ Expect(prune.ExitCode()).To(Equal(0))
+
+ Expect(podmanTest.NumberOfContainers()).To(Equal(0))
+ })
+
It("podman image prune none images", func() {
SkipIfRemote()
podmanTest.BuildImage(pruneImage, "alpine_bash:latest", "true")
diff --git a/test/e2e/volume_prune_test.go b/test/e2e/volume_prune_test.go
index ba249278b..3049646b0 100644
--- a/test/e2e/volume_prune_test.go
+++ b/test/e2e/volume_prune_test.go
@@ -89,7 +89,7 @@ var _ = Describe("Podman volume prune", func() {
session = podmanTest.Podman([]string{"volume", "ls"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- Expect(len(session.OutputToStringArray())).To(Equal(2))
+ Expect(len(session.OutputToStringArray())).To(Equal(0))
podmanTest.Cleanup()
})
diff --git a/test/system/010-images.bats b/test/system/010-images.bats
index 3224c9b42..6957d4830 100644
--- a/test/system/010-images.bats
+++ b/test/system/010-images.bats
@@ -27,11 +27,11 @@ load helpers
@test "podman images - json" {
# 'created': podman includes fractional seconds, podman-remote does not
tests="
-names[0] | $PODMAN_TEST_IMAGE_FQN
-id | [0-9a-f]\\\{64\\\}
-digest | sha256:[0-9a-f]\\\{64\\\}
-created | [0-9-]\\\+T[0-9:.]\\\+Z
-size | [0-9]\\\+
+Names[0] | $PODMAN_TEST_IMAGE_FQN
+ID | [0-9a-f]\\\{64\\\}
+Digest | sha256:[0-9a-f]\\\{64\\\}
+CreatedAt | [0-9-]\\\+T[0-9:.]\\\+Z
+Size | [0-9]\\\+
"
run_podman images -a --format json
diff --git a/vendor/github.com/containers/common/pkg/config/config.go b/vendor/github.com/containers/common/pkg/config/config.go
index 0a09d994e..db70e53a4 100644
--- a/vendor/github.com/containers/common/pkg/config/config.go
+++ b/vendor/github.com/containers/common/pkg/config/config.go
@@ -160,11 +160,6 @@ type ContainersConfig struct {
// ShmSize holds the size of /dev/shm.
ShmSize string `toml:"shm_size"`
- // SignaturePolicyPath is the path to a signature policy to use for
- // validating images. If left empty, the containers/image default signature
- // policy will be used.
- SignaturePolicyPath string `toml:"_"`
-
// UTSNS indicates how to create a UTS namespace for the container
UTSNS string `toml:"utsns"`
@@ -283,6 +278,11 @@ type EngineConfig struct {
// backwards compat with older version of libpod and Podman.
SetOptions
+ // SignaturePolicyPath is the path to a signature policy to use for
+ // validating images. If left empty, the containers/image default signature
+ // policy will be used.
+ SignaturePolicyPath string `toml:"_"`
+
// SDNotify tells container engine to allow containers to notify the host systemd of
// readiness using the SD_NOTIFY mechanism.
SDNotify bool
@@ -827,6 +827,9 @@ func isDirectory(path string) error {
}
func rootlessConfigPath() (string, error) {
+ if configHome := os.Getenv("XDG_CONFIG_HOME"); configHome != "" {
+ return filepath.Join(configHome, UserOverrideContainersConfig), nil
+ }
home, err := unshare.HomeDir()
if err != nil {
return "", err
diff --git a/vendor/github.com/containers/common/pkg/config/default.go b/vendor/github.com/containers/common/pkg/config/default.go
index dca320d87..04c3f9773 100644
--- a/vendor/github.com/containers/common/pkg/config/default.go
+++ b/vendor/github.com/containers/common/pkg/config/default.go
@@ -123,7 +123,6 @@ func DefaultConfig() (*Config, error) {
return nil, err
}
- var signaturePolicyPath string
netns := "bridge"
if unshare.IsRootless() {
home, err := unshare.HomeDir()
@@ -132,7 +131,7 @@ func DefaultConfig() (*Config, error) {
}
sigPath := filepath.Join(home, DefaultRootlessSignaturePolicyPath)
if _, err := os.Stat(sigPath); err == nil {
- signaturePolicyPath = sigPath
+ defaultEngineConfig.SignaturePolicyPath = sigPath
}
netns = "slirp4netns"
}
@@ -154,23 +153,22 @@ func DefaultConfig() (*Config, error) {
Env: []string{
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
},
- EnvHost: false,
- HTTPProxy: false,
- Init: false,
- InitPath: "",
- IPCNS: "private",
- LogDriver: DefaultLogDriver,
- LogSizeMax: DefaultLogSizeMax,
- NetNS: netns,
- NoHosts: false,
- PidsLimit: DefaultPidsLimit,
- PidNS: "private",
- SeccompProfile: SeccompDefaultPath,
- ShmSize: DefaultShmSize,
- SignaturePolicyPath: signaturePolicyPath,
- UTSNS: "private",
- UserNS: "private",
- UserNSSize: DefaultUserNSSize,
+ EnvHost: false,
+ HTTPProxy: false,
+ Init: false,
+ InitPath: "",
+ IPCNS: "private",
+ LogDriver: DefaultLogDriver,
+ LogSizeMax: DefaultLogSizeMax,
+ NetNS: netns,
+ NoHosts: false,
+ PidsLimit: DefaultPidsLimit,
+ PidNS: "private",
+ SeccompProfile: SeccompDefaultPath,
+ ShmSize: DefaultShmSize,
+ UTSNS: "private",
+ UserNS: "private",
+ UserNSSize: DefaultUserNSSize,
},
Network: NetworkConfig{
DefaultNetwork: "podman",
diff --git a/vendor/github.com/containers/common/pkg/config/default_linux.go b/vendor/github.com/containers/common/pkg/config/default_linux.go
index 43ef5da78..91b73d344 100644
--- a/vendor/github.com/containers/common/pkg/config/default_linux.go
+++ b/vendor/github.com/containers/common/pkg/config/default_linux.go
@@ -18,7 +18,7 @@ func isCgroup2UnifiedMode() (isUnified bool, isUnifiedErr error) {
if err := syscall.Statfs(cgroupRoot, &st); err != nil {
isUnified, isUnifiedErr = false, err
} else {
- isUnified, isUnifiedErr = st.Type == unix.CGROUP2_SUPER_MAGIC, nil
+ isUnified, isUnifiedErr = int64(st.Type) == int64(unix.CGROUP2_SUPER_MAGIC), nil
}
return
}
diff --git a/vendor/github.com/containers/common/pkg/config/libpodConfig.go b/vendor/github.com/containers/common/pkg/config/libpodConfig.go
index be168208b..333f43815 100644
--- a/vendor/github.com/containers/common/pkg/config/libpodConfig.go
+++ b/vendor/github.com/containers/common/pkg/config/libpodConfig.go
@@ -302,10 +302,9 @@ func rootlessLibpodConfigPath() (string, error) {
func (c *Config) libpodConfig() *ConfigFromLibpod {
return &ConfigFromLibpod{
- SignaturePolicyPath: c.Containers.SignaturePolicyPath,
- InitPath: c.Containers.InitPath,
- MaxLogSize: c.Containers.LogSizeMax,
- EnableLabeling: c.Containers.EnableLabeling,
+ InitPath: c.Containers.InitPath,
+ MaxLogSize: c.Containers.LogSizeMax,
+ EnableLabeling: c.Containers.EnableLabeling,
SetOptions: c.Engine.SetOptions,
VolumePath: c.Engine.VolumePath,
@@ -334,6 +333,7 @@ func (c *Config) libpodConfig() *ConfigFromLibpod {
DetachKeys: c.Engine.DetachKeys,
SDNotify: c.Engine.SDNotify,
CgroupCheck: c.Engine.CgroupCheck,
+ SignaturePolicyPath: c.Engine.SignaturePolicyPath,
CNIConfigDir: c.Network.NetworkConfigDir,
CNIPluginDir: c.Network.CNIPluginDirs,
@@ -343,11 +343,11 @@ func (c *Config) libpodConfig() *ConfigFromLibpod {
func (c *Config) libpodToContainersConfig(libpodConf *ConfigFromLibpod) {
- c.Containers.SignaturePolicyPath = libpodConf.SignaturePolicyPath
c.Containers.InitPath = libpodConf.InitPath
c.Containers.LogSizeMax = libpodConf.MaxLogSize
c.Containers.EnableLabeling = libpodConf.EnableLabeling
+ c.Engine.SignaturePolicyPath = libpodConf.SignaturePolicyPath
c.Engine.SetOptions = libpodConf.SetOptions
c.Engine.VolumePath = libpodConf.VolumePath
c.Engine.ImageDefaultTransport = libpodConf.ImageDefaultTransport
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 1ad73e1bc..b143eea5a 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -82,7 +82,7 @@ github.com/containers/buildah/pkg/secrets
github.com/containers/buildah/pkg/supplemented
github.com/containers/buildah/pkg/umask
github.com/containers/buildah/util
-# github.com/containers/common v0.5.0
+# github.com/containers/common v0.6.1
github.com/containers/common/pkg/capabilities
github.com/containers/common/pkg/config
github.com/containers/common/pkg/unshare