diff options
-rw-r--r-- | .github/workflows/multi-arch-build.yaml | 107 | ||||
-rw-r--r-- | Makefile | 12 | ||||
-rw-r--r-- | cmd/podman/common/create.go | 9 | ||||
-rw-r--r-- | cmd/podman/containers/create.go | 2 | ||||
-rw-r--r-- | cmd/podman/root.go | 8 | ||||
-rw-r--r-- | libpod/container_internal.go | 1 | ||||
-rw-r--r-- | libpod/runtime_ctr.go | 26 | ||||
-rw-r--r-- | pkg/api/handlers/libpod/containers_create.go | 1 | ||||
-rw-r--r-- | pkg/specgen/generate/container_create.go | 10 | ||||
-rw-r--r-- | pkg/specgen/generate/kube/kube.go | 13 | ||||
-rw-r--r-- | test/README.md | 2 | ||||
-rw-r--r-- | test/e2e/common_test.go | 2 | ||||
-rw-r--r-- | test/e2e/container_create_volume_test.go | 127 | ||||
-rw-r--r-- | test/e2e/pod_create_test.go | 16 | ||||
-rw-r--r-- | test/e2e/run_exit_test.go | 6 | ||||
-rw-r--r-- | test/system/250-systemd.bats | 39 | ||||
-rw-r--r-- | test/system/255-auto-update.bats | 11 | ||||
-rw-r--r-- | test/system/270-socket-activation.bats | 17 | ||||
-rw-r--r-- | test/system/helpers.systemd.bash | 30 |
19 files changed, 301 insertions, 138 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/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/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/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/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/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 a73ed94e8..25eaba45b 100644 --- a/test/system/255-auto-update.bats +++ b/test/system/255-auto-update.bats @@ -4,14 +4,12 @@ # load helpers +load helpers.systemd -UNIT_DIR="/usr/lib/systemd/system" SNAME_FILE=$BATS_TMPDIR/services function setup() { skip_if_remote "systemd tests are meaningless over remote" - skip_if_rootless - basic_setup } @@ -29,7 +27,7 @@ function teardown() { rm -f $SNAME_FILE run_podman ? rmi quay.io/libpod/alpine:latest - run_podman ? rmi quay.io/libpod/alpine_nginx:latest + run_podman ? rmi quay.io/libpod/busybox:latest run_podman ? rmi quay.io/libpod/localtest:latest basic_teardown } @@ -58,8 +56,7 @@ function generate_service() { fi run_podman run -d --name $cname $label $target_img top -d 120 - run_podman generate systemd --new $cname - echo "$output" > "$UNIT_DIR/container-$cname.service" + (cd $UNIT_DIR; run_podman generate systemd --new --files --name $cname) echo "container-$cname" >> $SNAME_FILE run_podman rm -f $cname @@ -185,7 +182,7 @@ function _confirm_update() { do local img_base="alpine" if [[ $auto_update == "registry" ]]; then - img_base="alpine_nginx" + img_base="busybox" elif [[ $auto_update == "local" ]]; then img_base="localtest" fi 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/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 "$@" +} |