diff options
145 files changed, 3823 insertions, 1349 deletions
diff --git a/.copr/Makefile b/.copr/Makefile index a2a6e93ca..05d9eb592 100644 --- a/.copr/Makefile +++ b/.copr/Makefile @@ -2,7 +2,18 @@ mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST))) current_dir := $(notdir $(patsubst %/,%,$(dir $(mkfile_path)))) outdir := $(CURDIR) +topdir := $(CURDIR)/rpmbuild +SHORT_COMMIT ?= $(shell git rev-parse --short=8 HEAD) srpm: + mkdir -p $(topdir) sh $(current_dir)/prepare.sh - rpmbuild -bs -D "dist %{nil}" -D "_sourcedir build/" -D "_srcrpmdir $(outdir)" --nodeps contrib/spec/podman.spec + rpmbuild -bs -D "dist %{nil}" -D "_sourcedir build/" -D "_srcrpmdir $(outdir)" -D "_topdir $(topdir)" --nodeps contrib/spec/podman.spec + +build_binary: + mkdir -p $(topdir) + rpmbuild --rebuild -D "_rpmdir $(outdir)" -D "_topdir $(topdir)" $(outdir)/podman-*.git$(SHORT_COMMIT).src.rpm + +clean: + rm -fr rpms + rm -fr cri-o diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 4b6ddb2e4..acb2b2bd3 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -4,7 +4,6 @@ BUG REPORT INFORMATION --------------------------------------------------- Use the commands below to provide key information from your environment: You do NOT have to include this information if this is a FEATURE REQUEST ---> **NOTE** A large number of issues reported against Podman are often found to already be fixed in more current versions of the project. Before reporting an issue, please verify the @@ -14,9 +13,10 @@ update your version of Podman to the latest possible and retry your command befo an issue. If you are filing a bug against `podman build`, please instead file a bug -against Buildah (https://github.com/projectatomic/buildah/issues). Podman build +against Buildah (https://github.com/containers/buildah/issues). Podman build executes Buildah to perform container builds, and as such the Buildah maintainers are best equipped to handle these bugs. +--> **Is this a BUG REPORT or FEATURE REQUEST?**: @@ -2,33 +2,131 @@ set -xeuo pipefail export GOPATH=/go -export PATH=$HOME/gopath/bin:$PATH -export GOSRC=/$GOPATH/src/github.com/containers/libpod +export PATH=$HOME/gopath/bin:$PATH:$GOPATH/bin +export GOSRC=$GOPATH/src/github.com/containers/libpod + +DIST=${DIST:=""} +pwd + +# -i install +# -b build +# -t integration test +# -u unit test +# -v validate +# -p run python tests + +build=0 +install=0 +integrationtest=0 +unittest=0 +validate=0 +runpython=0 +options=0 +install_tools_made=0 + +while getopts "biptuv" opt; do + case "$opt" in + b) build=1 + options=1 + ;; + i) install=1 + options=1 + ;; + p) runpython=1 + options=1 + ;; + t) integrationtest=1 + options=1 + ;; + u) unittest=1 + options=1 + ;; + v) validate=1 + options=1 + ;; + esac +done + +# If no options are passed, do everything +if [ $options -eq 0 ]; then + build=1 + install=1 + integrationtest=1 + unittest=1 + validate=1 +fi + +# Make Install tools function used by multiple sections below +make_install_tools () { + # Only make the install tools once + if [ $install_tools_made -eq 0 ]; then + make install.tools TAGS="${TAGS}" + fi + install_tools_made=1 +} + +CONTAINER_RUNTIME=${CONTAINER_RUNTIME:-none} + +if [ "${CONTAINER_RUNTIME}" == "none" ]; then + mkdir -p /$GOPATH/src/github.com/containers/ + mv /var/tmp/checkout $GOSRC + cd $GOSRC + pwd +fi -# PAPR adds a merge commit, for testing, which fails the -# short-commit-subject validation test, so tell git-validate.sh to only check -# up to, but not including, the merge commit. -export GITVALIDATE_TIP=$(cd $GOSRC; git log -2 --pretty='%H' | tail -n 1) export TAGS="seccomp $($GOSRC/hack/btrfs_tag.sh) $($GOSRC/hack/libdm_tag.sh) $($GOSRC/hack/btrfs_installed_tag.sh) $($GOSRC/hack/ostree_tag.sh) $($GOSRC/hack/selinux_tag.sh)" -make gofmt TAGS="${TAGS}" -make localunit TAGS="${TAGS}" +# Validate +if [ $validate -eq 1 ]; then + make_install_tools + # PAPR adds a merge commit, for testing, which fails the + # short-commit-subject validation test, so tell git-validate.sh to only check + # up to, but not including, the merge commit. + export GITVALIDATE_TIP=$(cd $GOSRC; git log -2 --pretty='%H' | tail -n 1) + make gofmt TAGS="${TAGS}" + + # Only check lint and gitvalidation on more recent + # distros with updated git and tooling + if [[ ${DIST} == "Fedora" ]]; then + HEAD=$GITVALIDATE_TIP make -C $GOSRC .gitvalidation TAGS="${TAGS}" + make lint + fi +fi + +# Unit tests +if [ $unittest -eq 1 ]; then + make localunit TAGS="${TAGS}" +fi -make install.tools TAGS="${TAGS}" +# Make Podman +if [ $build -eq 1 ]; then + make_install_tools + make TAGS="${TAGS}" GOPATH=$GOPATH +fi + +# Install Podman +if [ $install -eq 1 ]; then + make_install_tools + make TAGS="${TAGS}" install.bin PREFIX=/usr ETCDIR=/etc + make TAGS="${TAGS}" install.man PREFIX=/usr ETCDIR=/etc + make TAGS="${TAGS}" install.cni PREFIX=/usr ETCDIR=/etc + make TAGS="${TAGS}" install.systemd PREFIX=/usr ETCDIR=/etc + if [ $runpython -eq 1 ]; then + make TAGS="${TAGS}" install.python PREFIX=/usr ETCDIR=/etc + fi + +fi -# Only check lint and gitvalidation on more recent -# distros with updated git and tooling -if [[ ${DIST} == "Fedora" ]]; then - HEAD=$GITVALIDATE_TIP make -C $GOSRC .gitvalidation TAGS="${TAGS}" - make lint +# Run integration tests +if [ $integrationtest -eq 1 ]; then + make TAGS="${TAGS}" test-binaries + SKIP_USERNS=1 make varlink_generate GOPATH=/go + if [ $runpython -eq 1 ]; then + SKIP_USERNS=1 make clientintegration GOPATH=/go + fi + SKIP_USERNS=1 make ginkgo GOPATH=/go fi -# Make and install podman -make TAGS="${TAGS}" -make TAGS="${TAGS}" install PREFIX=/usr ETCDIR=/etc -make TAGS="${TAGS}" test-binaries -# Run the ginkgo integration tests -SKIP_USERNS=1 GOPATH=/go make localintegration exit 0 @@ -17,11 +17,39 @@ tests: artifacts: - build.log -context: "FAH28" +context: "FAH28 - Containerized (Podman in Podman)" + +--- + + host: + distro: centos/7/atomic/smoketested + specs: + ram: 8192 + cpus: 4 + extra-repos: + - name: epel + metalink: https://mirrors.fedoraproject.org/metalink?repo=epel-7&arch=$basearch + gpgcheck: 0 + - name: cri-o + baseurl: https://cbs.centos.org/repos/virt7-container-common-candidate/$basearch/os + gpgcheck: 0 + + required: true + + timeout: 90m + + tests: + - CONTAINER_RUNTIME="docker" sh .papr_prepare.sh + + artifacts: + - build.log + + context: "CAH 7-smoketested - Containerized (Podman in Docker)" + --- host: - distro: centos/7/atomic/smoketested + distro: centos/7/cloud specs: ram: 8192 cpus: 4 @@ -33,53 +61,112 @@ extra-repos: baseurl: https://cbs.centos.org/repos/virt7-container-common-candidate/$basearch/os gpgcheck: 0 +packages: + - btrfs-progs-devel + - glib2-devel + - glibc-devel + - glibc-static + - git + - go-md2man + - gpgme-devel + - libassuan-devel + - libgpg-error-devel + - libseccomp-devel + - libselinux-devel + - ostree-devel + - pkgconfig + - make + - nc + - go-compilers-golang-compiler + - podman + required: true timeout: 90m tests: - - sh .papr_prepare.sh + - sed 's/^expand-check.*/expand-check=0/g' -i /etc/selinux/semanage.conf + - sh .papr.sh -b -i -t artifacts: - build.log -context: "CAH smoketested" - +context: "CentOS 7 Cloud" --- -inherit: true host: distro: fedora/28/cloud specs: ram: 8192 cpus: 4 packages: + - btrfs-progs-devel + - glib2-devel + - glibc-devel + - glibc-static + - git + - go-md2man + - gpgme-devel + - libassuan-devel + - libgpg-error-devel + - libseccomp-devel + - libselinux-devel + - ostree-devel + - pkgconfig + - make + - nc + - go-compilers-golang-compiler - podman - - buildah + - python3-varlink + - python3-dateutil + - python3-psutil + tests: - sed 's/^expand-check.*/expand-check=0/g' -i /etc/selinux/semanage.conf - yum -y reinstall container-selinux - - CONTAINER_RUNTIME="podman" sh .papr_prepare.sh + - sh .papr.sh -b -i -t -p + required: false timeout: 90m -context: "Fedora fedora/28/cloud Podman" +context: "Fedora 28 Cloud" --- -container: - image: registry.fedoraproject.org/fedora:28 +host: + distro: fedora/29/cloud/pungi + specs: + ram: 8192 + cpus: 4 +packages: + - btrfs-progs-devel + - glib2-devel + - glibc-devel + - glibc-static + - git + - go-md2man + - gpgme-devel + - libassuan-devel + - libgpg-error-devel + - libseccomp-devel + - libselinux-devel + - ostree-devel + - pkgconfig + - make + - nc + - go-compilers-golang-compiler + - podman + - python3-varlink + - python3-dateutil + - python3-psutil + tests: - - sh contrib/build_rpm.sh -required: true -context: "Fedora RPM regressions" + - sed 's/^expand-check.*/expand-check=0/g' -i /etc/selinux/semanage.conf + - yum -y reinstall container-selinux + - sh .papr.sh -b -i -t ---- +required: false -container: - image: registry.centos.org/centos:7 -tests: - - sh contrib/build_rpm.sh -required: true -context: "CentOS RPM regressions" +timeout: 90m +context: "Fedora 29 Cloud" diff --git a/.papr_prepare.sh b/.papr_prepare.sh index 987dcc267..30561bf26 100644 --- a/.papr_prepare.sh +++ b/.papr_prepare.sh @@ -14,4 +14,4 @@ fi ${CONTAINER_RUNTIME} build -t ${IMAGE} -f Dockerfile.${DIST} . 2>build.log # Run the tests -${CONTAINER_RUNTIME} run --rm --privileged --net=host -v $PWD:/go/src/github.com/containers/libpod --workdir /go/src/github.com/containers/libpod -e CGROUP_MANAGER=cgroupfs -e PYTHON=$PYTHON -e STORAGE_OPTIONS="--storage-driver=vfs" -e CRIO_ROOT="/go/src/github.com/containers/libpod" -e PODMAN_BINARY="/usr/bin/podman" -e CONMON_BINARY="/usr/libexec/podman/conmon" -e DIST=$DIST $IMAGE sh .papr.sh +${CONTAINER_RUNTIME} run --rm --privileged --net=host -v $PWD:/go/src/github.com/containers/libpod --workdir /go/src/github.com/containers/libpod -e CGROUP_MANAGER=cgroupfs -e PYTHON=$PYTHON -e STORAGE_OPTIONS="--storage-driver=vfs" -e CRIO_ROOT="/go/src/github.com/containers/libpod" -e PODMAN_BINARY="/usr/bin/podman" -e CONMON_BINARY="/usr/libexec/podman/conmon" -e DIST=$DIST -e CONTAINER_RUNTIME=$CONTAINER_RUNTIME $IMAGE sh .papr.sh @@ -7,12 +7,14 @@ in the [API.md](https://github.com/containers/libpod/blob/master/API.md) file in [func BuildImage(build: BuildInfo) BuildResponse](#BuildImage) -[func Commit(name: string, image_name: string, changes: []string, author: string, message: string, pause: bool) string](#Commit) +[func Commit(name: string, image_name: string, changes: []string, author: string, message: string, pause: bool, manifestType: string) string](#Commit) [func CreateContainer(create: Create) string](#CreateContainer) [func CreateImage() NotImplemented](#CreateImage) +[func CreatePod(create: PodCreate) string](#CreatePod) + [func DeleteStoppedContainers() []string](#DeleteStoppedContainers) [func DeleteUnusedImages() []string](#DeleteUnusedImages) @@ -33,6 +35,10 @@ in the [API.md](https://github.com/containers/libpod/blob/master/API.md) file in [func GetInfo() PodmanInfo](#GetInfo) +[func GetPod(name: string) ListPodData](#GetPod) + +[func GetPodStats(name: string) string, ContainerStats](#GetPodStats) + [func GetVersion() Version](#GetVersion) [func HistoryImage(name: string) ImageHistory](#HistoryImage) @@ -43,8 +49,12 @@ in the [API.md](https://github.com/containers/libpod/blob/master/API.md) file in [func InspectImage(name: string) string](#InspectImage) +[func InspectPod(name: string) string](#InspectPod) + [func KillContainer(name: string, signal: int) string](#KillContainer) +[func KillPod(name: string, signal: int) string](#KillPod) + [func ListContainerChanges(name: string) ContainerChanges](#ListContainerChanges) [func ListContainerProcesses(name: string, opts: []string) []string](#ListContainerProcesses) @@ -53,8 +63,12 @@ in the [API.md](https://github.com/containers/libpod/blob/master/API.md) file in [func ListImages() ImageInList](#ListImages) +[func ListPods() ListPodData](#ListPods) + [func PauseContainer(name: string) string](#PauseContainer) +[func PausePod(name: string) string](#PausePod) + [func Ping() StringResponse](#Ping) [func PullImage(name: string) string](#PullImage) @@ -65,26 +79,40 @@ in the [API.md](https://github.com/containers/libpod/blob/master/API.md) file in [func RemoveImage(name: string, force: bool) string](#RemoveImage) +[func RemovePod(name: string, force: bool) string](#RemovePod) + [func RenameContainer() NotImplemented](#RenameContainer) [func ResizeContainerTty() NotImplemented](#ResizeContainerTty) [func RestartContainer(name: string, timeout: int) string](#RestartContainer) +[func RestartPod(name: string) string](#RestartPod) + [func SearchImage(name: string, limit: int) ImageSearch](#SearchImage) [func StartContainer(name: string) string](#StartContainer) +[func StartPod(name: string) string](#StartPod) + [func StopContainer(name: string, timeout: int) string](#StopContainer) +[func StopPod(name: string) string](#StopPod) + [func TagImage(name: string, tagged: string) string](#TagImage) +[func TopPod() NotImplemented](#TopPod) + [func UnpauseContainer(name: string) string](#UnpauseContainer) +[func UnpausePod(name: string) string](#UnpausePod) + [func UpdateContainer() NotImplemented](#UpdateContainer) [func WaitContainer(name: string) int](#WaitContainer) +[func WaitPod() NotImplemented](#WaitPod) + [type BuildInfo](#BuildInfo) [type BuildResponse](#BuildResponse) @@ -123,8 +151,16 @@ in the [API.md](https://github.com/containers/libpod/blob/master/API.md) file in [type ListContainerData](#ListContainerData) +[type ListPodContainerInfo](#ListPodContainerInfo) + +[type ListPodData](#ListPodData) + [type NotImplemented](#NotImplemented) +[type PodContainerErrorData](#PodContainerErrorData) + +[type PodCreate](#PodCreate) + [type PodmanInfo](#PodmanInfo) [type Sockets](#Sockets) @@ -139,6 +175,12 @@ in the [API.md](https://github.com/containers/libpod/blob/master/API.md) file in [error ImageNotFound](#ImageNotFound) +[error NoContainerRunning](#NoContainerRunning) + +[error PodContainerError](#PodContainerError) + +[error PodNotFound](#PodNotFound) + [error RuntimeError](#RuntimeError) ## Methods @@ -157,7 +199,7 @@ that contains the build logs and resulting image ID. ### <a name="Commit"></a>func Commit <div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> -method Commit(name: [string](https://godoc.org/builtin#string), image_name: [string](https://godoc.org/builtin#string), changes: [[]string](#[]string), author: [string](https://godoc.org/builtin#string), message: [string](https://godoc.org/builtin#string), pause: [bool](https://godoc.org/builtin#bool)) [string](https://godoc.org/builtin#string)</div> +method Commit(name: [string](https://godoc.org/builtin#string), image_name: [string](https://godoc.org/builtin#string), changes: [[]string](#[]string), author: [string](https://godoc.org/builtin#string), message: [string](https://godoc.org/builtin#string), pause: [bool](https://godoc.org/builtin#bool), manifestType: [string](https://godoc.org/builtin#string)) [string](https://godoc.org/builtin#string)</div> Commit, creates an image from an existing container. It requires the name or ID of the container as well as the resulting image name. Optionally, you can define an author and message to be added to the resulting image. You can also define changes to the resulting image for the following @@ -184,6 +226,23 @@ $ varlink call unix:/run/podman/io.podman/io.podman.CreateContainer '{"create": method CreateImage() [NotImplemented](#NotImplemented)</div> This function is not implemented yet. +### <a name="CreatePod"></a>func CreatePod +<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> + +method CreatePod(create: [PodCreate](#PodCreate)) [string](https://godoc.org/builtin#string)</div> +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. +#### Example +~~~ +$ varlink call unix:/run/podman/io.podman/io.podman.CreatePod '{"create": {"name": "test"}}' +{ + "pod": "b05dee7bd4ccfee688099fe1588a7a898d6ddd6897de9251d4671c9b0feacb2a" +} +# $ varlink call unix:/run/podman/io.podman/io.podman.CreatePod '{"create": {"infra": true, "share": ["ipc", "net", "uts"]}}' +{ + "pod": "d7697449a8035f613c1a8891286502aca68fff7d5d49a85279b3bda229af3b28" +} +~~~ ### <a name="DeleteStoppedContainers"></a>func DeleteStoppedContainers <div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> @@ -253,7 +312,8 @@ capability of varlink if the client invokes it. method GetContainerStats(name: [string](https://godoc.org/builtin#string)) [ContainerStats](#ContainerStats)</div> GetContainerStats takes the name or ID of a container and returns a single ContainerStats structure which contains attributes like memory and cpu usage. If the container cannot be found, a -[ContainerNotFound](#ContainerNotFound) error will be returned. +[ContainerNotFound](#ContainerNotFound) error will be returned. If the container is not running, a [NoContainerRunning](#NoContainerRunning) +error will be returned #### Example ~~~ $ varlink call -m unix:/run/podman/io.podman/io.podman.GetContainerStats '{"name": "c33e4164f384"}' @@ -287,6 +347,45 @@ If the image cannot be found, an [ImageNotFound](#ImageNotFound) error will be r method GetInfo() [PodmanInfo](#PodmanInfo)</div> GetInfo returns a [PodmanInfo](#PodmanInfo) struct that describes podman and its host such as storage stats, build information of Podman, and system-wide registries. +### <a name="GetPod"></a>func GetPod +<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> + +method GetPod(name: [string](https://godoc.org/builtin#string)) [ListPodData](#ListPodData)</div> +GetPod takes a name or ID of a pod and returns single [ListPodData](#ListPodData) +structure. A [PodNotFound](#PodNotFound) error will be returned if the pod cannot be found. +See also [ListPods](ListPods). +### <a name="GetPodStats"></a>func GetPodStats +<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> + +method GetPodStats(name: [string](https://godoc.org/builtin#string)) [string](https://godoc.org/builtin#string), [ContainerStats](#ContainerStats)</div> +GetPodStats takes the name or ID of a pod and returns a pod name and slice of ContainerStats structure which +contains attributes like memory and cpu usage. If the pod cannot be found, a [PodNotFound](#PodNotFound) +error will be returned. If the pod has no running containers associated with it, a [NoContainerRunning](#NoContainerRunning) +error will be returned. +#### Example +~~~ +$ varlink call unix:/run/podman/io.podman/io.podman.GetPodStats '{"name": "7f62b508b6f12b11d8fe02e"}' +{ + "containers": [ + { + "block_input": 0, + "block_output": 0, + "cpu": 2.833470544016107524276e-08, + "cpu_nano": 54363072, + "id": "a64b51f805121fe2c5a3dc5112eb61d6ed139e3d1c99110360d08b58d48e4a93", + "mem_limit": 12276146176, + "mem_perc": 7.974359265237864966003e-03, + "mem_usage": 978944, + "name": "quirky_heisenberg", + "net_input": 866, + "net_output": 7388, + "pids": 1, + "system_nano": 20000000 + } + ], + "pod": "7f62b508b6f12b11d8fe02e0db4de6b9e43a7d7699b33a4fc0d574f6e82b4ebd" +} +~~~ ### <a name="GetVersion"></a>func GetVersion <div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> @@ -320,6 +419,13 @@ method InspectImage(name: [string](https://godoc.org/builtin#string)) [string](h InspectImage takes the name or ID of an image and returns a string respresentation of data associated with the mage. You must serialize the string into JSON to use it further. An [ImageNotFound](#ImageNotFound) error will be returned if the image cannot be found. +### <a name="InspectPod"></a>func InspectPod +<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> + +method InspectPod(name: [string](https://godoc.org/builtin#string)) [string](https://godoc.org/builtin#string)</div> +InspectPod takes the name or ID of an image and returns a string respresentation of data associated with the +pod. You must serialize the string into JSON to use it further. A [PodNotFound](#PodNotFound) error will +be returned if the pod cannot be found. ### <a name="KillContainer"></a>func KillContainer <div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> @@ -327,13 +433,22 @@ method KillContainer(name: [string](https://godoc.org/builtin#string), signal: [ KillContainer takes the name or ID of a container as well as a signal to be applied to the container. Once the container has been killed, the container's ID is returned. If the container cannot be found, a [ContainerNotFound](#ContainerNotFound) error is returned. See also [StopContainer](StopContainer). +### <a name="KillPod"></a>func KillPod +<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> + +method KillPod(name: [string](https://godoc.org/builtin#string), signal: [int](https://godoc.org/builtin#int)) [string](https://godoc.org/builtin#string)</div> +KillPod takes the name or ID of a pod as well as a signal to be applied to the pod. If the pod cannot be found, a +[PodNotFound](#PodNotFound) error is returned. +Containers in a pod are killed independently. If there is an error killing one container, the ID of those containers +will be returned in a list, along with the ID of the pod in a [PodContainerError](#PodContainerError). +If the pod was killed with no errors, the pod ID is returned. +See also [StopPod](StopPod). ### <a name="ListContainerChanges"></a>func ListContainerChanges <div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> method ListContainerChanges(name: [string](https://godoc.org/builtin#string)) [ContainerChanges](#ContainerChanges)</div> ListContainerChanges takes a name or ID of a container and returns changes between the container and -its base image. It returns a struct of changed, deleted, and added path names. If the -container cannot be found, a [ContainerNotFound](#ContainerNotFound) error will be returned. +its base image. It returns a struct of changed, deleted, and added path names. ### <a name="ListContainerProcesses"></a>func ListContainerProcesses <div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> @@ -366,6 +481,12 @@ returned as an array of ListContainerData structs. See also [GetContainer](#Get method ListImages() [ImageInList](#ImageInList)</div> ListImages returns an array of ImageInList structures which provide basic information about an image currently in storage. See also [InspectImage](InspectImage). +### <a name="ListPods"></a>func ListPods +<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> + +method ListPods() [ListPodData](#ListPodData)</div> +ListPods returns a list of pods in no particular order. They are +returned as an array of ListPodData structs. See also [GetPod](#GetPod). ### <a name="PauseContainer"></a>func PauseContainer <div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> @@ -373,6 +494,16 @@ method PauseContainer(name: [string](https://godoc.org/builtin#string)) [string] PauseContainer takes the name or ID of container and pauses it. If the container cannot be found, a [ContainerNotFound](#ContainerNotFound) error will be returned; otherwise the ID of the container is returned. See also [UnpauseContainer](#UnpauseContainer). +### <a name="PausePod"></a>func PausePod +<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> + +method PausePod(name: [string](https://godoc.org/builtin#string)) [string](https://godoc.org/builtin#string)</div> +PausePod takes the name or ID of a pod and pauses the running containers associated with it. If the pod cannot be found, +a [PodNotFound](#PodNotFound) error will be returned. +Containers in a pod are paused independently. If there is an error pausing one container, the ID of those containers +will be returned in a list, along with the ID of the pod in a [PodContainerError](#PodContainerError). +If the pod was paused with no errors, the pod ID is returned. +See also [UnpausePod](#UnpausePod). ### <a name="Ping"></a>func Ping <div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> @@ -435,6 +566,24 @@ varlink call -m unix:/run/podman/io.podman/io.podman.RemoveImage '{"name": "regi "image": "426866d6fa419873f97e5cbd320eeb22778244c1dfffa01c944db3114f55772e" } ~~~ +### <a name="RemovePod"></a>func RemovePod +<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> + +method RemovePod(name: [string](https://godoc.org/builtin#string), force: [bool](https://godoc.org/builtin#bool)) [string](https://godoc.org/builtin#string)</div> +RemovePod takes the name or ID of a pod as well a boolean representing whether a running +container in the pod can be stopped and removed. If a pod has containers associated with it, and force is not true, +an error will occur. +If the pod cannot be found by name or ID, a [PodNotFound](#PodNotFound) error will be returned. +Containers in a pod are removed independently. If there is an error removing any container, the ID of those containers +will be returned in a list, along with the ID of the pod in a [PodContainerError](#PodContainerError). +If the pod was removed with no errors, the pod ID is returned. +#### Example +~~~ +$ varlink call -m unix:/run/podman/io.podman/io.podman.RemovePod '{"name": "62f4fd98cb57", "force": "true"}' +{ + "pod": "62f4fd98cb57f529831e8f90610e54bba74bd6f02920ffb485e15376ed365c20" +} +~~~ ### <a name="RenameContainer"></a>func RenameContainer <div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> @@ -453,6 +602,23 @@ RestartContainer will restart a running container given a container name or ID a value is the time before a forcible stop is used to stop the container. If the container cannot be found by name or ID, a [ContainerNotFound](#ContainerNotFound) error will be returned; otherwise, the ID of the container will be returned. +### <a name="RestartPod"></a>func RestartPod +<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> + +method RestartPod(name: [string](https://godoc.org/builtin#string)) [string](https://godoc.org/builtin#string)</div> +RestartPod will restart containers in a pod given a pod name or ID. Containers in +the pod that are running will be stopped, then all stopped containers will be run. +If the pod cannot be found by name or ID, a [PodNotFound](#PodNotFound) error will be returned. +Containers in a pod are restarted independently. If there is an error restarting one container, the ID of those containers +will be returned in a list, along with the ID of the pod in a [PodContainerError](#PodContainerError). +If the pod was restarted with no errors, the pod ID is returned. +#### Example +~~~ +$ varlink call -m unix:/run/podman/io.podman/io.podman.RestartPod '{"name": "135d71b9495f"}' +{ + "pod": "135d71b9495f7c3967f536edad57750bfdb569336cd107d8aabab45565ffcfb6" +} +~~~ ### <a name="SearchImage"></a>func SearchImage <div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> @@ -467,6 +633,22 @@ method StartContainer(name: [string](https://godoc.org/builtin#string)) [string] StartContainer starts a created or stopped container. It takes the name or ID of container. It returns the container ID once started. If the container cannot be found, a [ContainerNotFound](#ContainerNotFound) error will be returned. See also [CreateContainer](#CreateContainer). +### <a name="StartPod"></a>func StartPod +<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> + +method StartPod(name: [string](https://godoc.org/builtin#string)) [string](https://godoc.org/builtin#string)</div> +StartPod starts containers in a pod. It takes the name or ID of pod. If the pod cannot be found, a [PodNotFound](#PodNotFound) +error will be returned. Containers in a pod are started independently. If there is an error starting one container, the ID of those containers +will be returned in a list, along with the ID of the pod in a [PodContainerError](#PodContainerError). +If the pod was started with no errors, the pod ID is returned. +See also [CreatePod](#CreatePod). +#### Example +~~~ +$ varlink call -m unix:/run/podman/io.podman/io.podman.StartPod '{"name": "135d71b9495f"}' +{ + "pod": "135d71b9495f7c3967f536edad57750bfdb569336cd107d8aabab45565ffcfb6", +} +~~~ ### <a name="StopContainer"></a>func StopContainer <div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> @@ -482,12 +664,34 @@ $ varlink call -m unix:/run/podman/io.podman/io.podman.StopContainer '{"name": " "container": "135d71b9495f7c3967f536edad57750bfdb569336cd107d8aabab45565ffcfb6" } ~~~ +### <a name="StopPod"></a>func StopPod +<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> + +method StopPod(name: [string](https://godoc.org/builtin#string)) [string](https://godoc.org/builtin#string)</div> +StopPod stops containers in a pod. It takes the name or ID of a pod. +If the pod cannot be found, a [PodNotFound](#PodNotFound) error will be returned instead. +Containers in a pod are stopped independently. If there is an error stopping one container, the ID of those containers +will be returned in a list, along with the ID of the pod in a [PodContainerError](#PodContainerError). +If the pod was stopped with no errors, the pod ID is returned. +See also [KillPod](KillPod). +#### Example +~~~ +$ varlink call -m unix:/run/podman/io.podman/io.podman.StopPod '{"name": "135d71b9495f"}' +{ + "pod": "135d71b9495f7c3967f536edad57750bfdb569336cd107d8aabab45565ffcfb6" +} +~~~ ### <a name="TagImage"></a>func TagImage <div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> method TagImage(name: [string](https://godoc.org/builtin#string), tagged: [string](https://godoc.org/builtin#string)) [string](https://godoc.org/builtin#string)</div> TagImage takes the name or ID of an image in local storage as well as the desired tag name. If the image cannot be found, an [ImageNotFound](#ImageNotFound) error will be returned; otherwise, the ID of the image is returned on success. +### <a name="TopPod"></a>func TopPod +<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> + +method TopPod() [NotImplemented](#NotImplemented)</div> +This method has not been implemented yet. ### <a name="UnpauseContainer"></a>func UnpauseContainer <div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> @@ -495,6 +699,16 @@ method UnpauseContainer(name: [string](https://godoc.org/builtin#string)) [strin UnpauseContainer takes the name or ID of container and unpauses a paused container. If the container cannot be found, a [ContainerNotFound](#ContainerNotFound) error will be returned; otherwise the ID of the container is returned. See also [PauseContainer](#PauseContainer). +### <a name="UnpausePod"></a>func UnpausePod +<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> + +method UnpausePod(name: [string](https://godoc.org/builtin#string)) [string](https://godoc.org/builtin#string)</div> +UnpausePod takes the name or ID of a pod and unpauses the paused containers associated with it. If the pod cannot be +found, a [PodNotFound](#PodNotFound) error will be returned. +Containers in a pod are unpaused independently. If there is an error unpausing one container, the ID of those containers +will be returned in a list, along with the ID of the pod in a [PodContainerError](#PodContainerError). +If the pod was unpaused with no errors, the pod ID is returned. +See also [PausePod](#PausePod). ### <a name="UpdateContainer"></a>func UpdateContainer <div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> @@ -507,6 +721,11 @@ method WaitContainer(name: [string](https://godoc.org/builtin#string)) [int](htt WaitContainer takes the name or ID of a container and waits until the container 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. +### <a name="WaitPod"></a>func WaitPod +<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> + +method WaitPod() [NotImplemented](#NotImplemented)</div> +This method has not be implemented yet. ## Types ### <a name="BuildInfo"></a>type BuildInfo @@ -989,11 +1208,63 @@ mounts [ContainerMount](#ContainerMount) containerrunning [bool](https://godoc.org/builtin#bool) namespaces [ContainerNameSpace](#ContainerNameSpace) +### <a name="ListPodContainerInfo"></a>type ListPodContainerInfo + +ListPodContainerInfo is a returned struct for describing containers +in a pod. + +name [string](https://godoc.org/builtin#string) + +id [string](https://godoc.org/builtin#string) + +status [string](https://godoc.org/builtin#string) +### <a name="ListPodData"></a>type ListPodData + +ListPodData is the returned struct for an individual pod + +id [string](https://godoc.org/builtin#string) + +name [string](https://godoc.org/builtin#string) + +createdat [string](https://godoc.org/builtin#string) + +cgroup [string](https://godoc.org/builtin#string) + +status [string](https://godoc.org/builtin#string) + +labels [map[string]](#map[string]) + +numberofcontainers [string](https://godoc.org/builtin#string) + +containersinfo [ListPodContainerInfo](#ListPodContainerInfo) ### <a name="NotImplemented"></a>type NotImplemented comment [string](https://godoc.org/builtin#string) +### <a name="PodContainerErrorData"></a>type PodContainerErrorData + + + +containerid [string](https://godoc.org/builtin#string) + +reason [string](https://godoc.org/builtin#string) +### <a name="PodCreate"></a>type PodCreate + +PodCreate is an input structure for creating pods. +It emulates options to podman pod create, however +changing pause image name and pause container +is not currently supported + +name [string](https://godoc.org/builtin#string) + +cgroupParent [string](https://godoc.org/builtin#string) + +labels [map[string]](#map[string]) + +share [[]string](#[]string) + +infra [bool](https://godoc.org/builtin#bool) ### <a name="PodmanInfo"></a>type PodmanInfo PodmanInfo describes the Podman host and build @@ -1045,6 +1316,16 @@ is includes as part of the error's text. ### <a name="ImageNotFound"></a>type ImageNotFound ImageNotFound means the image could not be found by the provided name or ID in local storage. +### <a name="NoContainerRunning"></a>type NoContainerRunning + +NoContainerRunning means none of the containers requested are running in a command that requires a running container. +### <a name="PodContainerError"></a>type PodContainerError + +PodContainerError means a container associated with a pod failed to preform an operation. It contains +a container ID of the container that failed. +### <a name="PodNotFound"></a>type PodNotFound + +PodNotFound means the pod could not be found by the provided name or ID in local storage. ### <a name="RuntimeError"></a>type RuntimeError RuntimeErrors generally means a runtime could not be found or gotten. diff --git a/Dockerfile b/Dockerfile index 70595a509..749c5edb9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -88,8 +88,8 @@ RUN set -x \ # Install buildah RUN set -x \ && export GOPATH=/go \ - && git clone https://github.com/projectatomic/buildah "$GOPATH/src/github.com/projectatomic/buildah" \ - && cd "$GOPATH/src/github.com/projectatomic/buildah" \ + && git clone https://github.com/containers/buildah "$GOPATH/src/github.com/containers/buildah" \ + && cd "$GOPATH/src/github.com/containers/buildah" \ && make \ && make install diff --git a/Dockerfile.CentOS b/Dockerfile.CentOS index cfb2a2d5d..9c752ca39 100644 --- a/Dockerfile.CentOS +++ b/Dockerfile.CentOS @@ -45,8 +45,8 @@ RUN set -x \ # Install buildah RUN set -x \ && export GOPATH=/go \ - && git clone https://github.com/projectatomic/buildah "$GOPATH/src/github.com/projectatomic/buildah" \ - && cd "$GOPATH/src/github.com/projectatomic/buildah" \ + && git clone https://github.com/containers/buildah "$GOPATH/src/github.com/containers/buildah" \ + && cd "$GOPATH/src/github.com/containers/buildah" \ && make \ && make install diff --git a/Dockerfile.Fedora b/Dockerfile.Fedora index 623edf96d..e246cfba1 100644 --- a/Dockerfile.Fedora +++ b/Dockerfile.Fedora @@ -48,8 +48,8 @@ RUN set -x \ # Install buildah RUN set -x \ && export GOPATH=/go \ - && git clone https://github.com/projectatomic/buildah "$GOPATH/src/github.com/projectatomic/buildah" \ - && cd "$GOPATH/src/github.com/projectatomic/buildah" \ + && git clone https://github.com/containers/buildah "$GOPATH/src/github.com/containers/buildah" \ + && cd "$GOPATH/src/github.com/containers/buildah" \ && make \ && make install @@ -1,6 +1,6 @@ GO ?= go DESTDIR ?= / -EPOCH_TEST_COMMIT ?= 6ffce631db6e01f66b09cb0e894600182caa872c +EPOCH_TEST_COMMIT ?= 63379c213325188a492d33981a6a525a19048d40 HEAD ?= HEAD CHANGELOG_BASE ?= HEAD~ CHANGELOG_TARGET ?= HEAD @@ -18,7 +18,7 @@ ETCDIR ?= ${DESTDIR}/etc ETCDIR_LIBPOD ?= ${ETCDIR}/crio TMPFILESDIR ?= ${PREFIX}/lib/tmpfiles.d SYSTEMDDIR ?= ${PREFIX}/lib/systemd/system -BUILDTAGS ?= seccomp $(shell hack/btrfs_tag.sh) $(shell hack/libdm_tag.sh) $(shell hack/btrfs_installed_tag.sh) $(shell hack/ostree_tag.sh) $(shell hack/selinux_tag.sh) $(shell hack/apparmor_tag.sh) varlink +BUILDTAGS ?= seccomp $(shell hack/btrfs_tag.sh) $(shell hack/btrfs_installed_tag.sh) $(shell hack/ostree_tag.sh) $(shell hack/selinux_tag.sh) $(shell hack/apparmor_tag.sh) varlink exclude_graphdriver_devicemapper BUILDTAGS_CROSS ?= containers_image_openpgp containers_image_ostree_stub exclude_graphdriver_btrfs exclude_graphdriver_devicemapper exclude_graphdriver_overlay ifneq (,$(findstring varlink,$(BUILDTAGS))) PODMAN_VARLINK_DEPENDENCIES = cmd/podman/varlink/iopodman.go @@ -170,10 +170,9 @@ localunit: varlink_generate $(GO) test -tags "$(BUILDTAGS)" -cover $(PACKAGES) ginkgo: - ginkgo -v test/e2e/ + ginkgo -v -tags "$(BUILDTAGS)" -cover -flakeAttempts 3 -progress -trace -noColor test/e2e/. -localintegration: varlink_generate test-binaries clientintegration - ginkgo -v -cover -flakeAttempts 3 -progress -trace -noColor test/e2e/. +localintegration: varlink_generate test-binaries clientintegration ginkgo clientintegration: $(MAKE) -C contrib/python/podman integration @@ -210,7 +209,8 @@ changelog: install: .gopathok install.bin install.man install.cni install.systemd install.python install.bin: - install ${SELINUXOPT} -D -m 755 bin/podman $(BINDIR)/podman + install ${SELINUXOPT} -d -m 755 $(BINDIR) + install ${SELINUXOPT} -m 755 bin/podman $(BINDIR)/podman install.man: docs install ${SELINUXOPT} -d -m 755 $(MANDIR)/man1 @@ -220,26 +220,29 @@ install.man: docs install ${SELINUXOPT} -m 644 docs/links/*1 -t $(MANDIR)/man1 install.config: - install ${SELINUXOPT} -D -m 644 libpod.conf ${SHAREDIR_CONTAINERS}/libpod.conf - install ${SELINUXOPT} -D -m 644 seccomp.json $(ETCDIR_LIBPOD)/seccomp.json - install ${SELINUXOPT} -D -m 644 crio-umount.conf $(OCIUMOUNTINSTALLDIR)/crio-umount.conf + install ${SELINUXOPT} -d -m 755 $(SHAREDIR_CONTAINERS) $(ETCDIR_LIBPOD) $(OCIUMOUNTINSTALLDIR) + install ${SELINUXOPT} -m 644 libpod.conf $(SHAREDIR_CONTAINERS)/libpod.conf + install ${SELINUXOPT} -m 644 seccomp.json $(ETCDIR_LIBPOD)/seccomp.json + install ${SELINUXOPT} -m 644 crio-umount.conf $(OCIUMOUNTINSTALLDIR)/crio-umount.conf install.completions: install ${SELINUXOPT} -d -m 755 ${BASHINSTALLDIR} - install ${SELINUXOPT} -m 644 -D completions/bash/podman ${BASHINSTALLDIR} + install ${SELINUXOPT} -m 644 completions/bash/podman ${BASHINSTALLDIR} install.cni: - install ${SELINUXOPT} -D -m 644 cni/87-podman-bridge.conflist ${ETCDIR}/cni/net.d/87-podman-bridge.conflist + install ${SELINUXOPT} -d -m 755 ${ETCDIR}/cni/net.d/ + install ${SELINUXOPT} -m 644 cni/87-podman-bridge.conflist ${ETCDIR}/cni/net.d/87-podman-bridge.conflist install.docker: docker-docs - install ${SELINUXOPT} -D -m 755 docker $(BINDIR)/docker - install ${SELINUXOPT} -d -m 755 $(MANDIR)/man1 + install ${SELINUXOPT} -d -m 755 $(BINDIR) $(MANDIR)/man1 + install ${SELINUXOPT} -m 755 docker $(BINDIR)/docker install ${SELINUXOPT} -m 644 docs/docker*.1 -t $(MANDIR)/man1 install.systemd: - install ${SELINUXOPT} -m 644 -D contrib/varlink/io.podman.socket ${SYSTEMDDIR}/io.podman.socket - install ${SELINUXOPT} -m 644 -D contrib/varlink/io.podman.service ${SYSTEMDDIR}/io.podman.service - install ${SELINUXOPT} -m 644 -D contrib/varlink/podman.conf ${TMPFILESDIR}/podman.conf + install ${SELINUXOPT} -m 755 -d ${SYSTEMDDIR} ${TMPFILESDIR} + install ${SELINUXOPT} -m 644 contrib/varlink/io.podman.socket ${SYSTEMDDIR}/io.podman.socket + install ${SELINUXOPT} -m 644 contrib/varlink/io.podman.service ${SYSTEMDDIR}/io.podman.service + install ${SELINUXOPT} -m 644 contrib/varlink/podman.conf ${TMPFILESDIR}/podman.conf install.python: $(MAKE) DESTDIR=${DESTDIR} -C contrib/python/podman install @@ -261,7 +264,15 @@ uninstall: .PHONY: install.tools -install.tools: .install.gitvalidation .install.gometalinter .install.md2man .install.easyjson +install.tools: .install.gitvalidation .install.gometalinter .install.md2man .install.easyjson .install.ginkgo .install.gomega + +.install.gomega: .gopathok + $(GO) get github.com/onsi/gomega/... + +.install.ginkgo: .gopathok + if [ ! -x "$(GOBIN)/ginkgo" ]; then \ + $(GO) get -u github.com/onsi/ginkgo/ginkgo; \ + fi .install.gitvalidation: .gopathok if [ ! -x "$(GOBIN)/git-validation" ]; then \ @@ -283,7 +294,7 @@ install.tools: .install.gitvalidation .install.gometalinter .install.md2man .ins fi .install.easyjson: .gopathok - if [ ! -x "$(GOBIN)/ffjson" ]; then\ + if [ ! -x "$(GOBIN)/easyffjson" ]; then \ $(GO) get -u github.com/mailru/easyjson/...; \ fi @@ -302,11 +313,11 @@ easyjson_generate: .gopathok libpod/container_easyjson.go libpod/pod_easyjson.go libpod/container_easyjson.go: libpod/container.go rm -f libpod/container_easyjson.go - cd "$(GOPKGDIR)" && easyjson ./libpod/container.go + cd "$(GOPKGDIR)" && easyjson -build_tags "$(BUILDTAGS)" ./libpod/container.go libpod/pod_easyjson.go: libpod/pod.go rm -f libpod/pod_easyjson.go - cd "$(GOPKGDIR)" && easyjson ./libpod/pod.go + cd "$(GOPKGDIR)" && easyjson -build_tags "$(BUILDTAGS)" ./libpod/pod.go .PHONY: install.libseccomp.sudo install.libseccomp.sudo: @@ -1,7 +1,7 @@ ![PODMAN logo](logo/podman-logo-source.svg) # libpod - library for running OCI-based containers in Pods -### Latest Version: 0.9.1 +### Latest Version: 0.9.3.1 ### Status: Active Development ## What is the scope of this project? @@ -30,7 +30,7 @@ The plan is to use OCI projects and best of breed libraries for different aspect - Images: Image management using [containers/image](https://github.com/containers/image) - Storage: Container and image storage is managed by [containers/storage](https://github.com/containers/storage) - Networking: Networking support through use of [CNI](https://github.com/containernetworking/cni) -- Builds: Builds are supported via [Buildah](https://github.com/projectatomic/buildah). +- Builds: Builds are supported via [Buildah](https://github.com/containers/buildah). - Conmon: [Conmon](https://github.com/kubernetes-sigs/cri-o) is a tool for monitoring OCI runtimes. It is part of the CRI-O package ## Podman Information for Developers @@ -64,12 +64,44 @@ Release notes for recent Podman versions **[Contributing](CONTRIBUTING.md)** Information about contributing to this project. -### Current Roadmap +## Current Roadmap -1. Varlink API for Podman +1. Python frontend for Varlink API 1. Integrate libpod into CRI-O to replace its existing container management backend -1. Pod commands for Podman -1. Rootless containers -1. Support for cleaning up containers via post-run hooks - -[spec-hooks]: https://github.com/opencontainers/runtime-spec/blob/v1.0.1/config.md#posix-platform-hooks +1. Further work on the podman pod command +1. Further improvements on rootless containers +1. In-memory locking to replace file locks + +[spec-hooks]: https://github.com/opencontainers/runtime-spec/blob/v2.0.1/config.md#posix-platform-hooks + +## Buildah and Podman relationship + +Buildah and Podman are two complementary Open-source projects that are available on +most Linux platforms and both projects reside at [GitHub.com](https://github.com) +with Buildah [here](https://github.com/containers/buildah) and +Podman [here](https://github.com/containers/libpod). Both Buildah and Podman are +command line tools that work on OCI images and containers. The two projects +differentiate in their specialization. + +Buildah specializes in building OCI images. Buildah's commands replicate all +of the commands that are found in a Dockerfile. Buildah’s goal is also to +provide a lower level coreutils interface to build images, allowing people to build +containers without requiring a Dockerfile. The intent with Buildah is to allow other +scripting languages to build container images, without requiring a daemon. + +Podman specializes in all of the commands and functions that help you to maintain and modify +OCI images, such as pulling and tagging. It also allows you to create, run, and maintain those containers +created from those images. + +A major difference between Podman and Buildah is their concept of a container. Podman +allows users to create "traditional containers" where the intent of these containers is +to be long lived. While Buildah containers are really just created to allow content +to be added back to the container image. An easy way to think of it is the +`buildah run` command emulates the RUN command in a Dockerfile while the `podman run` +command emulates the `docker run` command in functionality. Because of this and their underlying +storage differences, you can not see Podman containers from within Buildah or vice versa. + +In short Buildah is an efficient way to create OCI images while Podman allows +you to manage and maintain those images and containers in a production environment using +familiar container cli commands. For more details, see the +[Container Tools Guide](https://github.com/containers/buildah/tree/master/docs/containertools). diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 046c0c0df..f411ad28a 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,5 +1,52 @@ # Release Notes +## 0.9.3.1 +### Bugfixes +- Fixed a critical issue where SELinux contexts set on tmpfs volumes were causing runc crashes + +## 0.9.3 +### Features +- Added a flag to `libpod.conf`, `label`, to globally enable/disable SELinux labelling for libpod +- Added `--mount` flag to `podman create` and `podman run` as a new, more explicit way of specifying volume mounts + +### Bugfixes +- Fixed a crash during container creation when an image had no names +- Fixed default rootfs mount propagation to for containers to match Docker +- Fixed permissions of `/proc` in containers +- Fixed permissions of some default bind mounts (for example, `/etc/hosts`) in read-only containers +- Fixed `/dev/shm` in `--ipc=container` and `--ipc=host` containers to use the correct SHM +- Fixed rootless Podman to properly join the namespaces of other containers +- Fixed the output of `podman diff` to not display some default changes that will not be committed +- Fixed rootless to better handle cases where insufficient UIDs/GIDs are mapped into the container + +## 0.9.2.1 +### Bugfixes +- Updated Buildah dependency to fix several bugs in `podman build` + +### Misc +- Small performance improvement in image handling code to not recalculate digests + +## 0.9.2 +### Features +- Added `--interval` flag to `podman wait` to determine the interval between checks for container status +- Added a switch in `libpod.conf` to disable reserving ports for running containers. This lowers the safety of port allocations, but can significantly reduce memory usage. +- Added ability to search all the contents of a registry if no image name is specified when using `podman search` + +### Bugfixes +- Further fixes for sharing of UTS namespaces within pods +- Fixed a deadlock in containers/storage that could be caused by numerous parallel Podman processes. +- Fixed Podman running into open file limits when many ports are forwarded +- Fixed default mount propagation on volume mounts +- Fixed default mounts under /dev remaining if /dev is bind-mounted into the container +- Fixed rootless `podman create` with no command specified throwing an error + +### Misc +- Added `podman rm --volumes` flag for compatability with Docker. As Podman does not presently support named volumes, this does nothing for now, but provides improved compatability with the Docker command line. +- Improved error messages from `podman pull` + +### Compatability +- Podman is no longer being built by default with support for the Devicemapper storage driver. If you are using this storage driver, you should investigate switching to overlayfs. + ## 0.9.1.1 ### Bugfixes - Added support for configuring iptables and firewalld firewalls to allow container traffic. This should resolve numerous issues with network access in containers. diff --git a/changelog.txt b/changelog.txt index 918d10ba9..879302ee0 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,79 @@ +- Changelog for v0.9.3.1 (2018-09-25) + * Update release notes for 0.9.3.1 + * Disable problematic SELinux code causing runc issues + * Bump gitvalidation epoch + * Bump to v0.9.4-dev + +- Changelog for v0.9.3 (2018-09-21) + * Update release notes for 0.9.3 + * Add --mount option for `create` & `run` command + * Refactor Wait() to not require a timeout + * Updates from reviews + * Implement new subcommands + * Don't mount /dev/shm if the user told you --ipc=none + * rootless: error out if there are not enough UIDs/GIDs available + * Vendor in latest containers/buildah + * rootless: fix create with images not in the storage + * rootless: skip usage of filepath.Join + * create, rootless: join the userns of ns:PATH + * create, rootless: join the userns of container:CONTAINER + * spec: refactor ns modes to a common interface + * Don't output inodes created to run a container + * Add rpmbuild to the openshift fedora test image + * Add new field to libpod to indicate whether or not to use labelling + * Bind Mounts should be mounted read-only when in read-only mode + * test, rootless: enforce cgroupfs manager + * report when rootless + * add the gopath environment variable to the openshift dockerfile + * Vendor in latest opencontainers/runtime-tools + * Add python-varlink to the Fedora openshift image + * Add Dockerfile for openshift lint, gofmt, and validate testing + * Vendor in latest containers/buildah + * Don't crash if an image has no names + * Replace all usages of "install -D" with "install -d" + * Increase pidWaitTimeout to 1000ms + * Small updates to OCI spec generation + * Add new tests for ipc namespace sharing + * Hooks supports two directories, process default and override + * Bump gitvalidation epoch + * Bump to v0.9.3-dev + +- Changelog for v0.9.2.1 (2018-09-17) + * Update release notes for 0.9.2.1 + * Vendor in latest projectatomic/buildah + * Vndr latest containers/image + * Bump gitvalidation epoch + * Bump to v0.9.3-dev + +- Changelog for v0.9.2 (2018-09-14) + * Update release notes for 0.9.2 + * change search test to look for fedora and not fedora-minimal + * Don't mount /dev/* if user mounted /dev + * add registry information to varlink info + * libpod/image/pull: Return image-pulling errors from doPullImage + * Update gitvalidation epoch to avoid a bad commit + * Update README to reflect current development efforts + * rootless: do not raise an error if the entrypoint is specified + * Add Buildah Podman relationship to README.md + * Swap default mount propagation from private to rprivate + * Add a way to disable port reservation + * Add notes to check version on problem + * Do not set rlimits if we are rootless + * Up default Podman rlimits to avoid max open files + * Search registries with an empty query + * Vendor in latest containers/image + * Remove duplicate code between create.go and run.go + * Add --interval flag to podman wait + * Add `podman rm --volumes` flag + * Vendor in latest containers/storage to eliminage deadlock + * do not build with devicemapper + * run different cgroup tests depending on conditions + * dont make python when running make + * Explicitly set default CNI network name in libpod.conf + * Pass on securityOpts from podInfraContainer to container added to pod. + * Bump gitvalidation epoch + * Bump to v0.9.2-dev + - Changelog for v0.9.1.1 (2018-09-10) * Update release notes for 0.9.1.1 * Replace existing iptables handler with firewall code diff --git a/cmd/podman/build.go b/cmd/podman/build.go index 0ca0b3d83..1b8a5faec 100644 --- a/cmd/podman/build.go +++ b/cmd/podman/build.go @@ -1,13 +1,13 @@ package main import ( + "github.com/containers/buildah" + "github.com/containers/buildah/imagebuildah" + buildahcli "github.com/containers/buildah/pkg/cli" + "github.com/containers/buildah/pkg/parse" "github.com/containers/libpod/cmd/podman/libpodruntime" "github.com/containers/libpod/pkg/rootless" "github.com/pkg/errors" - "github.com/projectatomic/buildah" - "github.com/projectatomic/buildah/imagebuildah" - buildahcli "github.com/projectatomic/buildah/pkg/cli" - "github.com/projectatomic/buildah/pkg/parse" "github.com/sirupsen/logrus" "github.com/urfave/cli" "io/ioutil" @@ -50,7 +50,7 @@ func getDockerfiles(files []string) []string { } func buildCmd(c *cli.Context) error { - // The following was taken directly from projectatomic/buildah/cmd/bud.go + // The following was taken directly from containers/buildah/cmd/bud.go // TODO Find a away to vendor more of this in rather than copy from bud output := "" diff --git a/cmd/podman/commit.go b/cmd/podman/commit.go index 517eefd07..234926de0 100644 --- a/cmd/podman/commit.go +++ b/cmd/podman/commit.go @@ -6,13 +6,13 @@ import ( "os" "strings" + "github.com/containers/buildah" "github.com/containers/image/manifest" "github.com/containers/libpod/cmd/podman/libpodruntime" "github.com/containers/libpod/libpod" "github.com/containers/libpod/libpod/image" "github.com/containers/libpod/pkg/util" "github.com/pkg/errors" - "github.com/projectatomic/buildah" "github.com/urfave/cli" ) diff --git a/cmd/podman/common.go b/cmd/podman/common.go index 578de7f38..9ab0e57e5 100644 --- a/cmd/podman/common.go +++ b/cmd/podman/common.go @@ -8,11 +8,11 @@ import ( "regexp" "strings" + "github.com/containers/buildah" "github.com/containers/libpod/libpod" "github.com/containers/storage" "github.com/fatih/camelcase" "github.com/pkg/errors" - "github.com/projectatomic/buildah" "github.com/urfave/cli" ) @@ -418,6 +418,10 @@ var createFlags = []cli.Flag{ Usage: "UTS namespace to use", }, cli.StringSliceFlag{ + Name: "mount", + Usage: "Attach a filesystem mount to the container (default [])", + }, + cli.StringSliceFlag{ Name: "volume, v", Usage: "Bind mount a volume into the container (default [])", }, diff --git a/cmd/podman/create.go b/cmd/podman/create.go index bc010d047..fc0c71536 100644 --- a/cmd/podman/create.go +++ b/cmd/podman/create.go @@ -24,6 +24,7 @@ import ( "github.com/docker/docker/pkg/signal" "github.com/docker/go-connections/nat" "github.com/docker/go-units" + spec "github.com/opencontainers/runtime-spec/specs-go" "github.com/opencontainers/selinux/go-selinux/label" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -57,6 +58,30 @@ var createCommand = cli.Command{ } func createCmd(c *cli.Context) error { + if err := createInit(c); err != nil { + return err + } + + if os.Geteuid() != 0 { + rootless.SetSkipStorageSetup(true) + } + + runtime, err := libpodruntime.GetContainerRuntime(c) + if err != nil { + return errors.Wrapf(err, "error creating libpod runtime") + } + defer runtime.Shutdown(false) + + ctr, _, err := createContainer(c, runtime) + if err != nil { + return err + } + + fmt.Printf("%s\n", ctr.ID()) + return nil +} + +func createInit(c *cli.Context) error { // TODO should allow user to create based off a directory on the host not just image // Need CLI support for this @@ -83,63 +108,51 @@ func createCmd(c *cli.Context) error { return errors.Errorf("image name or ID is required") } + return nil +} + +func createContainer(c *cli.Context, runtime *libpod.Runtime) (*libpod.Container, *cc.CreateConfig, error) { + rtc := runtime.GetConfig() + ctx := getContext() rootfs := "" if c.Bool("rootfs") { rootfs = c.Args()[0] } - mappings, err := util.ParseIDMapping(c.StringSlice("uidmap"), c.StringSlice("gidmap"), c.String("subuidmap"), c.String("subgidmap")) - if err != nil { - return err - } - storageOpts, err := libpodruntime.GetDefaultStoreOptions() - if err != nil { - return err - } - storageOpts.UIDMap = mappings.UIDMap - storageOpts.GIDMap = mappings.GIDMap - - if os.Geteuid() != 0 { - rootless.SetSkipStorageSetup(true) - } - - runtime, err := libpodruntime.GetRuntimeWithStorageOpts(c, &storageOpts) - if err != nil { - return errors.Wrapf(err, "error creating libpod runtime") - } - defer runtime.Shutdown(false) - - rtc := runtime.GetConfig() - ctx := getContext() - imageName := "" var data *inspect.ImageData = nil + if rootfs == "" && !rootless.SkipStorageSetup() { newImage, err := runtime.ImageRuntime().New(ctx, c.Args()[0], rtc.SignaturePolicyPath, "", os.Stderr, nil, image.SigningOptions{}, false, false) if err != nil { - return err + return nil, nil, err } data, err = newImage.Inspect(ctx) - imageName = newImage.Names()[0] + names := newImage.Names() + if len(names) > 0 { + imageName = names[0] + } else { + imageName = newImage.ID() + } } createConfig, err := parseCreateOpts(ctx, c, runtime, imageName, data) if err != nil { - return err + return nil, nil, err } runtimeSpec, err := cc.CreateConfigToOCISpec(createConfig) if err != nil { - return err + return nil, nil, err } options, err := createConfig.GetContainerCreateOptions(runtime) if err != nil { - return err + return nil, nil, err } became, ret, err := joinOrCreateRootlessUserNamespace(createConfig, runtime) if err != nil { - return err + return nil, nil, err } if became { os.Exit(ret) @@ -147,27 +160,25 @@ func createCmd(c *cli.Context) error { ctr, err := runtime.NewContainer(ctx, runtimeSpec, options...) if err != nil { - return err + return nil, nil, err } createConfigJSON, err := json.Marshal(createConfig) if err != nil { - return err + return nil, nil, err } if err := ctr.AddArtifact("create-config", createConfigJSON); err != nil { - return err + return nil, nil, err } - logrus.Debug("new container created ", ctr.ID()) - if c.String("cidfile") != "" { err := libpod.WriteFile(ctr.ID(), c.String("cidfile")) if err != nil { logrus.Error(err) } } - fmt.Printf("%s\n", ctr.ID()) - return nil + logrus.Debugf("New container created %q", ctr.ID()) + return ctr, createConfig, nil } // Checks if a user-specified AppArmor profile is loaded, or loads the default profile if @@ -311,7 +322,7 @@ func parseSecurityOpt(config *cc.CreateConfig, securityOpts []string) error { } } } - config.ProcessLabel, config.MountLabel, err = label.InitLabels(labelOpts) + config.LabelOpts = labelOpts return err } @@ -449,6 +460,10 @@ func parseCreateOpts(ctx context.Context, c *cli.Context, runtime *libpod.Runtim } blkioWeight = uint16(u) } + var mountList []spec.Mount + if mountList, err = parseMounts(c.StringSlice("mount")); err != nil { + return nil, err + } if err = parseVolumes(c.StringSlice("volume")); err != nil { return nil, err @@ -518,17 +533,6 @@ func parseCreateOpts(ctx context.Context, c *cli.Context, runtime *libpod.Runtim } } - shmDir := "" - if ipcMode.IsHost() { - shmDir = "/dev/shm" - } else if ipcMode.IsContainer() { - ctr, err := runtime.LookupContainer(ipcMode.Container()) - if err != nil { - return nil, errors.Wrapf(err, "container %q not found", ipcMode.Container()) - } - shmDir = ctr.ShmDir() - } - // USER user := c.String("user") if user == "" { @@ -629,7 +633,7 @@ func parseCreateOpts(ctx context.Context, c *cli.Context, runtime *libpod.Runtim command = append(command, data.ContainerConfig.Cmd...) } - if len(command) == 0 { + if data != nil && len(command) == 0 { return nil, errors.Errorf("No command specified on command line or as CMD or ENTRYPOINT in this image") } @@ -681,7 +685,7 @@ func parseCreateOpts(ctx context.Context, c *cli.Context, runtime *libpod.Runtim } var systemd bool - if c.BoolT("systemd") && ((filepath.Base(command[0]) == "init") || (filepath.Base(command[0]) == "systemd")) { + if command != nil && c.BoolT("systemd") && ((filepath.Base(command[0]) == "init") || (filepath.Base(command[0]) == "systemd")) { systemd = true if signalString == "" { stopSignal, err = signal.ParseSignal("RTMIN+3") @@ -765,7 +769,6 @@ func parseCreateOpts(ctx context.Context, c *cli.Context, runtime *libpod.Runtim Ulimit: c.StringSlice("ulimit"), }, Rm: c.Bool("rm"), - ShmDir: shmDir, StopSignal: stopSignal, StopTimeout: c.Uint("stop-timeout"), Sysctl: sysctl, @@ -774,6 +777,7 @@ func parseCreateOpts(ctx context.Context, c *cli.Context, runtime *libpod.Runtim Tty: tty, User: user, UsernsMode: usernsMode, + Mounts: mountList, Volumes: c.StringSlice("volume"), WorkDir: workDir, Rootfs: rootfs, @@ -796,6 +800,11 @@ func parseCreateOpts(ctx context.Context, c *cli.Context, runtime *libpod.Runtim return config, nil } +type namespace interface { + IsContainer() bool + Container() string +} + func joinOrCreateRootlessUserNamespace(createConfig *cc.CreateConfig, runtime *libpod.Runtime) (bool, int, error) { if os.Geteuid() == 0 { return false, 0, nil @@ -827,5 +836,26 @@ func joinOrCreateRootlessUserNamespace(createConfig *cc.CreateConfig, runtime *l } } + namespacesStr := []string{string(createConfig.IpcMode), string(createConfig.NetMode), string(createConfig.UsernsMode), string(createConfig.PidMode), string(createConfig.UtsMode)} + for _, i := range namespacesStr { + if cc.IsNS(i) { + return rootless.JoinNSPath(cc.NS(i)) + } + } + + namespaces := []namespace{createConfig.IpcMode, createConfig.NetMode, createConfig.UsernsMode, createConfig.PidMode, createConfig.UtsMode} + for _, i := range namespaces { + if i.IsContainer() { + ctr, err := runtime.LookupContainer(i.Container()) + if err != nil { + return false, -1, err + } + pid, err := ctr.PID() + if err != nil { + return false, -1, err + } + return rootless.JoinNS(uint(pid)) + } + } return rootless.BecomeRootInUserNS() } diff --git a/cmd/podman/create_cli.go b/cmd/podman/create_cli.go index 812b62058..218e9b806 100644 --- a/cmd/podman/create_cli.go +++ b/cmd/podman/create_cli.go @@ -8,6 +8,8 @@ import ( cc "github.com/containers/libpod/pkg/spec" "github.com/docker/docker/pkg/sysinfo" + "github.com/docker/go-units" + spec "github.com/opencontainers/runtime-spec/specs-go" "github.com/pkg/errors" "github.com/sirupsen/logrus" ) @@ -74,6 +76,94 @@ func addWarning(warnings []string, msg string) []string { return append(warnings, msg) } +// Format supported. +// podman run --mount type=bind,src=/etc/resolv.conf,target=/etc/resolv.conf ... +// podman run --mount type=tmpfs,target=/dev/shm .. +func parseMounts(mounts []string) ([]spec.Mount, error) { + var mountList []spec.Mount + errInvalidSyntax := errors.Errorf("incorrect mount format : should be --mount type=<bind|tmpfs>,[src=<host-dir>,]target=<ctr-dir>,[options]") + for _, mount := range mounts { + var tokenCount int + var mountInfo spec.Mount + + arr := strings.SplitN(mount, ",", 2) + if len(arr) < 2 { + return nil, errInvalidSyntax + } + kv := strings.Split(arr[0], "=") + if kv[0] != "type" { + return nil, errInvalidSyntax + } + switch kv[1] { + case "bind": + mountInfo.Type = string(cc.TypeBind) + case "tmpfs": + mountInfo.Type = string(cc.TypeTmpfs) + mountInfo.Source = string(cc.TypeTmpfs) + mountInfo.Options = append(mountInfo.Options, []string{"rprivate", "noexec", "nosuid", "nodev", "size=65536k"}...) + + default: + return nil, errors.Errorf("invalid filesystem type %q", kv[1]) + } + + tokens := strings.Split(arr[1], ",") + for i, val := range tokens { + if i == (tokenCount - 1) { + //Parse tokens before options. + break + } + kv := strings.Split(val, "=") + switch kv[0] { + case "ro", "nosuid", "nodev", "noexec": + mountInfo.Options = append(mountInfo.Options, kv[0]) + case "shared", "rshared", "private", "rprivate", "slave", "rslave", "Z", "z": + if mountInfo.Type != "bind" { + return nil, errors.Errorf("%s can only be used with bind mounts", kv[0]) + } + mountInfo.Options = append(mountInfo.Options, kv[0]) + case "tmpfs-mode": + if mountInfo.Type != "tmpfs" { + return nil, errors.Errorf("%s can only be used with tmpfs mounts", kv[0]) + } + mountInfo.Options = append(mountInfo.Options, fmt.Sprintf("mode=%s", kv[1])) + case "tmpfs-size": + if mountInfo.Type != "tmpfs" { + return nil, errors.Errorf("%s can only be used with tmpfs mounts", kv[0]) + } + shmSize, err := units.FromHumanSize(kv[1]) + if err != nil { + return nil, errors.Wrapf(err, "unable to translate tmpfs-size") + } + + mountInfo.Options = append(mountInfo.Options, fmt.Sprintf("size=%d", shmSize)) + + case "bind-propagation": + if mountInfo.Type != "bind" { + return nil, errors.Errorf("%s can only be used with bind mounts", kv[0]) + } + mountInfo.Options = append(mountInfo.Options, kv[1]) + case "src", "source": + if mountInfo.Type == "tmpfs" { + return nil, errors.Errorf("can not use src= on a tmpfs file system") + } + if err := validateVolumeHostDir(kv[1]); err != nil { + return nil, err + } + mountInfo.Source = kv[1] + case "target", "dst", "destination": + if err := validateVolumeCtrDir(kv[1]); err != nil { + return nil, err + } + mountInfo.Destination = kv[1] + default: + return nil, errors.Errorf("incorrect mount option : %s", kv[0]) + } + } + mountList = append(mountList, mountInfo) + } + return mountList, nil +} + func parseVolumes(volumes []string) error { for _, volume := range volumes { arr := strings.SplitN(volume, ":", 3) diff --git a/cmd/podman/libpodruntime/runtime.go b/cmd/podman/libpodruntime/runtime.go index b7281ed8c..a0d497e8e 100644 --- a/cmd/podman/libpodruntime/runtime.go +++ b/cmd/podman/libpodruntime/runtime.go @@ -7,6 +7,7 @@ import ( "github.com/containers/libpod/libpod" "github.com/containers/libpod/pkg/rootless" + "github.com/containers/libpod/pkg/util" "github.com/containers/storage" "github.com/pkg/errors" "github.com/urfave/cli" @@ -21,6 +22,21 @@ func GetRuntime(c *cli.Context) (*libpod.Runtime, error) { return GetRuntimeWithStorageOpts(c, &storageOpts) } +// GetContainerRuntime generates a new libpod runtime configured by command line options for containers +func GetContainerRuntime(c *cli.Context) (*libpod.Runtime, error) { + mappings, err := util.ParseIDMapping(c.StringSlice("uidmap"), c.StringSlice("gidmap"), c.String("subuidmap"), c.String("subgidmap")) + if err != nil { + return nil, err + } + storageOpts, err := GetDefaultStoreOptions() + if err != nil { + return nil, err + } + storageOpts.UIDMap = mappings.UIDMap + storageOpts.GIDMap = mappings.GIDMap + return GetRuntimeWithStorageOpts(c, &storageOpts) +} + func GetRootlessStorageOpts() (storage.StoreOptions, error) { var opts storage.StoreOptions @@ -120,7 +136,9 @@ func GetRuntimeWithStorageOpts(c *cli.Context, storageOpts *storage.StoreOptions if c.GlobalIsSet("default-mounts-file") { options = append(options, libpod.WithDefaultMountsFile(c.GlobalString("default-mounts-file"))) } - options = append(options, libpod.WithHooksDir(c.GlobalString("hooks-dir-path"), c.GlobalIsSet("hooks-dir-path"))) + if c.GlobalIsSet("hooks-dir-path") { + options = append(options, libpod.WithHooksDir(c.GlobalString("hooks-dir-path"))) + } // TODO flag to set CNI plugins dir? diff --git a/cmd/podman/main.go b/cmd/podman/main.go index a532bc26e..840650a3f 100644 --- a/cmd/podman/main.go +++ b/cmd/podman/main.go @@ -147,6 +147,8 @@ func main() { if err := syscall.Setrlimit(syscall.RLIMIT_NOFILE, rlimits); err != nil { return errors.Wrapf(err, "error setting new rlimits") } + } else { + logrus.Info("running as rootless") } if logLevel == "debug" { diff --git a/cmd/podman/run.go b/cmd/podman/run.go index 3445daef5..f9a96e4a6 100644 --- a/cmd/podman/run.go +++ b/cmd/podman/run.go @@ -1,7 +1,6 @@ package main import ( - "encoding/json" "fmt" "io/ioutil" "os" @@ -11,11 +10,7 @@ import ( "github.com/containers/libpod/cmd/podman/libpodruntime" "github.com/containers/libpod/libpod" - "github.com/containers/libpod/libpod/image" - "github.com/containers/libpod/pkg/inspect" "github.com/containers/libpod/pkg/rootless" - cc "github.com/containers/libpod/pkg/spec" - "github.com/containers/libpod/pkg/util" "github.com/pkg/errors" "github.com/sirupsen/logrus" "github.com/urfave/cli" @@ -42,108 +37,24 @@ var runCommand = cli.Command{ } func runCmd(c *cli.Context) error { - var imageName string - - // Docker-compatibility: the "-h" flag for run/create is reserved for - // the hostname (see https://github.com/containers/libpod/issues/1367). - if c.Bool("help") { - cli.ShowCommandHelpAndExit(c, "run", 0) - } - - if err := validateFlags(c, createFlags); err != nil { - return err - } - - if c.String("cidfile") != "" { - if _, err := os.Stat(c.String("cidfile")); err == nil { - return errors.Errorf("container id file exists. ensure another container is not using it or delete %s", c.String("cidfile")) - } - if err := libpod.WriteFile("", c.String("cidfile")); err != nil { - return errors.Wrapf(err, "unable to write cidfile %s", c.String("cidfile")) - } - } - - storageOpts, err := libpodruntime.GetDefaultStoreOptions() - if err != nil { - return err - } - mappings, err := util.ParseIDMapping(c.StringSlice("uidmap"), c.StringSlice("gidmap"), c.String("subuidmap"), c.String("subgidmap")) - if err != nil { + if err := createInit(c); err != nil { return err } - storageOpts.UIDMap = mappings.UIDMap - storageOpts.GIDMap = mappings.GIDMap - if os.Geteuid() != 0 { rootless.SetSkipStorageSetup(true) } - runtime, err := libpodruntime.GetRuntimeWithStorageOpts(c, &storageOpts) + runtime, err := libpodruntime.GetContainerRuntime(c) if err != nil { return errors.Wrapf(err, "error creating libpod runtime") } defer runtime.Shutdown(false) - if len(c.Args()) < 1 { - return errors.Errorf("image name or ID is required") - } - - rootfs := "" - if c.Bool("rootfs") { - rootfs = c.Args()[0] - } - - ctx := getContext() - rtc := runtime.GetConfig() - - var newImage *image.Image = nil - var data *inspect.ImageData = nil - if rootfs == "" && !rootless.SkipStorageSetup() { - newImage, err = runtime.ImageRuntime().New(ctx, c.Args()[0], rtc.SignaturePolicyPath, "", os.Stderr, nil, image.SigningOptions{}, false, false) - if err != nil { - return errors.Wrapf(err, "unable to find image") - } - - data, err = newImage.Inspect(ctx) - if err != nil { - return err - } - if len(newImage.Names()) < 1 { - imageName = newImage.ID() - } else { - imageName = newImage.Names()[0] - } - } - createConfig, err := parseCreateOpts(ctx, c, runtime, imageName, data) + ctr, createConfig, err := createContainer(c, runtime) if err != nil { return err } - runtimeSpec, err := cc.CreateConfigToOCISpec(createConfig) - if err != nil { - return err - } - - options, err := createConfig.GetContainerCreateOptions(runtime) - if err != nil { - return err - } - - became, ret, err := joinOrCreateRootlessUserNamespace(createConfig, runtime) - if err != nil { - return err - } - if became { - os.Exit(ret) - } - - ctr, err := runtime.NewContainer(ctx, runtimeSpec, options...) - if err != nil { - return err - } - - logrus.Debugf("New container created %q", ctr.ID()) - if logrus.GetLevel() == logrus.DebugLevel { cgroupPath, err := ctr.CGroupPath() if err == nil { @@ -151,20 +62,7 @@ func runCmd(c *cli.Context) error { } } - createConfigJSON, err := json.Marshal(createConfig) - if err != nil { - return err - } - if err := ctr.AddArtifact("create-config", createConfigJSON); err != nil { - return err - } - - if c.String("cidfile") != "" { - if err := libpod.WriteFile(ctr.ID(), c.String("cidfile")); err != nil { - logrus.Error(err) - } - } - + ctx := getContext() // Handle detached start if createConfig.Detach { if err := ctr.Start(ctx); err != nil { diff --git a/cmd/podman/wait.go b/cmd/podman/wait.go index e919ab3ca..07db20eee 100644 --- a/cmd/podman/wait.go +++ b/cmd/podman/wait.go @@ -3,6 +3,7 @@ package main import ( "fmt" "os" + "time" "github.com/containers/libpod/cmd/podman/libpodruntime" "github.com/pkg/errors" @@ -15,7 +16,14 @@ var ( Block until one or more containers stop and then print their exit codes ` - waitFlags = []cli.Flag{LatestFlag} + waitFlags = []cli.Flag{ + cli.UintFlag{ + Name: "interval, i", + Usage: "Milliseconds to wait before polling for completion", + Value: 250, + }, + LatestFlag, + } waitCommand = cli.Command{ Name: "wait", Usage: "Block on one or more containers", @@ -57,7 +65,10 @@ func waitCmd(c *cli.Context) error { if err != nil { return errors.Wrapf(err, "unable to find container %s", container) } - returnCode, err := ctr.Wait() + if c.Uint("interval") == 0 { + return errors.Errorf("interval must be greater then 0") + } + returnCode, err := ctr.WaitWithInterval(time.Duration(c.Uint("interval")) * time.Millisecond) if err != nil { if lastError != nil { fmt.Fprintln(os.Stderr, lastError) diff --git a/completions/bash/podman b/completions/bash/podman index d9af43d37..b97c4b0d5 100644 --- a/completions/bash/podman +++ b/completions/bash/podman @@ -945,6 +945,7 @@ _podman_build() { --userns-uid-map-user --userns-gid-map-group --uts + --mount --volume -v " @@ -2012,7 +2013,9 @@ _podman_wait() { local boolean_options=" --help -h - -l + -i + -l + --interval --latest" case "$cur" in -*) diff --git a/contrib/python/podman/Makefile b/contrib/python/podman/Makefile index 64239755f..6ec4159f2 100644 --- a/contrib/python/podman/Makefile +++ b/contrib/python/podman/Makefile @@ -1,5 +1,6 @@ PYTHON ?= $(shell command -v python3 2>/dev/null || command -v python) DESTDIR ?= / +PODMAN_VERSION ?= '0.0.4' .PHONY: python-podman python-podman: @@ -17,6 +18,11 @@ integration: install: $(PYTHON) setup.py install --root ${DESTDIR} +.PHONY: upload +upload: + $(PODMAN_VERSION) $(PYTHON) setup.py sdist bdist_wheel + twine upload --repository-url https://test.pypi.org/legacy/ dist/* + .PHONY: clobber clobber: uninstall clean diff --git a/contrib/python/podman/podman/libs/_containers_start.py b/contrib/python/podman/podman/libs/_containers_start.py index 8e705771a..20130f5d6 100644 --- a/contrib/python/podman/podman/libs/_containers_start.py +++ b/contrib/python/podman/podman/libs/_containers_start.py @@ -20,6 +20,7 @@ class Mixin: Will block if container has been detached. """ with self._client() as podman: + logging.debug('Starting Container "%s"', self._id) results = podman.StartContainer(self._id) logging.debug('Started Container "%s"', results['container']) diff --git a/contrib/python/podman/podman/libs/containers.py b/contrib/python/podman/podman/libs/containers.py index f56137e12..e211a284e 100644 --- a/contrib/python/podman/podman/libs/containers.py +++ b/contrib/python/podman/podman/libs/containers.py @@ -3,6 +3,7 @@ import collections import functools import getpass import json +import logging import signal import time @@ -32,17 +33,26 @@ class Container(AttachMixin, StartMixin, collections.UserDict): """Get items from parent dict.""" return super().__getitem__(key) - def _refresh(self, podman): - ctnr = podman.GetContainer(self._id) - super().update(ctnr['container']) - - for k, v in self.data.items(): - setattr(self, k, v) - if 'containerrunning' in self.data: - setattr(self, 'running', self.data['containerrunning']) - self.data['running'] = self.data['containerrunning'] - - return self + def _refresh(self, podman, tries=1): + try: + ctnr = podman.GetContainer(self._id) + except BrokenPipeError: + logging.debug('Failed GetContainer(%s) try %d/3', self._id, tries) + if tries > 3: + raise + else: + with self._client() as pman: + self._refresh(pman, tries + 1) + else: + super().update(ctnr['container']) + + for k, v in self.data.items(): + setattr(self, k, v) + if 'containerrunning' in self.data: + setattr(self, 'running', self.data['containerrunning']) + self.data['running'] = self.data['containerrunning'] + + return self def refresh(self): """Refresh status fields for this container.""" diff --git a/contrib/python/podman/test/test_containers.py b/contrib/python/podman/test/test_containers.py index 70221e33d..3de1e54bc 100644 --- a/contrib/python/podman/test/test_containers.py +++ b/contrib/python/podman/test/test_containers.py @@ -111,8 +111,8 @@ class TestContainers(PodmanTestCase): list(actual.keys()))) # TODO: brittle, depends on knowing history of ctnr - self.assertGreaterEqual(len(actual['changed']), 2) - self.assertGreaterEqual(len(actual['added']), 2) + self.assertGreaterEqual(len(actual['changed']), 0) + self.assertGreaterEqual(len(actual['added']), 0) self.assertEqual(len(actual['deleted']), 0) def test_kill(self): diff --git a/contrib/python/podman/test/test_runner.sh b/contrib/python/podman/test/test_runner.sh index c37d9cf6e..76432cf47 100755 --- a/contrib/python/podman/test/test_runner.sh +++ b/contrib/python/podman/test/test_runner.sh @@ -97,11 +97,12 @@ EOT cat >$TMPDIR/ctnr/hello.sh <<-EOT echo 'Hello, World' +exit 0 EOT cat >$TMPDIR/ctnr/Dockerfile <<-EOT FROM alpine:latest -COPY ./hello.sh /tmp/hello.sh +COPY ./hello.sh /tmp/ RUN chmod 755 /tmp/hello.sh ENTRYPOINT ["/tmp/hello.sh"] EOT diff --git a/contrib/python/pypodman/.pylintrc b/contrib/python/pypodman/.pylintrc new file mode 100644 index 000000000..eed3ae65b --- /dev/null +++ b/contrib/python/pypodman/.pylintrc @@ -0,0 +1,4 @@ +[VARIABLES] + +# Enforce only pep8 variable names +variable-rgx=[a-z0-9_]{1,30}$ diff --git a/contrib/python/pypodman/Makefile b/contrib/python/pypodman/Makefile index 430231202..cd0fcf1de 100644 --- a/contrib/python/pypodman/Makefile +++ b/contrib/python/pypodman/Makefile @@ -1,5 +1,6 @@ PYTHON ?= $(shell command -v python3 2>/dev/null || command -v python) DESTDIR := / +PODMAN_VERSION ?= '0.0.4' .PHONY: python-pypodman python-pypodman: @@ -17,6 +18,11 @@ integration: install: $(PYTHON) setup.py install --root ${DESTDIR} +.PHONY: upload +upload: + $(PODMAN_VERSION) $(PYTHON) setup.py sdist bdist_wheel + twine upload --repository-url https://test.pypi.org/legacy/ dist/* + .PHONY: clobber clobber: uninstall clean diff --git a/contrib/python/pypodman/pypodman/lib/__init__.py b/contrib/python/pypodman/pypodman/lib/__init__.py index 80fa0e1e9..6208deefd 100644 --- a/contrib/python/pypodman/pypodman/lib/__init__.py +++ b/contrib/python/pypodman/pypodman/lib/__init__.py @@ -1,8 +1,18 @@ """Remote podman client support library.""" from pypodman.lib.action_base import AbstractActionBase -from pypodman.lib.config import PodmanArgumentParser +from pypodman.lib.parser_actions import (BooleanAction, BooleanValidate, + PathAction, PositiveIntAction, + UnitAction) +from pypodman.lib.podman_parser import PodmanArgumentParser from pypodman.lib.report import Report, ReportColumn +# Silence pylint overlording... +assert BooleanAction +assert BooleanValidate +assert PathAction +assert PositiveIntAction +assert UnitAction + __all__ = [ 'AbstractActionBase', 'PodmanArgumentParser', diff --git a/contrib/python/pypodman/pypodman/lib/action_base.py b/contrib/python/pypodman/pypodman/lib/action_base.py index 5cc4c22a9..f312a63e9 100644 --- a/contrib/python/pypodman/pypodman/lib/action_base.py +++ b/contrib/python/pypodman/pypodman/lib/action_base.py @@ -43,7 +43,12 @@ class AbstractActionBase(abc.ABC): def __init__(self, args): """Construct class.""" + # Dump all unset arguments before transmitting to service self._args = args + self.opts = { + k: v + for k, v in vars(self._args).items() if v is not None + } @property def remote_uri(self): diff --git a/contrib/python/pypodman/pypodman/lib/actions/__init__.py b/contrib/python/pypodman/pypodman/lib/actions/__init__.py index b0af3c589..a5eb35755 100644 --- a/contrib/python/pypodman/pypodman/lib/actions/__init__.py +++ b/contrib/python/pypodman/pypodman/lib/actions/__init__.py @@ -3,7 +3,10 @@ from pypodman.lib.actions.attach_action import Attach from pypodman.lib.actions.commit_action import Commit from pypodman.lib.actions.create_action import Create from pypodman.lib.actions.export_action import Export +from pypodman.lib.actions.history_action import History from pypodman.lib.actions.images_action import Images +from pypodman.lib.actions.import_action import Import +from pypodman.lib.actions.info_action import Info from pypodman.lib.actions.inspect_action import Inspect from pypodman.lib.actions.kill_action import Kill from pypodman.lib.actions.logs_action import Logs @@ -12,15 +15,22 @@ from pypodman.lib.actions.pause_action import Pause from pypodman.lib.actions.port_action import Port from pypodman.lib.actions.ps_action import Ps from pypodman.lib.actions.pull_action import Pull +from pypodman.lib.actions.push_action import Push +from pypodman.lib.actions.restart_action import Restart from pypodman.lib.actions.rm_action import Rm from pypodman.lib.actions.rmi_action import Rmi +from pypodman.lib.actions.run_action import Run +from pypodman.lib.actions.search_action import Search __all__ = [ 'Attach', 'Commit', 'Create', 'Export', + 'History', 'Images', + 'Import', + 'Info', 'Inspect', 'Kill', 'Logs', @@ -29,6 +39,10 @@ __all__ = [ 'Port', 'Ps', 'Pull', + 'Push', + 'Restart', 'Rm', 'Rmi', + 'Run', + 'Search', ] diff --git a/contrib/python/pypodman/pypodman/lib/actions/_create_args.py b/contrib/python/pypodman/pypodman/lib/actions/_create_args.py new file mode 100644 index 000000000..207f52796 --- /dev/null +++ b/contrib/python/pypodman/pypodman/lib/actions/_create_args.py @@ -0,0 +1,416 @@ +"""Implement common create container arguments together.""" + +from pypodman.lib import BooleanAction, UnitAction + + +class CreateArguments(): + """Helper to add all the create flags to a command.""" + + @classmethod + def add_arguments(cls, parser): + """Add CreateArguments to parser.""" + parser.add_argument( + '--add-host', + action='append', + metavar='HOST', + help='Add a line to /etc/hosts.' + ' The option can be set multiple times.' + ' (format: hostname:ip)') + parser.add_argument( + '--annotation', + action='append', + help='Add an annotation to the container.' + 'The option can be set multiple times.' + '(format: key=value)') + parser.add_argument( + '--attach', + '-a', + action='append', + metavar='FD', + help=('Attach to STDIN, STDOUT or STDERR. The option can be set' + ' for each of stdin, stdout, and stderr.')) + parser.add_argument( + '--blkio-weight', + choices=range(10, 1000), + metavar='[10-1000]', + help=('Block IO weight (relative weight) accepts a' + ' weight value between 10 and 1000.')) + parser.add_argument( + '--blkio-weight-device', + action='append', + metavar='WEIGHT', + help='Block IO weight, relative device weight.' + ' (format: DEVICE_NAME:WEIGHT)') + parser.add_argument( + '--cap-add', + action='append', + metavar='CAP', + help=('Add Linux capabilities' + 'The option can be set multiple times.')) + parser.add_argument( + '--cap-drop', + action='append', + metavar='CAP', + help=('Drop Linux capabilities' + 'The option can be set multiple times.')) + parser.add_argument( + '--cgroup-parent', + metavar='PATH', + help='Path to cgroups under which the cgroup for the' + ' container will be created. If the path is not' + ' absolute, the path is considered to be relative' + ' to the cgroups path of the init process. Cgroups' + ' will be created if they do not already exist.') + parser.add_argument( + '--cidfile', + metavar='PATH', + help='Write the container ID to the file, on the remote host.') + parser.add_argument( + '--conmon-pidfile', + metavar='PATH', + help=('Write the pid of the conmon process to a file,' + ' on the remote host.')) + parser.add_argument( + '--cpu-period', + type=int, + metavar='PERIOD', + help=('Limit the CPU CFS (Completely Fair Scheduler) period.')) + parser.add_argument( + '--cpu-quota', + type=int, + metavar='QUOTA', + help=('Limit the CPU CFS (Completely Fair Scheduler) quota.')) + parser.add_argument( + '--cpu-rt-period', + type=int, + metavar='PERIOD', + help=('Limit the CPU real-time period in microseconds.')) + parser.add_argument( + '--cpu-rt-runtime', + type=int, + metavar='LIMIT', + help=('Limit the CPU real-time runtime in microseconds.')) + parser.add_argument( + '--cpu-shares', + type=int, + metavar='SHARES', + help=('CPU shares (relative weight)')) + parser.add_argument( + '--cpus', + type=float, + help=('Number of CPUs. The default is 0.0 which means no limit')) + parser.add_argument( + '--cpuset-cpus', + metavar='LIST', + help=('CPUs in which to allow execution (0-3, 0,1)')) + parser.add_argument( + '--cpuset-mems', + metavar='NODES', + help=('Memory nodes (MEMs) in which to allow execution (0-3, 0,1).' + ' Only effective on NUMA systems')) + parser.add_argument( + '--detach', + '-d', + action=BooleanAction, + default=False, + help='Detached mode: run the container in the background and' + ' print the new container ID. (default: False)') + parser.add_argument( + '--detach-keys', + metavar='KEY(s)', + default=4, + help='Override the key sequence for detaching a container.' + ' (format: a single character [a-Z] or ctrl-<value> where' + ' <value> is one of: a-z, @, ^, [, , or _)') + parser.add_argument( + '--device', + action='append', + help=('Add a host device to the container' + 'The option can be set multiple times.'), + ) + parser.add_argument( + '--device-read-bps', + action='append', + metavar='LIMIT', + help=('Limit read rate (bytes per second) from a device' + ' (e.g. --device-read-bps=/dev/sda:1mb)' + 'The option can be set multiple times.'), + ) + parser.add_argument( + '--device-read-iops', + action='append', + metavar='LIMIT', + help=('Limit read rate (IO per second) from a device' + ' (e.g. --device-read-iops=/dev/sda:1000)' + 'The option can be set multiple times.'), + ) + parser.add_argument( + '--device-write-bps', + action='append', + metavar='LIMIT', + help=('Limit write rate (bytes per second) to a device' + ' (e.g. --device-write-bps=/dev/sda:1mb)' + 'The option can be set multiple times.'), + ) + parser.add_argument( + '--device-write-iops', + action='append', + metavar='LIMIT', + help=('Limit write rate (IO per second) to a device' + ' (e.g. --device-write-iops=/dev/sda:1000)' + 'The option can be set multiple times.'), + ) + parser.add_argument( + '--dns', + action='append', + metavar='SERVER', + help=('Set custom DNS servers.' + 'The option can be set multiple times.'), + ) + parser.add_argument( + '--dns-option', + action='append', + metavar='OPT', + help=('Set custom DNS options.' + 'The option can be set multiple times.'), + ) + parser.add_argument( + '--dns-search', + action='append', + metavar='DOMAIN', + help=('Set custom DNS search domains.' + 'The option can be set multiple times.'), + ) + parser.add_argument( + '--entrypoint', + help=('Overwrite the default ENTRYPOINT of the image.'), + ) + parser.add_argument( + '--env', + '-e', + action='append', + help=('Set environment variables.'), + ) + parser.add_argument( + '--env-file', + help=('Read in a line delimited file of environment variables,' + ' on the remote host.'), + ) + parser.add_argument( + '--expose', + action='append', + metavar='RANGE', + help=('Expose a port, or a range of ports' + ' (e.g. --expose=3300-3310) to set up port redirection.'), + ) + parser.add_argument( + '--gidmap', + metavar='MAP', + action='append', + help=('GID map for the user namespace'), + ) + parser.add_argument( + '--group-add', + action='append', + metavar='GROUP', + help=('Add additional groups to run as')) + parser.add_argument('--hostname', help='Container host name') + + # only way for argparse to handle these options. + vol_args = { + 'choices': ['bind', 'tmpfs', 'ignore'], + 'metavar': 'MODE', + 'type': str.lower, + 'help': 'Tells podman how to handle the builtin image volumes', + } + + volume_group = parser.add_mutually_exclusive_group() + volume_group.add_argument('--image-volume', **vol_args) + volume_group.add_argument('--builtin-volume', **vol_args) + + parser.add_argument( + '--interactive', + '-i', + action=BooleanAction, + default=False, + help='Keep STDIN open even if not attached. (default: False)') + parser.add_argument('--ipc', help='Create namespace') + parser.add_argument( + '--kernel-memory', action=UnitAction, help='Kernel memory limit') + parser.add_argument( + '--label', + '-l', + action='append', + help=('Add metadata to a container' + ' (e.g., --label com.example.key=value)')) + parser.add_argument( + '--label-file', help='Read in a line delimited file of labels') + parser.add_argument( + '--log-driver', + choices='json-file', + metavar='json-file', + default='json-file', + help='Logging driver for the container. (default: %(default)s)') + parser.add_argument( + '--log-opt', + action='append', + help='Logging driver specific options') + parser.add_argument( + '--memory', '-m', action=UnitAction, help='Memory limit') + parser.add_argument( + '--memory-reservation', + action=UnitAction, + help='Memory soft limit') + parser.add_argument( + '--memory-swap', + action=UnitAction, + help=('A limit value equal to memory plus swap.' + 'Must be used with the --memory flag')) + parser.add_argument( + '--memory-swappiness', + choices=range(0, 100), + metavar='[0-100]', + help="Tune a container's memory swappiness behavior") + parser.add_argument('--name', help='Assign a name to the container') + parser.add_argument( + '--network', + '--net', + metavar='BRIDGE', + help='Set the Network mode for the container.' + ' (format: bridge, host, container:UUID, ns:PATH, none)') + parser.add_argument( + '--oom-kill-disable', + action=BooleanAction, + help='Whether to disable OOM Killer for the container or not') + parser.add_argument( + '--oom-score-adj', + choices=range(-1000, 1000), + metavar='[-1000-1000]', + help="Tune the host's OOM preferences for containers") + parser.add_argument( + '--pid', + help='Set the PID Namespace mode for the container.' + '(format: host, container:UUID, ns:PATH)') + parser.add_argument( + '--pids-limit', + type=int, + metavar='LIMIT', + help=("Tune the container's pids limit." + " Set -1 to have unlimited pids for the container.")) + parser.add_argument('--pod', help='Run container in an existing pod') + parser.add_argument( + '--privileged', + action=BooleanAction, + help='Give extended privileges to this container.') + parser.add_argument( + '--publish', + '-p', + metavar='RANGE', + help="Publish a container's port, or range of ports, to the host") + parser.add_argument( + '--publish-all', + '-P', + action=BooleanAction, + help='Publish all exposed ports to random' + ' ports on the host interfaces' + '(default: False)') + parser.add_argument( + '--quiet', + '-q', + action='store_true', + help='Suppress output information when pulling images') + parser.add_argument( + '--read-only', + action=BooleanAction, + help="Mount the container's root filesystem as read only.") + parser.add_argument( + '--rm', + action=BooleanAction, + default=False, + help='Automatically remove the container when it exits.') + parser.add_argument( + '--rootfs', + action='store_true', + help=('If specified, the first argument refers to an' + ' exploded container on the file system of remote host.')) + parser.add_argument( + '--security-opt', + action='append', + metavar='OPT', + help='Set security options.') + parser.add_argument( + '--shm-size', action=UnitAction, help='Size of /dev/shm') + parser.add_argument( + '--sig-proxy', + action=BooleanAction, + default=True, + help='Proxy signals sent to the podman run' + ' command to the container process') + parser.add_argument( + '--stop-signal', + metavar='SIGTERM', + help='Signal to stop a container') + parser.add_argument( + '--stop-timeout', + metavar='TIMEOUT', + type=int, + default=10, + help='Seconds to wait on stopping container.') + parser.add_argument( + '--subgidname', + metavar='MAP', + help='Name for GID map from the /etc/subgid file') + parser.add_argument( + '--subuidname', + metavar='MAP', + help='Name for UID map from the /etc/subuid file') + parser.add_argument( + '--sysctl', + action='append', + help='Configure namespaced kernel parameters at runtime') + parser.add_argument( + '--tmpfs', + action='append', + metavar='MOUNT', + help='Create a tmpfs mount.' + ' (default: rw,noexec,nosuid,nodev,size=65536k.)') + parser.add_argument( + '--tty', + '-t', + action=BooleanAction, + default=False, + help='Allocate a pseudo-TTY for standard input of container.') + parser.add_argument( + '--uidmap', + action='append', + metavar='MAP', + help='UID map for the user namespace') + parser.add_argument( + '--ulimit', + action='append', + metavar='OPT', + help='Ulimit options', + ) + parser.add_argument( + '--user', + '-u', + help=('Sets the username or UID used and optionally' + ' the groupname or GID for the specified command.')) + parser.add_argument( + '--userns', + metavar='NAMESPACE', + help='Set the user namespace mode for the container') + parser.add_argument( + '--uts', + choices=['host', 'ns'], + help='Set the UTS mode for the container') + parser.add_argument('--volume', '-v', help='Create a bind mount.') + parser.add_argument( + '--volumes-from', + action='append', + help='Mount volumes from the specified container(s).') + parser.add_argument( + '--workdir', + '-w', + metavar='PATH', + help='Working directory inside the container') diff --git a/contrib/python/pypodman/pypodman/lib/actions/commit_action.py b/contrib/python/pypodman/pypodman/lib/actions/commit_action.py index 1e16550ad..0da6a2078 100644 --- a/contrib/python/pypodman/pypodman/lib/actions/commit_action.py +++ b/contrib/python/pypodman/pypodman/lib/actions/commit_action.py @@ -2,7 +2,7 @@ import sys import podman -from pypodman.lib import AbstractActionBase +from pypodman.lib import AbstractActionBase, BooleanAction class Commit(AbstractActionBase): @@ -47,14 +47,14 @@ class Commit(AbstractActionBase): parser.add_argument( '--pause', '-p', - choices=('True', 'False'), + action=BooleanAction, default=True, - type=bool, help='Pause the container when creating an image', ) parser.add_argument( '--quiet', '-q', + action='store_true', help='Suppress output', ) parser.add_argument( @@ -71,20 +71,24 @@ class Commit(AbstractActionBase): def __init__(self, args): """Construct Commit class.""" - super().__init__(args) if not args.container: raise ValueError('You must supply one container id' ' or name to be used as source.') if not args.image: raise ValueError('You must supply one image id' ' or name to be created.') + super().__init__(args) + + # used only on client + del self.opts['image'] + del self.opts['container'] def commit(self): """Create image from container.""" try: try: ctnr = self.client.containers.get(self._args.container[0]) - ident = ctnr.commit(**self._args) + ident = ctnr.commit(**self.opts) print(ident) except podman.ContainerNotFound as e: sys.stdout.flush() diff --git a/contrib/python/pypodman/pypodman/lib/actions/create_action.py b/contrib/python/pypodman/pypodman/lib/actions/create_action.py index 94dd33061..e0cb8c409 100644 --- a/contrib/python/pypodman/pypodman/lib/actions/create_action.py +++ b/contrib/python/pypodman/pypodman/lib/actions/create_action.py @@ -1,413 +1,11 @@ """Remote client command for creating container from image.""" -import argparse import sys from builtins import vars import podman from pypodman.lib import AbstractActionBase - -class UnitAction(argparse.Action): - """Validate number given is positive integer, with optional suffix.""" - - def __call__(self, parser, namespace, values, option_string=None): - """Validate input.""" - if isinstance(values, str): - if not values[:-1].isdigit(): - msg = 'unit must be a positive integer, with optional suffix' - raise argparse.ArgumentError(self, msg) - if not values[-1] in ('b', 'k', 'm', 'g'): - msg = 'unit only supports suffices of: b, k, m, g' - raise argparse.ArgumentError(self, msg) - elif values <= 0: - msg = 'number must be a positive integer.' - raise argparse.ArgumentError(self, msg) - - setattr(namespace, self.dest, values) - - -def add_options(parser): - """Add options for Create command.""" - parser.add_argument( - '--add-host', - action='append', - metavar='HOST', - help=('Add a line to /etc/hosts. The format is hostname:ip.' - ' The option can be set multiple times.'), - ) - parser.add_argument( - '--attach', - '-a', - action='append', - metavar='FD', - help=('Attach to STDIN, STDOUT or STDERR. The option can be set' - ' for each of stdin, stdout, and stderr.')) - parser.add_argument( - '--annotation', - action='append', - help=('Add an annotation to the container. The format is' - ' key=value. The option can be set multiple times.')) - parser.add_argument( - '--blkio-weight', - choices=range(10, 1000), - metavar='[10-1000]', - help=('Block IO weight (relative weight) accepts a' - ' weight value between 10 and 1000.')) - parser.add_argument( - '--blkio-weight-device', - action='append', - metavar='WEIGHT', - help=('Block IO weight (relative device weight,' - ' format: DEVICE_NAME:WEIGHT).')) - parser.add_argument( - '--cap-add', - action='append', - metavar='CAP', - help=('Add Linux capabilities' - 'The option can be set multiple times.')) - parser.add_argument( - '--cap-drop', - action='append', - metavar='CAP', - help=('Drop Linux capabilities' - 'The option can be set multiple times.')) - parser.add_argument( - '--cgroup-parent', - metavar='PATH', - help=('Path to cgroups under which the cgroup for the' - ' container will be created. If the path is not' - ' absolute, the path is considered to be relative' - ' to the cgroups path of the init process. Cgroups' - ' will be created if they do not already exist.')) - parser.add_argument( - '--cidfile', - metavar='PATH', - help='Write the container ID to the file, on the remote host.') - parser.add_argument( - '--conmon-pidfile', - metavar='PATH', - help=('Write the pid of the conmon process to a file,' - ' on the remote host.')) - parser.add_argument( - '--cpu-count', - type=int, - metavar='COUNT', - help=('Limit the number of CPUs available' - ' for execution by the container.')) - parser.add_argument( - '--cpu-period', - type=int, - metavar='PERIOD', - help=('Limit the CPU CFS (Completely Fair Scheduler) period.')) - parser.add_argument( - '--cpu-quota', - type=int, - metavar='QUOTA', - help=('Limit the CPU CFS (Completely Fair Scheduler) quota.')) - parser.add_argument( - '--cpu-rt-period', - type=int, - metavar='PERIOD', - help=('Limit the CPU real-time period in microseconds.')) - parser.add_argument( - '--cpu-rt-runtime', - type=int, - metavar='LIMIT', - help=('Limit the CPU real-time runtime in microseconds.')) - parser.add_argument( - '--cpu-shares', - type=int, - metavar='SHARES', - help=('CPU shares (relative weight)')) - parser.add_argument( - '--cpus', - type=int, - help=('Number of CPUs. The default is 0 which means no limit')) - parser.add_argument( - '--cpuset-cpus', - metavar='LIST', - help=('CPUs in which to allow execution (0-3, 0,1)')) - parser.add_argument( - '--cpuset-mems', - metavar='NODES', - help=('Memory nodes (MEMs) in which to allow execution (0-3, 0,1).' - ' Only effective on NUMA systems')) - parser.add_argument( - '--detach', - '-d', - choices=['True', 'False'], - help=('Detached mode: run the container in the background and' - ' print the new container ID. The default is false.')) - parser.add_argument( - '--detach-keys', - metavar='KEY(s)', - help=('Override the key sequence for detaching a container.' - ' Format is a single character [a-Z] or ctrl-<value> where' - ' <value> is one of: a-z, @, ^, [, , or _.')) - parser.add_argument( - '--device', - action='append', - help=('Add a host device to the container' - 'The option can be set multiple times.'), - ) - parser.add_argument( - '--device-read-bps', - action='append', - metavar='LIMIT', - help=('Limit read rate (bytes per second) from a device' - ' (e.g. --device-read-bps=/dev/sda:1mb)' - 'The option can be set multiple times.'), - ) - parser.add_argument( - '--device-read-iops', - action='append', - metavar='LIMIT', - help=('Limit read rate (IO per second) from a device' - ' (e.g. --device-read-iops=/dev/sda:1000)' - 'The option can be set multiple times.'), - ) - parser.add_argument( - '--device-write-bps', - action='append', - metavar='LIMIT', - help=('Limit write rate (bytes per second) to a device' - ' (e.g. --device-write-bps=/dev/sda:1mb)' - 'The option can be set multiple times.'), - ) - parser.add_argument( - '--device-write-iops', - action='append', - metavar='LIMIT', - help=('Limit write rate (IO per second) to a device' - ' (e.g. --device-write-iops=/dev/sda:1000)' - 'The option can be set multiple times.'), - ) - parser.add_argument( - '--dns', - action='append', - metavar='SERVER', - help=('Set custom DNS servers.' - 'The option can be set multiple times.'), - ) - parser.add_argument( - '--dns-option', - action='append', - metavar='OPT', - help=('Set custom DNS options.' - 'The option can be set multiple times.'), - ) - parser.add_argument( - '--dns-search', - action='append', - metavar='DOMAIN', - help=('Set custom DNS search domains.' - 'The option can be set multiple times.'), - ) - parser.add_argument( - '--entrypoint', - help=('Overwrite the default ENTRYPOINT of the image.'), - ) - parser.add_argument( - '--env', - '-e', - action='append', - help=('Set environment variables.'), - ) - parser.add_argument( - '--env-file', - help=('Read in a line delimited file of environment variables,' - ' on the remote host.'), - ) - parser.add_argument( - '--expose', - metavar='PORT(s)', - help=('Expose a port, or a range of ports' - ' (e.g. --expose=3300-3310) to set up port redirection.'), - ) - parser.add_argument( - '--gidmap', - metavar='MAP', - help=('GID map for the user namespace'), - ) - parser.add_argument( - '--group-add', - action='append', - metavar='GROUP', - help=('Add additional groups to run as')) - parser.add_argument('--hostname', help='Container host name') - - volume_group = parser.add_mutually_exclusive_group() - volume_group.add_argument( - '--image-volume', - choices=['bind', 'tmpfs', 'ignore'], - metavar='MODE', - help='Tells podman how to handle the builtin image volumes') - volume_group.add_argument( - '--builtin-volume', - choices=['bind', 'tmpfs', 'ignore'], - metavar='MODE', - help='Tells podman how to handle the builtin image volumes') - parser.add_argument( - '--interactive', - '-i', - choices=['True', 'False'], - help='Keep STDIN open even if not attached. The default is false') - parser.add_argument('--ipc', help='Create namespace') - parser.add_argument( - '--kernel-memory', - action=UnitAction, - metavar='UNIT', - help=('Kernel memory limit (format: <number>[<unit>],' - ' where unit = b, k, m or g)')) - parser.add_argument( - '--label', - '-l', - help=('Add metadata to a container' - ' (e.g., --label com.example.key=value)')) - parser.add_argument( - '--label-file', help='Read in a line delimited file of labels') - parser.add_argument( - '--log-driver', - choices=['json-file', 'journald'], - help='Logging driver for the container.') - parser.add_argument( - '--log-opt', action='append', help='Logging driver specific options') - parser.add_argument( - '--mac-address', help='Container MAC address (e.g. 92:d0:c6:0a:29:33)') - parser.add_argument( - '--memory', - '-m', - action=UnitAction, - metavar='UNIT', - help='Memory limit (format: [], where unit = b, k, m or g)') - parser.add_argument( - '--memory-reservation', - action=UnitAction, - metavar='UNIT', - help='Memory soft limit (format: [], where unit = b, k, m or g)') - parser.add_argument( - '--memory-swap', - action=UnitAction, - metavar='UNIT', - help=('A limit value equal to memory plus swap.' - 'Must be used with the --memory flag')) - parser.add_argument( - '--memory-swappiness', - choices=range(0, 100), - metavar='[0-100]', - help="Tune a container's memory swappiness behavior") - parser.add_argument('--name', help='Assign a name to the container') - parser.add_argument( - '--network', - metavar='BRIDGE', - help=('Set the Network mode for the container.')) - parser.add_argument( - '--oom-kill-disable', - choices=['True', 'False'], - help='Whether to disable OOM Killer for the container or not') - parser.add_argument( - '--oom-score-adj', - choices=range(-1000, 1000), - metavar='[-1000-1000]', - help="Tune the host's OOM preferences for containers") - parser.add_argument('--pid', help='Set the PID mode for the container') - parser.add_argument( - '--pids-limit', - type=int, - metavar='LIMIT', - help=("Tune the container's pids limit." - " Set -1 to have unlimited pids for the container.")) - parser.add_argument('--pod', help='Run container in an existing pod') - parser.add_argument( - '--privileged', - choices=['True', 'False'], - help='Give extended privileges to this container.') - parser.add_argument( - '--publish', - '-p', - metavar='PORT(s)', - help="Publish a container's port, or range of ports, to the host") - parser.add_argument( - '--publish-all', - '-P', - action='store_true', - help=("Publish all exposed ports to random" - " ports on the host interfaces")) - parser.add_argument( - '--quiet', - '-q', - action='store_true', - help='Suppress output information when pulling images') - parser.add_argument( - '--read-only', - choices=['True', 'False'], - help="Mount the container's root filesystem as read only.") - parser.add_argument( - '--rm', - choices=['True', 'False'], - help='Automatically remove the container when it exits.') - parser.add_argument( - '--rootfs', - action='store_true', - help=('If specified, the first argument refers to an' - ' exploded container on the file system of remote host.')) - parser.add_argument( - '--security-opt', - action='append', - metavar='OPT', - help='Set security options.') - parser.add_argument( - '--shm-size', - action=UnitAction, - metavar='UNIT', - help='Size of /dev/shm') - parser.add_argument( - '--stop-signal', metavar='SIGTERM', help='Signal to stop a container') - parser.add_argument( - '--stop-timeout', - metavar='TIMEOUT', - help='Seconds to wait on stopping container.') - parser.add_argument( - '--subgidname', - metavar='MAP', - help='Name for GID map from the /etc/subgid file') - parser.add_argument( - '--subuidname', - metavar='MAP', - help='Name for UID map from the /etc/subuid file') - parser.add_argument( - '--sysctl', - action='append', - help='Configure namespaced kernel parameters at runtime') - parser.add_argument('--tmpfs', help='Create a tmpfs mount') - parser.add_argument( - '--tty', - '-t', - choices=['True', 'False'], - help='Allocate a pseudo-TTY for standard input of container.') - parser.add_argument( - '--uidmap', metavar='MAP', help='UID map for the user namespace') - parser.add_argument('--ulimit', metavar='OPT', help='Ulimit options') - parser.add_argument( - '--user', - '-u', - help=('Sets the username or UID used and optionally' - ' the groupname or GID for the specified command.')) - parser.add_argument( - '--userns', - choices=['host', 'ns'], - help='Set the usernamespace mode for the container') - parser.add_argument( - '--uts', - choices=['host', 'ns'], - help='Set the UTS mode for the container') - parser.add_argument('--volume', '-v', help='Create a bind mount.') - parser.add_argument( - '--volumes-from', - action='append', - help='Mount volumes from the specified container(s).') - parser.add_argument( - '--workdir', '-w', help='Working directory inside the container') +from ._create_args import CreateArguments class Create(AbstractActionBase): @@ -419,40 +17,40 @@ class Create(AbstractActionBase): parser = parent.add_parser( 'create', help='create container from image') - add_options(parser) + CreateArguments.add_arguments(parser) - parser.add_argument('image', nargs='*', help='source image id.') + parser.add_argument('image', nargs=1, help='source image id') + parser.add_argument( + 'command', + nargs='*', + help='command and args to run.', + ) parser.set_defaults(class_=cls, method='create') def __init__(self, args): """Construct Create class.""" super().__init__(args) - if not args.image: - raise ValueError('You must supply at least one image id' - ' or name to be retrieved.') + + # image id used only on client + del self.opts['image'] def create(self): """Create container.""" - # Dump all unset arguments before transmitting to service - opts = {k: v for k, v in vars(self._args).items() if v is not None} - - # image id(s) used only on client - del opts['image'] - - for ident in self._args.image: - try: - img = self.client.images.get(ident) - img.container(**opts) - print(ident) - except podman.ImageNotFound as e: - sys.stdout.flush() - print( - 'Image {} not found.'.format(e.name), - file=sys.stderr, - flush=True) - except podman.ErrorOccurred as e: - sys.stdout.flush() - print( - '{}'.format(e.reason).capitalize(), - file=sys.stderr, - flush=True) + try: + for ident in self._args.image: + try: + img = self.client.images.get(ident) + img.container(**self.opts) + print(ident) + except podman.ImageNotFound as e: + sys.stdout.flush() + print( + 'Image {} not found.'.format(e.name), + file=sys.stderr, + flush=True) + except podman.ErrorOccurred as e: + sys.stdout.flush() + print( + '{}'.format(e.reason).capitalize(), + file=sys.stderr, + flush=True) diff --git a/contrib/python/pypodman/pypodman/lib/actions/export_action.py b/contrib/python/pypodman/pypodman/lib/actions/export_action.py index 2a6c2a3cf..f62cd3535 100644 --- a/contrib/python/pypodman/pypodman/lib/actions/export_action.py +++ b/contrib/python/pypodman/pypodman/lib/actions/export_action.py @@ -29,7 +29,6 @@ class Export(AbstractActionBase): def __init__(self, args): """Construct Export class.""" - super().__init__(args) if not args.container: raise ValueError('You must supply one container id' ' or name to be used as source.') @@ -37,6 +36,7 @@ class Export(AbstractActionBase): if not args.output: raise ValueError('You must supply one filename' ' to be created as tarball using --output.') + super().__init__(args) def export(self): """Create tarball from container filesystem.""" diff --git a/contrib/python/pypodman/pypodman/lib/actions/history_action.py b/contrib/python/pypodman/pypodman/lib/actions/history_action.py new file mode 100644 index 000000000..3e3f539fc --- /dev/null +++ b/contrib/python/pypodman/pypodman/lib/actions/history_action.py @@ -0,0 +1,83 @@ +"""Remote client for reporting image history.""" +import json +from collections import OrderedDict + +import humanize + +import podman +from pypodman.lib import (AbstractActionBase, BooleanAction, Report, + ReportColumn) + + +class History(AbstractActionBase): + """Class for reporting Image History.""" + + @classmethod + def subparser(cls, parent): + """Add History command to parent parser.""" + parser = parent.add_parser('history', help='report image history') + super().subparser(parser) + parser.add_argument( + '--human', + '-H', + action=BooleanAction, + default='True', + help='Display sizes and dates in human readable format.' + ' (default: %(default)s)') + parser.add_argument( + '--format', + choices=('json', 'table'), + help="Alter the output for a format like 'json' or 'table'." + " (default: table)") + parser.add_argument( + 'image', nargs='+', help='image for history report') + parser.set_defaults(class_=cls, method='history') + + def __init__(self, args): + """Construct History class.""" + super().__init__(args) + + self.columns = OrderedDict({ + 'id': + ReportColumn('id', 'ID', 12), + 'created': + ReportColumn('created', 'CREATED', 11), + 'createdBy': + ReportColumn('createdBy', 'CREATED BY', 45), + 'size': + ReportColumn('size', 'SIZE', 8), + 'comment': + ReportColumn('comment', 'COMMENT', 0) + }) + + def history(self): + """Report image history.""" + rows = list() + for ident in self._args.image: + for details in self.client.images.get(ident).history(): + fields = dict(details._asdict()) + + if self._args.human: + fields.update({ + 'size': + humanize.naturalsize(details.size, binary=True), + 'created': + humanize.naturaldate( + podman.datetime_parse(details.created)), + }) + del fields['tags'] + + rows.append(fields) + + if self._args.quiet: + for row in rows: + ident = row['id'][:12] if self._args.truncate else row['id'] + print(ident) + elif self._args.format == 'json': + print(json.dumps(rows, indent=2), flush=True) + else: + with Report(self.columns, heading=self._args.heading) as report: + report.layout( + rows, self.columns.keys(), truncate=self._args.truncate) + for row in rows: + report.row(**row) diff --git a/contrib/python/pypodman/pypodman/lib/actions/images_action.py b/contrib/python/pypodman/pypodman/lib/actions/images_action.py index b8f5ccc78..d28e32db9 100644 --- a/contrib/python/pypodman/pypodman/lib/actions/images_action.py +++ b/contrib/python/pypodman/pypodman/lib/actions/images_action.py @@ -65,7 +65,7 @@ class Images(AbstractActionBase): 'created': humanize.naturaldate(podman.datetime_parse(image.created)), 'size': - humanize.naturalsize(int(image.size)), + humanize.naturalsize(int(image.size), binary=True), 'repoDigests': ' '.join(image.repoDigests), }) diff --git a/contrib/python/pypodman/pypodman/lib/actions/import_action.py b/contrib/python/pypodman/pypodman/lib/actions/import_action.py new file mode 100644 index 000000000..49b8a5a57 --- /dev/null +++ b/contrib/python/pypodman/pypodman/lib/actions/import_action.py @@ -0,0 +1,60 @@ +"""Remote client command to import tarball as image filesystem.""" +import sys + +import podman +from pypodman.lib import AbstractActionBase + + +class Import(AbstractActionBase): + """Class for importing tarball as image filesystem.""" + + @classmethod + def subparser(cls, parent): + """Add Import command to parent parser.""" + parser = parent.add_parser( + 'import', help='import tarball as image filesystem') + parser.add_argument( + '--change', + '-c', + action='append', + choices=('CMD', 'ENTRYPOINT', 'ENV', 'EXPOSE', 'LABEL', + 'STOPSIGNAL', 'USER', 'VOLUME', 'WORKDIR'), + type=str.upper, + help='Apply the following possible instructions', + ) + parser.add_argument( + '--message', '-m', help='Set commit message for imported image.') + parser.add_argument( + 'source', + metavar='PATH', + nargs=1, + help='tarball to use as source on remote system', + ) + parser.add_argument( + 'reference', + metavar='TAG', + nargs='*', + help='Optional tag for image. (default: None)', + ) + parser.set_defaults(class_=cls, method='import_') + + def __init__(self, args): + """Construct Import class.""" + super().__init__(args) + + def import_(self): + """Import tarball as image filesystem.""" + try: + ident = self.client.images.import_image( + self.opts.source, + self.opts.reference, + message=self.opts.message, + changes=self.opts.change) + print(ident) + except podman.ErrorOccurred as e: + sys.stdout.flush() + print( + '{}'.format(e.reason).capitalize(), + file=sys.stderr, + flush=True) + return 1 diff --git a/contrib/python/pypodman/pypodman/lib/actions/info_action.py b/contrib/python/pypodman/pypodman/lib/actions/info_action.py new file mode 100644 index 000000000..988284541 --- /dev/null +++ b/contrib/python/pypodman/pypodman/lib/actions/info_action.py @@ -0,0 +1,49 @@ +"""Remote client command for reporting on Podman service.""" +import json +import sys + +import podman +import yaml +from pypodman.lib import AbstractActionBase + + +class Info(AbstractActionBase): + """Class for reporting on Podman Service.""" + + @classmethod + def subparser(cls, parent): + """Add Info command to parent parser.""" + parser = parent.add_parser( + 'info', help='report info on podman service') + parser.add_argument( + '--format', + choices=('json', 'yaml'), + help="Alter the output for a format like 'json' or 'yaml'." + " (default: yaml)") + parser.set_defaults(class_=cls, method='info') + + def __init__(self, args): + """Construct Info class.""" + super().__init__(args) + + def info(self): + """Report on Podman Service.""" + try: + info = self.client.system.info() + except podman.ErrorOccurred as e: + sys.stdout.flush() + print( + '{}'.format(e.reason).capitalize(), + file=sys.stderr, + flush=True) + return 1 + else: + if self._args.format == 'json': + print(json.dumps(info._asdict(), indent=2), flush=True) + else: + print( + yaml.dump( + dict(info._asdict()), + canonical=False, + default_flow_style=False), + flush=True) diff --git a/contrib/python/pypodman/pypodman/lib/actions/inspect_action.py b/contrib/python/pypodman/pypodman/lib/actions/inspect_action.py index 0559cd40a..514b4702a 100644 --- a/contrib/python/pypodman/pypodman/lib/actions/inspect_action.py +++ b/contrib/python/pypodman/pypodman/lib/actions/inspect_action.py @@ -41,7 +41,7 @@ class Inspect(AbstractActionBase): def _get_container(self, ident): try: - logging.debug("Get container %s", ident) + logging.debug("Getting container %s", ident) ctnr = self.client.containers.get(ident) except podman.ContainerNotFound: pass @@ -50,7 +50,7 @@ class Inspect(AbstractActionBase): def _get_image(self, ident): try: - logging.debug("Get image %s", ident) + logging.debug("Getting image %s", ident) img = self.client.images.get(ident) except podman.ImageNotFound: pass diff --git a/contrib/python/pypodman/pypodman/lib/actions/kill_action.py b/contrib/python/pypodman/pypodman/lib/actions/kill_action.py index 3caa42cf0..cb3d3f035 100644 --- a/contrib/python/pypodman/pypodman/lib/actions/kill_action.py +++ b/contrib/python/pypodman/pypodman/lib/actions/kill_action.py @@ -19,7 +19,7 @@ class Kill(AbstractActionBase): choices=range(1, signal.NSIG), metavar='[1,{}]'.format(signal.NSIG), default=9, - help='Signal to send to the container. (Default: 9)') + help='Signal to send to the container. (default: 9)') parser.add_argument( 'containers', nargs='+', diff --git a/contrib/python/pypodman/pypodman/lib/actions/logs_action.py b/contrib/python/pypodman/pypodman/lib/actions/logs_action.py index 764a4b9c7..91ff7bb08 100644 --- a/contrib/python/pypodman/pypodman/lib/actions/logs_action.py +++ b/contrib/python/pypodman/pypodman/lib/actions/logs_action.py @@ -5,20 +5,7 @@ import sys from collections import deque import podman -from pypodman.lib import AbstractActionBase - - -class PositiveIntAction(argparse.Action): - """Validate number given is positive integer.""" - - def __call__(self, parser, namespace, values, option_string=None): - """Validate input.""" - if values > 0: - setattr(namespace, self.dest, values) - return - - msg = 'Must be a positive integer.' - raise argparse.ArgumentError(self, msg) +from pypodman.lib import AbstractActionBase, PositiveIntAction class Logs(AbstractActionBase): @@ -32,7 +19,6 @@ class Logs(AbstractActionBase): '--tail', metavar='LINES', action=PositiveIntAction, - type=int, help='Output the specified number of LINES at the end of the logs') parser.add_argument( 'container', diff --git a/contrib/python/pypodman/pypodman/lib/actions/port_action.py b/contrib/python/pypodman/pypodman/lib/actions/port_action.py index 60bbe12c4..6d6578cee 100644 --- a/contrib/python/pypodman/pypodman/lib/actions/port_action.py +++ b/contrib/python/pypodman/pypodman/lib/actions/port_action.py @@ -29,10 +29,10 @@ class Port(AbstractActionBase): def __init__(self, args): """Construct Port class.""" - super().__init__(args) if not args.all and not args.containers: - ValueError('You must supply at least one' - ' container id or name, or --all.') + raise ValueError('You must supply at least one' + ' container id or name, or --all.') + super().__init__(args) def port(self): """Retrieve ports from containers.""" diff --git a/contrib/python/pypodman/pypodman/lib/actions/ps_action.py b/contrib/python/pypodman/pypodman/lib/actions/ps_action.py index 8c0a739d7..cd7a7947d 100644 --- a/contrib/python/pypodman/pypodman/lib/actions/ps_action.py +++ b/contrib/python/pypodman/pypodman/lib/actions/ps_action.py @@ -18,10 +18,8 @@ class Ps(AbstractActionBase): super().subparser(parser) parser.add_argument( '--sort', - choices=[ - 'createdat', 'id', 'image', 'names', 'runningfor', 'size', - 'status' - ], + choices=('createdat', 'id', 'image', 'names', 'runningfor', 'size', + 'status'), default='createdat', type=str.lower, help=('Change sort ordered of displayed containers.' diff --git a/contrib/python/pypodman/pypodman/lib/actions/pull_action.py b/contrib/python/pypodman/pypodman/lib/actions/pull_action.py index d609eac28..d8fbfc1f0 100644 --- a/contrib/python/pypodman/pypodman/lib/actions/pull_action.py +++ b/contrib/python/pypodman/pypodman/lib/actions/pull_action.py @@ -17,7 +17,7 @@ class Pull(AbstractActionBase): ) parser.add_argument( 'targets', - nargs='*', + nargs='+', help='image id(s) to retrieve.', ) parser.set_defaults(class_=cls, method='pull') @@ -25,9 +25,6 @@ class Pull(AbstractActionBase): def __init__(self, args): """Construct Pull class.""" super().__init__(args) - if not args.targets: - raise ValueError('You must supply at least one container id' - ' or name to be retrieved.') def pull(self): """Retrieve image.""" diff --git a/contrib/python/pypodman/pypodman/lib/actions/push_action.py b/contrib/python/pypodman/pypodman/lib/actions/push_action.py new file mode 100644 index 000000000..0030cb5b9 --- /dev/null +++ b/contrib/python/pypodman/pypodman/lib/actions/push_action.py @@ -0,0 +1,56 @@ +"""Remote client command for pushing image elsewhere.""" +import sys + +import podman +from pypodman.lib import AbstractActionBase + + +class Push(AbstractActionBase): + """Class for pushing images to repository.""" + + @classmethod + def subparser(cls, parent): + """Add Push command to parent parser.""" + parser = parent.add_parser( + 'push', + help='push image elsewhere', + ) + parser.add_argument( + '--tlsverify', + action='store_true', + default=True, + help='Require HTTPS and verify certificates when' + ' contacting registries (default: %(default)s)') + parser.add_argument( + 'image', nargs=1, help='name or id of image to push') + parser.add_argument( + 'tag', + nargs=1, + help='destination image id', + ) + parser.set_defaults(class_=cls, method='push') + + def __init__(self, args): + """Construct Push class.""" + super().__init__(args) + + def pull(self): + """Store image elsewhere.""" + try: + try: + img = self.client.images.get(self._args.image[0]) + except podman.ImageNotFound as e: + sys.stdout.flush() + print( + 'Image {} not found.'.format(e.name), + file=sys.stderr, + flush=True) + else: + img.push(self._args.tag[0], tlsverify=self._args.tlsverify) + print(self._args.image[0]) + except podman.ErrorOccurred as e: + sys.stdout.flush() + print( + '{}'.format(e.reason).capitalize(), + file=sys.stderr, + flush=True) diff --git a/contrib/python/pypodman/pypodman/lib/actions/restart_action.py b/contrib/python/pypodman/pypodman/lib/actions/restart_action.py new file mode 100644 index 000000000..d99d1ad65 --- /dev/null +++ b/contrib/python/pypodman/pypodman/lib/actions/restart_action.py @@ -0,0 +1,50 @@ +"""Remote client command for restarting containers.""" +import logging +import sys + +import podman +from pypodman.lib import AbstractActionBase, PositiveIntAction + + +class Restart(AbstractActionBase): + """Class for Restarting containers.""" + + @classmethod + def subparser(cls, parent): + """Add Restart command to parent parser.""" + parser = parent.add_parser('restart', help='restart container(s)') + parser.add_argument( + '--timeout', + action=PositiveIntAction, + default=10, + help='Timeout to wait before forcibly stopping the container' + ' (default: %(default)s seconds)') + parser.add_argument( + 'targets', nargs='+', help='container id(s) to restart') + parser.set_defaults(class_=cls, method='restart') + + def __init__(self, args): + """Construct Restart class.""" + super().__init__(args) + + def restart(self): + """Restart container(s).""" + try: + for ident in self._args.targets: + try: + ctnr = self.client.containers.get(ident) + logging.debug('Restarting Container %s', ctnr.id) + ctnr.restart(timeout=self._args.timeout) + print(ident) + except podman.ContainerNotFound as e: + sys.stdout.flush() + print( + 'Container {} not found.'.format(e.name), + file=sys.stderr, + flush=True) + except podman.ErrorOccurred as e: + sys.stdout.flush() + print( + '{}'.format(e.reason).capitalize(), + file=sys.stderr, + flush=True) diff --git a/contrib/python/pypodman/pypodman/lib/actions/rm_action.py b/contrib/python/pypodman/pypodman/lib/actions/rm_action.py index 62c0b8599..e8074ef4e 100644 --- a/contrib/python/pypodman/pypodman/lib/actions/rm_action.py +++ b/contrib/python/pypodman/pypodman/lib/actions/rm_action.py @@ -19,15 +19,12 @@ class Rm(AbstractActionBase): help=('force delete of running container(s).' ' (default: %(default)s)')) parser.add_argument( - 'targets', nargs='*', help='container id(s) to delete') + 'targets', nargs='+', help='container id(s) to delete') parser.set_defaults(class_=cls, method='remove') def __init__(self, args): """Construct Rm class.""" super().__init__(args) - if not args.targets: - raise ValueError('You must supply at least one container id' - ' or name to be deleted.') def remove(self): """Remove container(s).""" diff --git a/contrib/python/pypodman/pypodman/lib/actions/rmi_action.py b/contrib/python/pypodman/pypodman/lib/actions/rmi_action.py index 9ff533821..c6ba835cb 100644 --- a/contrib/python/pypodman/pypodman/lib/actions/rmi_action.py +++ b/contrib/python/pypodman/pypodman/lib/actions/rmi_action.py @@ -18,15 +18,12 @@ class Rmi(AbstractActionBase): action='store_true', help=('force delete of image(s) and associated containers.' ' (default: %(default)s)')) - parser.add_argument('targets', nargs='*', help='image id(s) to delete') + parser.add_argument('targets', nargs='+', help='image id(s) to delete') parser.set_defaults(class_=cls, method='remove') def __init__(self, args): """Construct Rmi class.""" super().__init__(args) - if not args.targets: - raise ValueError('You must supply at least one image id' - ' or name to be deleted.') def remove(self): """Remove image(s).""" diff --git a/contrib/python/pypodman/pypodman/lib/actions/run_action.py b/contrib/python/pypodman/pypodman/lib/actions/run_action.py new file mode 100644 index 000000000..a63eb7917 --- /dev/null +++ b/contrib/python/pypodman/pypodman/lib/actions/run_action.py @@ -0,0 +1,73 @@ +"""Remote client command for run a command in a new container.""" +import logging +import sys + +import podman +from pypodman.lib import AbstractActionBase + +from ._create_args import CreateArguments + + +class Run(AbstractActionBase): + """Class for running a command in a container.""" + + @classmethod + def subparser(cls, parent): + """Add Run command to parent parser.""" + parser = parent.add_parser('run', help='Run container from image') + + CreateArguments.add_arguments(parser) + + parser.add_argument('image', nargs=1, help='source image id.') + parser.add_argument( + 'command', + nargs='*', + help='command and args to run.', + ) + parser.set_defaults(class_=cls, method='run') + + def __init__(self, args): + """Construct Run class.""" + super().__init__(args) + if args.detach and args.rm: + raise ValueError('Incompatible options: --detach and --rm') + + # image id used only on client + del self.opts['image'] + + def run(self): + """Run container.""" + for ident in self._args.image: + try: + try: + img = self.client.images.get(ident) + ctnr = img.container(**self.opts) + except podman.ImageNotFound as e: + sys.stdout.flush() + print( + 'Image {} not found.'.format(e.name), + file=sys.stderr, + flush=True) + continue + else: + logging.debug('New container created "{}"'.format(ctnr.id)) + + if self._args.detach: + ctnr.start() + print(ctnr.id) + else: + ctnr.attach(eot=4) + ctnr.start() + print(ctnr.id) + + if self._args.rm: + ctnr.remove(force=True) + except (BrokenPipeError, KeyboardInterrupt): + print('\nContainer "{}" disconnected.'.format(ctnr.id)) + except podman.ErrorOccurred as e: + sys.stdout.flush() + print( + 'Run for container "{}" failed: {} {}'.format( + ctnr.id, repr(e), e.reason.capitalize()), + file=sys.stderr, + flush=True) diff --git a/contrib/python/pypodman/pypodman/lib/actions/search_action.py b/contrib/python/pypodman/pypodman/lib/actions/search_action.py new file mode 100644 index 000000000..d2a585d92 --- /dev/null +++ b/contrib/python/pypodman/pypodman/lib/actions/search_action.py @@ -0,0 +1,160 @@ +"""Remote client command for searching registries for an image.""" +import argparse +import sys +from collections import OrderedDict + +import podman +from pypodman.lib import (AbstractActionBase, BooleanValidate, + PositiveIntAction, Report, ReportColumn) + + +class FilterAction(argparse.Action): + """Parse filter argument components.""" + + def __init__(self, + option_strings, + dest, + nargs=None, + const=None, + default=None, + type=None, + choices=None, + required=False, + help=None, + metavar='FILTER'): + """Create FilterAction object.""" + help = (help or '') + (' (format: stars=##' + ' or is-automated=[True|False]' + ' or is-official=[True|False])') + super().__init__( + option_strings=option_strings, + dest=dest, + nargs=nargs, + const=const, + default=default, + type=type, + choices=choices, + required=required, + help=help, + metavar=metavar) + + def __call__(self, parser, namespace, values, option_string=None): + """ + Convert and Validate input. + + Note: side effects + 1) self.dest value is set to subargument dest + 2) new attribute self.dest + '_value' is created with 2nd value. + """ + opt, val = values.split('=', 1) + if opt == 'stars': + msg = ('{} option "stars" requires' + ' a positive integer').format(self.dest) + try: + val = int(val) + except ValueError: + parser.error(msg) + + if val < 0: + parser.error(msg) + elif opt == 'is-automated': + try: + val = BooleanValidate()(val) + except ValueError: + msg = ('{} option "is-automated"' + ' must be True or False.'.format(self.dest)) + parser.error(msg) + elif opt == 'is-official': + try: + val = BooleanValidate()(val) + except ValueError: + msg = ('{} option "is-official"' + ' must be True or False.'.format(self.dest)) + parser.error(msg) + else: + msg = ('{} only supports one of the following options:\n' + ' stars, is-automated, or is-official').format(self.dest) + parser.error(msg) + setattr(namespace, self.dest, opt) + setattr(namespace, self.dest + '_value', val) + + +class Search(AbstractActionBase): + """Class for searching registries for an image.""" + + @classmethod + def subparser(cls, parent): + """Add Search command to parent parser.""" + parser = parent.add_parser('search', help='search for images') + super().subparser(parser) + parser.add_argument( + '--filter', + '-f', + action=FilterAction, + help='Filter output based on conditions provided.') + parser.add_argument( + '--limit', + action=PositiveIntAction, + default=25, + help='Limit the number of results.' + ' (default: %(default)s)') + parser.add_argument('term', nargs=1, help='search term for image') + parser.set_defaults(class_=cls, method='search') + + def __init__(self, args): + """Construct Search class.""" + super().__init__(args) + + self.columns = OrderedDict({ + 'name': + ReportColumn('name', 'NAME', 44), + 'description': + ReportColumn('description', 'DESCRIPTION', 44), + 'star_count': + ReportColumn('star_count', 'STARS', 5), + 'is_official': + ReportColumn('is_official', 'OFFICIAL', 8), + 'is_automated': + ReportColumn('is_automated', 'AUTOMATED', 9), + }) + + def search(self): + """Search registries for image.""" + try: + rows = list() + for entry in self.client.images.search( + self._args.term[0], limit=self._args.limit): + + if self._args.filter == 'is-official': + if self._args.filter_value != entry.is_official: + continue + elif self._args.filter == 'is-automated': + if self._args.filter_value != entry.is_automated: + continue + elif self._args.filter == 'stars': + if self._args.filter_value > entry.star_count: + continue + + fields = dict(entry._asdict()) + + status = '[OK]' if entry.is_official else '' + fields['is_official'] = status + + status = '[OK]' if entry.is_automated else '' + fields['is_automated'] = status + + if self._args.truncate: + fields.update({'name': entry.name[-44:]}) + rows.append(fields) + + with Report(self.columns, heading=self._args.heading) as report: + report.layout( + rows, self.columns.keys(), truncate=self._args.truncate) + for row in rows: + report.row(**row) + except podman.ErrorOccurred as e: + sys.stdout.flush() + print( + '{}'.format(e.reason).capitalize(), + file=sys.stderr, + flush=True) diff --git a/contrib/python/pypodman/pypodman/lib/parser_actions.py b/contrib/python/pypodman/pypodman/lib/parser_actions.py new file mode 100644 index 000000000..2a5859e47 --- /dev/null +++ b/contrib/python/pypodman/pypodman/lib/parser_actions.py @@ -0,0 +1,185 @@ +""" +Supplimental argparse.Action converters and validaters. + +The constructors are very verbose but remain for IDE support. +""" +import argparse +import os + +# API defined by argparse.Action shut up pylint +# pragma pylint: disable=redefined-builtin +# pragma pylint: disable=too-few-public-methods +# pragma pylint: disable=too-many-arguments + + +class BooleanValidate(): + """Validate value is boolean string.""" + + def __call__(self, value): + """Return True, False or raise ValueError.""" + val = value.capitalize() + if val == 'False': + return False + elif val == 'True': + return True + else: + raise ValueError('"{}" is not True or False'.format(value)) + + +class BooleanAction(argparse.Action): + """Convert and validate bool argument.""" + + def __init__(self, + option_strings, + dest, + nargs=None, + const=None, + default=None, + type=None, + choices=('True', 'False'), + required=False, + help=None, + metavar='{True,False}'): + """Create BooleanAction object.""" + super().__init__( + option_strings=option_strings, + dest=dest, + nargs=nargs, + const=const, + default=default, + type=type, + choices=choices, + required=required, + help=help, + metavar=metavar) + + def __call__(self, parser, namespace, values, option_string=None): + """Convert and Validate input.""" + try: + val = BooleanValidate()(values) + except ValueError: + parser.error('{} must be True or False.'.format(self.dest)) + else: + setattr(namespace, self.dest, val) + + +class UnitAction(argparse.Action): + """Validate number given is positive integer, with optional suffix.""" + + def __init__(self, + option_strings, + dest, + nargs=None, + const=None, + default=None, + type=None, + choices=None, + required=False, + help=None, + metavar='UNIT'): + """Create UnitAction object.""" + help = (help or metavar or dest + ) + ' (format: <number>[<unit>], where unit = b, k, m or g)' + super().__init__( + option_strings=option_strings, + dest=dest, + nargs=nargs, + const=const, + default=default, + type=type, + choices=choices, + required=required, + help=help, + metavar=metavar) + + def __call__(self, parser, namespace, values, option_string=None): + """Validate input as a UNIT.""" + try: + val = int(values) + except ValueError: + if not values[:-1].isdigit(): + msg = ('{} must be a positive integer,' + ' with optional suffix').format(self.dest) + parser.error(msg) + if not values[-1] in ('b', 'k', 'm', 'g'): + msg = '{} only supports suffices of: b, k, m, g'.format( + self.dest) + parser.error(msg) + else: + if val <= 0: + msg = '{} must be a positive integer'.format(self.dest) + parser.error(msg) + + setattr(namespace, self.dest, values) + + +class PositiveIntAction(argparse.Action): + """Validate number given is positive integer.""" + + def __init__(self, + option_strings, + dest, + nargs=None, + const=None, + default=None, + type=int, + choices=None, + required=False, + help=None, + metavar=None): + """Create PositiveIntAction object.""" + self.message = '{} must be a positive integer'.format(dest) + help = help or self.message + + super().__init__( + option_strings=option_strings, + dest=dest, + nargs=nargs, + const=const, + default=default, + type=int, + choices=choices, + required=required, + help=help, + metavar=metavar) + + def __call__(self, parser, namespace, values, option_string=None): + """Validate input.""" + if values > 0: + setattr(namespace, self.dest, values) + return + + parser.error(self.message) + + +class PathAction(argparse.Action): + """Expand user- and relative-paths.""" + + def __init__(self, + option_strings, + dest, + nargs=None, + const=None, + default=None, + type=None, + choices=None, + required=False, + help=None, + metavar='PATH'): + """Create PathAction object.""" + super().__init__( + option_strings=option_strings, + dest=dest, + nargs=nargs, + const=const, + default=default, + type=type, + choices=choices, + required=required, + help=help, + metavar=metavar) + + def __call__(self, parser, namespace, values, option_string=None): + """Resolve full path value on local filesystem.""" + setattr(namespace, self.dest, + os.path.abspath(os.path.expanduser(values))) diff --git a/contrib/python/pypodman/pypodman/lib/config.py b/contrib/python/pypodman/pypodman/lib/podman_parser.py index 2f0cbf8ae..4150e5d50 100644 --- a/contrib/python/pypodman/pypodman/lib/config.py +++ b/contrib/python/pypodman/pypodman/lib/podman_parser.py @@ -7,10 +7,13 @@ import logging import os import sys from contextlib import suppress +from pathlib import Path import pkg_resources import pytoml +from .parser_actions import PathAction, PositiveIntAction + # TODO: setup.py and obtain __version__ from rpm.spec try: __version__ = pkg_resources.get_distribution('pypodman').version @@ -33,35 +36,14 @@ class HelpFormatter(argparse.RawDescriptionHelpFormatter): super().__init__(*args, **kwargs) -class PortAction(argparse.Action): - """Validate port number given is positive integer.""" - - def __call__(self, parser, namespace, values, option_string=None): - """Validate input.""" - if values > 0: - setattr(namespace, self.dest, values) - return - - msg = 'port numbers must be a positive integer.' - raise argparse.ArgumentError(self, msg) - - -class PathAction(argparse.Action): - """Expand user- and relative-paths.""" - - def __call__(self, parser, namespace, values, option_string=None): - """Resolve full path value.""" - setattr(namespace, self.dest, - os.path.abspath(os.path.expanduser(values))) - - class PodmanArgumentParser(argparse.ArgumentParser): """Default remote podman configuration.""" def __init__(self, **kwargs): """Construct the parser.""" kwargs['add_help'] = True - kwargs['description'] = __doc__ + kwargs['description'] = ('Portable and simple management' + ' tool for containers and images') kwargs['formatter_class'] = HelpFormatter super().__init__(**kwargs) @@ -83,9 +65,9 @@ class PodmanArgumentParser(argparse.ArgumentParser): '--run-dir', metavar='DIRECTORY', help=('directory to place local socket bindings.' - ' (default: XDG_RUNTIME_DIR/pypodman')) + ' (default: XDG_RUNTIME_DIR/pypodman)')) self.add_argument( - '--user', + '--username', '-l', default=getpass.getuser(), help='Authenicating user on remote host. (default: %(default)s)') @@ -94,8 +76,7 @@ class PodmanArgumentParser(argparse.ArgumentParser): self.add_argument( '--port', '-p', - type=int, - action=PortAction, + action=PositiveIntAction, help='port for ssh tunnel to remote host. (default: 22)') self.add_argument( '--remote-socket-path', @@ -105,18 +86,17 @@ class PodmanArgumentParser(argparse.ArgumentParser): self.add_argument( '--identity-file', '-i', - metavar='PATH', action=PathAction, - help=('path to ssh identity file. (default: ~user/.ssh/id_dsa)')) + help='path to ssh identity file. (default: ~user/.ssh/id_dsa)') self.add_argument( '--config-home', metavar='DIRECTORY', action=PathAction, help=('home of configuration "pypodman.conf".' - ' (default: XDG_CONFIG_HOME/pypodman')) + ' (default: XDG_CONFIG_HOME/pypodman)')) actions_parser = self.add_subparsers( - dest='subparser_name', help='actions') + dest='subparser_name', help='commands') # import buried here to prevent import loops import pypodman.lib.actions # pylint: disable=cyclic-import @@ -157,11 +137,12 @@ class PodmanArgumentParser(argparse.ArgumentParser): if dir_ is None: continue with suppress(OSError): - with open(os.path.join(dir_, - 'pypodman/pypodman.conf')) as stream: + cnf = Path(dir_, 'pypodman', 'pypodman.conf') + with cnf.open() as stream: config.update(pytoml.load(stream)) def reqattr(name, value): + """Raise an error if value is unset.""" if value: setattr(args, name, value) return value @@ -173,7 +154,7 @@ class PodmanArgumentParser(argparse.ArgumentParser): getattr(args, 'run_dir') or os.environ.get('RUN_DIR') or config['default'].get('run_dir') - or os.path.join(args.xdg_runtime_dir, 'pypodman') + or Path(args.xdg_runtime_dir, 'pypodman') ) # yapf: disable setattr( @@ -185,11 +166,11 @@ class PodmanArgumentParser(argparse.ArgumentParser): ) # yapf:disable reqattr( - 'user', - getattr(args, 'user') + 'username', + getattr(args, 'username') or os.environ.get('USER') or os.environ.get('LOGNAME') - or config['default'].get('user') + or config['default'].get('username') or getpass.getuser() ) # yapf:disable @@ -215,22 +196,21 @@ class PodmanArgumentParser(argparse.ArgumentParser): getattr(args, 'identity_file') or os.environ.get('IDENTITY_FILE') or config['default'].get('identity_file') - or os.path.expanduser('~{}/.ssh/id_dsa'.format(args.user)) + or os.path.expanduser('~{}/.ssh/id_dsa'.format(args.username)) ) # yapf:disable if not os.path.isfile(args.identity_file): args.identity_file = None if args.host: - args.local_socket_path = os.path.join(args.run_dir, - "podman.socket") + args.local_socket_path = Path(args.run_dir, 'podman.socket') else: args.local_socket_path = args.remote_socket_path - args.local_uri = "unix:{}".format(args.local_socket_path) + args.local_uri = 'unix:{}'.format(args.local_socket_path) if args.host: - components = ['ssh://', args.user, '@', args.host] + components = ['ssh://', args.username, '@', args.host] if args.port: components.extend((':', str(args.port))) components.append(args.remote_socket_path) diff --git a/contrib/python/pypodman/pypodman/lib/report.py b/contrib/python/pypodman/pypodman/lib/report.py index a06e6055e..1db4268da 100644 --- a/contrib/python/pypodman/pypodman/lib/report.py +++ b/contrib/python/pypodman/pypodman/lib/report.py @@ -53,7 +53,7 @@ class Report(): fmt = [] for key in keys: - slice_ = [i.get(key, '') for i in iterable] + slice_ = [str(i.get(key, '')) for i in iterable] data_len = len(max(slice_, key=len)) info = self._columns.get(key, diff --git a/contrib/python/pypodman/requirements.txt b/contrib/python/pypodman/requirements.txt index 69cf41761..ba01ed36e 100644 --- a/contrib/python/pypodman/requirements.txt +++ b/contrib/python/pypodman/requirements.txt @@ -1,4 +1,5 @@ humanize podman pytoml +PyYAML setuptools>=39 diff --git a/contrib/spec/podman.spec.in b/contrib/spec/podman.spec.in index be7b78227..a577581a3 100644 --- a/contrib/spec/podman.spec.in +++ b/contrib/spec/podman.spec.in @@ -39,7 +39,7 @@ %global shortcommit_conmon %(c=%{commit_conmon}; echo ${c:0:7}) Name: podman -Version: 0.9.2 +Version: 0.9.4 Release: #COMMITDATE#.git%{shortcommit0}%{?dist} Summary: Manage Pods, Containers and Container Images License: ASL 2.0 @@ -50,9 +50,7 @@ Source1: crio.tar.gz #ExclusiveArch: %%{?go_arches:%%{go_arches}}%%{!?go_arches:%%{ix86} x86_64 aarch64 %%{arm}} ExclusiveArch: aarch64 %{arm} ppc64le s390x x86_64 # If go_compiler is not set to 1, there is no virtual provide. Use golang instead. -BuildRequires: %{?go_compiler:compiler(go-compiler)}%{!?go_compiler:golang} BuildRequires: btrfs-progs-devel -BuildRequires: device-mapper-devel BuildRequires: glib2-devel BuildRequires: glibc-devel BuildRequires: glibc-static @@ -142,7 +140,7 @@ Provides: bundled(golang(github.com/ostreedev/ostree-go)) = master Provides: bundled(golang(github.com/pkg/errors)) = v0.8.0 Provides: bundled(golang(github.com/pmezard/go-difflib)) = 792786c7400a136282c1664665ae0a8db921c6c2 Provides: bundled(golang(github.com/pquerna/ffjson)) = d49c2bc1aa135aad0c6f4fc2056623ec78f5d5ac -Provides: bundled(golang(github.com/projectatomic/buildah)) = a2c8358455f9b6a254c572455af2a0afcfcec544 +Provides: bundled(golang(github.com/containers/buildah)) = a2c8358455f9b6a254c572455af2a0afcfcec544 Provides: bundled(golang(github.com/seccomp/containers-golang)) = master Provides: bundled(golang(github.com/seccomp/libseccomp-golang)) = v0.9.0 Provides: bundled(golang(github.com/sirupsen/logrus)) = v1.0.0 diff --git a/docs/libpod.conf.5.md b/docs/libpod.conf.5.md index e881c4296..198e927ee 100644 --- a/docs/libpod.conf.5.md +++ b/docs/libpod.conf.5.md @@ -59,6 +59,9 @@ libpod to manage containers. The default namespace is "", which corresponds to no namespace. When no namespace is set, all containers and pods are visible. +**label**="true|false" + Indicates whether the containers should use label separation. + ## FILES `/usr/share/containers/libpod.conf`, default libpod configuration path diff --git a/docs/podman-create.1.md b/docs/podman-create.1.md index 8cbe64a3e..c42671b76 100644 --- a/docs/podman-create.1.md +++ b/docs/podman-create.1.md @@ -372,6 +372,36 @@ unit, `b` is used. Set LIMIT to `-1` to enable unlimited swap. Tune a container's memory swappiness behavior. Accepts an integer between 0 and 100. +**--mount**=*type=TYPE,TYPE-SPECIFIC-OPTION[,...]* + +Attach a filesystem mount to the container + +Current supported mount TYPES are bind, and tmpfs. + + e.g. + + type=bind,source=/path/on/host,destination=/path/in/container + + type=tmpfs,tmpfs-size=512M,destination=/path/in/container + + Common Options: + + · src, source: mount source spec for bind and volume. Mandatory for bind. + + · dst, destination, target: mount destination spec. + + · ro, read-only: true or false (default). + + Options specific to bind: + + · bind-propagation: shared, slave, private, rshared, rslave, or rprivate(default). See also mount(2). + + Options specific to tmpfs: + + · tmpfs-size: Size of the tmpfs mount in bytes. Unlimited by default in Linux. + + · tmpfs-mode: File mode of the tmpfs in octal. (e.g. 700 or 0700.) Defaults to 1777 in Linux. + **--name**="" Assign a name to the container @@ -506,6 +536,8 @@ Security Options "seccomp=unconfined" : Turn off seccomp confinement for the container "seccomp=profile.json : White listed syscalls seccomp Json file to be used as a seccomp filter +Note: Labelling can be disabled for all containers by setting label=false in the **libpod.conf** (`/etc/containers/libpod.conf`) file. + **--shm-size**="" Size of `/dev/shm`. The format is `<number><unit>`. `number` must be greater than `0`. @@ -736,7 +768,7 @@ $ podman create --uidmap 0:30000:7000 --gidmap 0:30000:7000 fedora echo hello **/etc/subgid** ## SEE ALSO -subgid(5), subuid(5) +subgid(5), subuid(5), libpod.conf(5) ## HISTORY October 2017, converted from Docker documentation to podman by Dan Walsh for podman <dwalsh@redhat.com> diff --git a/docs/podman-run.1.md b/docs/podman-run.1.md index 0960125a3..fccebb7f7 100644 --- a/docs/podman-run.1.md +++ b/docs/podman-run.1.md @@ -528,6 +528,8 @@ Security Options - `seccomp=unconfined` : Turn off seccomp confinement for the container - `seccomp=profile.json` : White listed syscalls seccomp Json file to be used as a seccomp filter +Note: Labelling can be disabled for all containers by setting label=false in the **libpod.conf** (`/etc/containers/libpod.conf`) file. + **--shm-size**="" Size of `/dev/shm`. The format is `<number><unit>`. `number` must be greater than `0`. @@ -653,6 +655,36 @@ Set the UTS mode for the container **NOTE**: the host mode gives the container access to changing the host's hostname and is therefore considered insecure. +**--mount**=*type=TYPE,TYPE-SPECIFIC-OPTION[,...]* + +Attach a filesystem mount to the container + +Current supported mount TYPES are bind, and tmpfs. + + e.g. + + type=bind,source=/path/on/host,destination=/path/in/container + + type=tmpfs,tmpfs-size=512M,destination=/path/in/container + + Common Options: + + · src, source: mount source spec for bind and volume. Mandatory for bind. + + · dst, destination, target: mount destination spec. + + · ro, read-only: true or false (default). + + Options specific to bind: + + · bind-propagation: Z, z, shared, slave, private, rshared, rslave, or rprivate(default). See also mount(2). + + Options specific to tmpfs: + + · tmpfs-size: Size of the tmpfs mount in bytes. Unlimited by default in Linux. + + · tmpfs-mode: File mode of the tmpfs in octal. (e.g. 700 or 0700.) Defaults to 1777 in Linux. + **-v**|**--volume**[=*[HOST-DIR:CONTAINER-DIR[:OPTIONS]]*] Create a bind mount. If you specify, ` -v /HOST-DIR:/CONTAINER-DIR`, podman @@ -929,6 +961,12 @@ colon: $ podman run -v /var/db:/data1 -i -t fedora bash ``` +Using --mount flags, To mount a host directory as a container folder, specify +the absolute path to the directory and the absolute path for the container +directory: + +$ podman run --mount type=bind,src=/var/db,target=/data1 busybox sh + When using SELinux, be aware that the host has no knowledge of container SELinux policy. Therefore, in the above example, if SELinux policy is enforced, the `/var/db` directory is not writable to the container. A "Permission Denied" @@ -1025,9 +1063,11 @@ $ podman run --uidmap 0:30000:7000 --gidmap 0:30000:7000 fedora echo hello **/etc/subgid** ## SEE ALSO -subgid(5), subuid(5) +subgid(5), subuid(5), libpod.conf(5) ## HISTORY +September 2018, updated by Kunal Kushwaha <kushwaha_kunal_v7@lab.ntt.co.jp> + October 2017, converted from Docker documentation to podman by Dan Walsh for podman <dwalsh@redhat.com> November 2015, updated by Sally O'Malley <somalley@redhat.com> diff --git a/docs/podman-wait.1.md b/docs/podman-wait.1.md index 74ccdbe0c..dd5dc7907 100644 --- a/docs/podman-wait.1.md +++ b/docs/podman-wait.1.md @@ -17,6 +17,9 @@ After the container stops, the container's return code is printed. Print usage statement +**--interval, i**" + Microseconds to wait before polling for completion + **--latest, -l** Instead of providing the container name or ID, use the last created container. If you use methods other than Podman diff --git a/docs/podman.1.md b/docs/podman.1.md index eb07ed491..3a0943d6b 100644 --- a/docs/podman.1.md +++ b/docs/podman.1.md @@ -54,14 +54,14 @@ Path to the OCI compatible binary used to run containers **--storage-driver, -s**=**value** -Storage driver. The default storage driver for UID 0 is configured in /etc/containers/storage.conf, and is *vfs* for other users. The `STORAGE_DRIVER` environment variable overrides the default. The --storage-driver specified driver overrides all. +Storage driver. The default storage driver for UID 0 is configured in /etc/containers/storage.conf (`$HOME/.config/containers/storage.conf` in rootless mode), and is *vfs* for other users. The `STORAGE_DRIVER` environment variable overrides the default. The --storage-driver specified driver overrides all. Overriding this option will cause the *storage-opt* settings in /etc/containers/storage.conf to be ignored. The user must specify additional options via the `--storage-opt` flag. **--storage-opt**=**value** -Storage driver option, Default storage driver options are configured in /etc/containers/storage.conf. The `STORAGE_OPTS` environment variable overrides the default. The --storage-opt specified options overrides all. +Storage driver option, Default storage driver options are configured in /etc/containers/storage.conf (`$HOME/.config/containers/storage.conf` in rootless mode). The `STORAGE_OPTS` environment variable overrides the default. The --storage-opt specified options overrides all. **--syslog** @@ -153,37 +153,41 @@ the exit codes follow the `chroot` standard, see below: **libpod.conf** (`/etc/containers/libpod.conf`) -libpod.conf is the configuration file for all tools using libpod to manage containers. When Podman runs in rootless mode, then the file `$HOME/.config/containers/libpod.conf` is used. + libpod.conf is the configuration file for all tools using libpod to manage containers. When Podman runs in rootless mode, then the file `$HOME/.config/containers/libpod.conf` is used. -**storage.conf** (`/etc/containers/storage.conf`) +**mounts.conf** (`/usr/share/containers/mounts.conf` and optionally `/etc/containers/mounts.conf`) -storage.conf is the storage configuration file for all tools using containers/storage + The mounts.conf file specifies volume mount directories that are automatically mounted inside containers when executing the `podman run` or `podman start` commands. When Podman runs in rootless mode, the file `$HOME/.config/containers/mounts.conf` is also used. Please refer to containers-mounts.conf(5) for further details. -The storage configuration file specifies all of the available container storage options for tools using shared container storage. +**OCI hooks JSON** (`/etc/containers/oci/hooks.d/*.json`, `/usr/share/containers/oci/hooks.d/*.json`) -When Podman runs in rootless mode, the file `$HOME/.config/containers/storage.conf` is also loaded. + Each `*.json` file in `/etc/containers/oci/hooks.d` and `/usr/share/containers/oci/hooks.d` configures a hook for Podman containers, with `/etc/containers/oci/hooks.d` having higher precedence. For more details on the syntax of the JSON files and the semantics of hook injection, see `oci-hooks(5)`. -**mounts.conf** (`/usr/share/containers/mounts.conf` and optionally `/etc/containers/mounts.conf`) + Podman and libpod currently support both the 1.0.0 and 0.1.0 hook schemas, although the 0.1.0 schema is deprecated. + + For the annotation conditions, libpod uses any annotations set in the generated OCI configuration. -The mounts.conf files specify volume mount directories that are automatically mounted inside containers when executing the `podman run` or `podman start` commands. When Podman runs in rootless mode, the file `$HOME/.config/containers/mounts.conf` is also used. Please refer to containers-mounts.conf(5) for further details. + For the bind-mount conditions, only mounts explicitly requested by the caller via `--volume` are considered. Bind mounts that libpod inserts by default (e.g. `/dev/shm`) are not considered. -**hook JSON** (`/usr/share/containers/oci/hooks.d/*.json`) + Hooks are not used when running in rootless mode. -Each `*.json` file in `/usr/share/containers/oci/hooks.d` configures a hook for Podman containers. For more details on the syntax of the JSON files and the semantics of hook injection, see `oci-hooks(5)`. +**policy.json** (`/etc/containers/policy.json`) -Podman and libpod currently support both the 1.0.0 and 0.1.0 hook schemas, although the 0.1.0 schema is deprecated. + Signature verification policy files are used to specify policy, e.g. trusted keys, applicable when deciding whether to accept an image, or individual signatures of that image, as valid. -For the annotation conditions, libpod uses any annotations set in the generated OCI configuration. +**registries.conf** (`/etc/containers/registries.conf`) -For the bind-mount conditions, only mounts explicitly requested by the caller via `--volume` are considered. Bind mounts that libpod inserts by default (e.g. `/dev/shm`) are not considered. + registries.conf is the configuration file which specifies which container registries should be consulted when completing image names which do not include a registry or domain portion. -Hooks are not used when running in rootless mode. + When Podman runs in rootless mode, the file `$HOME/.config/containers/registries.conf` is used. -**registries.conf** (`/etc/containers/registries.conf`) +**storage.conf** (`/etc/containers/storage.conf`) + + storage.conf is the storage configuration file for all tools using containers/storage -registries.conf is the configuration file which specifies which container registries should be consulted when completing image names which do not include a registry or domain portion. + The storage configuration file specifies all of the available container storage options for tools using shared container storage. -When Podman runs in rootless mode, the file `$HOME/.config/containers/registries.conf` is used. + When Podman runs in rootless mode, the file `$HOME/.config/containers/storage.conf` is also loaded. ## Rootless mode Podman can also be used as non-root user. When podman runs in rootless mode, an user namespace is automatically created. @@ -209,7 +213,7 @@ Currently it is not possible to create a network device, so rootless containers then only the loopback device will be available. ## SEE ALSO -`oci-hooks(5)`, `containers-mounts.conf(5)`, `containers-registries.conf(5)`, `containers-storage.conf(5)`, `crio(8)`, `libpod.conf(5)` +`containers-mounts.conf(5)`, `containers-registries.conf(5)`, `containers-storage.conf(5)`, `crio(8)`, `libpod.conf(5)`, `oci-hooks(5)`, `policy.json(5)` ## HISTORY Dec 2016, Originally compiled by Dan Walsh <dwalsh@redhat.com> diff --git a/libpod.conf b/libpod.conf index cc4a10cff..2976cec02 100644 --- a/libpod.conf +++ b/libpod.conf @@ -80,3 +80,14 @@ pause_image = "k8s.gcr.io/pause:3.1" # Default command to run the pause container pause_command = "/pause" + +# Determines whether libpod will reserve ports on the host when they are +# forwarded to containers. When enabled, when ports are forwarded to containers, +# they are held open by conmon as long as the container is running, ensuring that +# they cannot be reused by other programs on the host. However, this can cause +# significant memory usage if a container has many ports forwarded to it. +# Disabling this can save memory. +#enable_port_reservation = true + +# Default libpod support for container labeling +# label=true diff --git a/libpod/container.go b/libpod/container.go index e748cb84d..0b1879208 100644 --- a/libpod/container.go +++ b/libpod/container.go @@ -45,6 +45,10 @@ const CgroupfsDefaultCgroupParent = "/libpod_parent" // manager in libpod const SystemdDefaultCgroupParent = "machine.slice" +// DefaultWaitInterval is the default interval between container status checks +// while waiting. +const DefaultWaitInterval = 250 * time.Millisecond + // LinuxNS represents a Linux namespace type LinuxNS int @@ -968,3 +972,8 @@ func (c *Container) RootGID() int { func (c *Container) IsInfra() bool { return c.config.IsInfra } + +// IsReadOnly returns whether the container is running in read only mode +func (c *Container) IsReadOnly() bool { + return c.config.Spec.Root.Readonly +} diff --git a/libpod/container_api.go b/libpod/container_api.go index 86e2370ea..fc2058de6 100644 --- a/libpod/container_api.go +++ b/libpod/container_api.go @@ -339,7 +339,9 @@ func (c *Container) Exec(tty, privileged bool, env, cmd []string, user string) e } pidFile := c.execPidPath(sessionID) - const pidWaitTimeout = 250 + // 1 second seems a reasonable time to wait + // See https://github.com/containers/libpod/issues/1495 + const pidWaitTimeout = 1000 // Wait until the runtime makes the pidfile // TODO: If runtime errors before the PID file is created, we have to @@ -591,14 +593,20 @@ func (c *Container) Inspect(size bool) (*inspect.ContainerInspectData, error) { return c.getContainerInspectData(size, driverData) } -// Wait blocks on a container to exit and returns its exit code +// Wait blocks until the container exits and returns its exit code. func (c *Container) Wait() (int32, error) { + return c.WaitWithInterval(DefaultWaitInterval) +} + +// WaitWithInterval blocks until the container to exit and returns its exit +// code. The argument is the interval at which checks the container's status. +func (c *Container) WaitWithInterval(waitTimeout time.Duration) (int32, error) { if !c.valid { return -1, ErrCtrRemoved } - - err := wait.PollImmediateInfinite(100*time.Millisecond, + err := wait.PollImmediateInfinite(waitTimeout, func() (bool, error) { + logrus.Debugf("Checking container %s status...", c.ID()) stopped, err := c.isStopped() if err != nil { return false, err diff --git a/libpod/container_commit.go b/libpod/container_commit.go index 93ad4006e..7b6266d97 100644 --- a/libpod/container_commit.go +++ b/libpod/container_commit.go @@ -4,11 +4,11 @@ import ( "context" "strings" + "github.com/containers/buildah" + "github.com/containers/buildah/util" is "github.com/containers/image/storage" "github.com/containers/libpod/libpod/image" "github.com/pkg/errors" - "github.com/projectatomic/buildah" - "github.com/projectatomic/buildah/util" "github.com/sirupsen/logrus" ) diff --git a/libpod/container_easyjson.go b/libpod/container_easyjson.go index 06521daab..2d0481f3b 100644 --- a/libpod/container_easyjson.go +++ b/libpod/container_easyjson.go @@ -2781,6 +2781,16 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer } easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo8(in, &*out.Windows) } + case "vm": + if in.IsNull() { + in.Skip() + out.VM = nil + } else { + if out.VM == nil { + out.VM = new(specs_go.VM) + } + easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo9(in, &*out.VM) + } default: in.SkipRecursive() } @@ -2918,6 +2928,276 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo8(out, *in.Windows) } + if in.VM != nil { + const prefix string = ",\"vm\":" + if first { + first = false + out.RawString(prefix[1:]) + } else { + out.RawString(prefix) + } + easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo9(out, *in.VM) + } + out.RawByte('}') +} +func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo9(in *jlexer.Lexer, out *specs_go.VM) { + isTopLevel := in.IsStart() + if in.IsNull() { + if isTopLevel { + in.Consumed() + } + in.Skip() + return + } + in.Delim('{') + for !in.IsDelim('}') { + key := in.UnsafeString() + in.WantColon() + if in.IsNull() { + in.Skip() + in.WantComma() + continue + } + switch key { + case "hypervisor": + easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo10(in, &out.Hypervisor) + case "kernel": + easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo11(in, &out.Kernel) + case "image": + easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo12(in, &out.Image) + default: + in.SkipRecursive() + } + in.WantComma() + } + in.Delim('}') + if isTopLevel { + in.Consumed() + } +} +func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo9(out *jwriter.Writer, in specs_go.VM) { + out.RawByte('{') + first := true + _ = first + if true { + const prefix string = ",\"hypervisor\":" + if first { + first = false + out.RawString(prefix[1:]) + } else { + out.RawString(prefix) + } + easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo10(out, in.Hypervisor) + } + { + const prefix string = ",\"kernel\":" + if first { + first = false + out.RawString(prefix[1:]) + } else { + out.RawString(prefix) + } + easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo11(out, in.Kernel) + } + if true { + const prefix string = ",\"image\":" + if first { + first = false + out.RawString(prefix[1:]) + } else { + out.RawString(prefix) + } + easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo12(out, in.Image) + } + out.RawByte('}') +} +func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo12(in *jlexer.Lexer, out *specs_go.VMImage) { + isTopLevel := in.IsStart() + if in.IsNull() { + if isTopLevel { + in.Consumed() + } + in.Skip() + return + } + in.Delim('{') + for !in.IsDelim('}') { + key := in.UnsafeString() + in.WantColon() + if in.IsNull() { + in.Skip() + in.WantComma() + continue + } + switch key { + case "path": + out.Path = string(in.String()) + case "format": + out.Format = string(in.String()) + default: + in.SkipRecursive() + } + in.WantComma() + } + in.Delim('}') + if isTopLevel { + in.Consumed() + } +} +func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo12(out *jwriter.Writer, in specs_go.VMImage) { + out.RawByte('{') + first := true + _ = first + { + const prefix string = ",\"path\":" + if first { + first = false + out.RawString(prefix[1:]) + } else { + out.RawString(prefix) + } + out.String(string(in.Path)) + } + { + const prefix string = ",\"format\":" + if first { + first = false + out.RawString(prefix[1:]) + } else { + out.RawString(prefix) + } + out.String(string(in.Format)) + } + out.RawByte('}') +} +func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo11(in *jlexer.Lexer, out *specs_go.VMKernel) { + isTopLevel := in.IsStart() + if in.IsNull() { + if isTopLevel { + in.Consumed() + } + in.Skip() + return + } + in.Delim('{') + for !in.IsDelim('}') { + key := in.UnsafeString() + in.WantColon() + if in.IsNull() { + in.Skip() + in.WantComma() + continue + } + switch key { + case "path": + out.Path = string(in.String()) + case "parameters": + out.Parameters = string(in.String()) + case "initrd": + out.InitRD = string(in.String()) + default: + in.SkipRecursive() + } + in.WantComma() + } + in.Delim('}') + if isTopLevel { + in.Consumed() + } +} +func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo11(out *jwriter.Writer, in specs_go.VMKernel) { + out.RawByte('{') + first := true + _ = first + { + const prefix string = ",\"path\":" + if first { + first = false + out.RawString(prefix[1:]) + } else { + out.RawString(prefix) + } + out.String(string(in.Path)) + } + if in.Parameters != "" { + const prefix string = ",\"parameters\":" + if first { + first = false + out.RawString(prefix[1:]) + } else { + out.RawString(prefix) + } + out.String(string(in.Parameters)) + } + if in.InitRD != "" { + const prefix string = ",\"initrd\":" + if first { + first = false + out.RawString(prefix[1:]) + } else { + out.RawString(prefix) + } + out.String(string(in.InitRD)) + } + out.RawByte('}') +} +func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo10(in *jlexer.Lexer, out *specs_go.VMHypervisor) { + isTopLevel := in.IsStart() + if in.IsNull() { + if isTopLevel { + in.Consumed() + } + in.Skip() + return + } + in.Delim('{') + for !in.IsDelim('}') { + key := in.UnsafeString() + in.WantColon() + if in.IsNull() { + in.Skip() + in.WantComma() + continue + } + switch key { + case "path": + out.Path = string(in.String()) + case "parameters": + out.Parameters = string(in.String()) + default: + in.SkipRecursive() + } + in.WantComma() + } + in.Delim('}') + if isTopLevel { + in.Consumed() + } +} +func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo10(out *jwriter.Writer, in specs_go.VMHypervisor) { + out.RawByte('{') + first := true + _ = first + { + const prefix string = ",\"path\":" + if first { + first = false + out.RawString(prefix[1:]) + } else { + out.RawString(prefix) + } + out.String(string(in.Path)) + } + if in.Parameters != "" { + const prefix string = ",\"parameters\":" + if first { + first = false + out.RawString(prefix[1:]) + } else { + out.RawString(prefix) + } + out.String(string(in.Parameters)) + } out.RawByte('}') } func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo8(in *jlexer.Lexer, out *specs_go.Windows) { @@ -2962,6 +3242,29 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer } in.Delim(']') } + case "devices": + if in.IsNull() { + in.Skip() + out.Devices = nil + } else { + in.Delim('[') + if out.Devices == nil { + if !in.IsDelim(']') { + out.Devices = make([]specs_go.WindowsDevice, 0, 2) + } else { + out.Devices = []specs_go.WindowsDevice{} + } + } else { + out.Devices = (out.Devices)[:0] + } + for !in.IsDelim(']') { + var v96 specs_go.WindowsDevice + easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo13(in, &v96) + out.Devices = append(out.Devices, v96) + in.WantComma() + } + in.Delim(']') + } case "resources": if in.IsNull() { in.Skip() @@ -2970,7 +3273,7 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer if out.Resources == nil { out.Resources = new(specs_go.WindowsResources) } - easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo9(in, &*out.Resources) + easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo14(in, &*out.Resources) } case "credentialSpec": if m, ok := out.CredentialSpec.(easyjson.Unmarshaler); ok { @@ -2992,7 +3295,7 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer if out.HyperV == nil { out.HyperV = new(specs_go.WindowsHyperV) } - easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo10(in, &*out.HyperV) + easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo15(in, &*out.HyperV) } case "network": if in.IsNull() { @@ -3002,7 +3305,7 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer if out.Network == nil { out.Network = new(specs_go.WindowsNetwork) } - easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo11(in, &*out.Network) + easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo16(in, &*out.Network) } default: in.SkipRecursive() @@ -3030,11 +3333,30 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer out.RawString("null") } else { out.RawByte('[') - for v96, v97 := range in.LayerFolders { - if v96 > 0 { + for v97, v98 := range in.LayerFolders { + if v97 > 0 { out.RawByte(',') } - out.String(string(v97)) + out.String(string(v98)) + } + out.RawByte(']') + } + } + if len(in.Devices) != 0 { + const prefix string = ",\"devices\":" + if first { + first = false + out.RawString(prefix[1:]) + } else { + out.RawString(prefix) + } + { + out.RawByte('[') + for v99, v100 := range in.Devices { + if v99 > 0 { + out.RawByte(',') + } + easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo13(out, v100) } out.RawByte(']') } @@ -3047,7 +3369,7 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } else { out.RawString(prefix) } - easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo9(out, *in.Resources) + easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo14(out, *in.Resources) } if in.CredentialSpec != nil { const prefix string = ",\"credentialSpec\":" @@ -3093,7 +3415,7 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } else { out.RawString(prefix) } - easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo10(out, *in.HyperV) + easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo15(out, *in.HyperV) } if in.Network != nil { const prefix string = ",\"network\":" @@ -3103,11 +3425,11 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } else { out.RawString(prefix) } - easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo11(out, *in.Network) + easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo16(out, *in.Network) } out.RawByte('}') } -func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo11(in *jlexer.Lexer, out *specs_go.WindowsNetwork) { +func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo16(in *jlexer.Lexer, out *specs_go.WindowsNetwork) { isTopLevel := in.IsStart() if in.IsNull() { if isTopLevel { @@ -3142,9 +3464,9 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer out.EndpointList = (out.EndpointList)[:0] } for !in.IsDelim(']') { - var v98 string - v98 = string(in.String()) - out.EndpointList = append(out.EndpointList, v98) + var v101 string + v101 = string(in.String()) + out.EndpointList = append(out.EndpointList, v101) in.WantComma() } in.Delim(']') @@ -3167,9 +3489,9 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer out.DNSSearchList = (out.DNSSearchList)[:0] } for !in.IsDelim(']') { - var v99 string - v99 = string(in.String()) - out.DNSSearchList = append(out.DNSSearchList, v99) + var v102 string + v102 = string(in.String()) + out.DNSSearchList = append(out.DNSSearchList, v102) in.WantComma() } in.Delim(']') @@ -3186,7 +3508,7 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer in.Consumed() } } -func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo11(out *jwriter.Writer, in specs_go.WindowsNetwork) { +func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo16(out *jwriter.Writer, in specs_go.WindowsNetwork) { out.RawByte('{') first := true _ = first @@ -3200,11 +3522,11 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } { out.RawByte('[') - for v100, v101 := range in.EndpointList { - if v100 > 0 { + for v103, v104 := range in.EndpointList { + if v103 > 0 { out.RawByte(',') } - out.String(string(v101)) + out.String(string(v104)) } out.RawByte(']') } @@ -3229,11 +3551,11 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } { out.RawByte('[') - for v102, v103 := range in.DNSSearchList { - if v102 > 0 { + for v105, v106 := range in.DNSSearchList { + if v105 > 0 { out.RawByte(',') } - out.String(string(v103)) + out.String(string(v106)) } out.RawByte(']') } @@ -3250,7 +3572,7 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } out.RawByte('}') } -func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo10(in *jlexer.Lexer, out *specs_go.WindowsHyperV) { +func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo15(in *jlexer.Lexer, out *specs_go.WindowsHyperV) { isTopLevel := in.IsStart() if in.IsNull() { if isTopLevel { @@ -3281,7 +3603,7 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer in.Consumed() } } -func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo10(out *jwriter.Writer, in specs_go.WindowsHyperV) { +func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo15(out *jwriter.Writer, in specs_go.WindowsHyperV) { out.RawByte('{') first := true _ = first @@ -3297,7 +3619,7 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } out.RawByte('}') } -func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo9(in *jlexer.Lexer, out *specs_go.WindowsResources) { +func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo14(in *jlexer.Lexer, out *specs_go.WindowsResources) { isTopLevel := in.IsStart() if in.IsNull() { if isTopLevel { @@ -3324,7 +3646,7 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer if out.Memory == nil { out.Memory = new(specs_go.WindowsMemoryResources) } - easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo12(in, &*out.Memory) + easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo17(in, &*out.Memory) } case "cpu": if in.IsNull() { @@ -3334,7 +3656,7 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer if out.CPU == nil { out.CPU = new(specs_go.WindowsCPUResources) } - easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo13(in, &*out.CPU) + easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo18(in, &*out.CPU) } case "storage": if in.IsNull() { @@ -3344,7 +3666,7 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer if out.Storage == nil { out.Storage = new(specs_go.WindowsStorageResources) } - easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo14(in, &*out.Storage) + easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo19(in, &*out.Storage) } default: in.SkipRecursive() @@ -3356,7 +3678,7 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer in.Consumed() } } -func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo9(out *jwriter.Writer, in specs_go.WindowsResources) { +func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo14(out *jwriter.Writer, in specs_go.WindowsResources) { out.RawByte('{') first := true _ = first @@ -3368,7 +3690,7 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } else { out.RawString(prefix) } - easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo12(out, *in.Memory) + easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo17(out, *in.Memory) } if in.CPU != nil { const prefix string = ",\"cpu\":" @@ -3378,7 +3700,7 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } else { out.RawString(prefix) } - easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo13(out, *in.CPU) + easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo18(out, *in.CPU) } if in.Storage != nil { const prefix string = ",\"storage\":" @@ -3388,11 +3710,11 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } else { out.RawString(prefix) } - easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo14(out, *in.Storage) + easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo19(out, *in.Storage) } out.RawByte('}') } -func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo14(in *jlexer.Lexer, out *specs_go.WindowsStorageResources) { +func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo19(in *jlexer.Lexer, out *specs_go.WindowsStorageResources) { isTopLevel := in.IsStart() if in.IsNull() { if isTopLevel { @@ -3451,7 +3773,7 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer in.Consumed() } } -func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo14(out *jwriter.Writer, in specs_go.WindowsStorageResources) { +func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo19(out *jwriter.Writer, in specs_go.WindowsStorageResources) { out.RawByte('{') first := true _ = first @@ -3487,7 +3809,7 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } out.RawByte('}') } -func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo13(in *jlexer.Lexer, out *specs_go.WindowsCPUResources) { +func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo18(in *jlexer.Lexer, out *specs_go.WindowsCPUResources) { isTopLevel := in.IsStart() if in.IsNull() { if isTopLevel { @@ -3546,7 +3868,7 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer in.Consumed() } } -func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo13(out *jwriter.Writer, in specs_go.WindowsCPUResources) { +func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo18(out *jwriter.Writer, in specs_go.WindowsCPUResources) { out.RawByte('{') first := true _ = first @@ -3582,7 +3904,7 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } out.RawByte('}') } -func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo12(in *jlexer.Lexer, out *specs_go.WindowsMemoryResources) { +func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo17(in *jlexer.Lexer, out *specs_go.WindowsMemoryResources) { isTopLevel := in.IsStart() if in.IsNull() { if isTopLevel { @@ -3621,7 +3943,7 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer in.Consumed() } } -func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo12(out *jwriter.Writer, in specs_go.WindowsMemoryResources) { +func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo17(out *jwriter.Writer, in specs_go.WindowsMemoryResources) { out.RawByte('{') first := true _ = first @@ -3637,6 +3959,65 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } out.RawByte('}') } +func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo13(in *jlexer.Lexer, out *specs_go.WindowsDevice) { + isTopLevel := in.IsStart() + if in.IsNull() { + if isTopLevel { + in.Consumed() + } + in.Skip() + return + } + in.Delim('{') + for !in.IsDelim('}') { + key := in.UnsafeString() + in.WantColon() + if in.IsNull() { + in.Skip() + in.WantComma() + continue + } + switch key { + case "id": + out.ID = string(in.String()) + case "idType": + out.IDType = string(in.String()) + default: + in.SkipRecursive() + } + in.WantComma() + } + in.Delim('}') + if isTopLevel { + in.Consumed() + } +} +func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo13(out *jwriter.Writer, in specs_go.WindowsDevice) { + out.RawByte('{') + first := true + _ = first + { + const prefix string = ",\"id\":" + if first { + first = false + out.RawString(prefix[1:]) + } else { + out.RawString(prefix) + } + out.String(string(in.ID)) + } + { + const prefix string = ",\"idType\":" + if first { + first = false + out.RawString(prefix[1:]) + } else { + out.RawString(prefix) + } + out.String(string(in.IDType)) + } + out.RawByte('}') +} func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo7(in *jlexer.Lexer, out *specs_go.Solaris) { isTopLevel := in.IsStart() if in.IsNull() { @@ -3678,9 +4059,9 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer out.Anet = (out.Anet)[:0] } for !in.IsDelim(']') { - var v104 specs_go.SolarisAnet - easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo15(in, &v104) - out.Anet = append(out.Anet, v104) + var v107 specs_go.SolarisAnet + easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo20(in, &v107) + out.Anet = append(out.Anet, v107) in.WantComma() } in.Delim(']') @@ -3693,7 +4074,7 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer if out.CappedCPU == nil { out.CappedCPU = new(specs_go.SolarisCappedCPU) } - easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo16(in, &*out.CappedCPU) + easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo21(in, &*out.CappedCPU) } case "cappedMemory": if in.IsNull() { @@ -3703,7 +4084,7 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer if out.CappedMemory == nil { out.CappedMemory = new(specs_go.SolarisCappedMemory) } - easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo17(in, &*out.CappedMemory) + easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo22(in, &*out.CappedMemory) } default: in.SkipRecursive() @@ -3759,11 +4140,11 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } { out.RawByte('[') - for v105, v106 := range in.Anet { - if v105 > 0 { + for v108, v109 := range in.Anet { + if v108 > 0 { out.RawByte(',') } - easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo15(out, v106) + easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo20(out, v109) } out.RawByte(']') } @@ -3776,7 +4157,7 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } else { out.RawString(prefix) } - easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo16(out, *in.CappedCPU) + easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo21(out, *in.CappedCPU) } if in.CappedMemory != nil { const prefix string = ",\"cappedMemory\":" @@ -3786,11 +4167,11 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } else { out.RawString(prefix) } - easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo17(out, *in.CappedMemory) + easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo22(out, *in.CappedMemory) } out.RawByte('}') } -func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo17(in *jlexer.Lexer, out *specs_go.SolarisCappedMemory) { +func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo22(in *jlexer.Lexer, out *specs_go.SolarisCappedMemory) { isTopLevel := in.IsStart() if in.IsNull() { if isTopLevel { @@ -3823,7 +4204,7 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer in.Consumed() } } -func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo17(out *jwriter.Writer, in specs_go.SolarisCappedMemory) { +func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo22(out *jwriter.Writer, in specs_go.SolarisCappedMemory) { out.RawByte('{') first := true _ = first @@ -3849,7 +4230,7 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } out.RawByte('}') } -func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo16(in *jlexer.Lexer, out *specs_go.SolarisCappedCPU) { +func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo21(in *jlexer.Lexer, out *specs_go.SolarisCappedCPU) { isTopLevel := in.IsStart() if in.IsNull() { if isTopLevel { @@ -3880,7 +4261,7 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer in.Consumed() } } -func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo16(out *jwriter.Writer, in specs_go.SolarisCappedCPU) { +func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo21(out *jwriter.Writer, in specs_go.SolarisCappedCPU) { out.RawByte('{') first := true _ = first @@ -3896,7 +4277,7 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } out.RawByte('}') } -func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo15(in *jlexer.Lexer, out *specs_go.SolarisAnet) { +func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo20(in *jlexer.Lexer, out *specs_go.SolarisAnet) { isTopLevel := in.IsStart() if in.IsNull() { if isTopLevel { @@ -3939,7 +4320,7 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer in.Consumed() } } -func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo15(out *jwriter.Writer, in specs_go.SolarisAnet) { +func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo20(out *jwriter.Writer, in specs_go.SolarisAnet) { out.RawByte('{') first := true _ = first @@ -4050,9 +4431,9 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer out.UIDMappings = (out.UIDMappings)[:0] } for !in.IsDelim(']') { - var v107 specs_go.LinuxIDMapping - easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo18(in, &v107) - out.UIDMappings = append(out.UIDMappings, v107) + var v110 specs_go.LinuxIDMapping + easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo23(in, &v110) + out.UIDMappings = append(out.UIDMappings, v110) in.WantComma() } in.Delim(']') @@ -4073,9 +4454,9 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer out.GIDMappings = (out.GIDMappings)[:0] } for !in.IsDelim(']') { - var v108 specs_go.LinuxIDMapping - easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo18(in, &v108) - out.GIDMappings = append(out.GIDMappings, v108) + var v111 specs_go.LinuxIDMapping + easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo23(in, &v111) + out.GIDMappings = append(out.GIDMappings, v111) in.WantComma() } in.Delim(']') @@ -4093,9 +4474,9 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer for !in.IsDelim('}') { key := string(in.String()) in.WantColon() - var v109 string - v109 = string(in.String()) - (out.Sysctl)[key] = v109 + var v112 string + v112 = string(in.String()) + (out.Sysctl)[key] = v112 in.WantComma() } in.Delim('}') @@ -4108,7 +4489,7 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer if out.Resources == nil { out.Resources = new(specs_go.LinuxResources) } - easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo19(in, &*out.Resources) + easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo24(in, &*out.Resources) } case "cgroupsPath": out.CgroupsPath = string(in.String()) @@ -4128,9 +4509,9 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer out.Namespaces = (out.Namespaces)[:0] } for !in.IsDelim(']') { - var v110 specs_go.LinuxNamespace - easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo20(in, &v110) - out.Namespaces = append(out.Namespaces, v110) + var v113 specs_go.LinuxNamespace + easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo25(in, &v113) + out.Namespaces = append(out.Namespaces, v113) in.WantComma() } in.Delim(']') @@ -4151,9 +4532,9 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer out.Devices = (out.Devices)[:0] } for !in.IsDelim(']') { - var v111 specs_go.LinuxDevice - easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo21(in, &v111) - out.Devices = append(out.Devices, v111) + var v114 specs_go.LinuxDevice + easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo26(in, &v114) + out.Devices = append(out.Devices, v114) in.WantComma() } in.Delim(']') @@ -4166,7 +4547,7 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer if out.Seccomp == nil { out.Seccomp = new(specs_go.LinuxSeccomp) } - easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo22(in, &*out.Seccomp) + easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo27(in, &*out.Seccomp) } case "rootfsPropagation": out.RootfsPropagation = string(in.String()) @@ -4186,9 +4567,9 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer out.MaskedPaths = (out.MaskedPaths)[:0] } for !in.IsDelim(']') { - var v112 string - v112 = string(in.String()) - out.MaskedPaths = append(out.MaskedPaths, v112) + var v115 string + v115 = string(in.String()) + out.MaskedPaths = append(out.MaskedPaths, v115) in.WantComma() } in.Delim(']') @@ -4209,9 +4590,9 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer out.ReadonlyPaths = (out.ReadonlyPaths)[:0] } for !in.IsDelim(']') { - var v113 string - v113 = string(in.String()) - out.ReadonlyPaths = append(out.ReadonlyPaths, v113) + var v116 string + v116 = string(in.String()) + out.ReadonlyPaths = append(out.ReadonlyPaths, v116) in.WantComma() } in.Delim(']') @@ -4226,7 +4607,7 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer if out.IntelRdt == nil { out.IntelRdt = new(specs_go.LinuxIntelRdt) } - easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo23(in, &*out.IntelRdt) + easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo28(in, &*out.IntelRdt) } default: in.SkipRecursive() @@ -4252,11 +4633,11 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } { out.RawByte('[') - for v114, v115 := range in.UIDMappings { - if v114 > 0 { + for v117, v118 := range in.UIDMappings { + if v117 > 0 { out.RawByte(',') } - easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo18(out, v115) + easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo23(out, v118) } out.RawByte(']') } @@ -4271,11 +4652,11 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } { out.RawByte('[') - for v116, v117 := range in.GIDMappings { - if v116 > 0 { + for v119, v120 := range in.GIDMappings { + if v119 > 0 { out.RawByte(',') } - easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo18(out, v117) + easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo23(out, v120) } out.RawByte(']') } @@ -4290,16 +4671,16 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } { out.RawByte('{') - v118First := true - for v118Name, v118Value := range in.Sysctl { - if v118First { - v118First = false + v121First := true + for v121Name, v121Value := range in.Sysctl { + if v121First { + v121First = false } else { out.RawByte(',') } - out.String(string(v118Name)) + out.String(string(v121Name)) out.RawByte(':') - out.String(string(v118Value)) + out.String(string(v121Value)) } out.RawByte('}') } @@ -4312,7 +4693,7 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } else { out.RawString(prefix) } - easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo19(out, *in.Resources) + easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo24(out, *in.Resources) } if in.CgroupsPath != "" { const prefix string = ",\"cgroupsPath\":" @@ -4334,11 +4715,11 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } { out.RawByte('[') - for v119, v120 := range in.Namespaces { - if v119 > 0 { + for v122, v123 := range in.Namespaces { + if v122 > 0 { out.RawByte(',') } - easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo20(out, v120) + easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo25(out, v123) } out.RawByte(']') } @@ -4353,11 +4734,11 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } { out.RawByte('[') - for v121, v122 := range in.Devices { - if v121 > 0 { + for v124, v125 := range in.Devices { + if v124 > 0 { out.RawByte(',') } - easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo21(out, v122) + easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo26(out, v125) } out.RawByte(']') } @@ -4370,7 +4751,7 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } else { out.RawString(prefix) } - easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo22(out, *in.Seccomp) + easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo27(out, *in.Seccomp) } if in.RootfsPropagation != "" { const prefix string = ",\"rootfsPropagation\":" @@ -4392,11 +4773,11 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } { out.RawByte('[') - for v123, v124 := range in.MaskedPaths { - if v123 > 0 { + for v126, v127 := range in.MaskedPaths { + if v126 > 0 { out.RawByte(',') } - out.String(string(v124)) + out.String(string(v127)) } out.RawByte(']') } @@ -4411,11 +4792,11 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } { out.RawByte('[') - for v125, v126 := range in.ReadonlyPaths { - if v125 > 0 { + for v128, v129 := range in.ReadonlyPaths { + if v128 > 0 { out.RawByte(',') } - out.String(string(v126)) + out.String(string(v129)) } out.RawByte(']') } @@ -4438,11 +4819,11 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } else { out.RawString(prefix) } - easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo23(out, *in.IntelRdt) + easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo28(out, *in.IntelRdt) } out.RawByte('}') } -func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo23(in *jlexer.Lexer, out *specs_go.LinuxIntelRdt) { +func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo28(in *jlexer.Lexer, out *specs_go.LinuxIntelRdt) { isTopLevel := in.IsStart() if in.IsNull() { if isTopLevel { @@ -4473,7 +4854,7 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer in.Consumed() } } -func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo23(out *jwriter.Writer, in specs_go.LinuxIntelRdt) { +func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo28(out *jwriter.Writer, in specs_go.LinuxIntelRdt) { out.RawByte('{') first := true _ = first @@ -4489,7 +4870,7 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } out.RawByte('}') } -func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo22(in *jlexer.Lexer, out *specs_go.LinuxSeccomp) { +func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo27(in *jlexer.Lexer, out *specs_go.LinuxSeccomp) { isTopLevel := in.IsStart() if in.IsNull() { if isTopLevel { @@ -4526,9 +4907,9 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer out.Architectures = (out.Architectures)[:0] } for !in.IsDelim(']') { - var v127 specs_go.Arch - v127 = specs_go.Arch(in.String()) - out.Architectures = append(out.Architectures, v127) + var v130 specs_go.Arch + v130 = specs_go.Arch(in.String()) + out.Architectures = append(out.Architectures, v130) in.WantComma() } in.Delim(']') @@ -4549,9 +4930,9 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer out.Syscalls = (out.Syscalls)[:0] } for !in.IsDelim(']') { - var v128 specs_go.LinuxSyscall - easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo24(in, &v128) - out.Syscalls = append(out.Syscalls, v128) + var v131 specs_go.LinuxSyscall + easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo29(in, &v131) + out.Syscalls = append(out.Syscalls, v131) in.WantComma() } in.Delim(']') @@ -4566,7 +4947,7 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer in.Consumed() } } -func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo22(out *jwriter.Writer, in specs_go.LinuxSeccomp) { +func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo27(out *jwriter.Writer, in specs_go.LinuxSeccomp) { out.RawByte('{') first := true _ = first @@ -4590,11 +4971,11 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } { out.RawByte('[') - for v129, v130 := range in.Architectures { - if v129 > 0 { + for v132, v133 := range in.Architectures { + if v132 > 0 { out.RawByte(',') } - out.String(string(v130)) + out.String(string(v133)) } out.RawByte(']') } @@ -4609,18 +4990,18 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } { out.RawByte('[') - for v131, v132 := range in.Syscalls { - if v131 > 0 { + for v134, v135 := range in.Syscalls { + if v134 > 0 { out.RawByte(',') } - easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo24(out, v132) + easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo29(out, v135) } out.RawByte(']') } } out.RawByte('}') } -func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo24(in *jlexer.Lexer, out *specs_go.LinuxSyscall) { +func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo29(in *jlexer.Lexer, out *specs_go.LinuxSyscall) { isTopLevel := in.IsStart() if in.IsNull() { if isTopLevel { @@ -4655,9 +5036,9 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer out.Names = (out.Names)[:0] } for !in.IsDelim(']') { - var v133 string - v133 = string(in.String()) - out.Names = append(out.Names, v133) + var v136 string + v136 = string(in.String()) + out.Names = append(out.Names, v136) in.WantComma() } in.Delim(']') @@ -4680,9 +5061,9 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer out.Args = (out.Args)[:0] } for !in.IsDelim(']') { - var v134 specs_go.LinuxSeccompArg - easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo25(in, &v134) - out.Args = append(out.Args, v134) + var v137 specs_go.LinuxSeccompArg + easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo30(in, &v137) + out.Args = append(out.Args, v137) in.WantComma() } in.Delim(']') @@ -4697,7 +5078,7 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer in.Consumed() } } -func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo24(out *jwriter.Writer, in specs_go.LinuxSyscall) { +func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo29(out *jwriter.Writer, in specs_go.LinuxSyscall) { out.RawByte('{') first := true _ = first @@ -4713,11 +5094,11 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer out.RawString("null") } else { out.RawByte('[') - for v135, v136 := range in.Names { - if v135 > 0 { + for v138, v139 := range in.Names { + if v138 > 0 { out.RawByte(',') } - out.String(string(v136)) + out.String(string(v139)) } out.RawByte(']') } @@ -4742,18 +5123,18 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } { out.RawByte('[') - for v137, v138 := range in.Args { - if v137 > 0 { + for v140, v141 := range in.Args { + if v140 > 0 { out.RawByte(',') } - easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo25(out, v138) + easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo30(out, v141) } out.RawByte(']') } } out.RawByte('}') } -func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo25(in *jlexer.Lexer, out *specs_go.LinuxSeccompArg) { +func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo30(in *jlexer.Lexer, out *specs_go.LinuxSeccompArg) { isTopLevel := in.IsStart() if in.IsNull() { if isTopLevel { @@ -4790,7 +5171,7 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer in.Consumed() } } -func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo25(out *jwriter.Writer, in specs_go.LinuxSeccompArg) { +func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo30(out *jwriter.Writer, in specs_go.LinuxSeccompArg) { out.RawByte('{') first := true _ = first @@ -4836,7 +5217,7 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } out.RawByte('}') } -func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo21(in *jlexer.Lexer, out *specs_go.LinuxDevice) { +func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo26(in *jlexer.Lexer, out *specs_go.LinuxDevice) { isTopLevel := in.IsStart() if in.IsNull() { if isTopLevel { @@ -4903,7 +5284,7 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer in.Consumed() } } -func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo21(out *jwriter.Writer, in specs_go.LinuxDevice) { +func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo26(out *jwriter.Writer, in specs_go.LinuxDevice) { out.RawByte('{') first := true _ = first @@ -4979,7 +5360,7 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } out.RawByte('}') } -func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo20(in *jlexer.Lexer, out *specs_go.LinuxNamespace) { +func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo25(in *jlexer.Lexer, out *specs_go.LinuxNamespace) { isTopLevel := in.IsStart() if in.IsNull() { if isTopLevel { @@ -5012,7 +5393,7 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer in.Consumed() } } -func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo20(out *jwriter.Writer, in specs_go.LinuxNamespace) { +func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo25(out *jwriter.Writer, in specs_go.LinuxNamespace) { out.RawByte('{') first := true _ = first @@ -5038,7 +5419,7 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } out.RawByte('}') } -func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo19(in *jlexer.Lexer, out *specs_go.LinuxResources) { +func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo24(in *jlexer.Lexer, out *specs_go.LinuxResources) { isTopLevel := in.IsStart() if in.IsNull() { if isTopLevel { @@ -5073,9 +5454,9 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer out.Devices = (out.Devices)[:0] } for !in.IsDelim(']') { - var v139 specs_go.LinuxDeviceCgroup - easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo26(in, &v139) - out.Devices = append(out.Devices, v139) + var v142 specs_go.LinuxDeviceCgroup + easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo31(in, &v142) + out.Devices = append(out.Devices, v142) in.WantComma() } in.Delim(']') @@ -5088,7 +5469,7 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer if out.Memory == nil { out.Memory = new(specs_go.LinuxMemory) } - easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo27(in, &*out.Memory) + easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo32(in, &*out.Memory) } case "cpu": if in.IsNull() { @@ -5098,7 +5479,7 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer if out.CPU == nil { out.CPU = new(specs_go.LinuxCPU) } - easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo28(in, &*out.CPU) + easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo33(in, &*out.CPU) } case "pids": if in.IsNull() { @@ -5108,7 +5489,7 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer if out.Pids == nil { out.Pids = new(specs_go.LinuxPids) } - easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo29(in, &*out.Pids) + easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo34(in, &*out.Pids) } case "blockIO": if in.IsNull() { @@ -5118,7 +5499,7 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer if out.BlockIO == nil { out.BlockIO = new(specs_go.LinuxBlockIO) } - easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo30(in, &*out.BlockIO) + easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo35(in, &*out.BlockIO) } case "hugepageLimits": if in.IsNull() { @@ -5136,9 +5517,9 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer out.HugepageLimits = (out.HugepageLimits)[:0] } for !in.IsDelim(']') { - var v140 specs_go.LinuxHugepageLimit - easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo31(in, &v140) - out.HugepageLimits = append(out.HugepageLimits, v140) + var v143 specs_go.LinuxHugepageLimit + easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo36(in, &v143) + out.HugepageLimits = append(out.HugepageLimits, v143) in.WantComma() } in.Delim(']') @@ -5151,7 +5532,27 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer if out.Network == nil { out.Network = new(specs_go.LinuxNetwork) } - easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo32(in, &*out.Network) + easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo37(in, &*out.Network) + } + case "rdma": + if in.IsNull() { + in.Skip() + } else { + in.Delim('{') + if !in.IsDelim('}') { + out.Rdma = make(map[string]specs_go.LinuxRdma) + } else { + out.Rdma = nil + } + for !in.IsDelim('}') { + key := string(in.String()) + in.WantColon() + var v144 specs_go.LinuxRdma + easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo38(in, &v144) + (out.Rdma)[key] = v144 + in.WantComma() + } + in.Delim('}') } default: in.SkipRecursive() @@ -5163,7 +5564,7 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer in.Consumed() } } -func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo19(out *jwriter.Writer, in specs_go.LinuxResources) { +func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo24(out *jwriter.Writer, in specs_go.LinuxResources) { out.RawByte('{') first := true _ = first @@ -5177,11 +5578,11 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } { out.RawByte('[') - for v141, v142 := range in.Devices { - if v141 > 0 { + for v145, v146 := range in.Devices { + if v145 > 0 { out.RawByte(',') } - easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo26(out, v142) + easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo31(out, v146) } out.RawByte(']') } @@ -5194,7 +5595,7 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } else { out.RawString(prefix) } - easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo27(out, *in.Memory) + easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo32(out, *in.Memory) } if in.CPU != nil { const prefix string = ",\"cpu\":" @@ -5204,7 +5605,7 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } else { out.RawString(prefix) } - easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo28(out, *in.CPU) + easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo33(out, *in.CPU) } if in.Pids != nil { const prefix string = ",\"pids\":" @@ -5214,7 +5615,7 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } else { out.RawString(prefix) } - easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo29(out, *in.Pids) + easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo34(out, *in.Pids) } if in.BlockIO != nil { const prefix string = ",\"blockIO\":" @@ -5224,7 +5625,7 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } else { out.RawString(prefix) } - easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo30(out, *in.BlockIO) + easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo35(out, *in.BlockIO) } if len(in.HugepageLimits) != 0 { const prefix string = ",\"hugepageLimits\":" @@ -5236,11 +5637,11 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } { out.RawByte('[') - for v143, v144 := range in.HugepageLimits { - if v143 > 0 { + for v147, v148 := range in.HugepageLimits { + if v147 > 0 { out.RawByte(',') } - easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo31(out, v144) + easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo36(out, v148) } out.RawByte(']') } @@ -5253,11 +5654,110 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } else { out.RawString(prefix) } - easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo32(out, *in.Network) + easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo37(out, *in.Network) + } + if len(in.Rdma) != 0 { + const prefix string = ",\"rdma\":" + if first { + first = false + out.RawString(prefix[1:]) + } else { + out.RawString(prefix) + } + { + out.RawByte('{') + v149First := true + for v149Name, v149Value := range in.Rdma { + if v149First { + v149First = false + } else { + out.RawByte(',') + } + out.String(string(v149Name)) + out.RawByte(':') + easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo38(out, v149Value) + } + out.RawByte('}') + } } out.RawByte('}') } -func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo32(in *jlexer.Lexer, out *specs_go.LinuxNetwork) { +func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo38(in *jlexer.Lexer, out *specs_go.LinuxRdma) { + isTopLevel := in.IsStart() + if in.IsNull() { + if isTopLevel { + in.Consumed() + } + in.Skip() + return + } + in.Delim('{') + for !in.IsDelim('}') { + key := in.UnsafeString() + in.WantColon() + if in.IsNull() { + in.Skip() + in.WantComma() + continue + } + switch key { + case "hcaHandles": + if in.IsNull() { + in.Skip() + out.HcaHandles = nil + } else { + if out.HcaHandles == nil { + out.HcaHandles = new(uint32) + } + *out.HcaHandles = uint32(in.Uint32()) + } + case "hcaObjects": + if in.IsNull() { + in.Skip() + out.HcaObjects = nil + } else { + if out.HcaObjects == nil { + out.HcaObjects = new(uint32) + } + *out.HcaObjects = uint32(in.Uint32()) + } + default: + in.SkipRecursive() + } + in.WantComma() + } + in.Delim('}') + if isTopLevel { + in.Consumed() + } +} +func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo38(out *jwriter.Writer, in specs_go.LinuxRdma) { + out.RawByte('{') + first := true + _ = first + if in.HcaHandles != nil { + const prefix string = ",\"hcaHandles\":" + if first { + first = false + out.RawString(prefix[1:]) + } else { + out.RawString(prefix) + } + out.Uint32(uint32(*in.HcaHandles)) + } + if in.HcaObjects != nil { + const prefix string = ",\"hcaObjects\":" + if first { + first = false + out.RawString(prefix[1:]) + } else { + out.RawString(prefix) + } + out.Uint32(uint32(*in.HcaObjects)) + } + out.RawByte('}') +} +func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo37(in *jlexer.Lexer, out *specs_go.LinuxNetwork) { isTopLevel := in.IsStart() if in.IsNull() { if isTopLevel { @@ -5302,9 +5802,9 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer out.Priorities = (out.Priorities)[:0] } for !in.IsDelim(']') { - var v145 specs_go.LinuxInterfacePriority - easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo33(in, &v145) - out.Priorities = append(out.Priorities, v145) + var v150 specs_go.LinuxInterfacePriority + easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo39(in, &v150) + out.Priorities = append(out.Priorities, v150) in.WantComma() } in.Delim(']') @@ -5319,7 +5819,7 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer in.Consumed() } } -func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo32(out *jwriter.Writer, in specs_go.LinuxNetwork) { +func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo37(out *jwriter.Writer, in specs_go.LinuxNetwork) { out.RawByte('{') first := true _ = first @@ -5343,18 +5843,18 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } { out.RawByte('[') - for v146, v147 := range in.Priorities { - if v146 > 0 { + for v151, v152 := range in.Priorities { + if v151 > 0 { out.RawByte(',') } - easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo33(out, v147) + easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo39(out, v152) } out.RawByte(']') } } out.RawByte('}') } -func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo33(in *jlexer.Lexer, out *specs_go.LinuxInterfacePriority) { +func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo39(in *jlexer.Lexer, out *specs_go.LinuxInterfacePriority) { isTopLevel := in.IsStart() if in.IsNull() { if isTopLevel { @@ -5387,7 +5887,7 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer in.Consumed() } } -func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo33(out *jwriter.Writer, in specs_go.LinuxInterfacePriority) { +func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo39(out *jwriter.Writer, in specs_go.LinuxInterfacePriority) { out.RawByte('{') first := true _ = first @@ -5413,7 +5913,7 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } out.RawByte('}') } -func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo31(in *jlexer.Lexer, out *specs_go.LinuxHugepageLimit) { +func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo36(in *jlexer.Lexer, out *specs_go.LinuxHugepageLimit) { isTopLevel := in.IsStart() if in.IsNull() { if isTopLevel { @@ -5446,7 +5946,7 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer in.Consumed() } } -func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo31(out *jwriter.Writer, in specs_go.LinuxHugepageLimit) { +func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo36(out *jwriter.Writer, in specs_go.LinuxHugepageLimit) { out.RawByte('{') first := true _ = first @@ -5472,7 +5972,7 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } out.RawByte('}') } -func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo30(in *jlexer.Lexer, out *specs_go.LinuxBlockIO) { +func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo35(in *jlexer.Lexer, out *specs_go.LinuxBlockIO) { isTopLevel := in.IsStart() if in.IsNull() { if isTopLevel { @@ -5527,9 +6027,9 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer out.WeightDevice = (out.WeightDevice)[:0] } for !in.IsDelim(']') { - var v148 specs_go.LinuxWeightDevice - easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo34(in, &v148) - out.WeightDevice = append(out.WeightDevice, v148) + var v153 specs_go.LinuxWeightDevice + easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo40(in, &v153) + out.WeightDevice = append(out.WeightDevice, v153) in.WantComma() } in.Delim(']') @@ -5550,9 +6050,9 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer out.ThrottleReadBpsDevice = (out.ThrottleReadBpsDevice)[:0] } for !in.IsDelim(']') { - var v149 specs_go.LinuxThrottleDevice - easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo35(in, &v149) - out.ThrottleReadBpsDevice = append(out.ThrottleReadBpsDevice, v149) + var v154 specs_go.LinuxThrottleDevice + easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo41(in, &v154) + out.ThrottleReadBpsDevice = append(out.ThrottleReadBpsDevice, v154) in.WantComma() } in.Delim(']') @@ -5573,9 +6073,9 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer out.ThrottleWriteBpsDevice = (out.ThrottleWriteBpsDevice)[:0] } for !in.IsDelim(']') { - var v150 specs_go.LinuxThrottleDevice - easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo35(in, &v150) - out.ThrottleWriteBpsDevice = append(out.ThrottleWriteBpsDevice, v150) + var v155 specs_go.LinuxThrottleDevice + easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo41(in, &v155) + out.ThrottleWriteBpsDevice = append(out.ThrottleWriteBpsDevice, v155) in.WantComma() } in.Delim(']') @@ -5596,9 +6096,9 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer out.ThrottleReadIOPSDevice = (out.ThrottleReadIOPSDevice)[:0] } for !in.IsDelim(']') { - var v151 specs_go.LinuxThrottleDevice - easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo35(in, &v151) - out.ThrottleReadIOPSDevice = append(out.ThrottleReadIOPSDevice, v151) + var v156 specs_go.LinuxThrottleDevice + easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo41(in, &v156) + out.ThrottleReadIOPSDevice = append(out.ThrottleReadIOPSDevice, v156) in.WantComma() } in.Delim(']') @@ -5619,9 +6119,9 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer out.ThrottleWriteIOPSDevice = (out.ThrottleWriteIOPSDevice)[:0] } for !in.IsDelim(']') { - var v152 specs_go.LinuxThrottleDevice - easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo35(in, &v152) - out.ThrottleWriteIOPSDevice = append(out.ThrottleWriteIOPSDevice, v152) + var v157 specs_go.LinuxThrottleDevice + easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo41(in, &v157) + out.ThrottleWriteIOPSDevice = append(out.ThrottleWriteIOPSDevice, v157) in.WantComma() } in.Delim(']') @@ -5636,7 +6136,7 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer in.Consumed() } } -func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo30(out *jwriter.Writer, in specs_go.LinuxBlockIO) { +func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo35(out *jwriter.Writer, in specs_go.LinuxBlockIO) { out.RawByte('{') first := true _ = first @@ -5670,11 +6170,11 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } { out.RawByte('[') - for v153, v154 := range in.WeightDevice { - if v153 > 0 { + for v158, v159 := range in.WeightDevice { + if v158 > 0 { out.RawByte(',') } - easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo34(out, v154) + easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo40(out, v159) } out.RawByte(']') } @@ -5689,11 +6189,11 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } { out.RawByte('[') - for v155, v156 := range in.ThrottleReadBpsDevice { - if v155 > 0 { + for v160, v161 := range in.ThrottleReadBpsDevice { + if v160 > 0 { out.RawByte(',') } - easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo35(out, v156) + easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo41(out, v161) } out.RawByte(']') } @@ -5708,11 +6208,11 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } { out.RawByte('[') - for v157, v158 := range in.ThrottleWriteBpsDevice { - if v157 > 0 { + for v162, v163 := range in.ThrottleWriteBpsDevice { + if v162 > 0 { out.RawByte(',') } - easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo35(out, v158) + easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo41(out, v163) } out.RawByte(']') } @@ -5727,11 +6227,11 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } { out.RawByte('[') - for v159, v160 := range in.ThrottleReadIOPSDevice { - if v159 > 0 { + for v164, v165 := range in.ThrottleReadIOPSDevice { + if v164 > 0 { out.RawByte(',') } - easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo35(out, v160) + easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo41(out, v165) } out.RawByte(']') } @@ -5746,18 +6246,18 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } { out.RawByte('[') - for v161, v162 := range in.ThrottleWriteIOPSDevice { - if v161 > 0 { + for v166, v167 := range in.ThrottleWriteIOPSDevice { + if v166 > 0 { out.RawByte(',') } - easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo35(out, v162) + easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo41(out, v167) } out.RawByte(']') } } out.RawByte('}') } -func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo35(in *jlexer.Lexer, out *specs_go.LinuxThrottleDevice) { +func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo41(in *jlexer.Lexer, out *specs_go.LinuxThrottleDevice) { isTopLevel := in.IsStart() if in.IsNull() { if isTopLevel { @@ -5792,7 +6292,7 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer in.Consumed() } } -func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo35(out *jwriter.Writer, in specs_go.LinuxThrottleDevice) { +func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo41(out *jwriter.Writer, in specs_go.LinuxThrottleDevice) { out.RawByte('{') first := true _ = first @@ -5828,7 +6328,7 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } out.RawByte('}') } -func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo34(in *jlexer.Lexer, out *specs_go.LinuxWeightDevice) { +func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo40(in *jlexer.Lexer, out *specs_go.LinuxWeightDevice) { isTopLevel := in.IsStart() if in.IsNull() { if isTopLevel { @@ -5881,7 +6381,7 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer in.Consumed() } } -func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo34(out *jwriter.Writer, in specs_go.LinuxWeightDevice) { +func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo40(out *jwriter.Writer, in specs_go.LinuxWeightDevice) { out.RawByte('{') first := true _ = first @@ -5927,7 +6427,7 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } out.RawByte('}') } -func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo29(in *jlexer.Lexer, out *specs_go.LinuxPids) { +func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo34(in *jlexer.Lexer, out *specs_go.LinuxPids) { isTopLevel := in.IsStart() if in.IsNull() { if isTopLevel { @@ -5958,7 +6458,7 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer in.Consumed() } } -func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo29(out *jwriter.Writer, in specs_go.LinuxPids) { +func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo34(out *jwriter.Writer, in specs_go.LinuxPids) { out.RawByte('{') first := true _ = first @@ -5974,7 +6474,7 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } out.RawByte('}') } -func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo28(in *jlexer.Lexer, out *specs_go.LinuxCPU) { +func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo33(in *jlexer.Lexer, out *specs_go.LinuxCPU) { isTopLevel := in.IsStart() if in.IsNull() { if isTopLevel { @@ -6057,7 +6557,7 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer in.Consumed() } } -func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo28(out *jwriter.Writer, in specs_go.LinuxCPU) { +func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo33(out *jwriter.Writer, in specs_go.LinuxCPU) { out.RawByte('{') first := true _ = first @@ -6133,7 +6633,7 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } out.RawByte('}') } -func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo27(in *jlexer.Lexer, out *specs_go.LinuxMemory) { +func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo32(in *jlexer.Lexer, out *specs_go.LinuxMemory) { isTopLevel := in.IsStart() if in.IsNull() { if isTopLevel { @@ -6232,7 +6732,7 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer in.Consumed() } } -func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo27(out *jwriter.Writer, in specs_go.LinuxMemory) { +func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo32(out *jwriter.Writer, in specs_go.LinuxMemory) { out.RawByte('{') first := true _ = first @@ -6308,7 +6808,7 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } out.RawByte('}') } -func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo26(in *jlexer.Lexer, out *specs_go.LinuxDeviceCgroup) { +func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo31(in *jlexer.Lexer, out *specs_go.LinuxDeviceCgroup) { isTopLevel := in.IsStart() if in.IsNull() { if isTopLevel { @@ -6363,7 +6863,7 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer in.Consumed() } } -func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo26(out *jwriter.Writer, in specs_go.LinuxDeviceCgroup) { +func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo31(out *jwriter.Writer, in specs_go.LinuxDeviceCgroup) { out.RawByte('{') first := true _ = first @@ -6419,7 +6919,7 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } out.RawByte('}') } -func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo18(in *jlexer.Lexer, out *specs_go.LinuxIDMapping) { +func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo23(in *jlexer.Lexer, out *specs_go.LinuxIDMapping) { isTopLevel := in.IsStart() if in.IsNull() { if isTopLevel { @@ -6438,10 +6938,10 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer continue } switch key { - case "hostID": - out.HostID = uint32(in.Uint32()) case "containerID": out.ContainerID = uint32(in.Uint32()) + case "hostID": + out.HostID = uint32(in.Uint32()) case "size": out.Size = uint32(in.Uint32()) default: @@ -6454,29 +6954,29 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer in.Consumed() } } -func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo18(out *jwriter.Writer, in specs_go.LinuxIDMapping) { +func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo23(out *jwriter.Writer, in specs_go.LinuxIDMapping) { out.RawByte('{') first := true _ = first { - const prefix string = ",\"hostID\":" + const prefix string = ",\"containerID\":" if first { first = false out.RawString(prefix[1:]) } else { out.RawString(prefix) } - out.Uint32(uint32(in.HostID)) + out.Uint32(uint32(in.ContainerID)) } { - const prefix string = ",\"containerID\":" + const prefix string = ",\"hostID\":" if first { first = false out.RawString(prefix[1:]) } else { out.RawString(prefix) } - out.Uint32(uint32(in.ContainerID)) + out.Uint32(uint32(in.HostID)) } { const prefix string = ",\"size\":" @@ -6525,9 +7025,9 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer out.Prestart = (out.Prestart)[:0] } for !in.IsDelim(']') { - var v163 specs_go.Hook - easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo(in, &v163) - out.Prestart = append(out.Prestart, v163) + var v168 specs_go.Hook + easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo(in, &v168) + out.Prestart = append(out.Prestart, v168) in.WantComma() } in.Delim(']') @@ -6548,9 +7048,9 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer out.Poststart = (out.Poststart)[:0] } for !in.IsDelim(']') { - var v164 specs_go.Hook - easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo(in, &v164) - out.Poststart = append(out.Poststart, v164) + var v169 specs_go.Hook + easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo(in, &v169) + out.Poststart = append(out.Poststart, v169) in.WantComma() } in.Delim(']') @@ -6571,9 +7071,9 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer out.Poststop = (out.Poststop)[:0] } for !in.IsDelim(']') { - var v165 specs_go.Hook - easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo(in, &v165) - out.Poststop = append(out.Poststop, v165) + var v170 specs_go.Hook + easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo(in, &v170) + out.Poststop = append(out.Poststop, v170) in.WantComma() } in.Delim(']') @@ -6602,11 +7102,11 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } { out.RawByte('[') - for v166, v167 := range in.Prestart { - if v166 > 0 { + for v171, v172 := range in.Prestart { + if v171 > 0 { out.RawByte(',') } - easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo(out, v167) + easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo(out, v172) } out.RawByte(']') } @@ -6621,11 +7121,11 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } { out.RawByte('[') - for v168, v169 := range in.Poststart { - if v168 > 0 { + for v173, v174 := range in.Poststart { + if v173 > 0 { out.RawByte(',') } - easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo(out, v169) + easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo(out, v174) } out.RawByte(']') } @@ -6640,11 +7140,11 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } { out.RawByte('[') - for v170, v171 := range in.Poststop { - if v170 > 0 { + for v175, v176 := range in.Poststop { + if v175 > 0 { out.RawByte(',') } - easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo(out, v171) + easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo(out, v176) } out.RawByte(']') } @@ -6692,9 +7192,9 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer out.Options = (out.Options)[:0] } for !in.IsDelim(']') { - var v172 string - v172 = string(in.String()) - out.Options = append(out.Options, v172) + var v177 string + v177 = string(in.String()) + out.Options = append(out.Options, v177) in.WantComma() } in.Delim(']') @@ -6753,11 +7253,11 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } { out.RawByte('[') - for v173, v174 := range in.Options { - if v173 > 0 { + for v178, v179 := range in.Options { + if v178 > 0 { out.RawByte(',') } - out.String(string(v174)) + out.String(string(v179)) } out.RawByte(']') } @@ -6852,10 +7352,10 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer if out.ConsoleSize == nil { out.ConsoleSize = new(specs_go.Box) } - easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo36(in, &*out.ConsoleSize) + easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo42(in, &*out.ConsoleSize) } case "user": - easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo37(in, &out.User) + easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo43(in, &out.User) case "args": if in.IsNull() { in.Skip() @@ -6872,9 +7372,9 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer out.Args = (out.Args)[:0] } for !in.IsDelim(']') { - var v175 string - v175 = string(in.String()) - out.Args = append(out.Args, v175) + var v180 string + v180 = string(in.String()) + out.Args = append(out.Args, v180) in.WantComma() } in.Delim(']') @@ -6895,9 +7395,9 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer out.Env = (out.Env)[:0] } for !in.IsDelim(']') { - var v176 string - v176 = string(in.String()) - out.Env = append(out.Env, v176) + var v181 string + v181 = string(in.String()) + out.Env = append(out.Env, v181) in.WantComma() } in.Delim(']') @@ -6912,7 +7412,7 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer if out.Capabilities == nil { out.Capabilities = new(specs_go.LinuxCapabilities) } - easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo38(in, &*out.Capabilities) + easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo44(in, &*out.Capabilities) } case "rlimits": if in.IsNull() { @@ -6930,9 +7430,9 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer out.Rlimits = (out.Rlimits)[:0] } for !in.IsDelim(']') { - var v177 specs_go.POSIXRlimit - easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo39(in, &v177) - out.Rlimits = append(out.Rlimits, v177) + var v182 specs_go.POSIXRlimit + easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo45(in, &v182) + out.Rlimits = append(out.Rlimits, v182) in.WantComma() } in.Delim(']') @@ -6985,7 +7485,7 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } else { out.RawString(prefix) } - easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo36(out, *in.ConsoleSize) + easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo42(out, *in.ConsoleSize) } { const prefix string = ",\"user\":" @@ -6995,7 +7495,7 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } else { out.RawString(prefix) } - easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo37(out, in.User) + easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo43(out, in.User) } { const prefix string = ",\"args\":" @@ -7009,11 +7509,11 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer out.RawString("null") } else { out.RawByte('[') - for v178, v179 := range in.Args { - if v178 > 0 { + for v183, v184 := range in.Args { + if v183 > 0 { out.RawByte(',') } - out.String(string(v179)) + out.String(string(v184)) } out.RawByte(']') } @@ -7028,11 +7528,11 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } { out.RawByte('[') - for v180, v181 := range in.Env { - if v180 > 0 { + for v185, v186 := range in.Env { + if v185 > 0 { out.RawByte(',') } - out.String(string(v181)) + out.String(string(v186)) } out.RawByte(']') } @@ -7055,7 +7555,7 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } else { out.RawString(prefix) } - easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo38(out, *in.Capabilities) + easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo44(out, *in.Capabilities) } if len(in.Rlimits) != 0 { const prefix string = ",\"rlimits\":" @@ -7067,11 +7567,11 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } { out.RawByte('[') - for v182, v183 := range in.Rlimits { - if v182 > 0 { + for v187, v188 := range in.Rlimits { + if v187 > 0 { out.RawByte(',') } - easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo39(out, v183) + easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo45(out, v188) } out.RawByte(']') } @@ -7118,7 +7618,7 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } out.RawByte('}') } -func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo39(in *jlexer.Lexer, out *specs_go.POSIXRlimit) { +func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo45(in *jlexer.Lexer, out *specs_go.POSIXRlimit) { isTopLevel := in.IsStart() if in.IsNull() { if isTopLevel { @@ -7153,7 +7653,7 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer in.Consumed() } } -func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo39(out *jwriter.Writer, in specs_go.POSIXRlimit) { +func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo45(out *jwriter.Writer, in specs_go.POSIXRlimit) { out.RawByte('{') first := true _ = first @@ -7189,7 +7689,7 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } out.RawByte('}') } -func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo38(in *jlexer.Lexer, out *specs_go.LinuxCapabilities) { +func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo44(in *jlexer.Lexer, out *specs_go.LinuxCapabilities) { isTopLevel := in.IsStart() if in.IsNull() { if isTopLevel { @@ -7224,9 +7724,9 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer out.Bounding = (out.Bounding)[:0] } for !in.IsDelim(']') { - var v184 string - v184 = string(in.String()) - out.Bounding = append(out.Bounding, v184) + var v189 string + v189 = string(in.String()) + out.Bounding = append(out.Bounding, v189) in.WantComma() } in.Delim(']') @@ -7247,9 +7747,9 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer out.Effective = (out.Effective)[:0] } for !in.IsDelim(']') { - var v185 string - v185 = string(in.String()) - out.Effective = append(out.Effective, v185) + var v190 string + v190 = string(in.String()) + out.Effective = append(out.Effective, v190) in.WantComma() } in.Delim(']') @@ -7270,9 +7770,9 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer out.Inheritable = (out.Inheritable)[:0] } for !in.IsDelim(']') { - var v186 string - v186 = string(in.String()) - out.Inheritable = append(out.Inheritable, v186) + var v191 string + v191 = string(in.String()) + out.Inheritable = append(out.Inheritable, v191) in.WantComma() } in.Delim(']') @@ -7293,9 +7793,9 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer out.Permitted = (out.Permitted)[:0] } for !in.IsDelim(']') { - var v187 string - v187 = string(in.String()) - out.Permitted = append(out.Permitted, v187) + var v192 string + v192 = string(in.String()) + out.Permitted = append(out.Permitted, v192) in.WantComma() } in.Delim(']') @@ -7316,9 +7816,9 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer out.Ambient = (out.Ambient)[:0] } for !in.IsDelim(']') { - var v188 string - v188 = string(in.String()) - out.Ambient = append(out.Ambient, v188) + var v193 string + v193 = string(in.String()) + out.Ambient = append(out.Ambient, v193) in.WantComma() } in.Delim(']') @@ -7333,7 +7833,7 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer in.Consumed() } } -func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo38(out *jwriter.Writer, in specs_go.LinuxCapabilities) { +func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo44(out *jwriter.Writer, in specs_go.LinuxCapabilities) { out.RawByte('{') first := true _ = first @@ -7347,11 +7847,11 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } { out.RawByte('[') - for v189, v190 := range in.Bounding { - if v189 > 0 { + for v194, v195 := range in.Bounding { + if v194 > 0 { out.RawByte(',') } - out.String(string(v190)) + out.String(string(v195)) } out.RawByte(']') } @@ -7366,11 +7866,11 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } { out.RawByte('[') - for v191, v192 := range in.Effective { - if v191 > 0 { + for v196, v197 := range in.Effective { + if v196 > 0 { out.RawByte(',') } - out.String(string(v192)) + out.String(string(v197)) } out.RawByte(']') } @@ -7385,11 +7885,11 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } { out.RawByte('[') - for v193, v194 := range in.Inheritable { - if v193 > 0 { + for v198, v199 := range in.Inheritable { + if v198 > 0 { out.RawByte(',') } - out.String(string(v194)) + out.String(string(v199)) } out.RawByte(']') } @@ -7404,11 +7904,11 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } { out.RawByte('[') - for v195, v196 := range in.Permitted { - if v195 > 0 { + for v200, v201 := range in.Permitted { + if v200 > 0 { out.RawByte(',') } - out.String(string(v196)) + out.String(string(v201)) } out.RawByte(']') } @@ -7423,18 +7923,18 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } { out.RawByte('[') - for v197, v198 := range in.Ambient { - if v197 > 0 { + for v202, v203 := range in.Ambient { + if v202 > 0 { out.RawByte(',') } - out.String(string(v198)) + out.String(string(v203)) } out.RawByte(']') } } out.RawByte('}') } -func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo37(in *jlexer.Lexer, out *specs_go.User) { +func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo43(in *jlexer.Lexer, out *specs_go.User) { isTopLevel := in.IsStart() if in.IsNull() { if isTopLevel { @@ -7473,9 +7973,9 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer out.AdditionalGids = (out.AdditionalGids)[:0] } for !in.IsDelim(']') { - var v199 uint32 - v199 = uint32(in.Uint32()) - out.AdditionalGids = append(out.AdditionalGids, v199) + var v204 uint32 + v204 = uint32(in.Uint32()) + out.AdditionalGids = append(out.AdditionalGids, v204) in.WantComma() } in.Delim(']') @@ -7492,7 +7992,7 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer in.Consumed() } } -func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo37(out *jwriter.Writer, in specs_go.User) { +func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo43(out *jwriter.Writer, in specs_go.User) { out.RawByte('{') first := true _ = first @@ -7526,11 +8026,11 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } { out.RawByte('[') - for v200, v201 := range in.AdditionalGids { - if v200 > 0 { + for v205, v206 := range in.AdditionalGids { + if v205 > 0 { out.RawByte(',') } - out.Uint32(uint32(v201)) + out.Uint32(uint32(v206)) } out.RawByte(']') } @@ -7547,7 +8047,7 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainer } out.RawByte('}') } -func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo36(in *jlexer.Lexer, out *specs_go.Box) { +func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo42(in *jlexer.Lexer, out *specs_go.Box) { isTopLevel := in.IsStart() if in.IsNull() { if isTopLevel { @@ -7580,7 +8080,7 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComOpencontainer in.Consumed() } } -func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo36(out *jwriter.Writer, in specs_go.Box) { +func easyjson1dbef17bEncodeGithubComContainersLibpodVendorGithubComOpencontainersRuntimeSpecSpecsGo42(out *jwriter.Writer, in specs_go.Box) { out.RawByte('{') first := true _ = first diff --git a/libpod/container_internal.go b/libpod/container_internal.go index 79bc49c37..c88794212 100644 --- a/libpod/container_internal.go +++ b/libpod/container_internal.go @@ -926,6 +926,9 @@ func (c *Container) makeBindMounts() error { if err != nil { return errors.Wrapf(err, "error creating resolv.conf for container %s", c.ID()) } + if err = label.Relabel(newResolv, c.config.MountLabel, false); err != nil { + return errors.Wrapf(err, "error relabeling %q for container %q", newResolv, c.ID) + } c.state.BindMounts["/etc/resolv.conf"] = newResolv // Make /etc/hosts @@ -937,6 +940,9 @@ func (c *Container) makeBindMounts() error { if err != nil { return errors.Wrapf(err, "error creating hosts file for container %s", c.ID()) } + if err = label.Relabel(newHosts, c.config.MountLabel, false); err != nil { + return errors.Wrapf(err, "error relabeling %q for container %q", newHosts, c.ID) + } c.state.BindMounts["/etc/hosts"] = newHosts // Make /etc/hostname @@ -946,6 +952,9 @@ func (c *Container) makeBindMounts() error { if err != nil { return errors.Wrapf(err, "error creating hostname file for container %s", c.ID()) } + if err = label.Relabel(hostnamePath, c.config.MountLabel, false); err != nil { + return errors.Wrapf(err, "error relabeling %q for container %q", hostnamePath, c.ID) + } c.state.BindMounts["/etc/hostname"] = hostnamePath } @@ -1246,7 +1255,7 @@ func (c *Container) saveSpec(spec *spec.Spec) error { } func (c *Container) setupOCIHooks(ctx context.Context, config *spec.Spec) (extensionStageHooks map[string][]spec.Hook, err error) { - if c.runtime.config.HooksDir == "" { + if len(c.runtime.config.HooksDir) == 0 { return nil, nil } @@ -1277,16 +1286,25 @@ func (c *Container) setupOCIHooks(ctx context.Context, config *spec.Spec) (exten } } - manager, err := hooks.New(ctx, []string{c.runtime.config.HooksDir}, []string{"poststop"}, lang) - if err != nil { - if c.runtime.config.HooksDirNotExistFatal || !os.IsNotExist(err) { + var allHooks map[string][]spec.Hook + for _, hDir := range c.runtime.config.HooksDir { + manager, err := hooks.New(ctx, []string{hDir}, []string{"poststop"}, lang) + if err != nil { + if c.runtime.config.HooksDirNotExistFatal || !os.IsNotExist(err) { + return nil, err + } + logrus.Warnf("failed to load hooks: {}", err) + return nil, nil + } + hooks, err := manager.Hooks(config, c.Spec().Annotations, len(c.config.UserVolumes) > 0) + if err != nil { return nil, err } - logrus.Warnf("failed to load hooks: {}", err) - return nil, nil + for i, hook := range hooks { + allHooks[i] = hook + } } - - return manager.Hooks(config, c.Spec().Annotations, len(c.config.UserVolumes) > 0) + return allHooks, nil } // mount mounts the container's root filesystem diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go index c0912dc0d..b77beaf64 100644 --- a/libpod/container_internal_linux.go +++ b/libpod/container_internal_linux.go @@ -98,6 +98,28 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) { } } + // Check if the spec file mounts contain the label Relabel flags z or Z. + // If they do, relabel the source directory and then remove the option. + for _, m := range g.Mounts() { + var options []string + for _, o := range m.Options { + switch o { + case "z": + fallthrough + case "Z": + if err := label.Relabel(m.Source, c.MountLabel(), label.IsShared(o)); err != nil { + return nil, errors.Wrapf(err, "relabel failed %q", m.Source) + } + + default: + options = append(options, o) + } + } + m.Options = options + } + + g.SetProcessSelinuxLabel(c.ProcessLabel()) + g.SetLinuxMountLabel(c.MountLabel()) // Remove the default /dev/shm mount to ensure we overwrite it g.RemoveMount("/dev/shm") @@ -107,7 +129,10 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) { Type: "bind", Source: srcPath, Destination: dstPath, - Options: []string{"rw", "bind", "private"}, + Options: []string{"bind", "private"}, + } + if c.IsReadOnly() { + newMount.Options = append(newMount.Options, "ro") } if !MountExists(g.Mounts(), dstPath) { g.AddMount(newMount) diff --git a/libpod/diff.go b/libpod/diff.go index e86a186ed..f348e6b81 100644 --- a/libpod/diff.go +++ b/libpod/diff.go @@ -6,6 +6,18 @@ import ( "github.com/pkg/errors" ) +var containerMounts = map[string]bool{ + "/dev": true, + "/etc/hostname": true, + "/etc/hosts": true, + "/etc/resolv.conf": true, + "/proc": true, + "/run": true, + "/run/.containerenv": true, + "/run/secrets": true, + "/sys": true, +} + // GetDiff returns the differences between the two images, layers, or containers func (r *Runtime) GetDiff(from, to string) ([]archive.Change, error) { toLayer, err := r.getLayerID(to) @@ -19,7 +31,17 @@ func (r *Runtime) GetDiff(from, to string) ([]archive.Change, error) { return nil, err } } - return r.store.Changes(fromLayer, toLayer) + var rchanges []archive.Change + changes, err := r.store.Changes(fromLayer, toLayer) + if err == nil { + for _, c := range changes { + if containerMounts[c.Path] { + continue + } + rchanges = append(rchanges, c) + } + } + return rchanges, err } // GetLayerID gets a full layer id given a full or partial id diff --git a/libpod/image/pull.go b/libpod/image/pull.go index ce3e8e73e..9eac2b988 100644 --- a/libpod/image/pull.go +++ b/libpod/image/pull.go @@ -20,6 +20,7 @@ import ( "github.com/containers/image/types" "github.com/containers/libpod/pkg/registries" "github.com/containers/libpod/pkg/util" + multierror "github.com/hashicorp/go-multierror" "github.com/pkg/errors" "github.com/sirupsen/logrus" ) @@ -234,6 +235,7 @@ func (ir *Runtime) doPullImage(ctx context.Context, sc *types.SystemContext, goa return nil, err } var images []string + var pullErrors *multierror.Error for _, imageInfo := range goal.refPairs { copyOptions := getCopyOptions(sc, writer, dockerOptions, nil, signingOptions, "", nil) if imageInfo.srcRef.Transport().Name() == DockerTransport { @@ -254,6 +256,7 @@ func (ir *Runtime) doPullImage(ctx context.Context, sc *types.SystemContext, goa io.WriteString(writer, fmt.Sprintf("Trying to pull %s...", imageInfo.image)) } if err = cp.Image(ctx, policyContext, imageInfo.dstRef, imageInfo.srcRef, copyOptions); err != nil { + pullErrors = multierror.Append(pullErrors, err) logrus.Debugf("Error pulling image ref %s: %v", imageInfo.srcRef.StringWithinTransport(), err) if writer != nil { io.WriteString(writer, "Failed\n") @@ -273,10 +276,12 @@ func (ir *Runtime) doPullImage(ctx context.Context, sc *types.SystemContext, goa } // If the image passed in was fully-qualified, we will have 1 refpair. Bc the image is fq'd, we dont need to yap about registries. if !goal.usedSearchRegistries { + if pullErrors != nil && len(pullErrors.Errors) > 0 { // this should always be true + return nil, errors.Wrap(pullErrors.Errors[0], "unable to pull image") + } return nil, errors.Errorf("unable to pull image, or you do not have pull access") } - return nil, errors.Errorf("unable to find image on registries defined in %s, or you do not have pull access", registryPath) - + return nil, pullErrors } return images, nil } diff --git a/libpod/oci.go b/libpod/oci.go index e1c0d1261..3838394cb 100644 --- a/libpod/oci.go +++ b/libpod/oci.go @@ -66,6 +66,7 @@ type OCIRuntime struct { socketsDir string logSizeMax int64 noPivot bool + reservePorts bool } // syncInfo is used to return data from monitor process to daemon @@ -75,7 +76,7 @@ type syncInfo struct { } // Make a new OCI runtime with provided options -func newOCIRuntime(name string, path string, conmonPath string, conmonEnv []string, cgroupManager string, tmpDir string, logSizeMax int64, noPivotRoot bool) (*OCIRuntime, error) { +func newOCIRuntime(name string, path string, conmonPath string, conmonEnv []string, cgroupManager string, tmpDir string, logSizeMax int64, noPivotRoot bool, reservePorts bool) (*OCIRuntime, error) { runtime := new(OCIRuntime) runtime.name = name runtime.path = path @@ -85,6 +86,7 @@ func newOCIRuntime(name string, path string, conmonPath string, conmonEnv []stri runtime.tmpDir = tmpDir runtime.logSizeMax = logSizeMax runtime.noPivot = noPivotRoot + runtime.reservePorts = reservePorts runtime.exitsDir = filepath.Join(runtime.tmpDir, "exits") runtime.socketsDir = filepath.Join(runtime.tmpDir, "socket") @@ -311,15 +313,17 @@ func (r *OCIRuntime) createOCIContainer(ctr *Container, cgroupParent string) (er cmd.Env = append(cmd.Env, fmt.Sprintf("_OCI_STARTPIPE=%d", 4)) cmd.Env = append(cmd.Env, fmt.Sprintf("XDG_RUNTIME_DIR=%s", runtimeDir)) - ports, err := bindPorts(ctr.config.PortMappings) - if err != nil { - return err - } + if r.reservePorts { + ports, err := bindPorts(ctr.config.PortMappings) + if err != nil { + return err + } - // Leak the port we bound in the conmon process. These fd's won't be used - // by the container and conmon will keep the ports busy so that another - // process cannot use them. - cmd.ExtraFiles = append(cmd.ExtraFiles, ports...) + // Leak the port we bound in the conmon process. These fd's won't be used + // by the container and conmon will keep the ports busy so that another + // process cannot use them. + cmd.ExtraFiles = append(cmd.ExtraFiles, ports...) + } if rootless.IsRootless() { ctr.rootlessSlirpSyncR, ctr.rootlessSlirpSyncW, err = os.Pipe() diff --git a/libpod/options.go b/libpod/options.go index e6751d68d..977f3f4c2 100644 --- a/libpod/options.go +++ b/libpod/options.go @@ -181,7 +181,7 @@ func WithStaticDir(dir string) RuntimeOption { // WithHooksDir sets the directory to look for OCI runtime hooks config. // Note we are not saving this in database, since this is really just for used // for testing. -func WithHooksDir(hooksDir string, dirNotExistFatal bool) RuntimeOption { +func WithHooksDir(hooksDir string) RuntimeOption { return func(rt *Runtime) error { if rt.valid { return ErrRuntimeFinalized @@ -191,8 +191,8 @@ func WithHooksDir(hooksDir string, dirNotExistFatal bool) RuntimeOption { return errors.Wrap(ErrInvalidArg, "empty-string hook directories are not supported") } - rt.config.HooksDir = hooksDir - rt.config.HooksDirNotExistFatal = dirNotExistFatal + rt.config.HooksDir = []string{hooksDir} + rt.config.HooksDirNotExistFatal = true return nil } } @@ -373,15 +373,17 @@ func WithPrivileged(privileged bool) CtrCreateOption { } } -// WithSELinuxLabels sets the mount label for SELinux. -func WithSELinuxLabels(processLabel, mountLabel string) CtrCreateOption { +// WithSecLabels sets the labels for SELinux. +func WithSecLabels(labelOpts []string) CtrCreateOption { return func(ctr *Container) error { if ctr.valid { return ErrCtrFinalized } - - ctr.config.ProcessLabel = processLabel - ctr.config.MountLabel = mountLabel + var err error + ctr.config.ProcessLabel, ctr.config.MountLabel, err = ctr.runtime.initLabels(labelOpts) + if err != nil { + return errors.Wrapf(err, "failed to init labels") + } return nil } } diff --git a/libpod/runtime.go b/libpod/runtime.go index 63b8c971e..fbd4c7529 100644 --- a/libpod/runtime.go +++ b/libpod/runtime.go @@ -143,7 +143,7 @@ type RuntimeConfig struct { // to attach pods to CNIDefaultNetwork string `toml:"cni_default_network,omitempty"` // HooksDir Path to the directory containing hooks configuration files - HooksDir string `toml:"hooks_dir"` + HooksDir []string `toml:"hooks_dir"` // HooksDirNotExistFatal switches between fatal errors and non-fatal // warnings if the configured HooksDir does not exist. HooksDirNotExistFatal bool `toml:"hooks_dir_not_exist_fatal"` @@ -164,6 +164,16 @@ type RuntimeConfig struct { InfraImage string `toml:"infra_image"` // InfraCommand is the command run to start up a pod infra container InfraCommand string `toml:"infra_command"` + // EnablePortReservation determines whether libpod will reserve ports on + // the host when they are forwarded to containers. + // When enabled, when ports are forwarded to containers, they are + // held open by conmon as long as the container is running, ensuring + // that they cannot be reused by other programs on the host. + // However, this can cause significant memory usage if a container has + // many ports forwarded to it. Disabling this can save memory. + EnablePortReservation bool `toml:"enable_port_reservation"` + // EnableLabeling indicates wether libpod will support container labeling + EnableLabeling bool `toml:"label"` } var ( @@ -190,16 +200,18 @@ var ( ConmonEnvVars: []string{ "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", }, - CgroupManager: SystemdCgroupsManager, - HooksDir: hooks.DefaultDir, - StaticDir: filepath.Join(storage.DefaultStoreOptions.GraphRoot, "libpod"), - TmpDir: "", - MaxLogSize: -1, - NoPivotRoot: false, - CNIConfigDir: "/etc/cni/net.d/", - CNIPluginDir: []string{"/usr/libexec/cni", "/usr/lib/cni", "/opt/cni/bin"}, - InfraCommand: DefaultInfraCommand, - InfraImage: DefaultInfraImage, + CgroupManager: SystemdCgroupsManager, + HooksDir: []string{hooks.DefaultDir, hooks.OverrideDir}, + StaticDir: filepath.Join(storage.DefaultStoreOptions.GraphRoot, "libpod"), + TmpDir: "", + MaxLogSize: -1, + NoPivotRoot: false, + CNIConfigDir: "/etc/cni/net.d/", + CNIPluginDir: []string{"/usr/libexec/cni", "/usr/lib/cni", "/opt/cni/bin"}, + InfraCommand: DefaultInfraCommand, + InfraImage: DefaultInfraImage, + EnablePortReservation: true, + EnableLabeling: true, } ) @@ -467,7 +479,8 @@ func makeRuntime(runtime *Runtime) (err error) { ociRuntime, err := newOCIRuntime("runc", runtime.ociRuntimePath, runtime.conmonPath, runtime.config.ConmonEnvVars, runtime.config.CgroupManager, runtime.config.TmpDir, - runtime.config.MaxLogSize, runtime.config.NoPivotRoot) + runtime.config.MaxLogSize, runtime.config.NoPivotRoot, + runtime.config.EnablePortReservation) if err != nil { return err } diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go index a0b576bcd..6c487e367 100644 --- a/libpod/runtime_ctr.go +++ b/libpod/runtime_ctr.go @@ -11,6 +11,7 @@ import ( "github.com/containers/storage" "github.com/containers/storage/pkg/stringid" spec "github.com/opencontainers/runtime-spec/specs-go" + "github.com/opencontainers/selinux/go-selinux/label" "github.com/pkg/errors" "github.com/sirupsen/logrus" "github.com/ulule/deepcopier" @@ -77,6 +78,7 @@ func (r *Runtime) newContainer(ctx context.Context, rSpec *spec.Spec, options .. ctr.config.Namespace = r.config.Namespace } + ctr.runtime = r for _, option := range options { if err := option(ctr); err != nil { return nil, errors.Wrapf(err, "error running container create option") @@ -85,7 +87,6 @@ func (r *Runtime) newContainer(ctx context.Context, rSpec *spec.Spec, options .. ctr.valid = true ctr.state.State = ContainerStateConfigured - ctr.runtime = r var pod *Pod if ctr.config.Pod != "" { @@ -327,6 +328,10 @@ func (r *Runtime) removeContainer(ctx context.Context, c *Container, force bool) } } + if r.config.EnableLabeling { + label.ReleaseLabel(c.ProcessLabel()) + r.reserveLabels() + } // Delete the container // Only do this if we're not ContainerStateConfigured - if we are, // we haven't been created in the runtime yet @@ -460,3 +465,28 @@ func (r *Runtime) GetLatestContainer() (*Container, error) { } return ctrs[lastCreatedIndex], nil } + +// reserveLabels walks the list o fcontainers and reserves the label, so new containers will not +// get them. +// TODO Performance wise this should only run if the state has changed since the last time it was run. +func (r *Runtime) reserveLabels() error { + containers, err := r.state.AllContainers() + if err != nil { + return err + } + for _, ctr := range containers { + label.ReserveLabel(ctr.ProcessLabel()) + } + return nil +} + +// initLabels allocates an new label to return to the caller +func (r *Runtime) initLabels(labelOpts []string) (string, string, error) { + if !r.config.EnableLabeling { + return "", "", nil + } + if err := r.reserveLabels(); err != nil { + return "", "", errors.Wrapf(err, "unable to reserve labels") + } + return label.InitLabels(labelOpts) +} diff --git a/libpod/runtime_img.go b/libpod/runtime_img.go index 2e4e1b26f..a21ea7673 100644 --- a/libpod/runtime_img.go +++ b/libpod/runtime_img.go @@ -5,13 +5,13 @@ import ( "fmt" "io" + "github.com/containers/buildah/imagebuildah" "github.com/containers/libpod/libpod/common" "github.com/containers/libpod/libpod/image" "github.com/containers/storage" "github.com/containers/storage/pkg/archive" ociv1 "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" - "github.com/projectatomic/buildah/imagebuildah" ) // Runtime API diff --git a/pkg/namespaces/namespaces.go b/pkg/namespaces/namespaces.go index 1bdb2b00d..bee833fa9 100644 --- a/pkg/namespaces/namespaces.go +++ b/pkg/namespaces/namespaces.go @@ -28,6 +28,16 @@ func (n UsernsMode) Valid() bool { return true } +// IsContainer indicates whether container uses a container userns. +func (n UsernsMode) IsContainer() bool { + return false +} + +// Container is the id of the container which network this container is connected to. +func (n UsernsMode) Container() string { + return "" +} + // UTSMode represents the UTS namespace of the container. type UTSMode string @@ -191,8 +201,8 @@ func (n NetworkMode) IsContainer() bool { return len(parts) > 1 && parts[0] == "container" } -// ConnectedContainer is the id of the container which network this container is connected to. -func (n NetworkMode) ConnectedContainer() string { +// Container is the id of the container which network this container is connected to. +func (n NetworkMode) Container() string { parts := strings.SplitN(string(n), ":", 2) if len(parts) > 1 { return parts[1] diff --git a/pkg/rootless/rootless_linux.go b/pkg/rootless/rootless_linux.go index 92020cf1c..5c45f2694 100644 --- a/pkg/rootless/rootless_linux.go +++ b/pkg/rootless/rootless_linux.go @@ -9,15 +9,16 @@ import ( "os/exec" gosignal "os/signal" "os/user" - "path/filepath" "runtime" "strconv" + "strings" "syscall" "unsafe" "github.com/containers/storage/pkg/idtools" "github.com/docker/docker/pkg/signal" "github.com/pkg/errors" + "github.com/sirupsen/logrus" ) /* @@ -111,6 +112,48 @@ func JoinNS(pid uint) (bool, int, error) { return true, int(ret), nil } +// JoinNSPath re-exec podman in a new userNS and join the owner user namespace of the +// specified path. +func JoinNSPath(path string) (bool, int, error) { + if os.Geteuid() == 0 || os.Getenv("_LIBPOD_USERNS_CONFIGURED") != "" { + return false, -1, nil + } + + userNS, err := getUserNSForPath(path) + if err != nil { + return false, -1, err + } + defer userNS.Close() + + pidC := C.reexec_userns_join(C.int(userNS.Fd())) + if int(pidC) < 0 { + return false, -1, errors.Errorf("cannot re-exec process") + } + + ret := C.reexec_in_user_namespace_wait(pidC) + if ret < 0 { + return false, -1, errors.New("error waiting for the re-exec process") + } + + return true, int(ret), nil +} + +const defaultMinimumMappings = 65536 + +func getMinimumIDs(p string) int { + content, err := ioutil.ReadFile(p) + if err != nil { + logrus.Debugf("error reading data from %q, use a default value of %d", p, defaultMinimumMappings) + return defaultMinimumMappings + } + ret, err := strconv.Atoi(strings.TrimSuffix(string(content), "\n")) + if err != nil { + logrus.Debugf("error reading data from %q, use a default value of %d", p, defaultMinimumMappings) + return defaultMinimumMappings + } + return ret + 1 +} + // BecomeRootInUserNS re-exec podman in a new userNS. It returns whether podman was re-executed // into a new user namespace and the return code from the re-executed podman process. // If podman was re-executed the caller needs to propagate the error code returned by the child @@ -151,8 +194,28 @@ func BecomeRootInUserNS() (bool, int, error) { } } mappings, err := idtools.NewIDMappings(username, username) - if err != nil && os.Getenv("PODMAN_ALLOW_SINGLE_ID_MAPPING_IN_USERNS") == "" { - return false, -1, err + if os.Getenv("PODMAN_ALLOW_SINGLE_ID_MAPPING_IN_USERNS") == "" { + if err != nil { + return false, -1, err + } + + availableGIDs, availableUIDs := 0, 0 + for _, i := range mappings.UIDs() { + availableUIDs += i.Size + } + + minUIDs := getMinimumIDs("/proc/sys/kernel/overflowuid") + if availableUIDs < minUIDs { + return false, 0, fmt.Errorf("not enough UIDs available for the user, at least %d are needed", minUIDs) + } + + for _, i := range mappings.GIDs() { + availableGIDs += i.Size + } + minGIDs := getMinimumIDs("/proc/sys/kernel/overflowgid") + if availableGIDs < minGIDs { + return false, 0, fmt.Errorf("not enough GIDs available for the user, at least %d are needed", minGIDs) + } } if err == nil { uids = mappings.UIDs() @@ -226,7 +289,16 @@ func readUserNs(path string) (string, error) { } func readUserNsFd(fd uintptr) (string, error) { - return readUserNs(filepath.Join("/proc/self/fd", fmt.Sprintf("%d", fd))) + return readUserNs(fmt.Sprintf("/proc/self/fd/%d", fd)) +} + +func getOwner(fd uintptr) (uintptr, error) { + const nsGetUserns = 0xb701 + ret, _, errno := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(nsGetUserns), 0) + if errno != 0 { + return 0, errno + } + return (uintptr)(unsafe.Pointer(ret)), nil } func getParentUserNs(fd uintptr) (uintptr, error) { @@ -238,7 +310,31 @@ func getParentUserNs(fd uintptr) (uintptr, error) { return (uintptr)(unsafe.Pointer(ret)), nil } -// getUserNSForPid returns an open FD for the first direct child user namespace that created the process +func getUserNSForPath(path string) (*os.File, error) { + u, err := os.Open(path) + if err != nil { + return nil, errors.Wrapf(err, "cannot open %s", path) + } + defer u.Close() + fd, err := getOwner(u.Fd()) + if err != nil { + return nil, err + } + + return getUserNSFirstChild(fd) +} + +func getUserNSForPid(pid uint) (*os.File, error) { + path := fmt.Sprintf("/proc/%d/ns/user", pid) + u, err := os.Open(path) + if err != nil { + return nil, errors.Wrapf(err, "cannot open %s", path) + } + + return getUserNSFirstChild(u.Fd()) +} + +// getUserNSFirstChild returns an open FD for the first direct child user namespace that created the process // Each container creates a new user namespace where the runtime runs. The current process in the container // might have created new user namespaces that are child of the initial namespace we created. // This function finds the initial namespace created for the container that is a child of the current namespace. @@ -250,19 +346,12 @@ func getParentUserNs(fd uintptr) (uintptr, error) { // b // / // NS READ USING THE PID -> c -func getUserNSForPid(pid uint) (*os.File, error) { +func getUserNSFirstChild(fd uintptr) (*os.File, error) { currentNS, err := readUserNs("/proc/self/ns/user") if err != nil { return nil, err } - path := filepath.Join("/proc", fmt.Sprintf("%d", pid), "ns/user") - u, err := os.Open(path) - if err != nil { - return nil, errors.Wrapf(err, "cannot open %s", path) - } - - fd := u.Fd() ns, err := readUserNsFd(fd) if err != nil { return nil, errors.Wrapf(err, "cannot read user namespace") diff --git a/pkg/rootless/rootless_unsupported.go b/pkg/rootless/rootless_unsupported.go index 31728e5c2..d72402c9f 100644 --- a/pkg/rootless/rootless_unsupported.go +++ b/pkg/rootless/rootless_unsupported.go @@ -36,3 +36,9 @@ func SkipStorageSetup() bool { func JoinNS(pid uint) (bool, int, error) { return false, -1, errors.New("this function is not supported on this os") } + +// JoinNSPath re-exec podman in a new userNS and join the owner user namespace of the +// specified path. +func JoinNSPath(path string) (bool, int, error) { + return false, -1, errors.New("this function is not supported on this os") +} diff --git a/pkg/spec/config_linux.go b/pkg/spec/config_linux.go index ea04b95bd..6c0a99419 100644 --- a/pkg/spec/config_linux.go +++ b/pkg/spec/config_linux.go @@ -60,6 +60,9 @@ func (c *CreateConfig) addPrivilegedDevices(g *generate.Generator) error { for _, d := range hostDevices { g.AddDevice(Device(d)) } + + // Add resources device - need to clear the existing one first. + g.Spec().Linux.Resources.Devices = nil g.AddLinuxResourcesDevice(true, "", nil, nil, "rwm") return nil } diff --git a/pkg/spec/createconfig.go b/pkg/spec/createconfig.go index a441b4019..887ef8e95 100644 --- a/pkg/spec/createconfig.go +++ b/pkg/spec/createconfig.go @@ -15,7 +15,6 @@ import ( "github.com/docker/go-connections/nat" spec "github.com/opencontainers/runtime-spec/specs-go" "github.com/opencontainers/runtime-tools/generate" - "github.com/opencontainers/selinux/go-selinux/label" "github.com/pkg/errors" "github.com/sirupsen/logrus" "golang.org/x/sys/unix" @@ -113,8 +112,7 @@ type CreateConfig struct { Quiet bool //quiet ReadOnlyRootfs bool //read-only Resources CreateResourceConfig - Rm bool //rm - ShmDir string + Rm bool //rm StopSignal syscall.Signal // stop-signal StopTimeout uint // stop-timeout Sysctl map[string]string //sysctl @@ -124,14 +122,14 @@ type CreateConfig struct { UsernsMode namespaces.UsernsMode //userns User string //user UtsMode namespaces.UTSMode //uts + Mounts []spec.Mount //mounts Volumes []string //volume VolumesFrom []string - WorkDir string //workdir - MountLabel string //SecurityOpts - ProcessLabel string //SecurityOpts - NoNewPrivs bool //SecurityOpts - ApparmorProfile string //SecurityOpts - SeccompProfilePath string //SecurityOpts + WorkDir string //workdir + LabelOpts []string //SecurityOpts + NoNewPrivs bool //SecurityOpts + ApparmorProfile string //SecurityOpts + SeccompProfilePath string //SecurityOpts SecurityOpts []string Rootfs string LocalVolumes []string //Keeps track of the built-in volumes of container used in the --volumes-from flag @@ -145,58 +143,59 @@ func (c *CreateConfig) CreateBlockIO() (*spec.LinuxBlockIO, error) { return c.createBlockIO() } +func processOptions(options []string) []string { + var ( + foundrw, foundro bool + rootProp string + ) + options = append(options, "rbind") + for _, opt := range options { + switch opt { + case "rw": + foundrw = true + case "ro": + foundro = true + case "private", "rprivate", "slave", "rslave", "shared", "rshared": + rootProp = opt + } + } + if !foundrw && !foundro { + options = append(options, "rw") + } + if rootProp == "" { + options = append(options, "rprivate") + } + return options +} + +func (c *CreateConfig) initFSMounts() []spec.Mount { + var mounts []spec.Mount + for _, m := range c.Mounts { + m.Options = processOptions(m.Options) + if m.Type == "tmpfs" { + m.Options = append(m.Options, "tmpcopyup") + } else { + mounts = append(mounts, m) + } + } + return mounts +} + //GetVolumeMounts takes user provided input for bind mounts and creates Mount structs func (c *CreateConfig) GetVolumeMounts(specMounts []spec.Mount) ([]spec.Mount, error) { var m []spec.Mount for _, i := range c.Volumes { - var ( - options []string - foundrw, foundro, foundz, foundZ bool - rootProp string - ) - - // We need to handle SELinux options better here, specifically :Z + var options []string spliti := strings.Split(i, ":") if len(spliti) > 2 { options = strings.Split(spliti[2], ",") } - options = append(options, "rbind") - for _, opt := range options { - switch opt { - case "rw": - foundrw = true - case "ro": - foundro = true - case "z": - foundz = true - case "Z": - foundZ = true - case "private", "rprivate", "slave", "rslave", "shared", "rshared": - rootProp = opt - } - } - if !foundrw && !foundro { - options = append(options, "rw") - } - if foundz { - if err := label.Relabel(spliti[0], c.MountLabel, true); err != nil { - return nil, errors.Wrapf(err, "relabel failed %q", spliti[0]) - } - } - if foundZ { - if err := label.Relabel(spliti[0], c.MountLabel, false); err != nil { - return nil, errors.Wrapf(err, "relabel failed %q", spliti[0]) - } - } - if rootProp == "" { - options = append(options, "rprivate") - } m = append(m, spec.Mount{ Destination: spliti[1], Type: string(TypeBind), Source: spliti[0], - Options: options, + Options: processOptions(options), }) logrus.Debugf("User mount %s:%s options %v", spliti[0], spliti[1], options) @@ -380,9 +379,9 @@ func (c *CreateConfig) GetContainerCreateOptions(runtime *libpod.Runtime) ([]lib if IsNS(string(c.NetMode)) { // pass } else if c.NetMode.IsContainer() { - connectedCtr, err := c.Runtime.LookupContainer(c.NetMode.ConnectedContainer()) + connectedCtr, err := c.Runtime.LookupContainer(c.NetMode.Container()) if err != nil { - return nil, errors.Wrapf(err, "container %q not found", c.NetMode.ConnectedContainer()) + return nil, errors.Wrapf(err, "container %q not found", c.NetMode.Container()) } options = append(options, libpod.WithNetNSFrom(connectedCtr)) } else if !c.NetMode.IsHost() && !c.NetMode.IsNone() { @@ -449,11 +448,20 @@ func (c *CreateConfig) GetContainerCreateOptions(runtime *libpod.Runtime) ([]lib useImageVolumes := c.ImageVolumeType == "bind" // Gather up the options for NewContainer which consist of With... funcs options = append(options, libpod.WithRootFSFromImage(c.ImageID, c.Image, useImageVolumes)) - options = append(options, libpod.WithSELinuxLabels(c.ProcessLabel, c.MountLabel)) + options = append(options, libpod.WithSecLabels(c.LabelOpts)) options = append(options, libpod.WithConmonPidFile(c.ConmonPidFile)) options = append(options, libpod.WithLabels(c.Labels)) options = append(options, libpod.WithUser(c.User)) - options = append(options, libpod.WithShmDir(c.ShmDir)) + if c.IpcMode.IsHost() { + options = append(options, libpod.WithShmDir("/dev/shm")) + + } else if c.IpcMode.IsContainer() { + ctr, err := runtime.LookupContainer(c.IpcMode.Container()) + if err != nil { + return nil, errors.Wrapf(err, "container %q not found", c.IpcMode.Container()) + } + options = append(options, libpod.WithShmDir(ctr.ShmDir())) + } options = append(options, libpod.WithShmSize(c.Resources.ShmSize)) options = append(options, libpod.WithGroups(c.GroupAdd)) options = append(options, libpod.WithIDMappings(*c.IDMappings)) diff --git a/pkg/spec/spec.go b/pkg/spec/spec.go index cc3501e1e..ad14ea65d 100644 --- a/pkg/spec/spec.go +++ b/pkg/spec/spec.go @@ -18,6 +18,34 @@ import ( const cpuPeriod = 100000 +func supercedeUserMounts(mounts []spec.Mount, configMount []spec.Mount) []spec.Mount { + if len(mounts) > 0 { + // If we have overlappings mounts, remove them from the spec in favor of + // the user-added volume mounts + destinations := make(map[string]bool) + for _, mount := range mounts { + destinations[path.Clean(mount.Destination)] = true + } + // Copy all mounts from spec to defaultMounts, except for + // - mounts overridden by a user supplied mount; + // - all mounts under /dev if a user supplied /dev is present; + mountDev := destinations["/dev"] + for _, mount := range configMount { + if _, ok := destinations[path.Clean(mount.Destination)]; !ok { + if mountDev && strings.HasPrefix(mount.Destination, "/dev/") { + // filter out everything under /dev if /dev is user-mounted + continue + } + + logrus.Debugf("Adding mount %s", mount.Destination) + mounts = append(mounts, mount) + } + } + return mounts + } + return configMount +} + // CreateConfigToOCISpec parses information needed to create a container into an OCI runtime spec func CreateConfigToOCISpec(config *CreateConfig) (*spec.Spec, error) { //nolint cgroupPerm := "ro" @@ -211,8 +239,6 @@ func CreateConfigToOCISpec(config *CreateConfig) (*spec.Spec, error) { //nolint // SECURITY OPTS g.SetProcessNoNewPrivileges(config.NoNewPrivs) g.SetProcessApparmorProfile(config.ApparmorProfile) - g.SetProcessSelinuxLabel(config.ProcessLabel) - g.SetLinuxMountLabel(config.MountLabel) if canAddResources { blockAccessToKernelFilesystems(config, &g) @@ -248,6 +274,12 @@ func CreateConfigToOCISpec(config *CreateConfig) (*spec.Spec, error) { //nolint g.AddMount(tmpfsMnt) } + for _, m := range config.Mounts { + if m.Type == "tmpfs" { + g.AddMount(m) + } + } + for name, val := range config.Env { g.AddProcessEnv(name, val) } @@ -307,29 +339,14 @@ func CreateConfigToOCISpec(config *CreateConfig) (*spec.Spec, error) { //nolint return nil, errors.Wrap(err, "error getting volume mounts from --volumes-from flag") } - mounts, err := config.GetVolumeMounts(configSpec.Mounts) + volumeMounts, err := config.GetVolumeMounts(configSpec.Mounts) if err != nil { return nil, errors.Wrapf(err, "error getting volume mounts") } - if len(mounts) > 0 { - // If we have overlappings mounts, remove them from the spec in favor of - // the user-added volume mounts - destinations := make(map[string]bool) - for _, mount := range mounts { - destinations[path.Clean(mount.Destination)] = true - } - for _, mount := range configSpec.Mounts { - if _, ok := destinations[path.Clean(mount.Destination)]; !ok { - logrus.Debugf("Adding mount %s", mount.Destination) - mounts = append(mounts, mount) - } - } - configSpec.Mounts = mounts - } - if err := g.SetLinuxRootPropagation("shared"); err != nil { - return nil, errors.Wrapf(err, "failed to set propagation to rslave") - } + configSpec.Mounts = supercedeUserMounts(volumeMounts, configSpec.Mounts) + //--mount + configSpec.Mounts = supercedeUserMounts(config.initFSMounts(), configSpec.Mounts) if canAddResources { // BLOCK IO blkio, err := config.CreateBlockIO() diff --git a/pkg/varlinkapi/containers_create.go b/pkg/varlinkapi/containers_create.go index 843d7a5ba..ca1a57048 100644 --- a/pkg/varlinkapi/containers_create.go +++ b/pkg/varlinkapi/containers_create.go @@ -202,7 +202,6 @@ func varlinkCreateToCreateConfig(ctx context.Context, create iopodman.Create, ru Ulimit: create.Resources.Ulimit, }, Rm: create.Rm, - ShmDir: create.Shm_dir, StopSignal: stopSignal, StopTimeout: uint(create.Stop_timeout), Sysctl: create.Sys_ctl, diff --git a/pkg/varlinkapi/images.go b/pkg/varlinkapi/images.go index 3cd2b879a..d14c61c39 100644 --- a/pkg/varlinkapi/images.go +++ b/pkg/varlinkapi/images.go @@ -9,6 +9,8 @@ import ( "strings" "time" + "github.com/containers/buildah" + "github.com/containers/buildah/imagebuildah" "github.com/containers/image/docker" "github.com/containers/image/manifest" "github.com/containers/image/types" @@ -21,8 +23,6 @@ import ( "github.com/opencontainers/image-spec/specs-go/v1" "github.com/opencontainers/runtime-spec/specs-go" "github.com/pkg/errors" - "github.com/projectatomic/buildah" - "github.com/projectatomic/buildah/imagebuildah" ) // ListImages lists all the images in the store diff --git a/pkg/varlinkapi/system.go b/pkg/varlinkapi/system.go index a90b72a6d..54bce3d35 100644 --- a/pkg/varlinkapi/system.go +++ b/pkg/varlinkapi/system.go @@ -34,6 +34,9 @@ func (i *LibpodAPI) Ping(call iopodman.VarlinkCall) error { // GetInfo returns details about the podman host and its stores func (i *LibpodAPI) GetInfo(call iopodman.VarlinkCall) error { + var ( + registries, insecureRegistries []string + ) podmanInfo := iopodman.PodmanInfo{} info, err := i.Runtime.Info() if err != nil { @@ -76,7 +79,19 @@ func (i *LibpodAPI) GetInfo(call iopodman.VarlinkCall) error { Graph_status: graphStatus, } + registriesInterface := info[2].Data["registries"] + insecureRegistriesInterface := info[3].Data["registries"] + if registriesInterface != nil { + registries = registriesInterface.([]string) + } + if insecureRegistriesInterface != nil { + insecureRegistries = insecureRegistriesInterface.([]string) + } + podmanInfo.Store = infoStore podmanInfo.Podman = pmaninfo + podmanInfo.Registries = registries + podmanInfo.Insecure_registries = insecureRegistries + return call.ReplyGetInfo(podmanInfo) } diff --git a/test/e2e/libpod_suite_test.go b/test/e2e/libpod_suite_test.go index 88ec6bc19..a1e9ba57a 100644 --- a/test/e2e/libpod_suite_test.go +++ b/test/e2e/libpod_suite_test.go @@ -132,7 +132,7 @@ func PodmanCreate(tempDir string) PodmanTest { podmanBinary = os.Getenv("PODMAN_BINARY") } conmonBinary := filepath.Join("/usr/libexec/podman/conmon") - altConmonBinary := "/usr/libexec/podman/conmon" + altConmonBinary := "/usr/libexec/crio/conmon" if _, err := os.Stat(altConmonBinary); err == nil { conmonBinary = altConmonBinary } diff --git a/test/e2e/rootless_test.go b/test/e2e/rootless_test.go index 72ca37d6e..bd782a5fc 100644 --- a/test/e2e/rootless_test.go +++ b/test/e2e/rootless_test.go @@ -39,6 +39,7 @@ var _ = Describe("Podman rootless", func() { os.Exit(1) } podmanTest = PodmanCreate(tempdir) + podmanTest.CgroupManager = "cgroupfs" podmanTest.RestoreAllArtifacts() }) @@ -90,6 +91,7 @@ var _ = Describe("Podman rootless", func() { tempdir, err := CreateTempDirInTempDir() Expect(err).To(BeNil()) rootlessTest := PodmanCreate(tempdir) + rootlessTest.CgroupManager = "cgroupfs" err = filepath.Walk(tempdir, chownFunc) Expect(err).To(BeNil()) diff --git a/test/e2e/run_ns_test.go b/test/e2e/run_ns_test.go index a61b4ab03..88c0b1ad2 100644 --- a/test/e2e/run_ns_test.go +++ b/test/e2e/run_ns_test.go @@ -3,6 +3,7 @@ package integration import ( "fmt" "os" + "strings" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" @@ -59,6 +60,36 @@ var _ = Describe("Podman run ns", func() { Expect(session.OutputToString()).To(Equal(hostShm)) }) + It("podman run ipcns ipcmk host test", func() { + setup := podmanTest.SystemExec("ipcmk", []string{"-M", "1024"}) + setup.WaitWithDefaultTimeout() + Expect(setup.ExitCode()).To(Equal(0)) + output := strings.Split(setup.OutputToString(), " ") + ipc := output[len(output)-1] + session := podmanTest.Podman([]string{"run", "--ipc=host", fedoraMinimal, "ipcs", "-m", "-i", ipc}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + setup = podmanTest.SystemExec("ipcrm", []string{"-m", ipc}) + setup.WaitWithDefaultTimeout() + Expect(setup.ExitCode()).To(Equal(0)) + }) + + It("podman run ipcns ipcmk container test", func() { + setup := podmanTest.Podman([]string{"run", "-d", "--name", "test1", fedoraMinimal, "sleep", "999"}) + setup.WaitWithDefaultTimeout() + Expect(setup.ExitCode()).To(Equal(0)) + + session := podmanTest.Podman([]string{"exec", "test1", "ipcmk", "-M", "1024"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + output := strings.Split(session.OutputToString(), " ") + ipc := output[len(output)-1] + session = podmanTest.Podman([]string{"run", "--ipc=container:test1", fedoraMinimal, "ipcs", "-m", "-i", ipc}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + }) + It("podman run bad ipc pid test", func() { session := podmanTest.Podman([]string{"run", "--ipc=badpid", fedoraMinimal, "bash", "-c", "echo $$"}) session.WaitWithDefaultTimeout() diff --git a/test/e2e/run_test.go b/test/e2e/run_test.go index 3d487db66..5cec4f04b 100644 --- a/test/e2e/run_test.go +++ b/test/e2e/run_test.go @@ -50,10 +50,10 @@ var _ = Describe("Podman run", func() { It("podman run a container based on local image with short options and args", func() { // regression test for #714 - session := podmanTest.Podman([]string{"run", ALPINE, "find", "/", "-name", "etc"}) + session := podmanTest.Podman([]string{"run", ALPINE, "find", "/etc", "-name", "hosts"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - match, _ := session.GrepString("/etc") + match, _ := session.GrepString("/etc/hosts") Expect(match).Should(BeTrue()) }) @@ -234,6 +234,32 @@ var _ = Describe("Podman run", func() { Expect(session.OutputToString()).To(ContainSubstring("/run/test rw,relatime, shared")) }) + It("podman run with mount flag", func() { + mountPath := filepath.Join(podmanTest.TempDir, "secrets") + os.Mkdir(mountPath, 0755) + session := podmanTest.Podman([]string{"run", "--rm", "--mount", fmt.Sprintf("type=bind,src=%s,target=/run/test", mountPath), ALPINE, "grep", "/run/test", "/proc/self/mountinfo"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(session.OutputToString()).To(ContainSubstring("/run/test rw")) + + session = podmanTest.Podman([]string{"run", "--rm", "--mount", fmt.Sprintf("type=bind,src=%s,target=/run/test,ro", mountPath), ALPINE, "grep", "/run/test", "/proc/self/mountinfo"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(session.OutputToString()).To(ContainSubstring("/run/test ro")) + + session = podmanTest.Podman([]string{"run", "--rm", "--mount", fmt.Sprintf("type=bind,src=%s,target=/run/test,shared", mountPath), ALPINE, "grep", "/run/test", "/proc/self/mountinfo"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(session.OutputToString()).To(ContainSubstring("/run/test rw,relatime shared")) + + mountPath = filepath.Join(podmanTest.TempDir, "scratchpad") + os.Mkdir(mountPath, 0755) + session = podmanTest.Podman([]string{"run", "--rm", "--mount", "type=tmpfs,target=/run/test", ALPINE, "grep", "/run/test", "/proc/self/mountinfo"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(session.OutputToString()).To(ContainSubstring("/run/test rw,nosuid,nodev,noexec,relatime - tmpfs")) + }) + It("podman run with cidfile", func() { session := podmanTest.Podman([]string{"run", "--cidfile", tempdir + "cidfile", ALPINE, "ls"}) session.WaitWithDefaultTimeout() @@ -565,6 +591,19 @@ USER mail` Expect(session.ExitCode()).To(Equal(0)) }) + It("podman run --mount flag with multiple mounts", func() { + vol1 := filepath.Join(podmanTest.TempDir, "vol-test1") + err := os.MkdirAll(vol1, 0755) + Expect(err).To(BeNil()) + vol2 := filepath.Join(podmanTest.TempDir, "vol-test2") + err = os.MkdirAll(vol2, 0755) + Expect(err).To(BeNil()) + + session := podmanTest.Podman([]string{"run", "--mount", "type=bind,src=" + vol1 + ",target=/myvol1,z", "--mount", "type=bind,src=" + vol2 + ",target=/myvol2,z", ALPINE, "touch", "/myvol2/foo.txt"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + }) + It("podman run findmnt nothing shared", func() { vol1 := filepath.Join(podmanTest.TempDir, "vol-test1") err := os.MkdirAll(vol1, 0755) diff --git a/test/e2e/search_test.go b/test/e2e/search_test.go index 2c85ca765..1f06bf4a1 100644 --- a/test/e2e/search_test.go +++ b/test/e2e/search_test.go @@ -60,10 +60,10 @@ var _ = Describe("Podman search", func() { }) It("podman search single registry flag", func() { - search := podmanTest.Podman([]string{"search", "registry.fedoraproject.org/fedora-minimal"}) + search := podmanTest.Podman([]string{"search", "registry.fedoraproject.org/fedora"}) search.WaitWithDefaultTimeout() Expect(search.ExitCode()).To(Equal(0)) - Expect(search.LineInOutputContains("fedoraproject.org/fedora-minimal")).To(BeTrue()) + Expect(search.LineInOutputContains("fedoraproject.org/fedora")).To(BeTrue()) }) It("podman search format flag", func() { diff --git a/test/install/.gitignore b/test/install/.gitignore new file mode 100644 index 000000000..0a948f916 --- /dev/null +++ b/test/install/.gitignore @@ -0,0 +1 @@ +rpms/
\ No newline at end of file diff --git a/test/install/Dockerfile.Centos b/test/install/Dockerfile.Centos new file mode 100644 index 000000000..11f60029b --- /dev/null +++ b/test/install/Dockerfile.Centos @@ -0,0 +1,3 @@ +FROM registry.centos.org/centos/centos:7 + +RUN yum install -y rpms/noarch/* rpms/x86_64/*
\ No newline at end of file diff --git a/test/install/Dockerfile.Fedora b/test/install/Dockerfile.Fedora new file mode 100644 index 000000000..188e60328 --- /dev/null +++ b/test/install/Dockerfile.Fedora @@ -0,0 +1,3 @@ +FROM registry.fedoraproject.org/fedora:28 + +RUN dnf install -y rpms/noarch/* rpms/x86_64/*
\ No newline at end of file diff --git a/test/install/README.md b/test/install/README.md new file mode 100644 index 000000000..21e5ab26d --- /dev/null +++ b/test/install/README.md @@ -0,0 +1,11 @@ +# Installation Tests + +The Dockerfiles in this directory attempt to install the RPMs built from this +repo into the target OS. Make the RPMs first with: + +``` +make -f .copr/Makefile srpm outdir=test/install/rpms +make -f .copr/Makefile build_binary outdir=test/install/rpms +``` + +Then, run a container image build using the Dockerfiles in this directory.
\ No newline at end of file diff --git a/vendor.conf b/vendor.conf index c21cb4b8e..1f28159cd 100644 --- a/vendor.conf +++ b/vendor.conf @@ -10,7 +10,7 @@ github.com/containerd/cgroups 58556f5ad8448d99a6f7bea69ea4bdb7747cfeb0 github.com/containerd/continuity master github.com/containernetworking/cni v0.7.0-alpha1 github.com/containernetworking/plugins 1562a1e60ed101aacc5e08ed9dbeba8e9f3d4ec1 -github.com/containers/image d8b5cf2b804a48489e5203d51254ef576794049d +github.com/containers/image 85d7559d44fd71f30e46e43d809bfbf88d11d916 github.com/containers/storage 243c4cd616afdf06b4a975f18c4db083d26b1641 github.com/containers/psgo 5dde6da0bc8831b35243a847625bcf18183bd1ee github.com/coreos/go-systemd v14 @@ -90,7 +90,7 @@ k8s.io/kube-openapi 275e2ce91dec4c05a4094a7b1daee5560b555ac9 https://github.com/ k8s.io/utils 258e2a2fa64568210fbd6267cf1d8fd87c3cb86e https://github.com/kubernetes/utils github.com/mrunalp/fileutils master github.com/varlink/go master -github.com/projectatomic/buildah 9c8c58c33b0b6e15f2fa780042ef46552a8a26d4 +github.com/containers/buildah 53b05ae20fdd801f33cad5e01789898dba31029d github.com/Nvveen/Gotty master github.com/fsouza/go-dockerclient master github.com/openshift/imagebuilder master diff --git a/vendor/github.com/projectatomic/buildah/LICENSE b/vendor/github.com/containers/buildah/LICENSE index 8dada3eda..8dada3eda 100644 --- a/vendor/github.com/projectatomic/buildah/LICENSE +++ b/vendor/github.com/containers/buildah/LICENSE diff --git a/vendor/github.com/projectatomic/buildah/README.md b/vendor/github.com/containers/buildah/README.md index 8927488bc..fa4a58fd9 100644 --- a/vendor/github.com/projectatomic/buildah/README.md +++ b/vendor/github.com/containers/buildah/README.md @@ -1,9 +1,9 @@ -![buildah logo](https://cdn.rawgit.com/projectatomic/buildah/master/logos/buildah-logo_large.png) +![buildah logo](https://cdn.rawgit.com/containers/buildah/master/logos/buildah-logo_large.png) # [Buildah](https://www.youtube.com/embed/YVk5NgSiUw8) - a tool that facilitates building [Open Container Initiative (OCI)](https://www.opencontainers.org/) container images -[![Go Report Card](https://goreportcard.com/badge/github.com/projectatomic/buildah)](https://goreportcard.com/report/github.com/projectatomic/buildah) -[![Travis](https://travis-ci.org/projectatomic/buildah.svg?branch=master)](https://travis-ci.org/projectatomic/buildah) +[![Go Report Card](https://goreportcard.com/badge/github.com/containers/buildah)](https://goreportcard.com/report/github.com/containers/buildah) +[![Travis](https://travis-ci.org/containers/buildah.svg?branch=master)](https://travis-ci.org/containers/buildah) The Buildah package provides a command line tool that can be used to * create a working container, either from scratch or using an image as a starting point @@ -15,6 +15,8 @@ The Buildah package provides a command line tool that can be used to * delete a working container or an image * rename a local container +## Buildah Information for Developers + **[Buildah Demos](demos)** **[Changelog](CHANGELOG.md)** @@ -29,6 +31,38 @@ The Buildah package provides a command line tool that can be used to **[Tutorials](docs/tutorials)** +## Buildah and Podman relationship + +Buildah and Podman are two complementary Open-source projects that are available on +most Linux platforms and both projects reside at [GitHub.com](https://github.com) +with Buildah [here](https://github.com/containers/buildah) and +Podman [here](https://github.com/containers/libpod). Both Buildah and Podman are +command line tools that work on OCI images and containers. The two projects +differentiate in their specialization. + +Buildah specializes in building OCI images. Buildah's commands replicate all +of the commands that are found in a Dockerfile. Buildah’s goal is also to +provide a lower level coreutils interface to build images, allowing people to build +containers without requiring a Dockerfile. The intent with Buildah is to allow other +scripting languages to build container images, without requiring a daemon. + +Podman specializes in all of the commands and functions that help you to maintain and modify +OCI images, such as pulling and tagging. It also allows you to create, run, and maintain those containers +created from those images. + +A major difference between Podman and Buildah is their concept of a container. Podman +allows users to create "traditional containers" where the intent of these containers is +to be long lived. While Buildah containers are really just created to allow content +to be added back to the container image. An easy way to think of it is the +`buildah run` command emulates the RUN command in a Dockerfile while the `podman run` +command emulates the `docker run` command in functionality. Because of this and their underlying +storage differences, you can not see Podman containers from within Buildah or vice versa. + +In short Buildah is an efficient way to create OCI images while Podman allows +you to manage and maintain those images and containers in a production environment using +familiar container cli commands. For more details, see the +[Container Tools Guide](https://github.com/containers/buildah/tree/master/docs/containertools). + ## Example From [`./examples/lighttpd.sh`](examples/lighttpd.sh): diff --git a/vendor/github.com/projectatomic/buildah/add.go b/vendor/github.com/containers/buildah/add.go index 1aad8ad37..b1747db94 100644 --- a/vendor/github.com/projectatomic/buildah/add.go +++ b/vendor/github.com/containers/buildah/add.go @@ -11,12 +11,12 @@ import ( "syscall" "time" + "github.com/containers/buildah/util" "github.com/containers/libpod/pkg/chrootuser" "github.com/containers/storage/pkg/archive" "github.com/containers/storage/pkg/idtools" "github.com/opencontainers/runtime-spec/specs-go" "github.com/pkg/errors" - "github.com/projectatomic/buildah/util" "github.com/sirupsen/logrus" ) @@ -168,9 +168,13 @@ func (b *Builder) Add(destination string, extract bool, options AddAndCopyOption return errors.Wrapf(syscall.ENOENT, "no files found matching %q", src) } for _, gsrc := range glob { - srcfi, err := os.Stat(gsrc) + esrc, err := filepath.EvalSymlinks(gsrc) if err != nil { - return errors.Wrapf(err, "error reading %q", gsrc) + return errors.Wrapf(err, "error evaluating symlinks %q", gsrc) + } + srcfi, err := os.Stat(esrc) + if err != nil { + return errors.Wrapf(err, "error reading %q", esrc) } if srcfi.IsDir() { // The source is a directory, so copy the contents of @@ -180,13 +184,13 @@ func (b *Builder) Add(destination string, extract bool, options AddAndCopyOption if err = idtools.MkdirAllAndChownNew(dest, 0755, hostOwner); err != nil { return err } - logrus.Debugf("copying %q to %q", gsrc+string(os.PathSeparator)+"*", dest+string(os.PathSeparator)+"*") - if err := copyWithTar(gsrc, dest); err != nil { - return errors.Wrapf(err, "error copying %q to %q", gsrc, dest) + logrus.Debugf("copying %q to %q", esrc+string(os.PathSeparator)+"*", dest+string(os.PathSeparator)+"*") + if err := copyWithTar(esrc, dest); err != nil { + return errors.Wrapf(err, "error copying %q to %q", esrc, dest) } continue } - if !extract || !archive.IsArchivePath(gsrc) { + if !extract || !archive.IsArchivePath(esrc) { // This source is a file, and either it's not an // archive, or we don't care whether or not it's an // archive. @@ -195,16 +199,16 @@ func (b *Builder) Add(destination string, extract bool, options AddAndCopyOption d = filepath.Join(dest, filepath.Base(gsrc)) } // Copy the file, preserving attributes. - logrus.Debugf("copying %q to %q", gsrc, d) - if err := copyFileWithTar(gsrc, d); err != nil { - return errors.Wrapf(err, "error copying %q to %q", gsrc, d) + logrus.Debugf("copying %q to %q", esrc, d) + if err := copyFileWithTar(esrc, d); err != nil { + return errors.Wrapf(err, "error copying %q to %q", esrc, d) } continue } // We're extracting an archive into the destination directory. - logrus.Debugf("extracting contents of %q into %q", gsrc, dest) - if err := untarPath(gsrc, dest); err != nil { - return errors.Wrapf(err, "error extracting %q into %q", gsrc, dest) + logrus.Debugf("extracting contents of %q into %q", esrc, dest) + if err := untarPath(esrc, dest); err != nil { + return errors.Wrapf(err, "error extracting %q into %q", esrc, dest) } } } diff --git a/vendor/github.com/projectatomic/buildah/bind/mount.go b/vendor/github.com/containers/buildah/bind/mount.go index 695bde554..e1ae323b9 100644 --- a/vendor/github.com/projectatomic/buildah/bind/mount.go +++ b/vendor/github.com/containers/buildah/bind/mount.go @@ -8,11 +8,11 @@ import ( "path/filepath" "syscall" + "github.com/containers/buildah/util" "github.com/containers/storage/pkg/idtools" "github.com/containers/storage/pkg/mount" "github.com/opencontainers/runtime-spec/specs-go" "github.com/pkg/errors" - "github.com/projectatomic/buildah/util" "github.com/sirupsen/logrus" "golang.org/x/sys/unix" ) diff --git a/vendor/github.com/projectatomic/buildah/bind/mount_unsupported.go b/vendor/github.com/containers/buildah/bind/mount_unsupported.go index 88ca2ca8b..88ca2ca8b 100644 --- a/vendor/github.com/projectatomic/buildah/bind/mount_unsupported.go +++ b/vendor/github.com/containers/buildah/bind/mount_unsupported.go diff --git a/vendor/github.com/projectatomic/buildah/bind/util.go b/vendor/github.com/containers/buildah/bind/util.go index 4408c53bb..93ba4e2b7 100644 --- a/vendor/github.com/projectatomic/buildah/bind/util.go +++ b/vendor/github.com/containers/buildah/bind/util.go @@ -1,8 +1,8 @@ package bind import ( + "github.com/containers/buildah/util" "github.com/opencontainers/runtime-spec/specs-go" - "github.com/projectatomic/buildah/util" ) const ( diff --git a/vendor/github.com/projectatomic/buildah/buildah.go b/vendor/github.com/containers/buildah/buildah.go index 60688b372..7891810a2 100644 --- a/vendor/github.com/projectatomic/buildah/buildah.go +++ b/vendor/github.com/containers/buildah/buildah.go @@ -9,13 +9,13 @@ import ( "os" "path/filepath" + "github.com/containers/buildah/docker" + "github.com/containers/buildah/util" "github.com/containers/image/types" "github.com/containers/storage" "github.com/containers/storage/pkg/ioutils" "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" - "github.com/projectatomic/buildah/docker" - "github.com/projectatomic/buildah/util" ) const ( diff --git a/vendor/github.com/projectatomic/buildah/chroot/run.go b/vendor/github.com/containers/buildah/chroot/run.go index 9a70e0f51..58b7a883c 100644 --- a/vendor/github.com/projectatomic/buildah/chroot/run.go +++ b/vendor/github.com/containers/buildah/chroot/run.go @@ -17,15 +17,15 @@ import ( "syscall" "unsafe" + "github.com/containers/buildah/bind" + "github.com/containers/buildah/unshare" + "github.com/containers/buildah/util" "github.com/containers/storage/pkg/ioutils" "github.com/containers/storage/pkg/mount" "github.com/containers/storage/pkg/reexec" "github.com/opencontainers/runc/libcontainer/apparmor" "github.com/opencontainers/runtime-spec/specs-go" "github.com/pkg/errors" - "github.com/projectatomic/buildah/bind" - "github.com/projectatomic/buildah/unshare" - "github.com/projectatomic/buildah/util" "github.com/sirupsen/logrus" "github.com/syndtr/gocapability/capability" "golang.org/x/crypto/ssh/terminal" @@ -1075,11 +1075,14 @@ func setupChrootBindMounts(spec *specs.Spec, bundlePath string) (undoBinds func( // The target isn't there yet, so create it, and make a // note to remove it later. if srcinfo.IsDir() { - if err = os.Mkdir(target, 0111); err != nil { + if err = os.MkdirAll(target, 0111); err != nil { return undoBinds, errors.Wrapf(err, "error creating mountpoint %q in mount namespace", target) } removes = append(removes, target) } else { + if err = os.MkdirAll(filepath.Dir(target), 0111); err != nil { + return undoBinds, errors.Wrapf(err, "error ensuring parent of mountpoint %q (%q) is present in mount namespace", target, filepath.Dir(target)) + } var file *os.File if file, err = os.OpenFile(target, os.O_WRONLY|os.O_CREATE, 0); err != nil { return undoBinds, errors.Wrapf(err, "error creating mountpoint %q in mount namespace", target) diff --git a/vendor/github.com/projectatomic/buildah/chroot/seccomp.go b/vendor/github.com/containers/buildah/chroot/seccomp.go index f2c55017f..f2c55017f 100644 --- a/vendor/github.com/projectatomic/buildah/chroot/seccomp.go +++ b/vendor/github.com/containers/buildah/chroot/seccomp.go diff --git a/vendor/github.com/projectatomic/buildah/chroot/seccomp_unsupported.go b/vendor/github.com/containers/buildah/chroot/seccomp_unsupported.go index a5b74bf09..a5b74bf09 100644 --- a/vendor/github.com/projectatomic/buildah/chroot/seccomp_unsupported.go +++ b/vendor/github.com/containers/buildah/chroot/seccomp_unsupported.go diff --git a/vendor/github.com/projectatomic/buildah/chroot/selinux.go b/vendor/github.com/containers/buildah/chroot/selinux.go index 3e62d743d..3e62d743d 100644 --- a/vendor/github.com/projectatomic/buildah/chroot/selinux.go +++ b/vendor/github.com/containers/buildah/chroot/selinux.go diff --git a/vendor/github.com/projectatomic/buildah/chroot/selinux_unsupported.go b/vendor/github.com/containers/buildah/chroot/selinux_unsupported.go index 1c6f48912..1c6f48912 100644 --- a/vendor/github.com/projectatomic/buildah/chroot/selinux_unsupported.go +++ b/vendor/github.com/containers/buildah/chroot/selinux_unsupported.go diff --git a/vendor/github.com/projectatomic/buildah/chroot/unsupported.go b/vendor/github.com/containers/buildah/chroot/unsupported.go index 5312c0024..5312c0024 100644 --- a/vendor/github.com/projectatomic/buildah/chroot/unsupported.go +++ b/vendor/github.com/containers/buildah/chroot/unsupported.go diff --git a/vendor/github.com/projectatomic/buildah/chroot/util.go b/vendor/github.com/containers/buildah/chroot/util.go index 34cc77260..34cc77260 100644 --- a/vendor/github.com/projectatomic/buildah/chroot/util.go +++ b/vendor/github.com/containers/buildah/chroot/util.go diff --git a/vendor/github.com/projectatomic/buildah/commit.go b/vendor/github.com/containers/buildah/commit.go index b25ec7029..f89930399 100644 --- a/vendor/github.com/projectatomic/buildah/commit.go +++ b/vendor/github.com/containers/buildah/commit.go @@ -7,6 +7,7 @@ import ( "io/ioutil" "time" + "github.com/containers/buildah/util" cp "github.com/containers/image/copy" "github.com/containers/image/signature" is "github.com/containers/image/storage" @@ -15,7 +16,6 @@ import ( "github.com/containers/storage" "github.com/containers/storage/pkg/archive" "github.com/pkg/errors" - "github.com/projectatomic/buildah/util" "github.com/sirupsen/logrus" ) @@ -171,7 +171,7 @@ func Push(ctx context.Context, image string, dest types.ImageReference, options return errors.Wrapf(err, "error creating new signature policy context") } // Look up the image. - src, _, err := util.FindImage(options.Store, "", systemContext, image) + src, img, err := util.FindImage(options.Store, "", systemContext, image) if err != nil { return err } @@ -181,7 +181,9 @@ func Push(ctx context.Context, image string, dest types.ImageReference, options return errors.Wrapf(err, "error copying layers and metadata") } if options.ReportWriter != nil { - fmt.Fprintf(options.ReportWriter, "\n") + fmt.Fprintf(options.ReportWriter, "") } + digest := "@" + img.Digest.Hex() + fmt.Printf("Successfully pushed %s%s\n", dest.StringWithinTransport(), digest) return nil } diff --git a/vendor/github.com/projectatomic/buildah/common.go b/vendor/github.com/containers/buildah/common.go index dcf922dc9..dcf922dc9 100644 --- a/vendor/github.com/projectatomic/buildah/common.go +++ b/vendor/github.com/containers/buildah/common.go diff --git a/vendor/github.com/projectatomic/buildah/config.go b/vendor/github.com/containers/buildah/config.go index 2f4d8319a..f6a742d59 100644 --- a/vendor/github.com/projectatomic/buildah/config.go +++ b/vendor/github.com/containers/buildah/config.go @@ -8,13 +8,13 @@ import ( "strings" "time" + "github.com/containers/buildah/docker" "github.com/containers/image/manifest" "github.com/containers/image/transports" "github.com/containers/image/types" "github.com/containers/storage/pkg/stringid" ociv1 "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" - "github.com/projectatomic/buildah/docker" "github.com/sirupsen/logrus" ) diff --git a/vendor/github.com/projectatomic/buildah/delete.go b/vendor/github.com/containers/buildah/delete.go index 8de774ff9..8de774ff9 100644 --- a/vendor/github.com/projectatomic/buildah/delete.go +++ b/vendor/github.com/containers/buildah/delete.go diff --git a/vendor/github.com/projectatomic/buildah/docker/types.go b/vendor/github.com/containers/buildah/docker/types.go index 759fc1246..759fc1246 100644 --- a/vendor/github.com/projectatomic/buildah/docker/types.go +++ b/vendor/github.com/containers/buildah/docker/types.go diff --git a/vendor/github.com/projectatomic/buildah/image.go b/vendor/github.com/containers/buildah/image.go index b94720f59..df50d95bd 100644 --- a/vendor/github.com/projectatomic/buildah/image.go +++ b/vendor/github.com/containers/buildah/image.go @@ -11,6 +11,7 @@ import ( "path/filepath" "time" + "github.com/containers/buildah/docker" "github.com/containers/image/docker/reference" "github.com/containers/image/image" "github.com/containers/image/manifest" @@ -23,7 +24,6 @@ import ( specs "github.com/opencontainers/image-spec/specs-go" "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" - "github.com/projectatomic/buildah/docker" "github.com/sirupsen/logrus" ) diff --git a/vendor/github.com/projectatomic/buildah/imagebuildah/build.go b/vendor/github.com/containers/buildah/imagebuildah/build.go index 08d0f6268..4bcd38c05 100644 --- a/vendor/github.com/projectatomic/buildah/imagebuildah/build.go +++ b/vendor/github.com/containers/buildah/imagebuildah/build.go @@ -14,6 +14,8 @@ import ( "strings" "time" + "github.com/containers/buildah" + "github.com/containers/buildah/util" cp "github.com/containers/image/copy" is "github.com/containers/image/storage" "github.com/containers/image/transports" @@ -28,8 +30,6 @@ import ( "github.com/opencontainers/runtime-spec/specs-go" "github.com/openshift/imagebuilder" "github.com/pkg/errors" - "github.com/projectatomic/buildah" - "github.com/projectatomic/buildah/util" "github.com/sirupsen/logrus" ) diff --git a/vendor/github.com/projectatomic/buildah/imagebuildah/chroot_symlink.go b/vendor/github.com/containers/buildah/imagebuildah/chroot_symlink.go index f1fec7f70..f1fec7f70 100644 --- a/vendor/github.com/projectatomic/buildah/imagebuildah/chroot_symlink.go +++ b/vendor/github.com/containers/buildah/imagebuildah/chroot_symlink.go diff --git a/vendor/github.com/projectatomic/buildah/imagebuildah/util.go b/vendor/github.com/containers/buildah/imagebuildah/util.go index b437ea1cb..35dc5438a 100644 --- a/vendor/github.com/projectatomic/buildah/imagebuildah/util.go +++ b/vendor/github.com/containers/buildah/imagebuildah/util.go @@ -10,9 +10,9 @@ import ( "path/filepath" "strings" + "github.com/containers/buildah" "github.com/containers/storage/pkg/chrootarchive" "github.com/pkg/errors" - "github.com/projectatomic/buildah" "github.com/sirupsen/logrus" ) diff --git a/vendor/github.com/projectatomic/buildah/import.go b/vendor/github.com/containers/buildah/import.go index 31288334a..f5f156be2 100644 --- a/vendor/github.com/projectatomic/buildah/import.go +++ b/vendor/github.com/containers/buildah/import.go @@ -3,13 +3,13 @@ package buildah import ( "context" + "github.com/containers/buildah/docker" + "github.com/containers/buildah/util" is "github.com/containers/image/storage" "github.com/containers/image/types" "github.com/containers/storage" "github.com/opencontainers/go-digest" "github.com/pkg/errors" - "github.com/projectatomic/buildah/docker" - "github.com/projectatomic/buildah/util" ) func importBuilderDataFromImage(ctx context.Context, store storage.Store, systemContext *types.SystemContext, imageID, containerName, containerID string) (*Builder, error) { diff --git a/vendor/github.com/projectatomic/buildah/mount.go b/vendor/github.com/containers/buildah/mount.go index 4f1ae3c6e..4f1ae3c6e 100644 --- a/vendor/github.com/projectatomic/buildah/mount.go +++ b/vendor/github.com/containers/buildah/mount.go diff --git a/vendor/github.com/projectatomic/buildah/new.go b/vendor/github.com/containers/buildah/new.go index 1abb2f1f1..b0b655da9 100644 --- a/vendor/github.com/projectatomic/buildah/new.go +++ b/vendor/github.com/containers/buildah/new.go @@ -6,17 +6,18 @@ import ( "os" "strings" + "github.com/containers/buildah/util" "github.com/containers/image/pkg/sysregistries" is "github.com/containers/image/storage" "github.com/containers/image/transports" "github.com/containers/image/transports/alltransports" "github.com/containers/image/types" "github.com/containers/storage" + multierror "github.com/hashicorp/go-multierror" "github.com/opencontainers/selinux/go-selinux" "github.com/opencontainers/selinux/go-selinux/label" "github.com/openshift/imagebuilder" "github.com/pkg/errors" - "github.com/projectatomic/buildah/util" "github.com/sirupsen/logrus" ) @@ -144,6 +145,7 @@ func resolveImage(ctx context.Context, systemContext *types.SystemContext, store if err != nil { return nil, nil, errors.Wrapf(err, "error parsing reference to image %q", options.FromImage) } + var pullErrors *multierror.Error for _, image := range images { var err error if len(image) >= minimumTruncatedIDLength { @@ -158,6 +160,7 @@ func resolveImage(ctx context.Context, systemContext *types.SystemContext, store if options.PullPolicy == PullAlways { pulledImg, pulledReference, err := pullAndFindImage(ctx, store, image, options, systemContext) if err != nil { + pullErrors = multierror.Append(pullErrors, err) logrus.Debugf("unable to pull and read image %q: %v", image, err) continue } @@ -169,6 +172,7 @@ func resolveImage(ctx context.Context, systemContext *types.SystemContext, store srcRef, err := alltransports.ParseImageName(image) if err != nil { if options.Transport == "" { + pullErrors = multierror.Append(pullErrors, err) logrus.Debugf("error parsing image name %q: %v", image, err) continue } @@ -178,6 +182,7 @@ func resolveImage(ctx context.Context, systemContext *types.SystemContext, store } srcRef2, err := alltransports.ParseImageName(transport + image) if err != nil { + pullErrors = multierror.Append(pullErrors, err) logrus.Debugf("error parsing image name %q: %v", image, err) continue } @@ -199,11 +204,13 @@ func resolveImage(ctx context.Context, systemContext *types.SystemContext, store img, err = is.Transport.GetStoreImage(store, ref) if err != nil { if errors.Cause(err) == storage.ErrImageUnknown && options.PullPolicy != PullIfMissing { + pullErrors = multierror.Append(pullErrors, err) logrus.Debugf("no such image %q: %v", transports.ImageName(ref), err) continue } pulledImg, pulledReference, err := pullAndFindImage(ctx, store, image, options, systemContext) if err != nil { + pullErrors = multierror.Append(pullErrors, err) logrus.Debugf("unable to pull and read image %q: %v", image, err) continue } @@ -212,6 +219,11 @@ func resolveImage(ctx context.Context, systemContext *types.SystemContext, store } break } + + if img == nil && pullErrors != nil { + return nil, nil, pullErrors + } + return ref, img, nil } @@ -262,26 +274,23 @@ func newBuilder(ctx context.Context, store storage.Store, options BuilderOptions if options.Container != "" { name = options.Container } else { - var err2 error if image != "" { name = imageNamePrefix(image) + "-" + name } - suffix := 1 - tmpName := name - for errors.Cause(err2) != storage.ErrContainerUnknown { - _, err2 = store.Container(tmpName) - if err2 == nil { - suffix++ - tmpName = fmt.Sprintf("%s-%d", name, suffix) - } - } - name = tmpName } coptions := storage.ContainerOptions{} coptions.IDMappingOptions = newContainerIDMappingOptions(options.IDMappingOptions) container, err := store.CreateContainer("", []string{name}, imageID, "", "", &coptions) + suffix := 1 + for err != nil && errors.Cause(err) == storage.ErrDuplicateName && options.Container == "" { + suffix++ + tmpName := fmt.Sprintf("%s-%d", name, suffix) + if container, err = store.CreateContainer("", []string{tmpName}, imageID, "", "", &coptions); err == nil { + name = tmpName + } + } if err != nil { return nil, errors.Wrapf(err, "error creating container") } diff --git a/vendor/github.com/projectatomic/buildah/pkg/cli/common.go b/vendor/github.com/containers/buildah/pkg/cli/common.go index a438daf6a..94b92e1eb 100644 --- a/vendor/github.com/projectatomic/buildah/pkg/cli/common.go +++ b/vendor/github.com/containers/buildah/pkg/cli/common.go @@ -9,10 +9,10 @@ import ( "os" "strings" + "github.com/containers/buildah" + "github.com/containers/buildah/util" "github.com/opencontainers/runtime-spec/specs-go" "github.com/pkg/errors" - "github.com/projectatomic/buildah" - "github.com/projectatomic/buildah/util" "github.com/urfave/cli" ) diff --git a/vendor/github.com/projectatomic/buildah/pkg/parse/parse.go b/vendor/github.com/containers/buildah/pkg/parse/parse.go index 2dff18818..d206508b4 100644 --- a/vendor/github.com/projectatomic/buildah/pkg/parse/parse.go +++ b/vendor/github.com/containers/buildah/pkg/parse/parse.go @@ -15,12 +15,12 @@ import ( "strings" "unicode" + "github.com/containers/buildah" "github.com/containers/image/types" "github.com/containers/storage/pkg/idtools" "github.com/docker/go-units" "github.com/opencontainers/runtime-spec/specs-go" "github.com/pkg/errors" - "github.com/projectatomic/buildah" "github.com/sirupsen/logrus" "github.com/urfave/cli" "golang.org/x/crypto/ssh/terminal" diff --git a/vendor/github.com/projectatomic/buildah/pull.go b/vendor/github.com/containers/buildah/pull.go index 48d7f76ed..c2fc6637f 100644 --- a/vendor/github.com/projectatomic/buildah/pull.go +++ b/vendor/github.com/containers/buildah/pull.go @@ -5,6 +5,7 @@ import ( "io" "strings" + "github.com/containers/buildah/util" cp "github.com/containers/image/copy" "github.com/containers/image/docker/reference" tarfile "github.com/containers/image/docker/tarfile" @@ -17,7 +18,6 @@ import ( "github.com/containers/image/types" "github.com/containers/storage" "github.com/pkg/errors" - "github.com/projectatomic/buildah/util" "github.com/sirupsen/logrus" ) @@ -190,8 +190,8 @@ func pullImage(ctx context.Context, store storage.Store, imageName string, optio }() logrus.Debugf("copying %q to %q", spec, destName) - err = cp.Image(ctx, policyContext, destRef, srcRef, getCopyOptions(options.ReportWriter, sc, nil, "")) - if err == nil { + pullError := cp.Image(ctx, policyContext, destRef, srcRef, getCopyOptions(options.ReportWriter, sc, nil, "")) + if pullError == nil { return destRef, nil } @@ -206,9 +206,9 @@ func pullImage(ctx context.Context, store storage.Store, imageName string, optio return nil, err } if !hasRegistryInName && len(searchRegistries) == 0 { - return nil, errors.Errorf("image name provided is a short name and no search registries are defined in %s.", registryPath) + return nil, errors.Errorf("image name provided is a short name and no search registries are defined in %s: %s", registryPath, pullError) } - return nil, errors.Errorf("unable to find image in the registries defined in %q", registryPath) + return nil, pullError } // getImageDigest creates an image object and uses the hex value of the digest as the image ID diff --git a/vendor/github.com/projectatomic/buildah/run.go b/vendor/github.com/containers/buildah/run.go index 12560de3c..d73f0d239 100644 --- a/vendor/github.com/projectatomic/buildah/run.go +++ b/vendor/github.com/containers/buildah/run.go @@ -19,6 +19,9 @@ import ( "time" "github.com/containernetworking/cni/libcni" + "github.com/containers/buildah/bind" + "github.com/containers/buildah/chroot" + "github.com/containers/buildah/util" "github.com/containers/libpod/pkg/secrets" "github.com/containers/storage/pkg/idtools" "github.com/containers/storage/pkg/ioutils" @@ -29,9 +32,6 @@ import ( "github.com/opencontainers/runtime-tools/generate" "github.com/opencontainers/selinux/go-selinux/label" "github.com/pkg/errors" - "github.com/projectatomic/buildah/bind" - "github.com/projectatomic/buildah/chroot" - "github.com/projectatomic/buildah/util" "github.com/sirupsen/logrus" "golang.org/x/crypto/ssh/terminal" "golang.org/x/sys/unix" @@ -506,10 +506,19 @@ func runSetupBuiltinVolumes(mountLabel, mountPoint, containerDir string, copyWit return nil, errors.Wrapf(err, "error relabeling directory %q for volume %q", volumePath, volume) } srcPath := filepath.Join(mountPoint, volume) + stat, err := os.Stat(srcPath) + if err != nil { + return nil, errors.Wrapf(err, "failed to stat %q for volume %q", srcPath, volume) + } + if err = os.Chmod(volumePath, stat.Mode().Perm()); err != nil { + return nil, errors.Wrapf(err, "failed to chmod %q for volume %q", volumePath, volume) + } + if err = os.Chown(volumePath, int(stat.Sys().(*syscall.Stat_t).Uid), int(stat.Sys().(*syscall.Stat_t).Gid)); err != nil { + return nil, errors.Wrapf(err, "error chowning directory %q for volume %q", volumePath, volume) + } if err = copyWithTar(srcPath, volumePath); err != nil && !os.IsNotExist(err) { return nil, errors.Wrapf(err, "error populating directory %q for volume %q using contents of %q", volumePath, volume, srcPath) } - } // Add the bind mount. mounts = append(mounts, specs.Mount{ @@ -868,9 +877,11 @@ func (b *Builder) configureUIDGID(g *generate.Generator, mountPoint string, opti g.AddProcessAdditionalGid(gid) } - // Remove capabilities if not running as root + // Remove capabilities if not running as root except Bounding set if user.UID != 0 { + bounding := g.Config.Process.Capabilities.Bounding g.ClearProcessCapabilities() + g.Config.Process.Capabilities.Bounding = bounding } return nil diff --git a/vendor/github.com/projectatomic/buildah/run_linux.go b/vendor/github.com/containers/buildah/run_linux.go index a7519a092..a7519a092 100644 --- a/vendor/github.com/projectatomic/buildah/run_linux.go +++ b/vendor/github.com/containers/buildah/run_linux.go diff --git a/vendor/github.com/projectatomic/buildah/run_unsupport.go b/vendor/github.com/containers/buildah/run_unsupport.go index 4824a0c4e..4824a0c4e 100644 --- a/vendor/github.com/projectatomic/buildah/run_unsupport.go +++ b/vendor/github.com/containers/buildah/run_unsupport.go diff --git a/vendor/github.com/projectatomic/buildah/seccomp.go b/vendor/github.com/containers/buildah/seccomp.go index a435b5f71..a435b5f71 100644 --- a/vendor/github.com/projectatomic/buildah/seccomp.go +++ b/vendor/github.com/containers/buildah/seccomp.go diff --git a/vendor/github.com/projectatomic/buildah/seccomp_unsupported.go b/vendor/github.com/containers/buildah/seccomp_unsupported.go index cba8390c5..cba8390c5 100644 --- a/vendor/github.com/projectatomic/buildah/seccomp_unsupported.go +++ b/vendor/github.com/containers/buildah/seccomp_unsupported.go diff --git a/vendor/github.com/projectatomic/buildah/selinux.go b/vendor/github.com/containers/buildah/selinux.go index 2b850cf9f..2b850cf9f 100644 --- a/vendor/github.com/projectatomic/buildah/selinux.go +++ b/vendor/github.com/containers/buildah/selinux.go diff --git a/vendor/github.com/projectatomic/buildah/selinux_unsupported.go b/vendor/github.com/containers/buildah/selinux_unsupported.go index 0aa7c46e4..0aa7c46e4 100644 --- a/vendor/github.com/projectatomic/buildah/selinux_unsupported.go +++ b/vendor/github.com/containers/buildah/selinux_unsupported.go diff --git a/vendor/github.com/projectatomic/buildah/unmount.go b/vendor/github.com/containers/buildah/unmount.go index cdb511170..cdb511170 100644 --- a/vendor/github.com/projectatomic/buildah/unmount.go +++ b/vendor/github.com/containers/buildah/unmount.go diff --git a/vendor/github.com/projectatomic/buildah/unshare/unshare.c b/vendor/github.com/containers/buildah/unshare/unshare.c index 83864359b..83864359b 100644 --- a/vendor/github.com/projectatomic/buildah/unshare/unshare.c +++ b/vendor/github.com/containers/buildah/unshare/unshare.c diff --git a/vendor/github.com/projectatomic/buildah/unshare/unshare.go b/vendor/github.com/containers/buildah/unshare/unshare.go index 4eea74956..d89dfc053 100644 --- a/vendor/github.com/projectatomic/buildah/unshare/unshare.go +++ b/vendor/github.com/containers/buildah/unshare/unshare.go @@ -13,10 +13,10 @@ import ( "strings" "syscall" + "github.com/containers/buildah/util" "github.com/containers/storage/pkg/reexec" "github.com/opencontainers/runtime-spec/specs-go" "github.com/pkg/errors" - "github.com/projectatomic/buildah/util" ) // Cmd wraps an exec.Cmd created by the reexec package in unshare(), and diff --git a/vendor/github.com/projectatomic/buildah/unshare/unshare_cgo.go b/vendor/github.com/containers/buildah/unshare/unshare_cgo.go index 26a0b2c20..26a0b2c20 100644 --- a/vendor/github.com/projectatomic/buildah/unshare/unshare_cgo.go +++ b/vendor/github.com/containers/buildah/unshare/unshare_cgo.go diff --git a/vendor/github.com/projectatomic/buildah/unshare/unshare_gccgo.go b/vendor/github.com/containers/buildah/unshare/unshare_gccgo.go index c4811782a..c4811782a 100644 --- a/vendor/github.com/projectatomic/buildah/unshare/unshare_gccgo.go +++ b/vendor/github.com/containers/buildah/unshare/unshare_gccgo.go diff --git a/vendor/github.com/projectatomic/buildah/unshare/unshare_unsupported.go b/vendor/github.com/containers/buildah/unshare/unshare_unsupported.go index feeceae66..feeceae66 100644 --- a/vendor/github.com/projectatomic/buildah/unshare/unshare_unsupported.go +++ b/vendor/github.com/containers/buildah/unshare/unshare_unsupported.go diff --git a/vendor/github.com/projectatomic/buildah/util.go b/vendor/github.com/containers/buildah/util.go index ef9be87fb..ef9be87fb 100644 --- a/vendor/github.com/projectatomic/buildah/util.go +++ b/vendor/github.com/containers/buildah/util.go diff --git a/vendor/github.com/projectatomic/buildah/util/types.go b/vendor/github.com/containers/buildah/util/types.go index dc5f4b6c8..dc5f4b6c8 100644 --- a/vendor/github.com/projectatomic/buildah/util/types.go +++ b/vendor/github.com/containers/buildah/util/types.go diff --git a/vendor/github.com/projectatomic/buildah/util/util.go b/vendor/github.com/containers/buildah/util/util.go index 93323232d..93323232d 100644 --- a/vendor/github.com/projectatomic/buildah/util/util.go +++ b/vendor/github.com/containers/buildah/util/util.go diff --git a/vendor/github.com/projectatomic/buildah/vendor.conf b/vendor/github.com/containers/buildah/vendor.conf index 870fb4bdd..e69c92496 100644 --- a/vendor/github.com/projectatomic/buildah/vendor.conf +++ b/vendor/github.com/containers/buildah/vendor.conf @@ -4,8 +4,8 @@ github.com/BurntSushi/toml master github.com/containerd/continuity master github.com/containernetworking/cni v0.7.0-alpha1 github.com/seccomp/containers-golang master -github.com/containers/image 5df44e095ed826fbe2beeaabb329c749d7d6c3b6 -github.com/containers/storage 9fcbb57eb6c732e7b67003bb8ed861f169d33d63 +github.com/containers/image 85d7559d44fd71f30e46e43d809bfbf88d11d916 +github.com/containers/storage 243c4cd616afdf06b4a975f18c4db083d26b1641 github.com/docker/distribution 5f6282db7d65e6d72ad7c2cc66310724a57be716 github.com/docker/docker 86f080cff0914e9694068ed78d503701667c4c00 github.com/docker/docker-credential-helpers d68f9aeca33f5fd3f08eeae5e9d175edf4e731d1 @@ -42,7 +42,7 @@ github.com/ostreedev/ostree-go aeb02c6b6aa2889db3ef62f7855650755befd460 github.com/pborman/uuid master github.com/pkg/errors master github.com/pquerna/ffjson d49c2bc1aa135aad0c6f4fc2056623ec78f5d5ac -github.com/containers/libpod d20f3a51463ce75d139dd830e19a173906b0b0cb +github.com/containers/libpod 2afadeec6696fefac468a49c8ba24b0bc275aa75 github.com/sirupsen/logrus master github.com/syndtr/gocapability master github.com/tchap/go-patricia master diff --git a/vendor/github.com/containers/image/copy/copy.go b/vendor/github.com/containers/image/copy/copy.go index 183993c5d..59354ea38 100644 --- a/vendor/github.com/containers/image/copy/copy.go +++ b/vendor/github.com/containers/image/copy/copy.go @@ -533,20 +533,21 @@ func (ic *imageCopier) copyLayer(ctx context.Context, srcInfo types.BlobInfo) (t if err != nil { return types.BlobInfo{}, "", err } - var diffIDResult diffIDResult // = {digest:""} if diffIDIsNeeded { select { case <-ctx.Done(): return types.BlobInfo{}, "", ctx.Err() - case diffIDResult = <-diffIDChan: + case diffIDResult := <-diffIDChan: if diffIDResult.err != nil { return types.BlobInfo{}, "", errors.Wrap(diffIDResult.err, "Error computing layer DiffID") } logrus.Debugf("Computed DiffID %s for layer %s", diffIDResult.digest, srcInfo.Digest) ic.c.cachedDiffIDs[srcInfo.Digest] = diffIDResult.digest + return blobInfo, diffIDResult.digest, nil } + } else { + return blobInfo, ic.c.cachedDiffIDs[srcInfo.Digest], nil } - return blobInfo, diffIDResult.digest, nil } // copyLayerFromStream is an implementation detail of copyLayer; mostly providing a separate “defer” scope. diff --git a/vendor/github.com/opencontainers/runtime-tools/generate/generate.go b/vendor/github.com/opencontainers/runtime-tools/generate/generate.go index 900278f9f..955a9d5f9 100644 --- a/vendor/github.com/opencontainers/runtime-tools/generate/generate.go +++ b/vendor/github.com/opencontainers/runtime-tools/generate/generate.go @@ -162,7 +162,7 @@ func New(os string) (generator Generator, err error) { Destination: "/proc", Type: "proc", Source: "proc", - Options: nil, + Options: []string{"nosuid", "noexec", "nodev"}, }, { Destination: "/dev", diff --git a/version/version.go b/version/version.go index 7943adee4..fc6a6a1f9 100644 --- a/version/version.go +++ b/version/version.go @@ -4,4 +4,4 @@ package version // NOTE: remember to bump the version at the top // of the top-level README.md file when this is // bumped. -const Version = "0.9.2-dev" +const Version = "0.9.4-dev" |