diff options
37 files changed, 472 insertions, 215 deletions
diff --git a/.github/workflows/multi-arch-build.yaml b/.github/workflows/multi-arch-build.yaml index 9bd98078b..f364cd6c6 100644 --- a/.github/workflows/multi-arch-build.yaml +++ b/.github/workflows/multi-arch-build.yaml @@ -1,6 +1,6 @@ --- -# Please see contrib/podmanimage/README.md for details on the intentions +# Please see contrib/<reponame>image/README.md for details on the intentions # of this workflow. # # BIG FAT WARNING: This workflow is duplicated across containers/skopeo, @@ -11,7 +11,7 @@ name: build multi-arch images on: - # Upstream podman tends to be very active, with many merges per day. + # Upstream tends to be very active, with many merges per day. # Only run this daily via cron schedule, or manually, not by branch push. schedule: - cron: '0 8 * * *' @@ -20,19 +20,23 @@ on: jobs: multi: - name: multi-arch Podman build + name: multi-arch image build env: - PODMAN_QUAY_REGISTRY: quay.io/podman + REPONAME: podman # No easy way to parse this out of $GITHUB_REPOSITORY + # Server/namespace value used to format FQIN + REPONAME_QUAY_REGISTRY: quay.io/podman CONTAINERS_QUAY_REGISTRY: quay.io/containers # list of architectures for build PLATFORMS: linux/amd64,linux/s390x,linux/ppc64le,linux/arm64 + # Command to execute in container to obtain project version number + VERSION_CMD: "podman --version" # build several images (upstream, testing, stable) in parallel strategy: # By default, failure of one matrix item cancels all others fail-fast: false matrix: - # Builds are located under contrib/podmanimage/<source> directory + # Builds are located under contrib/<reponame>image/<source> directory source: - upstream - testing @@ -57,14 +61,14 @@ jobs: driver-opts: network=host install: true - - name: Build and locally push Podman + - name: Build and locally push image uses: docker/build-push-action@v2 with: - context: contrib/podmanimage/${{ matrix.source }} - file: ./contrib/podmanimage/${{ matrix.source }}/Dockerfile + context: contrib/${{ env.REPONAME }}image/${{ matrix.source }} + file: ./contrib/${{ env.REPONAME }}image/${{ matrix.source }}/Dockerfile platforms: ${{ env.PLATFORMS }} push: true - tags: localhost:5000/podman/${{ matrix.source }} + tags: localhost:5000/${{ env.REPONAME }}/${{ matrix.source }} # Simple verification that stable images work, and # also grab version number use in forming the FQIN. @@ -73,41 +77,41 @@ jobs: id: sniff_test run: | podman pull --tls-verify=false \ - localhost:5000/podman/${{ matrix.source }} - VERSION_OUTPUT="$(podman run \ - localhost:5000/podman/${{ matrix.source }} \ - podman --storage-driver=vfs version)" + localhost:5000/$REPONAME/${{ matrix.source }} + VERSION_OUTPUT=$(podman run \ + localhost:5000/$REPONAME/${{ matrix.source }} \ + $VERSION_CMD) echo "$VERSION_OUTPUT" - VERSION=$(grep -Em1 '^Version: ' <<<"$VERSION_OUTPUT" | awk '{print $2}') + VERSION=$(awk -r -e "/^${REPONAME} version /"'{print $3}' <<<"$VERSION_OUTPUT") test -n "$VERSION" - echo "::set-output name=version::${VERSION}" + echo "::set-output name=version::$VERSION" - - name: Generate podman reg. image FQIN(s) - id: podman_reg + - name: Generate image FQIN(s) to push + id: gen_fqin run: | if [[ "${{ matrix.source }}" == 'stable' ]]; then - # The `podman version` in image just built + # The command version in image just built VERSION='v${{ steps.sniff_test.outputs.version }}' # workaround vim syntax-highlight bug: ' # Image tags previously pushed to quay ALLTAGS=$(skopeo list-tags \ - docker://$PODMAN_QUAY_REGISTRY/stable | \ + docker://$REPONAME_QUAY_REGISTRY/stable | \ jq -r '.Tags[]') - # New version? Push quay.io/podman/stable:vX.X.X and :latest + # New version? Push quay.io/$REPONAME/stable:vX.X.X and :latest if ! fgrep -qx "$VERSION" <<<"$ALLTAGS"; then # Assume version-tag is also the most up to date (i.e. "latest") - FQIN="$PODMAN_QUAY_REGISTRY/stable:$VERSION,$PODMAN_QUAY_REGISTRY/stable:latest" + FQIN="$REPONAME_QUAY_REGISTRY/stable:$VERSION,$REPONAME_QUAY_REGISTRY/stable:latest" else # Not a new version-tagged image # Assume other contents changed, so this is the "new" latest. - FQIN="$PODMAN_QUAY_REGISTRY/stable:latest" + FQIN="$REPONAME_QUAY_REGISTRY/stable:latest" fi elif [[ "${{ matrix.source }}" == 'testing' ]]; then # Assume some contents changed, always push latest testing. - FQIN="$PODMAN_QUAY_REGISTRY/testing:latest" + FQIN="$REPONAME_QUAY_REGISTRY/testing:latest" elif [[ "${{ matrix.source }}" == 'upstream' ]]; then # Assume some contents changed, always push latest upstream. - FQIN="$PODMAN_QUAY_REGISTRY/upstream:latest" + FQIN="$REPONAME_QUAY_REGISTRY/upstream:latest" else echo "::error::Unknown matrix item '${{ matrix.source }}'" exit 1 @@ -126,14 +130,14 @@ jobs: VERSION='v${{ steps.sniff_test.outputs.version }}' # workaround vim syntax-highlight bug: ' ALLTAGS=$(skopeo list-tags \ - docker://$CONTAINERS_QUAY_REGISTRY/podman | \ + docker://$CONTAINERS_QUAY_REGISTRY/$REPONAME | \ jq -r '.Tags[]') - # New version? Push quay.io/containers/podman:vX.X.X and latest + # New version? Push quay.io/containers/$REPONAME:vX.X.X and latest if ! fgrep -qx "$VERSION" <<<"$ALLTAGS"; then - FQIN="$CONTAINERS_QUAY_REGISTRY/podman:$VERSION,$CONTAINERS_QUAY_REGISTRY/podman:latest" + FQIN="$CONTAINERS_QUAY_REGISTRY/$REPONAME:$VERSION,$CONTAINERS_QUAY_REGISTRY/$REPONAME:latest" else # Not a new version-tagged image, only update latest. - FQIN="$CONTAINERS_QUAY_REGISTRY/podman:latest" + FQIN="$CONTAINERS_QUAY_REGISTRY/$REPONAME:latest" fi echo "::warning::Pushing $FQIN" echo "::set-output name=fqin::${FQIN}" @@ -153,40 +157,39 @@ jobs: DELIMITER EOF - # Separate steps to login and push for podman and containers quay - # repositories are required, because 2 sets of credentials are used and `docker - # login` as well as `podman login` do not support having 2 different - # credential sets for 1 registry. - # At the same time reuse of non-shell steps is not supported by Github Actions - # via anchors or composite actions + # Separate steps to login and push for $REPONAME_QUAY_REGISTRY and + # $CONTAINERS_QUAY_REGISTRY are required, because 2 sets of credentials + # are used and namespaced within the registry. At the same time, reuse + # of non-shell steps is not supported by Github Actions nor are YAML + # anchors/aliases, nor composite actions. - # Push to 'podman' Quay repo for stable, testing. and upstream - - name: Login to 'podman' Quay registry + # Push to $REPONAME_QUAY_REGISTRY for stable, testing. and upstream + - name: Login to ${{ env.REPONAME_QUAY_REGISTRY }} uses: docker/login-action@v1 - if: steps.podman_reg.outputs.push == 'true' + if: steps.gen_fqin.outputs.push == 'true' with: - registry: ${{ env.PODMAN_QUAY_REGISTRY }} + registry: ${{ env.REPONAME_QUAY_REGISTRY }} # N/B: Secrets are not passed to workflows that are triggered # by a pull request from a fork - username: ${{ secrets.PODMAN_QUAY_USERNAME }} - password: ${{ secrets.PODMAN_QUAY_PASSWORD }} + username: ${{ secrets.REPONAME_QUAY_USERNAME }} + password: ${{ secrets.REPONAME_QUAY_PASSWORD }} - - name: Push images to 'podman' Quay + - name: Push images to ${{ steps.gen_fqin.outputs.fqin }} uses: docker/build-push-action@v2 - if: steps.podman_reg.outputs.push == 'true' + if: steps.gen_fqin.outputs.push == 'true' with: - cache-from: type=registry,ref=localhost:5000/podman/${{ matrix.source }} + cache-from: type=registry,ref=localhost:5000/${{ env.REPONAME }}/${{ matrix.source }} cache-to: type=inline - context: contrib/podmanimage/${{ matrix.source }} - file: ./contrib/podmanimage/${{ matrix.source }}/Dockerfile + context: contrib/${{ env.REPONAME }}image/${{ matrix.source }} + file: ./contrib/${{ env.REPONAME }}image/${{ matrix.source }}/Dockerfile platforms: ${{ env.PLATFORMS }} push: true - tags: ${{ steps.podman_reg.outputs.fqin }} + tags: ${{ steps.gen_fqin.outputs.fqin }} labels: | ${{ env.LABELS }} - # Push to 'containers' Quay repo only stable podman - - name: Login to 'containers' Quay registry + # Push to $CONTAINERS_QUAY_REGISTRY only stable + - name: Login to ${{ env.CONTAINERS_QUAY_REGISTRY }} if: steps.containers_reg.outputs.push == 'true' uses: docker/login-action@v1 with: @@ -194,14 +197,14 @@ jobs: username: ${{ secrets.CONTAINERS_QUAY_USERNAME }} password: ${{ secrets.CONTAINERS_QUAY_PASSWORD }} - - name: Push images to 'containers' Quay + - name: Push images to ${{ steps.containers_reg.outputs.fqin }} if: steps.containers_reg.outputs.push == 'true' uses: docker/build-push-action@v2 with: - cache-from: type=registry,ref=localhost:5000/podman/${{ matrix.source }} + cache-from: type=registry,ref=localhost:5000/${{ env.REPONAME }}/${{ matrix.source }} cache-to: type=inline - context: contrib/podmanimage/${{ matrix.source }} - file: ./contrib/podmanimage/${{ matrix.source }}/Dockerfile + context: contrib/${{ env.REPONAME }}image/${{ matrix.source }} + file: ./contrib/${{ env.REPONAME }}image/${{ matrix.source }}/Dockerfile platforms: ${{ env.PLATFORMS }} push: true tags: ${{ steps.containers_reg.outputs.fqin }} @@ -261,7 +261,7 @@ codespell: codespell -S bin,vendor,.git,go.sum,changelog.txt,.cirrus.yml,"RELEASE_NOTES.md,*.xz,*.gz,*.tar,*.tgz,bin2img,*ico,*.png,*.1,*.5,copyimg,*.orig,apidoc.go" -L uint,iff,od,seeked,splitted,marge,ERRO,hist,ether -w .PHONY: validate -validate: gofmt lint .gitvalidation validate.completions man-page-check swagger-check tests-included +validate: gofmt lint .gitvalidation validate.completions man-page-check swagger-check tests-included tests-expect-exit .PHONY: build-all-new-commits build-all-new-commits: @@ -605,6 +605,16 @@ test-binaries: test/checkseccomp/checkseccomp test/goecho/goecho install.cataton tests-included: contrib/cirrus/pr-should-include-tests +.PHONY: tests-expect-exit +tests-expect-exit: + @if egrep 'Expect.*ExitCode' test/e2e/*.go | egrep -v ', ".*"\)'; then \ + echo "^^^ Unhelpful use of Expect(ExitCode())"; \ + echo " Please use '.Should(Exit(...))' pattern instead."; \ + echo " If that's not possible, please add an annotation (description) to your assertion:"; \ + echo " Expect(...).To(..., \"Friendly explanation of this check\")"; \ + exit 1; \ + fi + ### ### Release/Packaging targets ### diff --git a/cmd/podman/common/create.go b/cmd/podman/common/create.go index 64d1956eb..96414add4 100644 --- a/cmd/podman/common/create.go +++ b/cmd/podman/common/create.go @@ -655,15 +655,6 @@ func DefineCreateFlags(cmd *cobra.Command, cf *ContainerCLIOpts) { ) _ = cmd.RegisterFlagCompletionFunc(stopTimeoutFlagName, completion.AutocompleteNone) - storageOptFlagName := "storage-opt" - createFlags.StringSliceVar( - &cf.StorageOpt, - storageOptFlagName, []string{}, - "Storage driver options per container", - ) - //FIXME: What should we suggest here? The flag is not in the man page. - _ = cmd.RegisterFlagCompletionFunc(storageOptFlagName, completion.AutocompleteNone) - subgidnameFlagName := "subgidname" createFlags.StringVar( &cf.SubUIDName, diff --git a/cmd/podman/containers/create.go b/cmd/podman/containers/create.go index df0fa6f9d..c63c074f7 100644 --- a/cmd/podman/containers/create.go +++ b/cmd/podman/containers/create.go @@ -146,6 +146,8 @@ func replaceContainer(name string) error { } func createInit(c *cobra.Command) error { + cliVals.StorageOpt = registry.PodmanConfig().StorageOpts + if c.Flag("shm-size").Changed { cliVals.ShmSize = c.Flag("shm-size").Value.String() } diff --git a/cmd/podman/images/import.go b/cmd/podman/images/import.go index bed2d4105..bc80417cc 100644 --- a/cmd/podman/images/import.go +++ b/cmd/podman/images/import.go @@ -3,6 +3,9 @@ package images import ( "context" "fmt" + "io" + "io/ioutil" + "os" "strings" "github.com/containers/common/pkg/completion" @@ -97,6 +100,22 @@ func importCon(cmd *cobra.Command, args []string) error { default: return errors.Errorf("too many arguments. Usage TARBALL [REFERENCE]") } + + if source == "-" { + outFile, err := ioutil.TempFile("", "podman") + if err != nil { + return errors.Errorf("error creating file %v", err) + } + defer os.Remove(outFile.Name()) + defer outFile.Close() + + _, err = io.Copy(outFile, os.Stdin) + if err != nil { + return errors.Errorf("error copying file %v", err) + } + source = outFile.Name() + } + errFileName := parse.ValidateFileName(source) errURL := parse.ValidURL(source) if errURL == nil { diff --git a/cmd/podman/parse/net.go b/cmd/podman/parse/net.go index f93c4ab1e..870690db3 100644 --- a/cmd/podman/parse/net.go +++ b/cmd/podman/parse/net.go @@ -180,9 +180,12 @@ func ValidateFileName(filename string) error { // ValidURL checks a string urlStr is a url or not func ValidURL(urlStr string) error { - _, err := url.ParseRequestURI(urlStr) + url, err := url.ParseRequestURI(urlStr) if err != nil { - return errors.Wrapf(err, "invalid url path: %q", urlStr) + return errors.Wrapf(err, "invalid url %q", urlStr) + } + if url.Scheme == "" { + return errors.Errorf("invalid url %q: missing scheme", urlStr) } return nil } diff --git a/cmd/podman/root.go b/cmd/podman/root.go index 9e5d2a236..2633e4040 100644 --- a/cmd/podman/root.go +++ b/cmd/podman/root.go @@ -342,10 +342,6 @@ func rootFlags(cmd *cobra.Command, opts *entities.PodmanConfig) { pFlags.StringVar(&opts.StorageDriver, storageDriverFlagName, "", "Select which storage driver is used to manage storage of images and containers (default is overlay)") _ = cmd.RegisterFlagCompletionFunc(storageDriverFlagName, completion.AutocompleteNone) //TODO: what can we recommend here? - storageOptFlagName := "storage-opt" - pFlags.StringArrayVar(&opts.StorageOpts, storageOptFlagName, []string{}, "Used to pass an option to the storage driver") - _ = cmd.RegisterFlagCompletionFunc(storageOptFlagName, completion.AutocompleteNone) - tmpdirFlagName := "tmpdir" pFlags.StringVar(&opts.Engine.TmpDir, tmpdirFlagName, "", "Path to the tmp directory for libpod state content.\n\nNote: use the environment variable 'TMPDIR' to change the temporary storage location for container images, '/var/tmp'.\n") _ = cmd.RegisterFlagCompletionFunc(tmpdirFlagName, completion.AutocompleteDefault) @@ -365,6 +361,10 @@ func rootFlags(cmd *cobra.Command, opts *entities.PodmanConfig) { } } } + storageOptFlagName := "storage-opt" + pFlags.StringArrayVar(&opts.StorageOpts, storageOptFlagName, []string{}, "Used to pass an option to the storage driver") + _ = cmd.RegisterFlagCompletionFunc(storageOptFlagName, completion.AutocompleteNone) + // Override default --help information of `--help` global flag var dummyHelp bool pFlags.BoolVar(&dummyHelp, "help", false, "Help for podman") diff --git a/docs/source/includes.rst b/docs/source/includes.rst index 6e04d77f4..8d5f18e4d 100644 --- a/docs/source/includes.rst +++ b/docs/source/includes.rst @@ -16,4 +16,4 @@ .. _podman run: http://docs.podman.io/en/latest/markdown/podman-run.1.html .. _podman build: http://docs.podman.io/en/latest/markdown/podman-build.1.html .. _podman push: http://docs.podman.io/en/latest/markdown/podman-push.1.html -.. image:: https://github.com/containers/podman/blob/main/logo/podman-logo.png?raw=true +.. image:: https://raw.githubusercontent.com/containers/podman/main/logo/podman-logo.png diff --git a/docs/source/markdown/podman-container-runlabel.1.md b/docs/source/markdown/podman-container-runlabel.1.md index e343a12fe..ec67a2687 100644 --- a/docs/source/markdown/podman-container-runlabel.1.md +++ b/docs/source/markdown/podman-container-runlabel.1.md @@ -1,76 +1,58 @@ % podman-container-runlabel(1) ## NAME -podman-container-runlabel - Executes a command as described by a container image label +podman-container-runlabel - Executes a command as described by a container-image label ## SYNOPSIS **podman container runlabel** [*options*] *label* *image* [*arg...*] ## DESCRIPTION -**podman container runlabel** reads the provided `LABEL` field in the container -IMAGE and executes the provided value for the label as a command. If this field does not -exist, `podman container runlabel` will just exit. +**podman container runlabel** reads the specified `label` of the `image` and executes it as command on the host. If the label does not exist, Podman will exit with an error. Additional arguments will be appended to the command. -If the container image has a LABEL INSTALL instruction like the following: +Historically, container images describe the contents (e.g., layers) and how a container runtime (e.g., crun(1) or runc(1)) should execute the container. For instance, an image may set the environment and the command in its configuration. However, a container image cannot directly specify how a container engine such as Podman should execute it. For instance, an image configuration does not include information about log drivers, namespaces or which capabilities it needs to run correctly. -`LABEL INSTALL /usr/bin/podman run -t -i --rm \${OPT1} --privileged -v /:/host --net=host --ipc=host --pid=host -e HOST=/host -e NAME=\${NAME} -e IMAGE=\${IMAGE} -e CONFDIR=/etc/\${NAME} -e LOGDIR=/var/log/\${NAME} -e DATADIR=/var/lib/\${NAME} \${IMAGE} \${OPT2} /bin/install.sh \${OPT3}` +`podman container runlabel` addresses the limitation of container images in a simple yet efficient way. Podman will read the contents of the label and interpret it as a command that will be executed on the host. This way an image can describe exactly how it should be executed by Podman. For instance, a label with the content `/usr/bin/podman run -d --pid=host --privileged \${IMAGE}` instructs the image to be executed in a detached, privileged container that is using the PID namespace of the host. This lifts the self-description of a container image from "what" to "how". -`podman container runlabel` will set the following environment variables for use in the command: +Please note that the `runlabel` command is intended to be run in trusted environments exclusively. Using the command on untrusted images is not recommended. -If the container image does not have the desired label, an error message will be displayed along with a non-zero -return code. If the image is not found in local storage, Podman will attempt to pull it first. +## VARIABLES -**LABEL** -The label name specified via the command. +The contents of a label may refer to the following variables which will be substituted while processing the label. **IMAGE** -Image name specified via the command. +The name of the image. When executing `podman container runlabel label fedora` the `IMAGE` variable will be replaced with `fedora`. Valid formats are `IMAGE`, `$IMAGE`, `${IMAGE}` and `=IMAGE`. -**SUDO_UID** -The `SUDO_UID` environment variable. This is useful with the podman -`-u` option for user space tools. If the environment variable is -not available, the value of `/proc/self/loginuid` is used. +**NAME** +As specified by the `--name` option. The format is identical to the one of the IMAGE attribute. -**SUDO_GID** -The `SUDO_GID` environment variable. This is useful with the podman -`-u` option for user space tools. If the environment variable is -not available, the default GID of the value for `SUDO_UID` is used. -If this value is not available, the value of `/proc/self/loginuid` -is used. - -Any additional arguments will be appended to the command. +**PWD** +Will be replaced with the current working directory. ## OPTIONS #### **--authfile**=*path* -Path of the authentication file. Default is ${XDG\_RUNTIME\_DIR}/containers/auth.json, which is set using `podman login`. -If the authorization state is not found there, $HOME/.docker/config.json is checked, which is set using `docker login`. +Path of the containers-auth.json(5) file. Default is ${XDG\_RUNTIME\_DIR}/containers/auth.json, which is set using `podman login`. If the authorization state is not found there, $HOME/.docker/config.json is checked, which is set using `docker login`. -Note: You can also override the default path of the authentication file by setting the REGISTRY\_AUTH\_FILE -environment variable. `export REGISTRY_AUTH_FILE=path` +Note: You can also override the default path of the authentication file by setting the REGISTRY\_AUTH\_FILE environment variable. `export REGISTRY_AUTH_FILE=path` #### **--display** -Display the label's value of the image having populated its environment variables. -The runlabel command will not execute if --display is specified. +Display the label's value of the image having populated its environment variables. The runlabel command will not execute if --display is specified. #### **--cert-dir**=*path* -Use certificates at *path* (\*.crt, \*.cert, \*.key) to connect to the registry. -Please refer to containers-certs.d(5) for details. (This option is not available with the remote Podman client) +Use certificates at *path* (\*.crt, \*.cert, \*.key) to connect to the registry. Please refer to containers-certs.d(5) for details. (This option is not available with the remote Podman client) #### **--creds**=*[username[:password]]* -The [username[:password]] to use to authenticate with the registry if required. -If one or both values are not supplied, a command line prompt will appear and the -value can be entered. The password is entered without echo. +The [username[:password]] to use to authenticate with the registry if required. If one or both values are not supplied, a command line prompt will appear and the value can be entered. The password is entered without echo. #### **--help**, **-h** Print usage statement #### **--name**, **-n**=*name* -Use this name for creating content for the container. NAME will default to the IMAGENAME if it is not specified. +Use this name for creating content for the container. If not specified, name defaults to the name of the image. #### **--quiet**, **-q** @@ -78,34 +60,33 @@ Suppress output information when pulling images #### **--replace** -If a container exists of the default or given name, as needed it will be stopped, deleted and a new container will be -created from this image. +If a container exists of the default or given name, as needed it will be stopped, deleted and a new container will be created from this image. #### **--tls-verify** -Require HTTPS and verify certificates when contacting registries (default: true). If explicitly set to true, -then TLS verification will be used. If set to false, then TLS verification will not be used. If not specified, -TLS verification will be used unless the target registry is listed as an insecure registry in registries.conf. +Require HTTPS and verify certificates when contacting registries (default: true). If explicitly set to true, then TLS verification will be used. If set to false, then TLS verification will not be used. If not specified, TLS verification will be used unless the target registry is listed as an insecure registry in containers-registries.conf(5). ## EXAMPLES -Execute the run label of an image called foobar. +Execute the `run` label of an image called foobar. ``` -$ sudo podman container runlabel run foobar +$ podman container runlabel run foobar ``` -Execute the install label of an image called foobar with additional arguments. +Execute the `install` label of an image called foobar with additional arguments. ``` -$ sudo podman container runlabel install foobar apples oranges +$ podman container runlabel install foobar apples oranges ``` -Display the command that would be executed by runlabel. +Display the contents of the `run` label of image foobar. ``` -$ sudo podman container runlabel --display run foobar +$ podman container runlabel --display run foobar ``` ## SEE ALSO -podman(1), containers-certs.d(5) +podman(1), crun(1), runc(1), containers-auth.json(5), containers-certs.d(5), containers-registries.conf(5) ## HISTORY +August 2021, Refinements by Valentin Rothberg (rothberg at redhat dot com) + September 2018, Originally compiled by Brent Baude (bbaude at redhat dot com) diff --git a/docs/source/markdown/podman-container.1.md b/docs/source/markdown/podman-container.1.md index e69c5a170..3cc90d9ec 100644 --- a/docs/source/markdown/podman-container.1.md +++ b/docs/source/markdown/podman-container.1.md @@ -38,7 +38,7 @@ The container command allows you to manage containers | restore | [podman-container-restore(1)](podman-container-restore.1.md) | Restores one or more containers from a checkpoint. | | rm | [podman-rm(1)](podman-rm.1.md) | Remove one or more containers. | | run | [podman-run(1)](podman-run.1.md) | Run a command in a container. | -| runlabel | [podman-container-runlabel(1)](podman-container-runlabel.1.md) | Executes a command as described by a container image label. | +| runlabel | [podman-container-runlabel(1)](podman-container-runlabel.1.md) | Executes a command as described by a container-image label. | | start | [podman-start(1)](podman-start.1.md) | Starts one or more containers. | | stats | [podman-stats(1)](podman-stats.1.md) | Display a live stream of one or more container's resource usage statistics. | | stop | [podman-stop(1)](podman-stop.1.md) | Stop one or more running containers. | diff --git a/docs/source/markdown/podman-create.1.md b/docs/source/markdown/podman-create.1.md index 1720e6eb6..7f9cf0e75 100644 --- a/docs/source/markdown/podman-create.1.md +++ b/docs/source/markdown/podman-create.1.md @@ -181,6 +181,8 @@ Limit the CPU real-time period in microseconds Limit the container's Real Time CPU usage. This flag tell the kernel to restrict the container's Real Time CPU usage to the period you specify. +This flag is not supported on cgroups V2 systems. + #### **--cpu-rt-runtime**=*microseconds* Limit the CPU real-time runtime in microseconds @@ -190,6 +192,8 @@ Period of 1,000,000us and Runtime of 950,000us means that this container could c The sum of all runtimes across containers cannot exceed the amount allotted to the parent cgroup. +This flag is not supported on cgroups V2 systems. + #### **--cpu-shares**=*shares* CPU shares (relative weight) @@ -479,6 +483,8 @@ is not limited. If you specify a limit, it may be rounded up to a multiple of the operating system's page size and the value can be very large, millions of trillions. +This flag is not supported on cgroups V2 systems. + #### **--label**, **-l**=*label* Add metadata to a container (e.g., --label com.example.key=value) @@ -561,6 +567,8 @@ unit, `b` is used. Set LIMIT to `-1` to enable unlimited swap. Tune a container's memory swappiness behavior. Accepts an integer between 0 and 100. +This flag is not supported on cgroups V2 systems. + #### **--mount**=*type=TYPE,TYPE-SPECIFIC-OPTION[,...]* Attach a filesystem mount to the container diff --git a/docs/source/markdown/podman-run.1.md b/docs/source/markdown/podman-run.1.md index ce0cf1a2f..f08561904 100644 --- a/docs/source/markdown/podman-run.1.md +++ b/docs/source/markdown/podman-run.1.md @@ -199,6 +199,8 @@ Limit the CPU real-time period in microseconds. Limit the container's Real Time CPU usage. This flag tell the kernel to restrict the container's Real Time CPU usage to the period you specify. +This flag is not supported on cgroups V2 systems. + #### **--cpu-rt-runtime**=*microseconds* Limit the CPU real-time runtime in microseconds. @@ -208,6 +210,8 @@ Period of 1,000,000us and Runtime of 950,000us means that this container could c The sum of all runtimes across containers cannot exceed the amount allotted to the parent cgroup. +This flag is not supported on cgroups V2 systems. + #### **--cpu-shares**=*shares* CPU shares (relative weight). @@ -518,6 +522,8 @@ is not limited. If you specify a limit, it may be rounded up to a multiple of the operating system's page size and the value can be very large, millions of trillions. +This flag is not supported on cgroups V2 systems. + #### **--label**, **-l**=*key*=*value* Add metadata to a container. @@ -595,6 +601,8 @@ Set _number_ to **-1** to enable unlimited swap. Tune a container's memory swappiness behavior. Accepts an integer between *0* and *100*. +This flag is not supported on cgroups V2 systems. + #### **--mount**=*type=TYPE,TYPE-SPECIFIC-OPTION[,...]* Attach a filesystem mount to the container diff --git a/docs/source/markdown/podman-volume-ls.1.md b/docs/source/markdown/podman-volume-ls.1.md index 489057446..b562aff61 100644 --- a/docs/source/markdown/podman-volume-ls.1.md +++ b/docs/source/markdown/podman-volume-ls.1.md @@ -24,6 +24,7 @@ Volumes can be filtered by the following attributes: - name - opt - scope +- until #### **--format**=*format* diff --git a/libpod/container_internal.go b/libpod/container_internal.go index 2555f15ec..e7694227a 100644 --- a/libpod/container_internal.go +++ b/libpod/container_internal.go @@ -420,7 +420,6 @@ func (c *Container) setupStorage(ctx context.Context) error { if c.config.Rootfs == "" && (c.config.RootfsImageID == "" || c.config.RootfsImageName == "") { return errors.Wrapf(define.ErrInvalidArg, "must provide image ID and image name to use an image") } - options := storage.ContainerOptions{ IDMappingOptions: storage.IDMappingOptions{ HostUIDMapping: true, diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go index 6c69d1b72..ce4c5d758 100644 --- a/libpod/runtime_ctr.go +++ b/libpod/runtime_ctr.go @@ -47,6 +47,32 @@ func (r *Runtime) NewContainer(ctx context.Context, rSpec *spec.Spec, options .. return r.newContainer(ctx, rSpec, options...) } +func (r *Runtime) PrepareVolumeOnCreateContainer(ctx context.Context, ctr *Container) error { + // Copy the content from the underlying image into the newly created + // volume if configured to do so. + if !r.config.Containers.PrepareVolumeOnCreate { + return nil + } + + defer func() { + if err := ctr.cleanupStorage(); err != nil { + logrus.Errorf("error cleaning up container storage %s: %v", ctr.ID(), err) + } + }() + + mountPoint, err := ctr.mountStorage() + if err == nil { + // Finish up mountStorage + ctr.state.Mounted = true + ctr.state.Mountpoint = mountPoint + if err = ctr.save(); err != nil { + logrus.Errorf("Error saving container %s state: %v", ctr.ID(), err) + } + } + + return err +} + // RestoreContainer re-creates a container from an imported checkpoint func (r *Runtime) RestoreContainer(ctx context.Context, rSpec *spec.Spec, config *ContainerConfig) (*Container, error) { r.lock.Lock() diff --git a/pkg/api/handlers/libpod/containers_create.go b/pkg/api/handlers/libpod/containers_create.go index b92588346..65951861b 100644 --- a/pkg/api/handlers/libpod/containers_create.go +++ b/pkg/api/handlers/libpod/containers_create.go @@ -22,6 +22,7 @@ func CreateContainer(w http.ResponseWriter, r *http.Request) { utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "Decode()")) return } + warn, err := generate.CompleteSpec(r.Context(), runtime, &sg) if err != nil { utils.InternalServerError(w, err) diff --git a/pkg/api/server/docs.go b/pkg/api/server/docs.go index e72b78221..bf15afbf9 100644 --- a/pkg/api/server/docs.go +++ b/pkg/api/server/docs.go @@ -42,7 +42,7 @@ // // InfoExtensions: // x-logo: -// - url: https://raw.githubusercontent.com/containers/libpod/master/logo/podman-logo.png +// - url: https://raw.githubusercontent.com/containers/libpod/main/logo/podman-logo.png // - altText: "Podman logo" // // Produces: diff --git a/pkg/api/server/register_volumes.go b/pkg/api/server/register_volumes.go index d58bf0662..fb02cffcf 100644 --- a/pkg/api/server/register_volumes.go +++ b/pkg/api/server/register_volumes.go @@ -68,6 +68,7 @@ func (s *APIServer) registerVolumeHandlers(r *mux.Router) error { // - label=<key> or label=<key>:<value> Matches volumes based on the presence of a label alone or a label and a value. // - name=<volume-name> Matches all of volume name. // - opt=<driver-option> Matches a storage driver options + // - `until=<timestamp>` List volumes created before this timestamp. The `<timestamp>` can be Unix timestamps, date formatted timestamps, or Go duration strings (e.g. `10m`, `1h30m`) computed relative to the daemon machine’s time. // responses: // '200': // "$ref": "#/responses/VolumeList" @@ -166,6 +167,7 @@ func (s *APIServer) registerVolumeHandlers(r *mux.Router) error { // - driver=<volume-driver-name> Matches volumes based on their driver. // - label=<key> or label=<key>:<value> Matches volumes based on the presence of a label alone or a label and a value. // - name=<volume-name> Matches all of volume name. + // - `until=<timestamp>` List volumes created before this timestamp. The `<timestamp>` can be Unix timestamps, date formatted timestamps, or Go duration strings (e.g. `10m`, `1h30m`) computed relative to the daemon machine’s time. // // Note: // The boolean `dangling` filter is not yet implemented for this endpoint. diff --git a/pkg/domain/filters/volumes.go b/pkg/domain/filters/volumes.go index df23c31c0..d55c44ef5 100644 --- a/pkg/domain/filters/volumes.go +++ b/pkg/domain/filters/volumes.go @@ -51,6 +51,12 @@ func GenerateVolumeFilters(filters url.Values) ([]libpod.VolumeFilter, error) { } return false }) + case "until": + f, err := createUntilFilterVolumeFunction(val) + if err != nil { + return nil, err + } + vf = append(vf, f) case "dangling": danglingVal := val invert := false @@ -93,16 +99,11 @@ func GeneratePruneVolumeFilters(filters url.Values) ([]libpod.VolumeFilter, erro return util.MatchLabelFilters([]string{filterVal}, v.Labels()) }) case "until": - until, err := util.ComputeUntilTimestamp([]string{filterVal}) + f, err := createUntilFilterVolumeFunction(filterVal) if err != nil { return nil, err } - vf = append(vf, func(v *libpod.Volume) bool { - if !until.IsZero() && v.CreatedTime().Before(until) { - return true - } - return false - }) + vf = append(vf, f) default: return nil, errors.Errorf("%q is an invalid volume filter", filter) } @@ -110,3 +111,16 @@ func GeneratePruneVolumeFilters(filters url.Values) ([]libpod.VolumeFilter, erro } return vf, nil } + +func createUntilFilterVolumeFunction(filter string) (libpod.VolumeFilter, error) { + until, err := util.ComputeUntilTimestamp([]string{filter}) + if err != nil { + return nil, err + } + return func(v *libpod.Volume) bool { + if !until.IsZero() && v.CreatedTime().Before(until) { + return true + } + return false + }, nil +} diff --git a/pkg/specgen/generate/container_create.go b/pkg/specgen/generate/container_create.go index b569f8390..4e3a86ae4 100644 --- a/pkg/specgen/generate/container_create.go +++ b/pkg/specgen/generate/container_create.go @@ -153,7 +153,15 @@ func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGener if err != nil { return nil, err } - return rt.NewContainer(ctx, runtimeSpec, options...) + + ctr, err := rt.NewContainer(ctx, runtimeSpec, options...) + if err != nil { + return ctr, err + } + + // Copy the content from the underlying image into the newly created + // volume if configured to do so. + return ctr, rt.PrepareVolumeOnCreateContainer(ctx, ctr) } func extractCDIDevices(s *specgen.SpecGenerator) []libpod.CtrCreateOption { diff --git a/pkg/specgen/generate/kube/kube.go b/pkg/specgen/generate/kube/kube.go index 37cacdaa3..fb7eb99a2 100644 --- a/pkg/specgen/generate/kube/kube.go +++ b/pkg/specgen/generate/kube/kube.go @@ -276,10 +276,11 @@ func ToSpecGen(ctx context.Context, opts *CtrSpecGenOptions) (*specgen.SpecGener return nil, err } + volume.MountPath = dest switch volumeSource.Type { case KubeVolumeTypeBindMount: mount := spec.Mount{ - Destination: dest, + Destination: volume.MountPath, Source: volumeSource.Source, Type: "bind", Options: options, @@ -287,7 +288,7 @@ func ToSpecGen(ctx context.Context, opts *CtrSpecGenOptions) (*specgen.SpecGener s.Mounts = append(s.Mounts, mount) case KubeVolumeTypeNamed: namedVolume := specgen.NamedVolume{ - Dest: dest, + Dest: volume.MountPath, Name: volumeSource.Source, Options: options, } @@ -330,12 +331,16 @@ func parseMountPath(mountPath string, readOnly bool) (string, []string, error) { options = strings.Split(splitVol[1], ",") } if err := parse.ValidateVolumeCtrDir(dest); err != nil { - return "", options, errors.Wrapf(err, "error in parsing MountPath") + return "", options, errors.Wrapf(err, "parsing MountPath") } if readOnly { options = append(options, "ro") } - return dest, options, nil + opts, err := parse.ValidateVolumeOpts(options) + if err != nil { + return "", opts, errors.Wrapf(err, "parsing MountOptions") + } + return dest, opts, nil } func setupLivenessProbe(s *specgen.SpecGenerator, containerYAML v1.Container, restartPolicy string) error { diff --git a/test/README.md b/test/README.md index d7710cc95..769bdbfd7 100644 --- a/test/README.md +++ b/test/README.md @@ -84,7 +84,7 @@ file itself. Consider the following actual test: It("podman inspect bogus pod", func() { session := podmanTest.Podman([]string{"pod", "inspect", "foobar"}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Not(Equal(0))) + Expect(session).To(ExitWithError()) }) ``` diff --git a/test/apiv2/30-volumes.at b/test/apiv2/30-volumes.at index b639e05f9..fd1542293 100644 --- a/test/apiv2/30-volumes.at +++ b/test/apiv2/30-volumes.at @@ -174,6 +174,8 @@ t POST libpod/volumes/create \ # with date way back in the past, volume should not be deleted (compat api) t POST volumes/prune?filters='{"until":["500000"]}' 200 t GET libpod/volumes/json?filters='{"label":["testuntilcompat"]}' 200 length=1 +t GET libpod/volumes/json?filters='{"until":["500000"]}' 200 length=0 +t GET libpod/volumes/json?filters='{"until":["5000000000"]}' 200 length=1 # with date far in the future, volume should be deleted (compat api) t POST volumes/prune?filters='{"until":["5000000000"]}' 200 diff --git a/test/e2e/common_test.go b/test/e2e/common_test.go index 5a6cf7ffb..2e48e1763 100644 --- a/test/e2e/common_test.go +++ b/test/e2e/common_test.go @@ -811,7 +811,7 @@ func generateNetworkConfig(p *PodmanTestIntegration) (string, string) { func (p *PodmanTestIntegration) removeCNINetwork(name string) { session := p.Podman([]string{"network", "rm", "-f", name}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(BeNumerically("<=", 1)) + Expect(session.ExitCode()).To(BeNumerically("<=", 1), "Exit code must be 0 or 1") } func (p *PodmanSessionIntegration) jq(jqCommand string) (string, error) { diff --git a/test/e2e/container_create_volume_test.go b/test/e2e/container_create_volume_test.go new file mode 100644 index 000000000..001698239 --- /dev/null +++ b/test/e2e/container_create_volume_test.go @@ -0,0 +1,127 @@ +package integration + +import ( + "fmt" + "io/ioutil" + "os" + "path/filepath" + + . "github.com/containers/podman/v3/test/utils" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/gexec" +) + +func buildDataVolumeImage(pTest *PodmanTestIntegration, image, data, dest string) { + // Create a dummy file for data volume + dummyFile := filepath.Join(pTest.TempDir, data) + err := ioutil.WriteFile(dummyFile, []byte(data), 0644) + Expect(err).To(BeNil()) + + // Create a data volume container image but no CMD binary in it + containerFile := fmt.Sprintf(`FROM scratch +CMD doesnotexist.sh +ADD %s %s/ +VOLUME %s/`, data, dest, dest) + pTest.BuildImage(containerFile, image, "false") +} + +func createContainersConfFile(pTest *PodmanTestIntegration) { + configPath := filepath.Join(pTest.TempDir, "containers.conf") + containersConf := []byte(fmt.Sprintf("[containers]\nprepare_volume_on_create = true\n")) + err := ioutil.WriteFile(configPath, containersConf, os.ModePerm) + Expect(err).To(BeNil()) + + // Set custom containers.conf file + os.Setenv("CONTAINERS_CONF", configPath) + if IsRemote() { + pTest.RestartRemoteService() + } +} + +func checkDataVolumeContainer(pTest *PodmanTestIntegration, image, cont, dest, data string) { + create := pTest.Podman([]string{"create", "--name", cont, image}) + create.WaitWithDefaultTimeout() + Expect(create).Should(Exit(0)) + + inspect := pTest.InspectContainer(cont) + Expect(len(inspect)).To(Equal(1)) + Expect(len(inspect[0].Mounts)).To(Equal(1)) + Expect(inspect[0].Mounts[0].Destination).To(Equal(dest)) + + mntName, mntSource := inspect[0].Mounts[0].Name, inspect[0].Mounts[0].Source + + volList := pTest.Podman([]string{"volume", "list", "--quiet"}) + volList.WaitWithDefaultTimeout() + Expect(volList).Should(Exit(0)) + Expect(len(volList.OutputToStringArray())).To(Equal(1)) + Expect(volList.OutputToStringArray()[0]).To(Equal(mntName)) + + // Check the mount source directory + files, err := ioutil.ReadDir(mntSource) + Expect(err).To(BeNil()) + + if data == "" { + Expect(len(files)).To(Equal(0)) + } else { + Expect(len(files)).To(Equal(1)) + Expect(files[0].Name()).To(Equal(data)) + } +} + +var _ = Describe("Podman create data volume", func() { + var ( + tempdir string + err error + podmanTest *PodmanTestIntegration + ) + + BeforeEach(func() { + tempdir, err = CreateTempDirInTempDir() + if err != nil { + os.Exit(1) + } + podmanTest = PodmanTestCreate(tempdir) + podmanTest.Setup() + podmanTest.SeedImages() + }) + + AfterEach(func() { + podmanTest.Cleanup() + f := CurrentGinkgoTestDescription() + processTestResult(f) + os.Unsetenv("CONTAINERS_CONF") + }) + + It("podman create with volume data copy turned off", func() { + imgName, volData, volDest := "dataimg", "dummy", "/test" + + buildDataVolumeImage(podmanTest, imgName, volData, volDest) + + // Create a container with the default containers.conf and + // check that the volume is not copied from the image. + checkDataVolumeContainer(podmanTest, imgName, "ctr-nocopy", volDest, "") + }) + + It("podman create with volume data copy turned on", func() { + imgName, volData, volDest := "dataimg", "dummy", "/test" + + buildDataVolumeImage(podmanTest, imgName, volData, volDest) + + // Create a container with the custom containers.conf and + // check that the volume is copied from the image. + createContainersConfFile(podmanTest) + + checkDataVolumeContainer(podmanTest, imgName, "ctr-copy", volDest, volData) + }) + + It("podman run with volume data copy turned on", func() { + // Create a container with the custom containers.conf and + // check that the container is run successfully + createContainersConfFile(podmanTest) + + session := podmanTest.Podman([]string{"run", "--rm", ALPINE, "echo"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + }) +}) diff --git a/test/e2e/pod_create_test.go b/test/e2e/pod_create_test.go index 63f55fb88..4c6788b9d 100644 --- a/test/e2e/pod_create_test.go +++ b/test/e2e/pod_create_test.go @@ -566,11 +566,11 @@ ENTRYPOINT ["sleep","99999"] ns := "ns:/proc/self/ns/" podCreate := podmanTest.Podman([]string{"pod", "create", "--pid", ns, "--name", podName, "--share", "pid"}) podCreate.WaitWithDefaultTimeout() - Expect(podCreate.ExitCode()).To(Equal(0)) + Expect(podCreate).Should(Exit(0)) podInspect := podmanTest.Podman([]string{"pod", "inspect", podName}) podInspect.WaitWithDefaultTimeout() - Expect(podInspect.ExitCode()).To(Equal(0)) + Expect(podInspect).Should(Exit(0)) podJSON := podInspect.InspectPodToJSON() Expect(podJSON.InfraConfig.PidNS).To(Equal("path")) @@ -579,11 +579,11 @@ ENTRYPOINT ["sleep","99999"] podCreate = podmanTest.Podman([]string{"pod", "create", "--pid", ns, "--name", podName, "--share", "pid"}) podCreate.WaitWithDefaultTimeout() - Expect(podCreate.ExitCode()).To(Equal(0)) + Expect(podCreate).Should(Exit(0)) podInspect = podmanTest.Podman([]string{"pod", "inspect", podName}) podInspect.WaitWithDefaultTimeout() - Expect(podInspect.ExitCode()).To(Equal(0)) + Expect(podInspect).Should(Exit(0)) podJSON = podInspect.InspectPodToJSON() Expect(podJSON.InfraConfig.PidNS).To(Equal("pod")) @@ -592,11 +592,11 @@ ENTRYPOINT ["sleep","99999"] podCreate = podmanTest.Podman([]string{"pod", "create", "--pid", ns, "--name", podName, "--share", "pid"}) podCreate.WaitWithDefaultTimeout() - Expect(podCreate.ExitCode()).To(Equal(0)) + Expect(podCreate).Should(Exit(0)) podInspect = podmanTest.Podman([]string{"pod", "inspect", podName}) podInspect.WaitWithDefaultTimeout() - Expect(podInspect.ExitCode()).To(Equal(0)) + Expect(podInspect).Should(Exit(0)) podJSON = podInspect.InspectPodToJSON() Expect(podJSON.InfraConfig.PidNS).To(Equal("host")) @@ -605,11 +605,11 @@ ENTRYPOINT ["sleep","99999"] podCreate = podmanTest.Podman([]string{"pod", "create", "--pid", ns, "--name", podName, "--share", "pid"}) podCreate.WaitWithDefaultTimeout() - Expect(podCreate.ExitCode()).To(Equal(0)) + Expect(podCreate).Should(Exit(0)) podInspect = podmanTest.Podman([]string{"pod", "inspect", podName}) podInspect.WaitWithDefaultTimeout() - Expect(podInspect.ExitCode()).To(Equal(0)) + Expect(podInspect).Should(Exit(0)) podJSON = podInspect.InspectPodToJSON() Expect(podJSON.InfraConfig.PidNS).To(Equal("private")) diff --git a/test/e2e/run_exit_test.go b/test/e2e/run_exit_test.go index 21f1a8650..e86718577 100644 --- a/test/e2e/run_exit_test.go +++ b/test/e2e/run_exit_test.go @@ -49,11 +49,7 @@ var _ = Describe("Podman run exit", func() { It("podman run exit ExecErrorCodeNotFound", func() { result := podmanTest.Podman([]string{"run", ALPINE, "foobar"}) result.WaitWithDefaultTimeout() - Expect(result.ExitCode()).To(Not(Equal(define.ExecErrorCodeGeneric))) - // TODO This is failing we believe because of a race condition - // Between conmon and podman closing the socket early. - // Test with the following, once the race condition is solved - // Expect(result).Should(Exit(define.ExecErrorCodeNotFound)) + Expect(result).Should(Exit(define.ExecErrorCodeNotFound)) }) It("podman run exit 0", func() { diff --git a/test/e2e/volume_ls_test.go b/test/e2e/volume_ls_test.go index ff3551ad9..0dd1a2b7c 100644 --- a/test/e2e/volume_ls_test.go +++ b/test/e2e/volume_ls_test.go @@ -101,6 +101,22 @@ var _ = Describe("Podman volume ls", func() { Expect(len(session.OutputToStringArray())).To(Equal(0)) }) + It("podman ls volume with --filter until flag", func() { + session := podmanTest.Podman([]string{"volume", "create"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + + session = podmanTest.Podman([]string{"volume", "ls", "--filter", "until=5000000000"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + Expect(len(session.OutputToStringArray())).To(Equal(2)) + + session = podmanTest.Podman([]string{"volume", "ls", "--filter", "until=50000"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + Expect(len(session.OutputToStringArray())).To(Equal(0)) + }) + It("podman volume ls with --filter dangling", func() { volName1 := "volume1" session := podmanTest.Podman([]string{"volume", "create", volName1}) diff --git a/test/system/090-events.bats b/test/system/090-events.bats index d889bd7f9..22edaeee9 100644 --- a/test/system/090-events.bats +++ b/test/system/090-events.bats @@ -81,6 +81,7 @@ function _events_disjunctive_filters() { @test "events with disjunctive filters - journald" { skip_if_remote "remote does not support --events-backend" + skip_if_journald_unavailable "system does not support journald events" _events_disjunctive_filters --events-backend=journald } diff --git a/test/system/125-import.bats b/test/system/125-import.bats new file mode 100644 index 000000000..c53711618 --- /dev/null +++ b/test/system/125-import.bats @@ -0,0 +1,45 @@ +#!/usr/bin/env bats -*- bats -*- +# +# tests for podman import +# + +load helpers + +@test "podman import" { + local archive=$PODMAN_TMPDIR/archive.tar + local random_content=$(random_string 12) + # Generate a random name and tag (must be lower-case) + local random_name=x0$(random_string 12 | tr A-Z a-z) + local random_tag=t0$(random_string 7 | tr A-Z a-z) + local fqin=localhost/$random_name:$random_tag + + run_podman run --name import $IMAGE sh -c "echo ${random_content} > /random.txt" + run_podman export import -o $archive + run_podman rm -f import + + # Simple import + run_podman import -q $archive + iid="$output" + run_podman run -t --rm $iid cat /random.txt + is "$output" "$random_content" "simple import" + run_podman rmi -f $iid + + # Simple import via stdin + run_podman import -q - < <(cat $archive) + iid="$output" + run_podman run -t --rm $iid cat /random.txt + is "$output" "$random_content" "simple import via stdin" + run_podman rmi -f $iid + + # Tagged import + run_podman import -q $archive $fqin + run_podman run -t --rm $fqin cat /random.txt + is "$output" "$random_content" "tagged import" + run_podman rmi -f $fqin + + # Tagged import via stdin + run_podman import -q - $fqin < <(cat $archive) + run_podman run -t --rm $fqin cat /random.txt + is "$output" "$random_content" "tagged import via stdin" + run_podman rmi -f $fqin +} diff --git a/test/system/250-systemd.bats b/test/system/250-systemd.bats index aafe385c8..ee951ff21 100644 --- a/test/system/250-systemd.bats +++ b/test/system/250-systemd.bats @@ -4,17 +4,10 @@ # load helpers +load helpers.systemd SERVICE_NAME="podman_test_$(random_string)" -SYSTEMCTL="systemctl" -UNIT_DIR="/usr/lib/systemd/system" -if is_rootless; then - UNIT_DIR="$HOME/.config/systemd/user" - mkdir -p $UNIT_DIR - - SYSTEMCTL="$SYSTEMCTL --user" -fi UNIT_FILE="$UNIT_DIR/$SERVICE_NAME.service" function setup() { @@ -24,38 +17,28 @@ function setup() { } function teardown() { - run '?' $SYSTEMCTL stop "$SERVICE_NAME" + run '?' systemctl stop "$SERVICE_NAME" rm -f "$UNIT_FILE" - $SYSTEMCTL daemon-reload + systemctl daemon-reload run_podman rmi -a basic_teardown } -# Helper to setup xdg runtime for rootless -function xdg_rootless() { - # podman initializes this if unset, but systemctl doesn't - if is_rootless; then - if [ -z "$XDG_RUNTIME_DIR" ]; then - export XDG_RUNTIME_DIR=/run/user/$(id -u) - fi - fi -} - # Helper to start a systemd service running a container function service_setup() { run_podman generate systemd --new $cname echo "$output" > "$UNIT_FILE" run_podman rm $cname - $SYSTEMCTL daemon-reload + systemctl daemon-reload - run $SYSTEMCTL start "$SERVICE_NAME" + run systemctl start "$SERVICE_NAME" if [ $status -ne 0 ]; then die "Error starting systemd unit $SERVICE_NAME, output: $output" fi - run $SYSTEMCTL status "$SERVICE_NAME" + run systemctl status "$SERVICE_NAME" if [ $status -ne 0 ]; then die "Non-zero status of systemd unit $SERVICE_NAME, output: $output" fi @@ -63,20 +46,18 @@ function service_setup() { # Helper to stop a systemd service running a container function service_cleanup() { - run $SYSTEMCTL stop "$SERVICE_NAME" + run systemctl stop "$SERVICE_NAME" if [ $status -ne 0 ]; then die "Error stopping systemd unit $SERVICE_NAME, output: $output" fi rm -f "$UNIT_FILE" - $SYSTEMCTL daemon-reload + systemctl daemon-reload } # These tests can fail in dev. environment because of SELinux. # quick fix: chcon -t container_runtime_exec_t ./bin/podman @test "podman generate - systemd - basic" { - xdg_rootless - cname=$(random_string) # See #7407 for --pull=always. run_podman create --pull=always --name $cname --label "io.containers.autoupdate=registry" $IMAGE top @@ -100,8 +81,6 @@ function service_cleanup() { } @test "podman autoupdate local" { - xdg_rootless - cname=$(random_string) run_podman create --name $cname --label "io.containers.autoupdate=local" $IMAGE top @@ -128,8 +107,6 @@ function service_cleanup() { # These tests can fail in dev. environment because of SELinux. # quick fix: chcon -t container_runtime_exec_t ./bin/podman @test "podman generate systemd - envar" { - xdg_rootless - cname=$(random_string) FOO=value BAR=%s run_podman create --name $cname --env FOO -e BAR --env MYVAR=myval \ $IMAGE sh -c 'printenv && sleep 100' diff --git a/test/system/255-auto-update.bats b/test/system/255-auto-update.bats index 4d7a8e783..25eaba45b 100644 --- a/test/system/255-auto-update.bats +++ b/test/system/255-auto-update.bats @@ -4,21 +4,12 @@ # load helpers +load helpers.systemd -DASHUSER="" -UNIT_DIR="/run/systemd/system" SNAME_FILE=$BATS_TMPDIR/services function setup() { skip_if_remote "systemd tests are meaningless over remote" - - if is_rootless; then - test -n "${XDG_RUNTIME_DIR}" || skip "\$XDG_RUNTIME_DIR is unset" - UNIT_DIR="${XDG_RUNTIME_DIR}/systemd/user" - mkdir -p $UNIT_DIR - # Why isn't systemd smart enough to figure this out on its own? - DASHUSER="--user" - fi basic_setup } @@ -26,10 +17,10 @@ function teardown() { while read line; do if [[ "$line" =~ "podman-auto-update" ]]; then echo "Stop timer: $line.timer" - systemctl $DASHUSER stop $line.timer - systemctl $DASHUSER disable $line.timer + systemctl stop $line.timer + systemctl disable $line.timer else - systemctl $DASHUSER stop $line + systemctl stop $line fi rm -f $UNIT_DIR/$line.{service,timer} done < $SNAME_FILE @@ -69,9 +60,9 @@ function generate_service() { echo "container-$cname" >> $SNAME_FILE run_podman rm -f $cname - systemctl $DASHUSER daemon-reload - systemctl $DASHUSER start container-$cname - systemctl $DASHUSER status container-$cname + systemctl daemon-reload + systemctl start container-$cname + systemctl status container-$cname # Original image ID. # IMPORTANT: variable 'ori_image' is passed (out of scope) up to caller! @@ -84,7 +75,7 @@ function _wait_service_ready() { local timeout=6 while [[ $timeout -gt 1 ]]; do - if systemctl $DASHUSER -q is-active $sname; then + if systemctl -q is-active $sname; then return fi sleep 1 @@ -92,7 +83,7 @@ function _wait_service_ready() { done # Print serivce status as debug information before failed the case - systemctl $DASHUSER status $sname + systemctl status $sname die "Timed out waiting for $sname to start" } @@ -267,14 +258,14 @@ WantedBy=multi-user.target default.target EOF echo "podman-auto-update-$cname" >> $SNAME_FILE - systemctl $DASHUSER enable --now podman-auto-update-$cname.timer - systemctl $DASHUSER list-timers --all + systemctl enable --now podman-auto-update-$cname.timer + systemctl list-timers --all local expect='Finished Podman auto-update testing service' local failed_start=failed local count=0 while [ $count -lt 120 ]; do - run journalctl $DASHUSER -n 15 -u podman-auto-update-$cname.service + run journalctl -n 15 -u podman-auto-update-$cname.service if [[ "$output" =~ $expect ]]; then failed_start= break diff --git a/test/system/270-socket-activation.bats b/test/system/270-socket-activation.bats index 25206c6a7..031ba161b 100644 --- a/test/system/270-socket-activation.bats +++ b/test/system/270-socket-activation.bats @@ -4,21 +4,12 @@ # load helpers +load helpers.systemd SERVICE_NAME="podman_test_$(random_string)" -SYSTEMCTL="systemctl" -UNIT_DIR="/usr/lib/systemd/system" SERVICE_SOCK_ADDR="/run/podman/podman.sock" - if is_rootless; then - UNIT_DIR="$HOME/.config/systemd/user" - mkdir -p $UNIT_DIR - - SYSTEMCTL="$SYSTEMCTL --user" - if [ -z "$XDG_RUNTIME_DIR" ]; then - export XDG_RUNTIME_DIR=/run/user/$(id -u) - fi SERVICE_SOCK_ADDR="$XDG_RUNTIME_DIR/podman/podman.sock" fi @@ -66,13 +57,13 @@ EOF rm -f $pause_pid fi fi - $SYSTEMCTL start "$SERVICE_NAME.socket" + systemctl start "$SERVICE_NAME.socket" } function teardown() { - $SYSTEMCTL stop "$SERVICE_NAME.socket" + systemctl stop "$SERVICE_NAME.socket" rm -f "$SERVICE_FILE" "$SOCKET_FILE" - $SYSTEMCTL daemon-reload + systemctl daemon-reload basic_teardown } diff --git a/test/system/500-networking.bats b/test/system/500-networking.bats index 419d325b0..495c7948b 100644 --- a/test/system/500-networking.bats +++ b/test/system/500-networking.bats @@ -139,7 +139,7 @@ load helpers $IMAGE nc -l -n -v -p $myport cid="$output" - wait_for_port 127.0.0.1 $myport + wait_for_output "listening on .*:$myport .*" $cid # emit random string, and check it teststring=$(random_string 30) diff --git a/test/system/helpers.bash b/test/system/helpers.bash index 02fd7252c..bd9471ace 100644 --- a/test/system/helpers.bash +++ b/test/system/helpers.bash @@ -288,7 +288,7 @@ function wait_for_port() { # Wait while [ $_timeout -gt 0 ]; do - { exec 3<> /dev/tcp/$host/$port; } &>/dev/null && return + { exec 5<> /dev/tcp/$host/$port; } &>/dev/null && return sleep 1 _timeout=$(( $_timeout - 1 )) done diff --git a/test/system/helpers.systemd.bash b/test/system/helpers.systemd.bash new file mode 100644 index 000000000..4bde912a4 --- /dev/null +++ b/test/system/helpers.systemd.bash @@ -0,0 +1,30 @@ +# -*- bash -*- +# +# BATS helpers for systemd-related functionality +# + +# podman initializes this if unset, but systemctl doesn't +if [ -z "$XDG_RUNTIME_DIR" ]; then + if is_rootless; then + export XDG_RUNTIME_DIR=/run/user/$(id -u) + fi +fi + +# For tests which write systemd unit files +UNIT_DIR="/run/systemd/system" +_DASHUSER= +if is_rootless; then + UNIT_DIR="${XDG_RUNTIME_DIR}/systemd/user" + # Why isn't systemd smart enough to figure this out on its own? + _DASHUSER="--user" +fi + +mkdir -p $UNIT_DIR + +systemctl() { + command systemctl $_DASHUSER "$@" +} + +journalctl() { + command journalctl $_DASHUSER "$@" +} diff --git a/troubleshooting.md b/troubleshooting.md index 575ee16b8..24dcb8e35 100644 --- a/troubleshooting.md +++ b/troubleshooting.md @@ -356,7 +356,7 @@ If you do mount in the host's `/var/lib/containers/storage`, however, you must a Not doing this will cause Podman in the container to detect that temporary files have been cleared, leading it to assume a system restart has taken place. This can cause Podman to reset container states and lose track of running containers. -For running containers on the host from inside a container, we also recommend the [Podman remote client](remote_client.md), which only requires a single socket to be mounted into the container. +For running containers on the host from inside a container, we also recommend the [Podman remote client](docs/tutorials/remote_client.md), which only requires a single socket to be mounted into the container. ### 14) Rootless 'podman build' fails EPERM on NFS: |