diff options
25 files changed, 317 insertions, 65 deletions
diff --git a/cmd/podman/common/create.go b/cmd/podman/common/create.go index a3ff37c19..6270bad16 100644 --- a/cmd/podman/common/create.go +++ b/cmd/podman/common/create.go @@ -319,6 +319,9 @@ func DefineCreateFlags(cmd *cobra.Command, cf *entities.ContainerCreateOptions, "Kernel memory limit "+sizeWithUnitFormat, ) _ = cmd.RegisterFlagCompletionFunc(kernelMemoryFlagName, completion.AutocompleteNone) + // kernel-memory is deprecated in the runtime spec. + _ = createFlags.MarkHidden("kernel-memory") + logDriverFlagName := "log-driver" createFlags.StringVar( &cf.LogDriver, diff --git a/cmd/podman/common/create_opts.go b/cmd/podman/common/create_opts.go index 50d7c446d..223a91331 100644 --- a/cmd/podman/common/create_opts.go +++ b/cmd/podman/common/create_opts.go @@ -18,6 +18,7 @@ import ( "github.com/containers/podman/v3/pkg/specgen" "github.com/docker/docker/api/types/mount" "github.com/pkg/errors" + "github.com/sirupsen/logrus" ) func stringMaptoArray(m map[string]string) []string { @@ -383,6 +384,9 @@ func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, rtc *c if cc.HostConfig.Memory > 0 { cliOpts.Memory = strconv.Itoa(int(cc.HostConfig.Memory)) } + if cc.HostConfig.KernelMemory > 0 { + logrus.Warnf("The --kernel-memory flag has been deprecated. May not work properly on your system.") + } if cc.HostConfig.MemoryReservation > 0 { cliOpts.MemoryReservation = strconv.Itoa(int(cc.HostConfig.MemoryReservation)) diff --git a/cmd/podman/containers/start.go b/cmd/podman/containers/start.go index 1163b9093..8813fc273 100644 --- a/cmd/podman/containers/start.go +++ b/cmd/podman/containers/start.go @@ -87,6 +87,9 @@ func validateStart(cmd *cobra.Command, args []string) error { if len(args) == 0 && !startOptions.Latest && !startOptions.All { return errors.New("start requires at least one argument") } + if startOptions.All && startOptions.Latest { + return errors.Errorf("--all and --latest cannot be used together") + } if len(args) > 0 && startOptions.Latest { return errors.Errorf("--latest and containers cannot be used together") } diff --git a/cmd/podman/system/connection/list.go b/cmd/podman/system/connection/list.go index de85ce3fa..a3290e3d6 100644 --- a/cmd/podman/system/connection/list.go +++ b/cmd/podman/system/connection/list.go @@ -44,6 +44,7 @@ func init() { type namedDestination struct { Name string config.Destination + Default bool } func list(cmd *cobra.Command, _ []string) error { @@ -60,12 +61,14 @@ func list(cmd *cobra.Command, _ []string) error { "Identity": "Identity", "Name": "Name", "URI": "URI", + "Default": "Default", }} rows := make([]namedDestination, 0) for k, v := range cfg.Engine.ServiceDestinations { + def := false if k == cfg.Engine.ActiveService { - k += "*" + def = true } r := namedDestination{ @@ -74,6 +77,7 @@ func list(cmd *cobra.Command, _ []string) error { Identity: v.Identity, URI: v.URI, }, + Default: def, } rows = append(rows, r) } @@ -82,7 +86,7 @@ func list(cmd *cobra.Command, _ []string) error { return rows[i].Name < rows[j].Name }) - format := "{{.Name}}\t{{.Identity}}\t{{.URI}}\n" + format := "{{.Name}}\t{{.URI}}\t{{.Identity}}\t{{.Default}}\n" switch { case report.IsJSON(cmd.Flag("format").Value.String()): buf, err := registry.JSONLibrary().MarshalIndent(rows, "", " ") diff --git a/contrib/systemd/system/podman-restart.service.in b/contrib/systemd/system/podman-restart.service.in index a2951e111..46193e2c6 100644 --- a/contrib/systemd/system/podman-restart.service.in +++ b/contrib/systemd/system/podman-restart.service.in @@ -5,8 +5,9 @@ StartLimitIntervalSec=0 [Service] Type=oneshot +RemainAfterExit=true Environment=LOGGING="--log-level=info" ExecStart=@@PODMAN@@ $LOGGING start --all --filter restart-policy=always [Install] -WantedBy=multi-user.target +WantedBy=multi-user.target default.target diff --git a/docs/source/markdown/podman-create.1.md b/docs/source/markdown/podman-create.1.md index ee52bfd13..ca104cb4e 100644 --- a/docs/source/markdown/podman-create.1.md +++ b/docs/source/markdown/podman-create.1.md @@ -487,18 +487,6 @@ Default is to create a private IPC namespace (POSIX SysV IPC) for the container `host`: use the host shared memory,semaphores and message queues inside the container. Note: the host mode gives the container full access to local shared memory and is therefore considered insecure. `ns:<path>` path to an IPC namespace to join. -#### **--kernel-memory**=*number[unit]* - -Kernel memory limit (format: `<number>[<unit>]`, where unit = b (bytes), k (kilobytes), m (megabytes), or g (gigabytes)) - -Constrains the kernel memory available to a container. If a limit of 0 -is specified (not using `--kernel-memory`), the container's kernel memory -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) @@ -515,6 +503,11 @@ Not implemented Logging driver for the container. Currently available options are *k8s-file*, *journald*, *none* and *passthrough*, with *json-file* aliased to *k8s-file* for scripting compatibility. +The podman info command below will display the default log-driver for the system. +``` +$ podman info --format '{{ .Host.LogDriver }}' +journald +``` The *passthrough* driver passes down the standard streams (stdin, stdout, stderr) to the container. It is not allowed with the remote Podman client and on a tty, since it is vulnerable to attacks via TIOCSTI. diff --git a/docs/source/markdown/podman-pod-rm.1.md b/docs/source/markdown/podman-pod-rm.1.md index eac40ef62..fc834a69c 100644 --- a/docs/source/markdown/podman-pod-rm.1.md +++ b/docs/source/markdown/podman-pod-rm.1.md @@ -7,7 +7,7 @@ podman\-pod\-rm - Remove one or more stopped pods and containers **podman pod rm** [*options*] *pod* ## DESCRIPTION -**podman pod rm** will remove one or more stopped pods and their containers from the host. The pod name or ID can be used. The \-f option stops all containers and then removes them before removing the pod. +**podman pod rm** will remove one or more stopped pods and their containers from the host. The pod name or ID can be used. The \-f option stops all containers and then removes them before removing the pod. If all containers added by the user are in an exited state, the pod will be removed. ## OPTIONS diff --git a/docs/source/markdown/podman-run.1.md b/docs/source/markdown/podman-run.1.md index 5cc17f470..d0b111037 100644 --- a/docs/source/markdown/podman-run.1.md +++ b/docs/source/markdown/podman-run.1.md @@ -512,18 +512,6 @@ a private IPC namespace. - **host**: use the host shared memory,semaphores and message queues inside the container. Note: the host mode gives the container full access to local shared memory and is therefore considered insecure. - **ns:**_path_: path to an IPC namespace to join. -#### **--kernel-memory**=_number_[_unit_] - -Kernel memory limit. A _unit_ can be **b** (bytes), **k** (kilobytes), **m** (megabytes), or **g** (gigabytes). - -Constrains the kernel memory available to a container. If a limit of 0 -is specified (not using *--kernel-memory*), the container's kernel memory -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. @@ -538,8 +526,13 @@ Not implemented. #### **--log-driver**="*driver*" -Logging driver for the container. Currently available options are **k8s-file**, **journald**, **none** and **passthrough**, with **json-file** aliased to **k8s-file** for scripting compatibility. +Logging driver for the container. Currently available options are **k8s-file**, **journald**, **none** and **passthrough**, with **json-file** aliased to **k8s-file** for scripting compatibility. (Default journald) +The podman info command below will display the default log-driver for the system. +``` +$ podman info --format '{{ .Host.LogDriver }}' +journald +``` The **passthrough** driver passes down the standard streams (stdin, stdout, stderr) to the container. It is not allowed with the remote Podman client and on a tty, since it is vulnerable to attacks via TIOCSTI. diff --git a/docs/source/markdown/podman-system-connection-list.1.md b/docs/source/markdown/podman-system-connection-list.1.md index 6b25a045d..4dc85dd98 100644 --- a/docs/source/markdown/podman-system-connection-list.1.md +++ b/docs/source/markdown/podman-system-connection-list.1.md @@ -23,14 +23,14 @@ Valid placeholders for the Go template listed below: | *.Name* | Connection Name/Identifier | | *.Identity* | Path to file containing SSH identity | | *.URI* | URI to podman service. Valid schemes are ssh://[user@]*host*[:port]*Unix domain socket*[?secure=True], unix://*Unix domain socket*, and tcp://localhost[:*port*] | - -An asterisk is appended to the default connection. +| *.Default* | Indicates whether connection is the default | ## EXAMPLE ``` $ podman system connection list -Name URI Identity -devl ssh://root@example.com/run/podman/podman.sock ~/.ssh/id_rsa +Name URI Identity Default +devl ssh://root@example.com:/run/podman/podman.sock ~/.ssh/id_rsa True +devl ssh://user@example.com:/run/user/1000/podman/podman.sock ~/.ssh/id_rsa False ``` ## SEE ALSO podman-system(1) , containers.conf(5) diff --git a/docs/source/markdown/podman-system-connection.1.md b/docs/source/markdown/podman-system-connection.1.md index 6cd4a5fa8..b00a2aec3 100644 --- a/docs/source/markdown/podman-system-connection.1.md +++ b/docs/source/markdown/podman-system-connection.1.md @@ -24,8 +24,8 @@ The user will be prompted for the ssh login password or key file pass phrase as ## EXAMPLE ``` $ podman system connection list -Name URI Identity -devl ssh://root@example.com/run/podman/podman.sock ~/.ssh/id_rsa +Name URI Identity Default +devl ssh://root@example.com/run/podman/podman.sock ~/.ssh/id_rsa true ``` ## SEE ALSO podman-system(1) , containers.conf(5) diff --git a/libpod/container_internal.go b/libpod/container_internal.go index 4e8074840..43f5398a2 100644 --- a/libpod/container_internal.go +++ b/libpod/container_internal.go @@ -17,12 +17,14 @@ import ( "github.com/containers/buildah/copier" "github.com/containers/buildah/pkg/overlay" butil "github.com/containers/buildah/util" + "github.com/containers/common/pkg/chown" "github.com/containers/podman/v3/libpod/define" "github.com/containers/podman/v3/libpod/events" "github.com/containers/podman/v3/pkg/cgroups" "github.com/containers/podman/v3/pkg/ctime" "github.com/containers/podman/v3/pkg/hooks" "github.com/containers/podman/v3/pkg/hooks/exec" + "github.com/containers/podman/v3/pkg/lookup" "github.com/containers/podman/v3/pkg/rootless" "github.com/containers/podman/v3/pkg/selinux" "github.com/containers/podman/v3/pkg/util" @@ -485,8 +487,12 @@ func (c *Container) setupStorage(ctx context.Context) error { return errors.Wrapf(err, "error creating container storage") } - c.config.IDMappings.UIDMap = containerInfo.UIDMap - c.config.IDMappings.GIDMap = containerInfo.GIDMap + // only reconfig IDMappings if layer was mounted from storage + // if its a external overlay do not reset IDmappings + if !c.config.RootfsOverlay { + c.config.IDMappings.UIDMap = containerInfo.UIDMap + c.config.IDMappings.GIDMap = containerInfo.GIDMap + } processLabel, err := c.processLabel(containerInfo.ProcessLabel) if err != nil { @@ -1515,6 +1521,19 @@ func (c *Container) mountStorage() (_ string, deferredErr error) { } mountPoint = overlayMount.Source + execUser, err := lookup.GetUserGroupInfo(mountPoint, c.config.User, nil) + if err != nil { + return "", err + } + hostUID, hostGID, err := butil.GetHostIDs(util.IDtoolsToRuntimeSpec(c.config.IDMappings.UIDMap), util.IDtoolsToRuntimeSpec(c.config.IDMappings.GIDMap), uint32(execUser.Uid), uint32(execUser.Gid)) + if err != nil { + return "", errors.Wrap(err, "unable to get host UID and host GID") + } + + //note: this should not be recursive, if using external rootfs users should be responsible on configuring ownership. + if err := chown.ChangeHostPathOwnership(mountPoint, false, int(hostUID), int(hostGID)); err != nil { + return "", err + } } if mountPoint == "" { @@ -2084,7 +2103,7 @@ func (c *Container) checkReadyForRemoval() error { return errors.Wrapf(define.ErrCtrStateInvalid, "container %s is in invalid state", c.ID()) } - if c.ensureState(define.ContainerStateRunning, define.ContainerStatePaused) { + if c.ensureState(define.ContainerStateRunning, define.ContainerStatePaused) && !c.IsInfra() { return errors.Wrapf(define.ErrCtrStateInvalid, "cannot remove container %s as it is %s - running or paused containers cannot be removed without force", c.ID(), c.state.State.String()) } diff --git a/libpod/container_log_linux.go b/libpod/container_log_linux.go index ca1e11ef5..562169ce2 100644 --- a/libpod/container_log_linux.go +++ b/libpod/container_log_linux.go @@ -91,8 +91,12 @@ func (c *Container) readFromJournal(ctx context.Context, options *logs.LogOption var cursorError error for i := 1; i <= 3; i++ { cursor, cursorError = journal.GetCursor() + hundreds := 1 + for j := 1; j < i; j++ { + hundreds *= 2 + } if cursorError != nil { - time.Sleep(time.Duration(i*100) * time.Millisecond) + time.Sleep(time.Duration(hundreds*100) * time.Millisecond) continue } break diff --git a/libpod/runtime_pod_linux.go b/libpod/runtime_pod_linux.go index 9c6f1539f..7d7fef4d1 100644 --- a/libpod/runtime_pod_linux.go +++ b/libpod/runtime_pod_linux.go @@ -177,10 +177,9 @@ func (r *Runtime) removePod(ctx context.Context, p *Pod, removeCtrs, force bool, if err != nil { return err } - numCtrs := len(ctrs) - // If the only container in the pod is the pause container, remove the pod and container unconditionally. + // If the only running container in the pod is the pause container, remove the pod and container unconditionally. pauseCtrID := p.state.InfraContainerID if numCtrs == 1 && ctrs[0].ID() == pauseCtrID { removeCtrs = true @@ -264,6 +263,15 @@ func (r *Runtime) removePod(ctx context.Context, p *Pod, removeCtrs, force bool, } } + // Clear infra container ID before we remove the infra container. + // There is a potential issue if we don't do that, and removal is + // interrupted between RemoveAllContainers() below and the pod's removal + // later - we end up with a reference to a nonexistent infra container. + p.state.InfraContainerID = "" + if err := p.save(); err != nil { + return err + } + // Remove all containers in the pod from the state. if err := r.state.RemovePodContainers(p); err != nil { // If this fails, there isn't much more we can do. diff --git a/pkg/api/handlers/compat/images_tag.go b/pkg/api/handlers/compat/images_tag.go index 7858298be..5d413a821 100644 --- a/pkg/api/handlers/compat/images_tag.go +++ b/pkg/api/handlers/compat/images_tag.go @@ -4,6 +4,7 @@ import ( "fmt" "net/http" + "github.com/containers/common/libimage" "github.com/containers/podman/v3/libpod" "github.com/containers/podman/v3/pkg/api/handlers/utils" api "github.com/containers/podman/v3/pkg/api/types" @@ -16,7 +17,9 @@ func TagImage(w http.ResponseWriter, r *http.Request) { // /v1.xx/images/(name)/tag name := utils.GetName(r) - newImage, _, err := runtime.LibimageRuntime().LookupImage(name, nil) + // Allow tagging manifest list instead of resolving instances from manifest + lookupOptions := &libimage.LookupImageOptions{ManifestList: true} + newImage, _, err := runtime.LibimageRuntime().LookupImage(name, lookupOptions) if err != nil { utils.ImageNotFound(w, name, errors.Wrapf(err, "failed to find image %s", name)) return diff --git a/pkg/domain/infra/abi/images.go b/pkg/domain/infra/abi/images.go index d2222c017..8878bf128 100644 --- a/pkg/domain/infra/abi/images.go +++ b/pkg/domain/infra/abi/images.go @@ -331,7 +331,9 @@ func (ir *ImageEngine) Push(ctx context.Context, source string, destination stri } func (ir *ImageEngine) Tag(ctx context.Context, nameOrID string, tags []string, options entities.ImageTagOptions) error { - image, _, err := ir.Libpod.LibimageRuntime().LookupImage(nameOrID, nil) + // Allow tagging manifest list instead of resolving instances from manifest + lookupOptions := &libimage.LookupImageOptions{ManifestList: true} + image, _, err := ir.Libpod.LibimageRuntime().LookupImage(nameOrID, lookupOptions) if err != nil { return err } diff --git a/pkg/specgenutil/specgen.go b/pkg/specgenutil/specgen.go index 6a6397257..8007e5d8e 100644 --- a/pkg/specgenutil/specgen.go +++ b/pkg/specgenutil/specgen.go @@ -133,12 +133,14 @@ func getMemoryLimits(s *specgen.SpecGenerator, c *entities.ContainerCreateOption if err != nil { return nil, errors.Wrapf(err, "invalid value for memory") } - memory.Limit = &ml - if c.MemorySwap == "" { - limit := 2 * ml - memory.Swap = &(limit) + if ml > 0 { + memory.Limit = &ml + if c.MemorySwap == "" { + limit := 2 * ml + memory.Swap = &(limit) + } + hasLimits = true } - hasLimits = true } if m := c.MemoryReservation; len(m) > 0 { mr, err := units.RAMInBytes(m) diff --git a/test/e2e/manifest_test.go b/test/e2e/manifest_test.go index 27aaaba48..5978214ff 100644 --- a/test/e2e/manifest_test.go +++ b/test/e2e/manifest_test.go @@ -93,6 +93,25 @@ var _ = Describe("Podman manifest", func() { Expect(session.OutputToString()).To(ContainSubstring(imageListARM64InstanceDigest)) }) + It("podman manifest tag", func() { + session := podmanTest.Podman([]string{"manifest", "create", "foobar"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + session = podmanTest.Podman([]string{"manifest", "add", "foobar", "quay.io/libpod/busybox"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + session = podmanTest.Podman([]string{"tag", "foobar", "foobar2"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + session = podmanTest.Podman([]string{"manifest", "inspect", "foobar"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + session2 := podmanTest.Podman([]string{"manifest", "inspect", "foobar2"}) + session2.WaitWithDefaultTimeout() + Expect(session2).Should(Exit(0)) + Expect(session2.OutputToString()).To(Equal(session.OutputToString())) + }) + It("podman manifest add --all", func() { session := podmanTest.Podman([]string{"manifest", "create", "foo"}) session.WaitWithDefaultTimeout() diff --git a/test/e2e/pod_rm_test.go b/test/e2e/pod_rm_test.go index 6a8ac72fb..7dc3dfa7f 100644 --- a/test/e2e/pod_rm_test.go +++ b/test/e2e/pod_rm_test.go @@ -301,4 +301,21 @@ var _ = Describe("Podman pod rm", func() { Expect(session).Should(Exit(0)) Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) }) + + It("podman pod rm with exited containers", func() { + _, ec, podid := podmanTest.CreatePod(nil) + Expect(ec).To(Equal(0)) + + session := podmanTest.Podman([]string{"run", "--pod", podid, ALPINE}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + + session = podmanTest.Podman([]string{"run", "--pod", podid, ALPINE}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + + result := podmanTest.Podman([]string{"pod", "rm", podid}) + result.WaitWithDefaultTimeout() + Expect(result).Should(Exit(0)) + }) }) diff --git a/test/e2e/run_test.go b/test/e2e/run_test.go index f40d4a749..8502879ff 100644 --- a/test/e2e/run_test.go +++ b/test/e2e/run_test.go @@ -259,6 +259,18 @@ var _ = Describe("Podman run", func() { startsession.WaitWithDefaultTimeout() Expect(startsession).Should(Exit(0)) Expect(startsession.OutputToString()).To(Equal("hello")) + + // remove container for above test overlay-foo + osession = podmanTest.Podman([]string{"rm", "overlay-foo"}) + osession.WaitWithDefaultTimeout() + Expect(osession).Should(Exit(0)) + + // Test --rootfs with an external overlay with --uidmap + osession = podmanTest.Podman([]string{"run", "--uidmap", "0:1000:1000", "--rm", "--security-opt", "label=disable", + "--rootfs", rootfs + ":O", "echo", "hello"}) + osession.WaitWithDefaultTimeout() + Expect(osession).Should(Exit(0)) + Expect(osession.OutputToString()).To(Equal("hello")) }) It("podman run a container with --init", func() { diff --git a/test/e2e/system_connection_test.go b/test/e2e/system_connection_test.go index 6cdb78c5e..842ae8df6 100644 --- a/test/e2e/system_connection_test.go +++ b/test/e2e/system_connection_test.go @@ -208,13 +208,13 @@ var _ = Describe("podman system connection", func() { session = podmanTest.Podman(cmd) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) - Expect(session.Out).Should(Say("Name *Identity *URI")) + Expect(session.Out).Should(Say("Name *URI *Identity *Default")) cmd = []string{"system", "connection", "list", "--format", "{{.Name}}"} session = podmanTest.Podman(cmd) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) - Expect(session.OutputToString()).Should(Equal("devl* qe")) + Expect(session.OutputToString()).Should(Equal("devl qe")) }) It("failed default", func() { diff --git a/test/system/001-basic.bats b/test/system/001-basic.bats index 50735f576..78b8ecdfd 100644 --- a/test/system/001-basic.bats +++ b/test/system/001-basic.bats @@ -94,22 +94,21 @@ function setup() { } @test "podman-remote: defaults" { - if is_remote; then - skip "only applicable on a local run" - fi + skip_if_remote "only applicable on a local run" + + # By default, podman should include '--remote' in its help output + run_podman --help + is "$output" ".* --remote " "podman --help includes the --remote option" + # When it detects CONTAINER_HOST or _CONNECTION, --remote is not an option CONTAINER_HOST=foobar run_podman --help - # Should not have --remote flag - echo $output | grep -v -qw -- "--remote" - if [ $? -ne 0 ]; then - die "Should not have --remote flag" + if grep -- " --remote " <<<"$output"; then + die "podman --help, with CONTAINER_HOST set, is showing --remote" fi CONTAINER_CONNECTION=foobar run_podman --help - # Should not have --remote flag - echo $output | grep -v -qw -- "--remote" - if [ $? -ne 0 ]; then - die "Should not have --remote flag" + if grep -- " --remote " <<<"$output"; then + die "podman --help, with CONTAINER_CONNECTION set, is showing --remote" fi } diff --git a/test/system/015-help.bats b/test/system/015-help.bats index 5f38c34a1..b0795b524 100644 --- a/test/system/015-help.bats +++ b/test/system/015-help.bats @@ -86,6 +86,12 @@ function check_help() { run_podman 125 "$@" $cmd -l nonexistent-container is "$output" "Error: .*--latest and \(containers\|pods\|arguments\) cannot be used together" \ "'$command_string' with both -l and container" + + # Combine -l and -a, too (but spell it as --all, because "-a" + # means "attach" in podman container start) + run_podman 125 "$@" $cmd --all --latest + is "$output" "Error: \(--all and --latest cannot be used together\|--all, --latest and containers cannot be used together\|--all, --latest and arguments cannot be used together\|unknown flag\)" \ + "'$command_string' with both --all and --latest" fi fi diff --git a/test/system/030-run.bats b/test/system/030-run.bats index 44c2ee509..2c8d08b99 100644 --- a/test/system/030-run.bats +++ b/test/system/030-run.bats @@ -67,6 +67,11 @@ echo $rand | 0 | $rand is "$output" ".*invalidflag" "failed when passing undefined flags to the runtime" } +@test "podman run --memory=0 runtime option" { + run_podman run --memory=0 --rm $IMAGE echo hello + is "$output" "hello" "failed to run when --memory is set to 0" +} + # 'run --preserve-fds' passes a number of additional file descriptors into the container @test "podman run --preserve-fds" { skip_if_remote "preserve-fds is meaningless over remote" diff --git a/test/system/045-start.bats b/test/system/045-start.bats index 7e4bbde8d..2ea057cd3 100644 --- a/test/system/045-start.bats +++ b/test/system/045-start.bats @@ -36,10 +36,6 @@ load helpers expected="Error: either start all containers or the container(s) provided in the arguments" run_podman 125 start --all 12333 is "$output" "$expected" "start --all, with args, throws error" - if ! is_remote; then - run_podman 125 start --all --latest - is "$output" "$expected" "podman start --all --latest" - fi } @test "podman start --filter - start only containers that match the filter" { diff --git a/test/system/272-system-connection.bats b/test/system/272-system-connection.bats new file mode 100644 index 000000000..5a90d9398 --- /dev/null +++ b/test/system/272-system-connection.bats @@ -0,0 +1,159 @@ +#!/usr/bin/env bats -*- bats -*- +# +# tests for podman system connection +# + +load helpers + +# This will be set if we start a local service +_SERVICE_PID= + +function setup() { + if ! is_remote; then + skip "only applicable when running remote" + fi + + basic_setup +} + +function teardown() { + if ! is_remote; then + return + fi + + # In case test function failed to clean up + if [[ -n $_SERVICE_PID ]]; then + run kill $_SERVICE_PID + fi + + # Aaaaargh! When running as root, 'system service' creates a tmpfs + # mount on $root/overlay. This in turn causes cleanup to fail. + mount \ + | grep $PODMAN_TMPDIR \ + | awk '{print $3}' \ + | xargs -l1 --no-run-if-empty umount + + # Remove all system connections + run_podman system connection ls --format json + while read name; do + run_podman system connection rm "$name" + done < <(jq -r '.[].Name' <<<"$output") + + basic_teardown +} + +# Helper function: invokes $PODMAN (which is podman-remote) _without_ --url opt +# +# Needed because, in CI, PODMAN="/path/to/podman-remote --url /path/to/socket" +# which of course overrides podman's detection and use of a connection. +function _run_podman_remote() { + PODMAN=${PODMAN%%--url*} run_podman "$@" +} + +# Very basic test, does not actually connect at any time +@test "podman system connection - basic add / ls / remove" { + run_podman system connection ls + is "$output" "" "system connection ls: no connections" + + c1="c1_$(random_string 15)" + c2="c2_$(random_string 15)" + + run_podman system connection add $c1 tcp://localhost:12345 + run_podman system connection add --default $c2 tcp://localhost:54321 + run_podman system connection ls + is "$output" \ + ".*$c1[ ]\+tcp://localhost:12345[ ]\+false +$c2[ ]\+tcp://localhost:54321[ ]\+true" \ + "system connection ls" + + # Remove default connection; the remaining one should still not be default + run_podman system connection rm $c2 + run_podman system connection ls + is "$output" ".*$c1[ ]\+tcp://localhost:12345[ ]\+false" \ + "system connection ls (after removing default connection)" + + run_podman system connection rm $c1 +} + +# Test tcp socket; requires starting a local server +@test "podman system connection - tcp" { + # Start server + _SERVICE_PORT=$(random_free_port 63000-64999) + + # Add the connection, and run podman info *before* starting the service. + # This should fail. + run_podman system connection add myconnect tcp://localhost:$_SERVICE_PORT + # IMPORTANT NOTE: in CI, podman-remote is tested by setting PODMAN + # to "podman-remote --url sdfsdf". This of course overrides the default + # podman-remote action. Our solution: strip off the "--url xyz" part + # when invoking podman. + _run_podman_remote 125 info + is "$output" \ + "Cannot connect to Podman. Please verify.*dial tcp.*connection refused" \ + "podman info, without active service" + + # Start service. Now podman info should work fine. The %%-remote* + # converts "podman-remote --opts" to just "podman", which is what + # we need for the server. + ${PODMAN%%-remote*} --root ${PODMAN_TMPDIR}/root \ + --runroot ${PODMAN_TMPDIR}/runroot \ + system service -t 99 tcp:localhost:$_SERVICE_PORT & + _SERVICE_PID=$! + wait_for_port localhost $_SERVICE_PORT + + # FIXME: #12023, RemoteSocket is always /run/something +# run_podman info --format '{{.Host.RemoteSocket.Path}}' +# is "$output" "tcp:localhost:$_SERVICE_PORT" \ +# "podman info works, and talks to the correct server" + + _run_podman_remote info --format '{{.Store.GraphRoot}}' + is "$output" "${PODMAN_TMPDIR}/root" \ + "podman info, talks to the right service" + + # Add another connection; make sure it does not get set as default + _run_podman_remote system connection add fakeconnect tcp://localhost:$(( _SERVICE_PORT + 1)) + _run_podman_remote info --format '{{.Store.GraphRoot}}' + # (Don't bother checking output; we just care about exit status) + + # Stop server. Use 'run' to avoid failing on nonzero exit status + run kill $_SERVICE_PID + run wait $_SERVICE_PID + _SERVICE_PID= + + run_podman system connection rm fakeconnect + run_podman system connection rm myconnect +} + +# If we have ssh access to localhost (unlikely in CI), test that. +@test "podman system connection - ssh" { + rand=$(random_string 20) + echo $rand >$PODMAN_TMPDIR/testfile + + # Can we actually ssh to localhost? + run ssh -q -o BatchMode=yes \ + -o UserKnownHostsFile=/dev/null \ + -o StrictHostKeyChecking=no \ + -o CheckHostIP=no \ + localhost \ + cat $PODMAN_TMPDIR/testfile + test "$status" -eq 0 || skip "cannot ssh to localhost" + is "$output" "$rand" "weird! ssh worked, but could not cat local file" + + # OK, ssh works. + # Create a new connection, over ssh, but using existing socket file + # (Remember, we're already podman-remote, there's a service running) + run_podman info --format '{{.Host.RemoteSocket.Path}}' + local socketpath="$output" + run_podman system connection add --socket-path "$socketpath" \ + mysshcon ssh://localhost + is "$output" "" "output from system connection add" + + # debug logs will confirm that we use ssh connection + _run_podman_remote --log-level=debug info --format '{{.Host.RemoteSocket.Path}}' + is "$output" ".*msg=\"SSH Agent Key .*" "we are truly using ssh" + + # Clean up + run_podman system connection rm mysshconn +} + +# vim: filetype=sh |