From 34739f44131e9c493c4021d119c368c82d080c84 Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Sun, 24 Oct 2021 22:23:13 +0200 Subject: [PATCH 01/51] Replace 'an user' => 'a user' Signed-off-by: Stefan Weil --- docs/source/markdown/podman-build.1.md | 2 +- docs/source/markdown/podman.1.md | 2 +- libpod/network/cni/cni_types.go | 2 +- pkg/cgroups/cgroups.go | 2 +- pkg/systemd/dbus.go | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/source/markdown/podman-build.1.md b/docs/source/markdown/podman-build.1.md index 0f52ad592d..0e65e02c9c 100644 --- a/docs/source/markdown/podman-build.1.md +++ b/docs/source/markdown/podman-build.1.md @@ -631,7 +631,7 @@ Sets the configuration for user namespaces when handling `RUN` instructions. The configured value can be "" (the empty string) or "container" to indicate that a new user namespace should be created, it can be "host" to indicate that the user namespace in which `podman` itself is being run should be reused, or -it can be the path to an user namespace which is already in use by another +it can be the path to a user namespace which is already in use by another process. #### **--userns-uid-map**=*mapping* diff --git a/docs/source/markdown/podman.1.md b/docs/source/markdown/podman.1.md index 864ff34bc2..49d40be0c9 100644 --- a/docs/source/markdown/podman.1.md +++ b/docs/source/markdown/podman.1.md @@ -317,7 +317,7 @@ Podman can also be used as non-root user. When podman runs in rootless mode, a u Containers created by a non-root user are not visible to other users and are not seen or managed by Podman running as root. -It is required to have multiple uids/gids set for an user. Be sure the user is present in the files `/etc/subuid` and `/etc/subgid`. +It is required to have multiple uids/gids set for a user. Be sure the user is present in the files `/etc/subuid` and `/etc/subgid`. If you have a recent version of usermod, you can execute the following commands to add the ranges to the files diff --git a/libpod/network/cni/cni_types.go b/libpod/network/cni/cni_types.go index 91fd1c27b7..35548f4f9f 100644 --- a/libpod/network/cni/cni_types.go +++ b/libpod/network/cni/cni_types.go @@ -175,7 +175,7 @@ func newIPAMLocalHostRange(subnet types.IPNet, leaseRange *types.LeaseRange, gw Subnet: subnet.String(), } - // an user provided a range, we add it here + // a user provided a range, we add it here if leaseRange != nil { if leaseRange.StartIP != nil { hostRange.RangeStart = leaseRange.StartIP.String() diff --git a/pkg/cgroups/cgroups.go b/pkg/cgroups/cgroups.go index f1ef538e4c..1debc020c1 100644 --- a/pkg/cgroups/cgroups.go +++ b/pkg/cgroups/cgroups.go @@ -461,7 +461,7 @@ func (c *CgroupControl) CreateSystemdUnit(path string) error { return systemdCreate(path, conn) } -// GetUserConnection returns an user connection to D-BUS +// GetUserConnection returns a user connection to D-BUS func GetUserConnection(uid int) (*systemdDbus.Conn, error) { return systemdDbus.NewConnection(func() (*dbus.Conn, error) { return dbusAuthConnection(uid, dbus.SessionBusPrivate) diff --git a/pkg/systemd/dbus.go b/pkg/systemd/dbus.go index c49f537b6c..04aaa117a2 100644 --- a/pkg/systemd/dbus.go +++ b/pkg/systemd/dbus.go @@ -84,7 +84,7 @@ func IsSystemdSessionValid(uid int) bool { return true } -// GetDbusConnection returns an user connection to D-BUS +// GetDbusConnection returns a user connection to D-BUS func GetLogindConnection(uid int) (*godbus.Conn, error) { return dbusAuthConnectionLogind(uid) } From d489abf26e4968ba370f578d8d984d6a22493189 Mon Sep 17 00:00:00 2001 From: Junichi Uekawa Date: Fri, 22 Oct 2021 13:39:37 +0900 Subject: [PATCH 02/51] fuse-overlay probably means fuse-overlayfs. fuse-overlayfs is usually the package name. Signed-off-by: Junichi Uekawa --- docs/source/markdown/podman-create.1.md | 2 +- docs/source/markdown/podman-run.1.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/markdown/podman-create.1.md b/docs/source/markdown/podman-create.1.md index 40439dacbf..d46400e310 100644 --- a/docs/source/markdown/podman-create.1.md +++ b/docs/source/markdown/podman-create.1.md @@ -1453,7 +1453,7 @@ Note: RHEL7 and Centos 7 will not have this feature until RHEL7.7 is released. In order for users to run rootless, there must be an entry for their username in /etc/subuid and /etc/subgid which lists the UIDs for their user namespace. Rootless Podman works better if the fuse-overlayfs and slirp4netns packages are installed. -The fuse-overlay package provides a userspace overlay storage driver, otherwise users need to use +The fuse-overlayfs package provides a userspace overlay storage driver, otherwise users need to use the vfs storage driver, which is diskspace expensive and does not perform well. slirp4netns is required for VPN, without it containers need to be run with the --network=host flag. diff --git a/docs/source/markdown/podman-run.1.md b/docs/source/markdown/podman-run.1.md index c538935fda..6cda72952c 100644 --- a/docs/source/markdown/podman-run.1.md +++ b/docs/source/markdown/podman-run.1.md @@ -1801,7 +1801,7 @@ Note: RHEL7 and Centos 7 will not have this feature until RHEL7.7 is released. In order for users to run rootless, there must be an entry for their username in _/etc/subuid_ and _/etc/subgid_ which lists the UIDs for their user namespace. Rootless Podman works better if the fuse-overlayfs and slirp4netns packages are installed. -The **fuse-overlay** package provides a userspace overlay storage driver, otherwise users need to use +The **fuse-overlayfs** package provides a userspace overlay storage driver, otherwise users need to use the **vfs** storage driver, which is diskspace expensive and does not perform well. slirp4netns is required for VPN, without it containers need to be run with the **--network=host** flag. From b3eaa08c5fc8164c62052aaf37776ee1813e1b47 Mon Sep 17 00:00:00 2001 From: Daniel J Walsh Date: Mon, 18 Oct 2021 11:54:44 -0400 Subject: [PATCH 03/51] Generate Kube should not print default structs If podman uses Workdir="/" or the workdir specified in the image, it should not add it to the yaml. If Podman find environment variables in the image, they should not get added to the yaml. If the container or pod do not have changes to SELinux we should not print seLinuxOpt{} If the container or pod do not change any dns options the yaml should not have a dnsOption={} If the container is not privileged it should not have privileged=false in the yaml. Fixes: https://github.com/containers/podman/issues/11995 Signed-off-by: Daniel J Walsh --- .../source/markdown/podman-generate-kube.1.md | 56 ++-------------- libpod/kube.go | 64 ++++++++++++------- test/e2e/generate_kube_test.go | 9 ++- 3 files changed, 55 insertions(+), 74 deletions(-) diff --git a/docs/source/markdown/podman-generate-kube.1.md b/docs/source/markdown/podman-generate-kube.1.md index 9ae3941ecc..a583afcf9f 100644 --- a/docs/source/markdown/podman-generate-kube.1.md +++ b/docs/source/markdown/podman-generate-kube.1.md @@ -54,13 +54,7 @@ spec: - docker-entrypoint.sh - mysqld env: - - name: PATH - value: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin - - name: TERM - value: xterm - name: HOSTNAME - - name: container - value: podman - name: GOSU_VERSION value: "1.10" - name: GPG_KEYS @@ -77,14 +71,14 @@ spec: ports: - containerPort: 3306 hostPort: 36533 - protocol: TCP resources: {} securityContext: - allowPrivilegeEscalation: true - privileged: false - readOnlyRootFilesystem: false + capabilities: + drop: + - CAP_MKNOD + - CAP_NET_RAW + - CAP_AUDIT_WRITE tty: true - workingDir: / status: {} ``` @@ -106,31 +100,18 @@ spec: containers: - command: - /bin/sh - env: - - name: PATH - value: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin - - name: TERM - value: xterm - - name: container - value: podman image: docker.io/library/alpine:latest name: test-bind-mount resources: {} securityContext: - allowPrivilegeEscalation: true capabilities: drop: - CAP_MKNOD - CAP_NET_RAW - CAP_AUDIT_WRITE - privileged: false - readOnlyRootFilesystem: false - seLinuxOptions: {} volumeMounts: - mountPath: /volume name: home-user-my-data-host - workingDir: / - dnsConfig: {} restartPolicy: Never volumes: - hostPath: @@ -158,31 +139,18 @@ spec: containers: - command: - /bin/sh - env: - - name: PATH - value: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin - - name: TERM - value: xterm - - name: container - value: podman image: docker.io/library/alpine:latest name: test-bind-mount resources: {} securityContext: - allowPrivilegeEscalation: true capabilities: drop: - CAP_MKNOD - CAP_NET_RAW - CAP_AUDIT_WRITE - privileged: false - readOnlyRootFilesystem: false - seLinuxOptions: {} volumeMounts: - mountPath: /volume name: priceless-data-pvc - workingDir: / - dnsConfig: {} restartPolicy: Never volumes: - name: priceless-data-pvc @@ -210,22 +178,9 @@ spec: - command: - python3 - /root/code/graph.py - env: - - name: PATH - value: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin - - name: TERM - value: xterm - - name: HOSTNAME - - name: container - value: podman image: quay.io/baude/demoweb:latest name: practicalarchimedes resources: {} - securityContext: - allowPrivilegeEscalation: true - capabilities: {} - privileged: false - readOnlyRootFilesystem: false tty: true workingDir: /root/code status: {} @@ -242,7 +197,6 @@ spec: - name: "8050" nodePort: 31269 port: 8050 - protocol: TCP targetPort: 0 selector: app: demoweb diff --git a/libpod/kube.go b/libpod/kube.go index f5291ce60a..d2ac157490 100644 --- a/libpod/kube.go +++ b/libpod/kube.go @@ -332,7 +332,7 @@ func newPodObject(podName string, annotations map[string]string, initCtrs, conta InitContainers: initCtrs, Volumes: volumes, } - if dnsOptions != nil { + if dnsOptions != nil && (len(dnsOptions.Nameservers)+len(dnsOptions.Searches)+len(dnsOptions.Options) > 0) { ps.DNSConfig = dnsOptions } p := v1.Pod{ @@ -447,11 +447,6 @@ func containerToV1Container(ctx context.Context, c *Container) (v1.Container, [] kubeVolumes = append(kubeVolumes, volumes...) } - envVariables, err := libpodEnvVarsToKubeEnvVars(c.config.Spec.Process.Env) - if err != nil { - return kubeContainer, kubeVolumes, nil, annotations, err - } - portmappings, err := c.PortMappings() if err != nil { return kubeContainer, kubeVolumes, nil, annotations, err @@ -489,15 +484,23 @@ func containerToV1Container(ctx context.Context, c *Container) (v1.Container, [] kubeContainer.Command = nil } + if c.WorkingDir() != "/" && imgData.Config.WorkingDir != c.WorkingDir() { + kubeContainer.WorkingDir = c.WorkingDir() + } + if imgData.User == c.User() { kubeSec.RunAsGroup, kubeSec.RunAsUser = nil, nil } - kubeContainer.WorkingDir = c.WorkingDir() + envVariables, err := libpodEnvVarsToKubeEnvVars(c.config.Spec.Process.Env, imgData.Config.Env) + if err != nil { + return kubeContainer, kubeVolumes, nil, annotations, err + } + kubeContainer.Env = envVariables + kubeContainer.Ports = ports // This should not be applicable //container.EnvFromSource = - kubeContainer.Env = envVariables kubeContainer.SecurityContext = kubeSec kubeContainer.StdinOnce = false kubeContainer.TTY = c.config.Spec.Process.Terminal @@ -600,9 +603,14 @@ func ocicniPortMappingToContainerPort(portMappings []ocicni.PortMapping) ([]v1.C } // libpodEnvVarsToKubeEnvVars converts a key=value string slice to []v1.EnvVar -func libpodEnvVarsToKubeEnvVars(envs []string) ([]v1.EnvVar, error) { +func libpodEnvVarsToKubeEnvVars(envs []string, imageEnvs []string) ([]v1.EnvVar, error) { defaultEnv := env.DefaultEnvVariables() envVars := make([]v1.EnvVar, 0, len(envs)) + imageMap := make(map[string]string, len(imageEnvs)) + for _, ie := range envs { + split := strings.SplitN(ie, "=", 2) + imageMap[split[0]] = split[1] + } for _, e := range envs { split := strings.SplitN(e, "=", 2) if len(split) != 2 { @@ -611,6 +619,9 @@ func libpodEnvVarsToKubeEnvVars(envs []string) ([]v1.EnvVar, error) { if defaultEnv[split[0]] == split[1] { continue } + if imageMap[split[0]] == split[1] { + continue + } ev := v1.EnvVar{ Name: split[0], Value: split[1], @@ -808,33 +819,42 @@ func generateKubeSecurityContext(c *Container) (*v1.SecurityContext, error) { capabilities = newCaps } + sc := v1.SecurityContext{ + // RunAsNonRoot is an optional parameter; our first implementations should be root only; however + // I'm leaving this as a bread-crumb for later + //RunAsNonRoot: &nonRoot, + } + if capabilities != nil { + sc.Capabilities = capabilities + } var selinuxOpts v1.SELinuxOptions opts := strings.SplitN(c.config.Spec.Annotations[define.InspectAnnotationLabel], ":", 2) - if len(opts) == 2 { + switch len(opts) { + case 2: switch opts[0] { case "type": selinuxOpts.Type = opts[1] + sc.SELinuxOptions = &selinuxOpts case "level": selinuxOpts.Level = opts[1] + sc.SELinuxOptions = &selinuxOpts } - } - if len(opts) == 1 { + case 1: if opts[0] == "disable" { selinuxOpts.Type = "spc_t" + sc.SELinuxOptions = &selinuxOpts } } - sc := v1.SecurityContext{ - Capabilities: capabilities, - Privileged: &privileged, - SELinuxOptions: &selinuxOpts, - // RunAsNonRoot is an optional parameter; our first implementations should be root only; however - // I'm leaving this as a bread-crumb for later - //RunAsNonRoot: &nonRoot, - ReadOnlyRootFilesystem: &ro, - AllowPrivilegeEscalation: &allowPrivEscalation, + if !allowPrivEscalation { + sc.AllowPrivilegeEscalation = &allowPrivEscalation + } + if privileged { + sc.Privileged = &privileged + } + if ro { + sc.ReadOnlyRootFilesystem = &ro } - if c.User() != "" { if !c.batched { c.lock.Lock() diff --git a/test/e2e/generate_kube_test.go b/test/e2e/generate_kube_test.go index 07515fe7b2..21f4ad8fa2 100644 --- a/test/e2e/generate_kube_test.go +++ b/test/e2e/generate_kube_test.go @@ -67,6 +67,10 @@ var _ = Describe("Podman generate kube", func() { err := yaml.Unmarshal(kube.Out.Contents(), pod) Expect(err).To(BeNil()) Expect(pod.Spec.HostNetwork).To(Equal(false)) + Expect(pod.Spec.SecurityContext).To(BeNil()) + Expect(pod.Spec.DNSConfig).To(BeNil()) + Expect(pod.Spec.Containers[0].WorkingDir).To(Equal("")) + Expect(pod.Spec.Containers[0].Env).To(BeNil()) numContainers := 0 for range pod.Spec.Containers { @@ -103,6 +107,7 @@ var _ = Describe("Podman generate kube", func() { err = yaml.Unmarshal(kube.Out.Contents(), pod) Expect(err).To(BeNil()) Expect(kube.OutputToString()).To(ContainSubstring("type: spc_t")) + }) It("podman generate service kube on container with --security-opt type", func() { @@ -1079,7 +1084,7 @@ USER test1` top1.WaitWithDefaultTimeout() Expect(top1).Should(Exit(0)) - top2 := podmanTest.Podman([]string{"run", "-dt", "--name", "top2", "--pod", "pod1", "--label", "io.containers.autoupdate=registry", "--label", "io.containers.autoupdate.authfile=/some/authfile.json", ALPINE, "top"}) + top2 := podmanTest.Podman([]string{"run", "-dt", "--name", "top2", "--workdir", "/root", "--pod", "pod1", "--label", "io.containers.autoupdate=registry", "--label", "io.containers.autoupdate.authfile=/some/authfile.json", ALPINE, "top"}) top2.WaitWithDefaultTimeout() Expect(top2).Should(Exit(0)) @@ -1090,6 +1095,8 @@ USER test1` pod := new(v1.Pod) err := yaml.Unmarshal(kube.Out.Contents(), pod) Expect(err).To(BeNil()) + Expect(pod.Spec.Containers[0].WorkingDir).To(Equal("")) + Expect(pod.Spec.Containers[1].WorkingDir).To(Equal("/root")) for _, ctr := range []string{"top1", "top2"} { v, ok := pod.GetAnnotations()["io.containers.autoupdate/"+ctr] From c3f3e6d3b8feabb3116dd5867f2e1117bdb5734f Mon Sep 17 00:00:00 2001 From: Matthew Heon Date: Wed, 20 Oct 2021 10:29:32 -0400 Subject: [PATCH 04/51] Remove infra ID from DB before removing containers If we interrupt pod removal between removing containers and removing the whole pod, the infra ID was still in the DB, and most pod operations would try to retrieve the infra container (and would this fail). Clear the infra ID from the DB just before we remove all containers to prevent this. Fixes #12034 [NO NEW TESTS NEEDED] This is a very narrow race and I have no idea how to repro it. Signed-off-by: Matthew Heon --- libpod/runtime_pod_linux.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/libpod/runtime_pod_linux.go b/libpod/runtime_pod_linux.go index 7571fdfff2..a90ea61258 100644 --- a/libpod/runtime_pod_linux.go +++ b/libpod/runtime_pod_linux.go @@ -264,6 +264,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. From f8ede7c5ed01324f47ebc01f69c11ab1046e1ebb Mon Sep 17 00:00:00 2001 From: Ed Santiago Date: Wed, 20 Oct 2021 09:11:57 -0600 Subject: [PATCH 05/51] System tests: confirm that -a and -l clash ...and fix one instance where there was no check Signed-off-by: Ed Santiago --- cmd/podman/containers/start.go | 3 +++ test/system/015-help.bats | 6 ++++++ test/system/045-start.bats | 4 ---- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/cmd/podman/containers/start.go b/cmd/podman/containers/start.go index 1163b90935..8813fc2730 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/test/system/015-help.bats b/test/system/015-help.bats index 5f38c34a16..b0795b524e 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/045-start.bats b/test/system/045-start.bats index 7e4bbde8d9..2ea057cd3a 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" { From 3b67336b608efd72a0e7a023b85b1b3dc2dc4746 Mon Sep 17 00:00:00 2001 From: cdoern Date: Mon, 4 Oct 2021 10:18:01 -0400 Subject: [PATCH 06/51] Pod Rm Infra Improvements Made changes so that if the pod contains all exited containers and only infra is running, remove the pod. resolves #11713 Signed-off-by: cdoern --- docs/source/markdown/podman-pod-rm.1.md | 2 +- libpod/container_internal.go | 2 +- libpod/runtime_pod_linux.go | 3 +-- test/e2e/pod_rm_test.go | 17 +++++++++++++++++ 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/docs/source/markdown/podman-pod-rm.1.md b/docs/source/markdown/podman-pod-rm.1.md index d185385b6e..ce91dab5b3 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/libpod/container_internal.go b/libpod/container_internal.go index 2ca49758d9..d71179017a 100644 --- a/libpod/container_internal.go +++ b/libpod/container_internal.go @@ -2100,7 +2100,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/runtime_pod_linux.go b/libpod/runtime_pod_linux.go index a90ea61258..3a6098de84 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 diff --git a/test/e2e/pod_rm_test.go b/test/e2e/pod_rm_test.go index c5d91d6798..ac1f322ef6 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)) + }) }) From 465e27cf10d1019297dfed643ed22d3d558a00da Mon Sep 17 00:00:00 2001 From: Nalin Dahyabhai Date: Mon, 18 Oct 2021 12:29:12 -0400 Subject: [PATCH 07/51] Use exponential backoff when waiting for a journal entry When looking for a cursor that matches the first journal entry for a given container, wait and try to find it using exponential backoff. [NO NEW TESTS NEEDED] Signed-off-by: Nalin Dahyabhai --- libpod/container_log_linux.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libpod/container_log_linux.go b/libpod/container_log_linux.go index ca1e11ef5e..562169ce24 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 From 6f779b23002710a74d6f2360ad0dc0029b5eefac Mon Sep 17 00:00:00 2001 From: Easton Man Date: Tue, 19 Oct 2021 20:11:03 +0800 Subject: [PATCH 08/51] systemd: compatible with rootless mode - change the type to forking to allow fork. - add default.target for user systemd service Signed-off-by: Easton Man --- contrib/systemd/system/podman-restart.service | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/contrib/systemd/system/podman-restart.service b/contrib/systemd/system/podman-restart.service index baf12b3aed..b8c1adca2a 100644 --- a/contrib/systemd/system/podman-restart.service +++ b/contrib/systemd/system/podman-restart.service @@ -5,8 +5,9 @@ StartLimitIntervalSec=0 [Service] Type=oneshot +RemainAfterExit=true Environment=LOGGING="--log-level=info" ExecStart=/usr/bin/podman $LOGGING start --all --filter restart-policy=always [Install] -WantedBy=multi-user.target +WantedBy=multi-user.target default.target From 8887cc7e449602d5ff371de84e24b83e448d8480 Mon Sep 17 00:00:00 2001 From: Daniel J Walsh Date: Mon, 18 Oct 2021 15:04:19 -0400 Subject: [PATCH 09/51] podman run --memory=0 ... should not set memory limit On Docker this is ignored, and it should be on Podman as well. This is documented in the man page. Fixes: https://github.com/containers/podman/issues/12002 Signed-off-by: Daniel J Walsh --- pkg/specgenutil/specgen.go | 12 +++++++----- test/system/030-run.bats | 5 +++++ 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/pkg/specgenutil/specgen.go b/pkg/specgenutil/specgen.go index 6a6397257b..8007e5d8e4 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/system/030-run.bats b/test/system/030-run.bats index 8640d427a3..2900540de7 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" From eead06b9de022f16b2555614fda2f34a9724875a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20Sj=C3=B6lund?= Date: Sun, 24 Oct 2021 09:51:48 +0300 Subject: [PATCH 10/51] [CI:DOCS] Fix typo keep_id -> keep-id MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Erik Sjölund --- troubleshooting.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/troubleshooting.md b/troubleshooting.md index a6c014625a..4bc115e44c 100644 --- a/troubleshooting.md +++ b/troubleshooting.md @@ -51,9 +51,9 @@ In cases where the container image runs as a specific, non-root user, though, th solution is to fix the user namespace. This would include container images such as the Jupyter Notebook image (which runs as "jovyan") and the Postgres image (which runs as "postgres"). In either case, use the `--userns` switch to map user namespaces, -most of the time by using keep_id option. +most of the time by using the **keep-id** option. -$ podman run -v "$PWD":/home/jovyan/work --userns=keep_id jupyter/scipy-notebook +$ podman run -v "$PWD":/home/jovyan/work --userns=keep-id jupyter/scipy-notebook --- ### 3) No such image or Bare keys cannot contain ':' From 2ff511798c44baeb7b3f6ccc413ec8eff24cfb4e Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Sun, 24 Oct 2021 22:35:47 +0200 Subject: [PATCH 11/51] Fix some typos in documentation and comments (found by codespell) Signed-off-by: Stefan Weil --- RELEASE_NOTES.md | 6 +++--- cmd/podman/images/scp.go | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index cca300f076..e3d9445954 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -133,7 +133,7 @@ ### Features - Containers inside VMs created by `podman machine` will now automatically handle port forwarding - containers in `podman machine` VMs that publish ports via `--publish` or `--publish-all` will have these ports not just forwarded on the VM, but also on the host system. - The `podman play kube` command's `--network` option now accepts advanced network options (e.g. `--network slirp4netns:port_handler=slirp4netns`) ([#10807](https://github.com/containers/podman/issues/10807)). -- The `podman play kube` commmand now supports Kubernetes liveness probes, which will be created as Podman healthchecks. +- The `podman play kube` command now supports Kubernetes liveness probes, which will be created as Podman healthchecks. - Podman now provides a systemd unit, `podman-restart.service`, which, when enabled, will restart all containers that were started with `--restart=always` after the system reboots. - Rootless Podman can now be configured to use CNI networking by default by using the `rootless_networking` option in `containers.conf`. - Images can now be pulled using `image:tag@digest` syntax (e.g. `podman pull fedora:34@sha256:1b0d4ddd99b1a8c8a80e885aafe6034c95f266da44ead992aab388e6aa91611a`) ([#6721](https://github.com/containers/podman/issues/6721)). @@ -389,7 +389,7 @@ - Fixed a bug where images with empty layers were stored incorrectly, causing them to be unable to be pushed or saved. - Fixed a bug where the `podman rmi` command could fail to remove corrupt images from storage. - Fixed a bug where the remote Podman client's `podman save` command did not support the `oci-dir` and `docker-dir` formats ([#9742](https://github.com/containers/podman/issues/9742)). -- Fixed a bug where volume mounts from `podman play kube` created with a trailing `/` in the container path were were not properly superceding named volumes from the image ([#9618](https://github.com/containers/podman/issues/9618)). +- Fixed a bug where volume mounts from `podman play kube` created with a trailing `/` in the container path were were not properly superseding named volumes from the image ([#9618](https://github.com/containers/podman/issues/9618)). - Fixed a bug where Podman could fail to build on 32-bit architectures. ### Misc @@ -1034,7 +1034,7 @@ ## 2.0.5 ### Features - Rootless Podman will now add an entry to `/etc/passwd` for the user who ran Podman if run with `--userns=keep-id`. -- The `podman system connection` command has been reworked to support multiple connections, and reenabled for use! +- The `podman system connection` command has been reworked to support multiple connections, and re-enabled for use! - Podman now has a new global flag, `--connection`, to specify a connection to a remote Podman API instance. ### Changes diff --git a/cmd/podman/images/scp.go b/cmd/podman/images/scp.go index 1765634406..c89a090bf5 100644 --- a/cmd/podman/images/scp.go +++ b/cmd/podman/images/scp.go @@ -185,7 +185,7 @@ func saveToRemote(image, localFile string, tag string, uri *urlP.URL, iden strin return errors.Wrapf(define.ErrInvalidArg, "Renaming of an image is currently not supported") } podman := os.Args[0] - run := podman + " image save " + image + " --format=oci-archive --output=" + remoteFile // run ssh image load of the file copied via scp. Files are reverse in thie case... + run := podman + " image save " + image + " --format=oci-archive --output=" + remoteFile // run ssh image load of the file copied via scp. Files are reverse in this case... _, err = connection.ExecRemoteCommand(dial, run) if err != nil { return nil From 955d01f5a81ffe376dd883fec118db8256fb450b Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Sun, 24 Oct 2021 22:44:38 +0200 Subject: [PATCH 12/51] [NO NEW TESTS NEEDED] Fix off-by-one index comparision (reported by LGTM) LGTM alert: Off-by-one index comparison against length may lead to out-of-bounds read. Signed-off-by: Stefan Weil --- libpod/info.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libpod/info.go b/libpod/info.go index 2eba4bbff9..47fda07256 100644 --- a/libpod/info.go +++ b/libpod/info.go @@ -333,7 +333,7 @@ func readKernelVersion() (string, error) { return "", err } f := bytes.Fields(buf) - if len(f) < 2 { + if len(f) < 3 { return string(bytes.TrimSpace(buf)), nil } return string(f[2]), nil From 7275d389b6ad3238c800e079238fb098886536de Mon Sep 17 00:00:00 2001 From: Paul Holzinger Date: Tue, 26 Oct 2021 16:11:46 +0200 Subject: [PATCH 13/51] Document to not set K8S envars for CNI Setting these environment variables can cause issues with custom CNI plugins, see #12083. Signed-off-by: Paul Holzinger --- libpod/network/cni/run.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/libpod/network/cni/run.go b/libpod/network/cni/run.go index 14634262cd..3f78d79a47 100644 --- a/libpod/network/cni/run.go +++ b/libpod/network/cni/run.go @@ -199,10 +199,8 @@ func getRuntimeConfig(netns, conName, conID, networkName string, ports []cniPort IfName: opts.InterfaceName, Args: [][2]string{ {"IgnoreUnknown", "1"}, - // FIXME: Should we set the K8S args? - //{"K8S_POD_NAMESPACE", conName}, - //{"K8S_POD_INFRA_CONTAINER_ID", conID}, - // K8S_POD_NAME is used by dnsname to get the container name + // Do not set the K8S env vars, see https://github.com/containers/podman/issues/12083. + // Only K8S_POD_NAME is used by dnsname to get the container name. {"K8S_POD_NAME", conName}, }, CapabilityArgs: map[string]interface{}{}, From 729310a85170895ee3b508f0aa29dc9d3225e83c Mon Sep 17 00:00:00 2001 From: Daniel J Walsh Date: Mon, 25 Oct 2021 14:30:10 -0400 Subject: [PATCH 14/51] If Dockerfile exists in same directory as service, we should not use it. We should only use the Containerfiles/Dockerfiles found in the context directory. Fixes: https://github.com/containers/podman/issues/12054 [NO NEW TESTS NEEDED] It is difficult to setup a test for this in the CI/CD system, but build tests should find if this PR broke anything. Signed-off-by: Daniel J Walsh --- pkg/api/handlers/compat/images_build.go | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/pkg/api/handlers/compat/images_build.go b/pkg/api/handlers/compat/images_build.go index 606c52e410..6152f1c02d 100644 --- a/pkg/api/handlers/compat/images_build.go +++ b/pkg/api/handlers/compat/images_build.go @@ -151,22 +151,19 @@ func BuildImage(w http.ResponseWriter, r *http.Request) { var m = []string{} if err := json.Unmarshal([]byte(query.Dockerfile), &m); err != nil { // it's not json, assume just a string - m = append(m, query.Dockerfile) + m = []string{filepath.Join(contextDirectory, query.Dockerfile)} } containerFiles = m } else { - containerFiles = []string{"Dockerfile"} + containerFiles = []string{filepath.Join(contextDirectory, "Dockerfile")} if utils.IsLibpodRequest(r) { - containerFiles = []string{"Containerfile"} - if _, err = os.Stat(filepath.Join(contextDirectory, "Containerfile")); err != nil { - if _, err1 := os.Stat(filepath.Join(contextDirectory, "Dockerfile")); err1 == nil { - containerFiles = []string{"Dockerfile"} - } else { + containerFiles = []string{filepath.Join(contextDirectory, "Containerfile")} + if _, err = os.Stat(containerFiles[0]); err != nil { + containerFiles = []string{filepath.Join(contextDirectory, "Dockerfile")} + if _, err1 := os.Stat(containerFiles[0]); err1 != nil { utils.BadRequest(w, "dockerfile", query.Dockerfile, err) } } - } else { - containerFiles = []string{"Dockerfile"} } } From 47afa6d96218605f9ca5b78c5a420f38e4c84cf9 Mon Sep 17 00:00:00 2001 From: Hironori Shiina Date: Fri, 22 Oct 2021 21:04:48 -0400 Subject: [PATCH 15/51] Fix a few problems in 'podman logs --tail' with journald driver The following problems regarding `logs --tail` with the journald log driver are fixed: - One more line than a specified value is displayed. - '--tail 0' displays all lines while the other log drivers displays nothing. - Partial lines are not considered. - If the journald events backend is used and a container has exited, nothing is displayed. Integration tests that should have detected the bugs are also fixed. The tests are executed with json-file log driver three times without this fix. Signed-off-by: Hironori Shiina --- libpod/container_log_linux.go | 33 +++++++++++------ test/e2e/logs_test.go | 69 +++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+), 11 deletions(-) diff --git a/libpod/container_log_linux.go b/libpod/container_log_linux.go index 562169ce24..4029d0af77 100644 --- a/libpod/container_log_linux.go +++ b/libpod/container_log_linux.go @@ -121,7 +121,24 @@ func (c *Container) readFromJournal(ctx context.Context, options *logs.LogOption }() tailQueue := []*logs.LogLine{} // needed for options.Tail - doTail := options.Tail > 0 + doTail := options.Tail >= 0 + doTailFunc := func() { + // Flush *once* we hit the end of the journal. + startIndex := int64(len(tailQueue)) + outputLines := int64(0) + for startIndex > 0 && outputLines < options.Tail { + startIndex-- + for startIndex > 0 && tailQueue[startIndex].Partial() { + startIndex-- + } + outputLines++ + } + for i := startIndex; i < int64(len(tailQueue)); i++ { + logChannel <- tailQueue[i] + } + tailQueue = nil + doTail = false + } lastReadCursor := "" for { select { @@ -152,16 +169,7 @@ func (c *Container) readFromJournal(ctx context.Context, options *logs.LogOption // Hit the end of the journal (so far?). if cursor == lastReadCursor { if doTail { - // Flush *once* we hit the end of the journal. - startIndex := int64(len(tailQueue)-1) - options.Tail - if startIndex < 0 { - startIndex = 0 - } - for i := startIndex; i < int64(len(tailQueue)); i++ { - logChannel <- tailQueue[i] - } - tailQueue = nil - doTail = false + doTailFunc() } // Unless we follow, quit. if !options.Follow { @@ -194,6 +202,9 @@ func (c *Container) readFromJournal(ctx context.Context, options *logs.LogOption return } if status == events.Exited { + if doTail { + doTailFunc() + } return } continue diff --git a/test/e2e/logs_test.go b/test/e2e/logs_test.go index 71d30f063f..16e48da198 100644 --- a/test/e2e/logs_test.go +++ b/test/e2e/logs_test.go @@ -13,6 +13,19 @@ import ( . "github.com/onsi/gomega/gexec" ) +func isEventBackendJournald(podmanTest *PodmanTestIntegration) bool { + if !podmanTest.RemoteTest { + // If not remote test, '--events-backend' is set to 'file' or 'none' + return false + } + info := podmanTest.Podman([]string{"info", "--format", "{{.Host.EventLogger}}"}) + info.WaitWithDefaultTimeout() + if info.OutputToString() == "journald" { + return true + } + return false +} + var _ = Describe("Podman logs", func() { var ( tempdir string @@ -38,8 +51,18 @@ var _ = Describe("Podman logs", func() { }) for _, log := range []string{"k8s-file", "journald", "json-file"} { + // This is important to move the 'log' var to the correct scope under Ginkgo flow. + log := log + + skipIfJournaldInContainer := func() { + if log == "journald" { + SkipIfInContainer("journalctl inside a container doesn't work correctly") + } + } It("all lines: "+log, func() { + skipIfJournaldInContainer() + logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) logc.WaitWithDefaultTimeout() Expect(logc).To(Exit(0)) @@ -53,6 +76,8 @@ var _ = Describe("Podman logs", func() { }) It("tail two lines: "+log, func() { + skipIfJournaldInContainer() + logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) logc.WaitWithDefaultTimeout() Expect(logc).To(Exit(0)) @@ -65,6 +90,8 @@ var _ = Describe("Podman logs", func() { }) It("tail zero lines: "+log, func() { + skipIfJournaldInContainer() + logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) logc.WaitWithDefaultTimeout() Expect(logc).To(Exit(0)) @@ -77,6 +104,8 @@ var _ = Describe("Podman logs", func() { }) It("tail 99 lines: "+log, func() { + skipIfJournaldInContainer() + logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) logc.WaitWithDefaultTimeout() Expect(logc).To(Exit(0)) @@ -89,6 +118,8 @@ var _ = Describe("Podman logs", func() { }) It("tail 800 lines: "+log, func() { + skipIfJournaldInContainer() + logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "i=1; while [ \"$i\" -ne 1000 ]; do echo \"line $i\"; i=$((i + 1)); done"}) logc.WaitWithDefaultTimeout() Expect(logc).To(Exit(0)) @@ -101,6 +132,8 @@ var _ = Describe("Podman logs", func() { }) It("tail 2 lines with timestamps: "+log, func() { + skipIfJournaldInContainer() + logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) logc.WaitWithDefaultTimeout() Expect(logc).To(Exit(0)) @@ -113,6 +146,8 @@ var _ = Describe("Podman logs", func() { }) It("since time 2017-08-07: "+log, func() { + skipIfJournaldInContainer() + logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) logc.WaitWithDefaultTimeout() Expect(logc).To(Exit(0)) @@ -125,6 +160,8 @@ var _ = Describe("Podman logs", func() { }) It("since duration 10m: "+log, func() { + skipIfJournaldInContainer() + logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) logc.WaitWithDefaultTimeout() Expect(logc).To(Exit(0)) @@ -137,6 +174,8 @@ var _ = Describe("Podman logs", func() { }) It("until duration 10m: "+log, func() { + skipIfJournaldInContainer() + logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) logc.WaitWithDefaultTimeout() Expect(logc).To(Exit(0)) @@ -149,6 +188,7 @@ var _ = Describe("Podman logs", func() { }) It("until time NOW: "+log, func() { + skipIfJournaldInContainer() logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) logc.WaitWithDefaultTimeout() @@ -165,13 +205,17 @@ var _ = Describe("Podman logs", func() { }) It("latest and container name should fail: "+log, func() { + skipIfJournaldInContainer() + results := podmanTest.Podman([]string{"logs", "-l", "foobar"}) results.WaitWithDefaultTimeout() Expect(results).To(ExitWithError()) }) It("two containers showing short container IDs: "+log, func() { + skipIfJournaldInContainer() SkipIfRemote("FIXME: podman-remote logs does not support showing two containers at the same time") + log1 := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) log1.WaitWithDefaultTimeout() Expect(log1).Should(Exit(0)) @@ -192,6 +236,8 @@ var _ = Describe("Podman logs", func() { }) It("podman logs on a created container should result in 0 exit code: "+log, func() { + skipIfJournaldInContainer() + session := podmanTest.Podman([]string{"create", "--log-driver", log, "-t", "--name", "log", ALPINE}) session.WaitWithDefaultTimeout() Expect(session).To(Exit(0)) @@ -202,6 +248,8 @@ var _ = Describe("Podman logs", func() { }) It("streaming output: "+log, func() { + skipIfJournaldInContainer() + containerName := "logs-f" logc := podmanTest.Podman([]string{"run", "--log-driver", log, "--name", containerName, "-dt", ALPINE, "sh", "-c", "echo podman-1; sleep 1; echo podman-2"}) @@ -210,6 +258,14 @@ var _ = Describe("Podman logs", func() { results := podmanTest.Podman([]string{"logs", "-f", containerName}) results.WaitWithDefaultTimeout() + + if log == "journald" && !isEventBackendJournald(podmanTest) { + // --follow + journald log-driver is only supported with journald events-backend(PR #10431) + Expect(results).To(Exit(125)) + Expect(results.ErrorToString()).To(ContainSubstring("using --follow with the journald --log-driver but without the journald --events-backend")) + return + } + Expect(results).To(Exit(0)) Expect(results.OutputToString()).To(ContainSubstring("podman-1")) @@ -233,6 +289,8 @@ var _ = Describe("Podman logs", func() { }) It("follow output stopped container: "+log, func() { + skipIfJournaldInContainer() + containerName := "logs-f" logc := podmanTest.Podman([]string{"run", "--log-driver", log, "--name", containerName, "-d", ALPINE, "true"}) @@ -241,10 +299,17 @@ var _ = Describe("Podman logs", func() { results := podmanTest.Podman([]string{"logs", "-f", containerName}) results.WaitWithDefaultTimeout() + if log == "journald" && !isEventBackendJournald(podmanTest) { + // --follow + journald log-driver is only supported with journald events-backend(PR #10431) + Expect(results).To(Exit(125)) + return + } Expect(results).To(Exit(0)) }) It("using container with container log-size: "+log, func() { + skipIfJournaldInContainer() + logc := podmanTest.Podman([]string{"run", "--log-driver", log, "--log-opt=max-size=10k", "-d", ALPINE, "sh", "-c", "echo podman podman podman"}) logc.WaitWithDefaultTimeout() Expect(logc).To(Exit(0)) @@ -266,6 +331,8 @@ var _ = Describe("Podman logs", func() { }) It("Make sure logs match expected length: "+log, func() { + skipIfJournaldInContainer() + logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-t", "--name", "test", ALPINE, "sh", "-c", "echo 1; echo 2"}) logc.WaitWithDefaultTimeout() Expect(logc).To(Exit(0)) @@ -284,6 +351,8 @@ var _ = Describe("Podman logs", func() { }) It("podman logs test stdout and stderr: "+log, func() { + skipIfJournaldInContainer() + cname := "log-test" logc := podmanTest.Podman([]string{"run", "--log-driver", log, "--name", cname, ALPINE, "sh", "-c", "echo stdout; echo stderr >&2"}) logc.WaitWithDefaultTimeout() From a67bf0f9213e38e74681134a9265c88121960808 Mon Sep 17 00:00:00 2001 From: Paul Holzinger Date: Tue, 26 Oct 2021 15:32:01 +0200 Subject: [PATCH 16/51] Slirp4netns with ipv6 set net.ipv6.conf.default.accept_dad=0 Duplicate Address Detection slows the ipv6 setup down for 1-2 seconds. Since slirp4netns is run it is own namespace and not directly routed we can skip this to make the ipv6 address immediately available. We change the default to make sure the slirp tap interface gets the correct value assigned so DAD is disabled for it. Also make sure to change this value back to the original after slirp4netns is ready in case users rely on this sysctl. Fixes #11062 Signed-off-by: Paul Holzinger --- libpod/networking_slirp4netns.go | 39 ++++++++++++++++++++++++++++++++ test/e2e/run_networking_test.go | 20 ++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/libpod/networking_slirp4netns.go b/libpod/networking_slirp4netns.go index c06d215e1a..e24b54032a 100644 --- a/libpod/networking_slirp4netns.go +++ b/libpod/networking_slirp4netns.go @@ -16,6 +16,7 @@ import ( "syscall" "time" + "github.com/containernetworking/plugins/pkg/ns" "github.com/containers/podman/v3/pkg/errorhandling" "github.com/containers/podman/v3/pkg/rootless" "github.com/containers/podman/v3/pkg/rootlessport" @@ -58,6 +59,8 @@ type slirp4netnsNetworkOptions struct { outboundAddr6 string } +const ipv6ConfDefaultAcceptDadSysctl = "/proc/sys/net/ipv6/conf/default/accept_dad" + func checkSlirpFlags(path string) (*slirpFeatures, error) { cmd := exec.Command(path, "--help") out, err := cmd.CombinedOutput() @@ -297,6 +300,39 @@ func (r *Runtime) setupSlirp4netns(ctr *Container) error { } cmd.Stdout = logFile cmd.Stderr = logFile + + var slirpReadyChan (chan struct{}) + + if netOptions.enableIPv6 { + slirpReadyChan = make(chan struct{}) + defer close(slirpReadyChan) + go func() { + err := ns.WithNetNSPath(netnsPath, func(_ ns.NetNS) error { + // Duplicate Address Detection slows the ipv6 setup down for 1-2 seconds. + // Since slirp4netns is run it is own namespace and not directly routed + // we can skip this to make the ipv6 address immediately available. + // We change the default to make sure the slirp tap interface gets the + // correct value assigned so DAD is disabled for it + // Also make sure to change this value back to the original after slirp4netns + // is ready in case users rely on this sysctl. + orgValue, err := ioutil.ReadFile(ipv6ConfDefaultAcceptDadSysctl) + if err != nil { + return err + } + err = ioutil.WriteFile(ipv6ConfDefaultAcceptDadSysctl, []byte("0"), 0644) + if err != nil { + return err + } + // wait for slirp to finish setup + <-slirpReadyChan + return ioutil.WriteFile(ipv6ConfDefaultAcceptDadSysctl, orgValue, 0644) + }) + if err != nil { + logrus.Warnf("failed to set net.ipv6.conf.default.accept_dad sysctl: %v", err) + } + }() + } + if err := cmd.Start(); err != nil { return errors.Wrapf(err, "failed to start slirp4netns process") } @@ -310,6 +346,9 @@ func (r *Runtime) setupSlirp4netns(ctr *Container) error { if err := waitForSync(syncR, cmd, logFile, 1*time.Second); err != nil { return err } + if slirpReadyChan != nil { + slirpReadyChan <- struct{}{} + } // Set a default slirp subnet. Parsing a string with the net helper is easier than building the struct myself _, ctr.slirp4netnsSubnet, _ = net.ParseCIDR(defaultSlirp4netnsSubnet) diff --git a/test/e2e/run_networking_test.go b/test/e2e/run_networking_test.go index 84707732bc..8d3b19b887 100644 --- a/test/e2e/run_networking_test.go +++ b/test/e2e/run_networking_test.go @@ -357,6 +357,26 @@ var _ = Describe("Podman run networking", func() { Expect(ncBusy).To(ExitWithError()) }) + It("podman run slirp4netns verify net.ipv6.conf.default.accept_dad=0", func() { + session := podmanTest.Podman([]string{"run", "--network", "slirp4netns:enable_ipv6=true", ALPINE, "ip", "addr"}) + session.Wait(30) + Expect(session).Should(Exit(0)) + // check the ipv6 setup id done without delay (https://github.com/containers/podman/issues/11062) + Expect(session.OutputToString()).To(ContainSubstring("inet6 fd00::")) + + const ipv6ConfDefaultAcceptDadSysctl = "/proc/sys/net/ipv6/conf/all/accept_dad" + + cat := SystemExec("cat", []string{ipv6ConfDefaultAcceptDadSysctl}) + cat.Wait(30) + Expect(cat).Should(Exit(0)) + sysctlValue := cat.OutputToString() + + session = podmanTest.Podman([]string{"run", "--network", "slirp4netns:enable_ipv6=true", ALPINE, "cat", ipv6ConfDefaultAcceptDadSysctl}) + session.Wait(30) + Expect(session).Should(Exit(0)) + Expect(session.OutputToString()).To(Equal(sysctlValue)) + }) + It("podman run network expose host port 18082 to container port 8000 using slirp4netns port handler", func() { session := podmanTest.Podman([]string{"run", "--network", "slirp4netns:port_handler=slirp4netns", "-dt", "-p", "18082:8000", ALPINE, "/bin/sh"}) session.Wait(30) From 9707ff5d49b46deafc32fcfb1ca9fc3c8575c693 Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Tue, 26 Oct 2021 21:05:22 +0200 Subject: [PATCH 17/51] vendor: update godbus to v5.0.6 Signed-off-by: Giuseppe Scrivano --- go.mod | 2 +- go.sum | 4 ++-- vendor/github.com/godbus/dbus/v5/auth.go | 2 +- vendor/github.com/godbus/dbus/v5/conn.go | 22 +++++++++++++++---- vendor/github.com/godbus/dbus/v5/message.go | 4 ++-- .../dbus/v5/transport_unixcred_netbsd.go | 14 ++++++++++++ vendor/modules.txt | 2 +- 7 files changed, 39 insertions(+), 11 deletions(-) create mode 100644 vendor/github.com/godbus/dbus/v5/transport_unixcred_netbsd.go diff --git a/go.mod b/go.mod index bdad4c2444..5808d70d7b 100644 --- a/go.mod +++ b/go.mod @@ -32,7 +32,7 @@ require ( github.com/dtylman/scp v0.0.0-20181017070807-f3000a34aef4 github.com/fsnotify/fsnotify v1.5.1 github.com/ghodss/yaml v1.0.0 - github.com/godbus/dbus/v5 v5.0.5 + github.com/godbus/dbus/v5 v5.0.6 github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf github.com/google/uuid v1.3.0 github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33 diff --git a/go.sum b/go.sum index b9eed814f7..952774d351 100644 --- a/go.sum +++ b/go.sum @@ -403,8 +403,8 @@ github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e h1:BWhy2j3IXJhjCbC68Fp github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/godbus/dbus/v5 v5.0.5 h1:9Eg0XUhQxtkV8ykTMKtMMYY72g4NgxtRq4jgh4Ih5YM= -github.com/godbus/dbus/v5 v5.0.5/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.0.6 h1:mkgN1ofwASrYnJ5W6U/BxG15eXXXjirgZc7CLqkcaro= +github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gogo/googleapis v1.2.0/go.mod h1:Njal3psf3qN6dwBtQfUmBZh2ybovJ0tlu3o/AC7HYjU= github.com/gogo/googleapis v1.4.0/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c= diff --git a/vendor/github.com/godbus/dbus/v5/auth.go b/vendor/github.com/godbus/dbus/v5/auth.go index eb0b2f4341..a59b4c0eb7 100644 --- a/vendor/github.com/godbus/dbus/v5/auth.go +++ b/vendor/github.com/godbus/dbus/v5/auth.go @@ -53,7 +53,7 @@ type Auth interface { // bus. Auth must not be called on shared connections. func (conn *Conn) Auth(methods []Auth) error { if methods == nil { - uid := strconv.Itoa(os.Getuid()) + uid := strconv.Itoa(os.Geteuid()) methods = []Auth{AuthExternal(uid), AuthCookieSha1(uid, getHomeDir())} } in := bufio.NewReader(conn.transport) diff --git a/vendor/github.com/godbus/dbus/v5/conn.go b/vendor/github.com/godbus/dbus/v5/conn.go index cb8966a742..76fc5cde3d 100644 --- a/vendor/github.com/godbus/dbus/v5/conn.go +++ b/vendor/github.com/godbus/dbus/v5/conn.go @@ -73,7 +73,7 @@ func SessionBus() (conn *Conn, err error) { return } -func getSessionBusAddress() (string, error) { +func getSessionBusAddress(autolaunch bool) (string, error) { if address := os.Getenv("DBUS_SESSION_BUS_ADDRESS"); address != "" && address != "autolaunch:" { return address, nil @@ -81,12 +81,26 @@ func getSessionBusAddress() (string, error) { os.Setenv("DBUS_SESSION_BUS_ADDRESS", address) return address, nil } + if !autolaunch { + return "", errors.New("dbus: couldn't determine address of session bus") + } return getSessionBusPlatformAddress() } // SessionBusPrivate returns a new private connection to the session bus. func SessionBusPrivate(opts ...ConnOption) (*Conn, error) { - address, err := getSessionBusAddress() + address, err := getSessionBusAddress(true) + if err != nil { + return nil, err + } + + return Dial(address, opts...) +} + +// SessionBusPrivate returns a new private connection to the session bus. If +// the session bus is not already open, do not attempt to launch it. +func SessionBusPrivateNoAutoStartup(opts ...ConnOption) (*Conn, error) { + address, err := getSessionBusAddress(false) if err != nil { return nil, err } @@ -121,7 +135,7 @@ func SystemBus() (conn *Conn, err error) { // ConnectSessionBus connects to the session bus. func ConnectSessionBus(opts ...ConnOption) (*Conn, error) { - address, err := getSessionBusAddress() + address, err := getSessionBusAddress(true) if err != nil { return nil, err } @@ -180,7 +194,7 @@ func Dial(address string, opts ...ConnOption) (*Conn, error) { // // Deprecated: use Dial with options instead. func DialHandler(address string, handler Handler, signalHandler SignalHandler) (*Conn, error) { - return Dial(address, WithSignalHandler(signalHandler)) + return Dial(address, WithHandler(handler), WithSignalHandler(signalHandler)) } // ConnOption is a connection option. diff --git a/vendor/github.com/godbus/dbus/v5/message.go b/vendor/github.com/godbus/dbus/v5/message.go index dd86aff4f4..16693eb301 100644 --- a/vendor/github.com/godbus/dbus/v5/message.go +++ b/vendor/github.com/godbus/dbus/v5/message.go @@ -279,8 +279,8 @@ func (msg *Message) EncodeToWithFDs(out io.Writer, order binary.ByteOrder) (fds // be either binary.LittleEndian or binary.BigEndian. If the message is not // valid or an error occurs when writing, an error is returned. func (msg *Message) EncodeTo(out io.Writer, order binary.ByteOrder) (err error) { - _, err = msg.EncodeToWithFDs(out, order); - return err; + _, err = msg.EncodeToWithFDs(out, order) + return err } // IsValid checks whether msg is a valid message and returns an diff --git a/vendor/github.com/godbus/dbus/v5/transport_unixcred_netbsd.go b/vendor/github.com/godbus/dbus/v5/transport_unixcred_netbsd.go new file mode 100644 index 0000000000..af7bafdf95 --- /dev/null +++ b/vendor/github.com/godbus/dbus/v5/transport_unixcred_netbsd.go @@ -0,0 +1,14 @@ +package dbus + +import "io" + +func (t *unixTransport) SendNullByte() error { + n, _, err := t.UnixConn.WriteMsgUnix([]byte{0}, nil, nil) + if err != nil { + return err + } + if n != 1 { + return io.ErrShortWrite + } + return nil +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 04bee22c9e..fad1d50935 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -353,7 +353,7 @@ github.com/ghodss/yaml github.com/go-logr/logr # github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 github.com/go-task/slim-sprig -# github.com/godbus/dbus/v5 v5.0.5 +# github.com/godbus/dbus/v5 v5.0.6 github.com/godbus/dbus/v5 # github.com/gogo/protobuf v1.3.2 github.com/gogo/protobuf/gogoproto From 0e1f67b725088c4d7425f56e260ddbb44078d11b Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Tue, 26 Oct 2021 21:05:42 +0200 Subject: [PATCH 18/51] cgroups: use SessionBusPrivateNoAutoStartup do not start up a dbus daemon if it is not already running. [NO NEW TESTS NEEDED] the fix is in a dependency. Closes: https://github.com/containers/podman/issues/9727 Signed-off-by: Giuseppe Scrivano --- pkg/cgroups/cgroups.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/cgroups/cgroups.go b/pkg/cgroups/cgroups.go index 1debc020c1..d0c0900129 100644 --- a/pkg/cgroups/cgroups.go +++ b/pkg/cgroups/cgroups.go @@ -464,7 +464,7 @@ func (c *CgroupControl) CreateSystemdUnit(path string) error { // GetUserConnection returns a user connection to D-BUS func GetUserConnection(uid int) (*systemdDbus.Conn, error) { return systemdDbus.NewConnection(func() (*dbus.Conn, error) { - return dbusAuthConnection(uid, dbus.SessionBusPrivate) + return dbusAuthConnection(uid, dbus.SessionBusPrivateNoAutoStartup) }) } From 2b85684ad1d2de0f412831e6225c176e0519bca3 Mon Sep 17 00:00:00 2001 From: Chris Evich Date: Tue, 26 Oct 2021 16:30:17 -0400 Subject: [PATCH 19/51] Fix systemd PID1 test Previously this test used an ad-hoc timeout mechanism to synchronize with output of the container ID. However, depending on runtime conditions this may not correctly correspond with complete startup of the systemd process. Consequently this test fails under some conditions with an error like: `System has not been booted with systemd as init system (PID 1). Can't operate. Failed to connect to bus: Host is down` Fix this by using the more appropriate `WaitContainerReady()` against output from system startup, close to finalization. In this way, the test status command cannot run until systemd is fully operational. Signed-off-by: Chris Evich --- test/e2e/systemd_test.go | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/test/e2e/systemd_test.go b/test/e2e/systemd_test.go index a1b25b723e..98def3d8f2 100644 --- a/test/e2e/systemd_test.go +++ b/test/e2e/systemd_test.go @@ -4,7 +4,6 @@ import ( "io/ioutil" "os" "strings" - "time" . "github.com/containers/podman/v3/test/utils" . "github.com/onsi/ginkgo" @@ -82,27 +81,13 @@ WantedBy=multi-user.target run := podmanTest.Podman([]string{"run", "--name", ctrName, "-t", "-i", "-d", ubi_init, "/sbin/init"}) run.WaitWithDefaultTimeout() Expect(run).Should(Exit(0)) - ctrID := run.OutputToString() logs := podmanTest.Podman([]string{"logs", ctrName}) logs.WaitWithDefaultTimeout() Expect(logs).Should(Exit(0)) // Give container 10 seconds to start - started := false - for i := 0; i < 10; i++ { - runningCtrs := podmanTest.Podman([]string{"ps", "-q", "--no-trunc"}) - runningCtrs.WaitWithDefaultTimeout() - Expect(runningCtrs).Should(Exit(0)) - - if strings.Contains(runningCtrs.OutputToString(), ctrID) { - started = true - break - } - - time.Sleep(1 * time.Second) - } - + started := podmanTest.WaitContainerReady(ctrName, "Reached target Multi-User System.", 30, 1) Expect(started).To(BeTrue()) systemctl := podmanTest.Podman([]string{"exec", "-t", "-i", ctrName, "systemctl", "status", "--no-pager"}) From 0519e7ef87a402a3f22193b49883cfc66812e61a Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Wed, 27 Oct 2021 09:31:32 +0200 Subject: [PATCH 20/51] utils: do not overwrite the err variable Signed-off-by: Giuseppe Scrivano --- utils/utils.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/utils.go b/utils/utils.go index b08630d2f7..55af41bb34 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -191,8 +191,8 @@ func moveProcessToScope(pidPath, slice, scope string) error { func MovePauseProcessToScope(pausePidPath string) { err := moveProcessToScope(pausePidPath, "user.slice", "podman-pause.scope") if err != nil { - unified, err := cgroups.IsCgroup2UnifiedMode() - if err != nil { + unified, err2 := cgroups.IsCgroup2UnifiedMode() + if err2 != nil { logrus.Warnf("Failed to detect if running with cgroup unified: %v", err) } if RunsOnSystemd() && unified { From 246782133cc36e66db0f4facccd7dabcd76a92d5 Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Wed, 27 Oct 2021 09:44:54 +0200 Subject: [PATCH 21/51] runtime: check for pause pid existence check that the pause pid exists before trying to move it to a separate scope. Closes: https://github.com/containers/podman/issues/12065 Signed-off-by: Giuseppe Scrivano --- libpod/runtime.go | 6 +++++- test/e2e/system_reset_test.go | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/libpod/runtime.go b/libpod/runtime.go index c22d873249..a99f55fb3f 100644 --- a/libpod/runtime.go +++ b/libpod/runtime.go @@ -541,7 +541,11 @@ func makeRuntime(ctx context.Context, runtime *Runtime) (retErr error) { return err } if became { - utils.MovePauseProcessToScope(pausePid) + // Check if the pause process was created. If it was created, then + // move it to its own systemd scope. + if _, err = os.Stat(pausePid); err == nil { + utils.MovePauseProcessToScope(pausePid) + } os.Exit(ret) } } diff --git a/test/e2e/system_reset_test.go b/test/e2e/system_reset_test.go index 102526a468..93ab166cd2 100644 --- a/test/e2e/system_reset_test.go +++ b/test/e2e/system_reset_test.go @@ -60,6 +60,8 @@ var _ = Describe("podman system reset", func() { session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) + Expect(session.ErrorToString()).To(Not(ContainSubstring("Failed to add pause process"))) + // If remote then the API service should have exited // On local tests this is a noop podmanTest.StartRemoteService() From a208bc24de85f78129859586571fcf25b6793f9e Mon Sep 17 00:00:00 2001 From: Matej Vasek Date: Sat, 23 Oct 2021 00:11:41 +0200 Subject: [PATCH 22/51] Set DOCKER_HOST in the VM [NO TESTS NEEDED] Signed-off-by: Matej Vasek --- pkg/machine/ignition.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/pkg/machine/ignition.go b/pkg/machine/ignition.go index e211f5ea6b..42d729458d 100644 --- a/pkg/machine/ignition.go +++ b/pkg/machine/ignition.go @@ -304,6 +304,24 @@ machine_enabled=true }, }) + setDockerHost := `export DOCKER_HOST="unix://$(podman info -f "{{.Host.RemoteSocket.Path}}")" +` + + files = append(files, File{ + Node: Node{ + Group: getNodeGrp("root"), + Path: "/etc/profile.d/docker-host.sh", + User: getNodeUsr("root"), + }, + FileEmbedded1: FileEmbedded1{ + Append: nil, + Contents: Resource{ + Source: encodeDataURLPtr(setDockerHost), + }, + Mode: intToPtr(0644), + }, + }) + return files } From 2d6252b98a94482346cc8dd16f97b4c59d16dc4d Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Thu, 28 Oct 2021 11:18:48 +0200 Subject: [PATCH 23/51] runtime: change PID existence check commit 6b3b0a17c625bdf71b0ec8b783b288886d8e48d7 introduced a check for the PID file before attempting to move the PID to a new scope. This is still vulnerable to TOCTOU race condition though, since the PID file or the PID can be removed/killed after the check was successful but before it was used. Closes: https://github.com/containers/podman/issues/12065 [NO NEW TESTS NEEDED] it fixes a CI flake Signed-off-by: Giuseppe Scrivano --- libpod/runtime.go | 4 +--- utils/utils.go | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/libpod/runtime.go b/libpod/runtime.go index a99f55fb3f..a208b6db44 100644 --- a/libpod/runtime.go +++ b/libpod/runtime.go @@ -543,9 +543,7 @@ func makeRuntime(ctx context.Context, runtime *Runtime) (retErr error) { if became { // Check if the pause process was created. If it was created, then // move it to its own systemd scope. - if _, err = os.Stat(pausePid); err == nil { - utils.MovePauseProcessToScope(pausePid) - } + utils.MovePauseProcessToScope(pausePid) os.Exit(ret) } } diff --git a/utils/utils.go b/utils/utils.go index 55af41bb34..109ae088b9 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -14,6 +14,7 @@ import ( "github.com/containers/podman/v3/libpod/define" "github.com/containers/podman/v3/pkg/cgroups" "github.com/containers/storage/pkg/archive" + "github.com/godbus/dbus/v5" "github.com/pkg/errors" "github.com/sirupsen/logrus" ) @@ -177,13 +178,26 @@ func RunsOnSystemd() bool { func moveProcessToScope(pidPath, slice, scope string) error { data, err := ioutil.ReadFile(pidPath) if err != nil { + // do not raise an error if the file doesn't exist + if os.IsNotExist(err) { + return nil + } return errors.Wrapf(err, "cannot read pid file %s", pidPath) } pid, err := strconv.ParseUint(string(data), 10, 0) if err != nil { return errors.Wrapf(err, "cannot parse pid file %s", pidPath) } - return RunUnderSystemdScope(int(pid), slice, scope) + err = RunUnderSystemdScope(int(pid), slice, scope) + + // If the PID is not valid anymore, do not return an error. + if dbusErr, ok := err.(dbus.Error); ok { + if dbusErr.Name == "org.freedesktop.DBus.Error.UnixProcessIdUnknown" { + return nil + } + } + + return err } // MovePauseProcessToScope moves the pause process used for rootless mode to keep the namespaces alive to From 6bf6d72372005447a3f4a09f31b08e0202f99bc4 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 27 Oct 2021 13:38:43 +0000 Subject: [PATCH 24/51] Set Checkpointed state to false after restore A restored container still had the state set to 'Checkpointed: true' which seems wrong if it running again. [NO NEW TESTS NEEDED] Signed-off-by: Adrian Reber --- libpod/container_internal_linux.go | 1 + 1 file changed, 1 insertion(+) diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go index 310110679a..208e089b51 100644 --- a/libpod/container_internal_linux.go +++ b/libpod/container_internal_linux.go @@ -1483,6 +1483,7 @@ func (c *Container) restore(ctx context.Context, options ContainerCheckpointOpti logrus.Debugf("Restored container %s", c.ID()) c.state.State = define.ContainerStateRunning + c.state.Checkpointed = false if !options.Keep { // Delete all checkpoint related files. At this point, in theory, all files From fa29ca7106a332ef62ccd73d474c8e7d831b1f9d Mon Sep 17 00:00:00 2001 From: Giacomo Sanchietti Date: Fri, 29 Oct 2021 14:22:49 +0200 Subject: [PATCH 25/51] Fix pause usage example The page contains a wrong 'stop' command example. Signed-off-by: Giacomo Sanchietti --- docs/source/markdown/podman-pause.1.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/markdown/podman-pause.1.md b/docs/source/markdown/podman-pause.1.md index 1233628225..90ea1e32ed 100644 --- a/docs/source/markdown/podman-pause.1.md +++ b/docs/source/markdown/podman-pause.1.md @@ -31,7 +31,7 @@ podman pause 860a4b23 Pause all **running** containers. ``` -podman stop -a +podman pause -a ``` ## SEE ALSO From 0ded340e6bbc7952678d93029726ec83992e5010 Mon Sep 17 00:00:00 2001 From: Praveen Kumar Date: Fri, 29 Oct 2021 11:10:26 -0700 Subject: [PATCH 26/51] Fix help message case for `podman version` This is a cosmetic change. The help message for `podman version` is in title case whereas all other command help messages are not in title case. This stands out as inconsistent when looking at the output of `podman help`. Signed-off-by: Praveen Kumar --- cmd/podman/system/version.go | 2 +- test/e2e/version_test.go | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/cmd/podman/system/version.go b/cmd/podman/system/version.go index 4502b156cc..f71af8e72a 100644 --- a/cmd/podman/system/version.go +++ b/cmd/podman/system/version.go @@ -20,7 +20,7 @@ var ( versionCommand = &cobra.Command{ Use: "version [options]", Args: validate.NoArgs, - Short: "Display the Podman Version Information", + Short: "Display the Podman version information", RunE: version, ValidArgsFunction: completion.AutocompleteNone, } diff --git a/test/e2e/version_test.go b/test/e2e/version_test.go index 75986e671b..9398248b88 100644 --- a/test/e2e/version_test.go +++ b/test/e2e/version_test.go @@ -31,7 +31,6 @@ var _ = Describe("Podman version", func() { f := CurrentGinkgoTestDescription() processTestResult(f) podmanTest.SeedImages() - }) It("podman version", func() { @@ -96,4 +95,13 @@ var _ = Describe("Podman version", func() { session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) }) + + It("podman help", func() { + session := podmanTest.Podman([]string{"help"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + Expect(session.Out.Contents()).Should( + ContainSubstring("Display the Podman version information"), + ) + }) }) From 2a0aad6beb9b0ff5bb9d09b306426a17d061a21c Mon Sep 17 00:00:00 2001 From: Ashley Cui Date: Wed, 27 Oct 2021 10:38:42 -0400 Subject: [PATCH 27/51] Add information on how podman machine is updated Update documentation on how the default podman machine distribution, FCOS, is updated. Signed-off-by: Ashley Cui --- docs/source/markdown/podman-machine-init.1.md | 4 ++++ docs/source/markdown/podman-machine-ssh.1.md | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/source/markdown/podman-machine-init.1.md b/docs/source/markdown/podman-machine-init.1.md index 8a65be5a96..8b26728d58 100644 --- a/docs/source/markdown/podman-machine-init.1.md +++ b/docs/source/markdown/podman-machine-init.1.md @@ -18,6 +18,10 @@ tied to the Linux kernel. SSH keys are automatically generated to access the VM, and system connections to the root account and a user account inside the VM are added. +By default, the VM distribution is [Fedora CoreOS](https://getfedora.org/en/coreos?stream=testing). +Fedora CoreOS upgrades come out every 14 days and are detected and installed automatically. The VM will be rebooted during the upgrade. +For more information on updates and advanced configuration, please see the FCOS update docs [here](https://docs.fedoraproject.org/en-US/fedora-coreos/auto-updates/) and [here](https://coreos.github.io/zincati/usage/updates-strategy/). + ## OPTIONS #### **--cpus**=*number* diff --git a/docs/source/markdown/podman-machine-ssh.1.md b/docs/source/markdown/podman-machine-ssh.1.md index a5cf691074..24ae586077 100644 --- a/docs/source/markdown/podman-machine-ssh.1.md +++ b/docs/source/markdown/podman-machine-ssh.1.md @@ -9,7 +9,7 @@ podman\-machine\-ssh - SSH into a virtual machine ## DESCRIPTION SSH into a Podman-managed virtual machine and optionally execute a command -on the virtual machine. Unless using the default virtual machine, the +on the virtual machine. Unless using the default virtual machine, the first argument must be the virtual machine name. The optional command to execute can then follow. If no command is provided, an interactive session with the virtual machine is established. From 5889c2c241e7ff3d2f26fb5e6e6e431b52b4e121 Mon Sep 17 00:00:00 2001 From: Chris Evich Date: Fri, 29 Oct 2021 11:06:21 -0400 Subject: [PATCH 28/51] Cirrus: Authorize rootless user self-ssh Future testing needs dictate rootless (in addition to root) users are able to ssh to localhost. Add ssh-key generation commands for the rootless user, and authorize their public key. Minor: Also remove update of `/etc/sub{uid,gid}` files, since this is now done automatically by `{user,group}add` commands. Signed-off-by: Chris Evich --- contrib/cirrus/lib.sh | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/contrib/cirrus/lib.sh b/contrib/cirrus/lib.sh index 9a7bfba8fa..9b7c613f5d 100644 --- a/contrib/cirrus/lib.sh +++ b/contrib/cirrus/lib.sh @@ -143,6 +143,8 @@ setup_rootless() { local rootless_uid local rootless_gid local env_var_val + local akfilepath + local sshcmd # Only do this once; established by setup_environment.sh # shellcheck disable=SC2154 @@ -169,24 +171,25 @@ setup_rootless() { ssh-keygen -P "" -f "$HOME/.ssh/id_rsa" msg "Allowing ssh key for $ROOTLESS_USER" + akfilepath="/home/$ROOTLESS_USER/.ssh/authorized_keys" (umask 077 && mkdir "/home/$ROOTLESS_USER/.ssh") chown -R $ROOTLESS_USER:$ROOTLESS_USER "/home/$ROOTLESS_USER/.ssh" install -o $ROOTLESS_USER -g $ROOTLESS_USER -m 0600 \ - "$HOME/.ssh/id_rsa.pub" "/home/$ROOTLESS_USER/.ssh/authorized_keys" + "$HOME/.ssh/id_rsa.pub" "$akfilepath" # Makes debugging easier - cat /root/.ssh/authorized_keys >> "/home/$ROOTLESS_USER/.ssh/authorized_keys" - - msg "Configuring subuid and subgid" - grep -q "${ROOTLESS_USER}" /etc/subuid || \ - echo "${ROOTLESS_USER}:$[rootless_uid * 100]:65536" | \ - tee -a /etc/subuid >> /etc/subgid + cat /root/.ssh/authorized_keys >> "$akfilepath" msg "Ensure the ssh daemon is up and running within 5 minutes" systemctl start sshd - lilto ssh $ROOTLESS_USER@localhost \ - -o UserKnownHostsFile=/dev/null \ - -o StrictHostKeyChecking=no \ - -o CheckHostIP=no true + sshcmd="ssh $ROOTLESS_USER@localhost + -o UserKnownHostsFile=/dev/null + -o StrictHostKeyChecking=no + -o CheckHostIP=no" + lilto $sshcmd true # retry until sshd is up + + msg "Configuring rootless user self-access to ssh to localhost" + $sshcmd ssh-keygen -P '""' -f "/home/$ROOTLESS_USER/.ssh/id_rsa" + cat "/home/$ROOTLESS_USER/.ssh/id_rsa" >> "$akfilepath" } install_test_configs() { From a8332f69460f687d704cd804673b0ccca8fd5403 Mon Sep 17 00:00:00 2001 From: Matej Vasek Date: Mon, 1 Nov 2021 22:30:57 +0100 Subject: [PATCH 29/51] Fix swagger definitions [NO TESTS NEEDED] Signed-off-by: Matej Vasek --- pkg/api/server/register_images.go | 4 ++-- pkg/api/server/swagger.go | 14 +++++++++++--- pkg/domain/entities/images.go | 1 + 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/pkg/api/server/register_images.go b/pkg/api/server/register_images.go index 95981226c2..f666692566 100644 --- a/pkg/api/server/register_images.go +++ b/pkg/api/server/register_images.go @@ -103,7 +103,7 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // - application/json // responses: // 200: - // $ref: "#/responses/DockerImageSummary" + // $ref: "#/responses/DockerImageSummaryResponse" // 500: // $ref: '#/responses/InternalError' r.Handle(VersionedPath("/images/json"), s.APIHandler(compat.GetImages)).Methods(http.MethodGet) @@ -831,7 +831,7 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // - application/json // responses: // 200: - // $ref: "#/responses/DockerImageSummary" + // $ref: "#/responses/LibpodImageSummaryResponse" // 500: // $ref: '#/responses/InternalError' r.Handle(VersionedPath("/libpod/images/json"), s.APIHandler(libpod.GetImages)).Methods(http.MethodGet) diff --git a/pkg/api/server/swagger.go b/pkg/api/server/swagger.go index 0fd66652e3..3f8f6f9c51 100644 --- a/pkg/api/server/swagger.go +++ b/pkg/api/server/swagger.go @@ -6,6 +6,7 @@ import ( "github.com/containers/podman/v3/pkg/domain/entities" "github.com/containers/podman/v3/pkg/domain/entities/reports" "github.com/containers/podman/v3/pkg/errorhandling" + docker "github.com/docker/docker/api/types" ) // No such image @@ -134,9 +135,16 @@ type swagPodAlreadyStopped struct { } } -// Image summary -// swagger:response DockerImageSummary -type swagImageSummary struct { +// Image summary for compat API +// swagger:response DockerImageSummaryResponse +type swagDockerImageSummaryResponse struct { + // in:body + Body []docker.ImageSummary +} + +// Image summary for libpod API +// swagger:response LibpodImageSummaryResponse +type swagLibpodImageSummaryResponse struct { // in:body Body []entities.ImageSummary } diff --git a/pkg/domain/entities/images.go b/pkg/domain/entities/images.go index 5a469d9812..6d93ad4033 100644 --- a/pkg/domain/entities/images.go +++ b/pkg/domain/entities/images.go @@ -50,6 +50,7 @@ func (i *Image) Id() string { // nolint return i.ID } +// swagger:model LibpodImageSummary type ImageSummary struct { ID string `json:"Id"` ParentId string // nolint From 3bd80ac9ae2ea512a5ce9140bedab742910d0513 Mon Sep 17 00:00:00 2001 From: Ondra Machacek Date: Wed, 20 Oct 2021 18:45:56 +0200 Subject: [PATCH 30/51] Handle HTTP 409 error messages properly for Pod actions This PR fixes the case when the API return HTTP 409 response. Where the API return the body format different then for other HTTP error codes. Signed-off-by: Ondra Machacek --- pkg/bindings/connection.go | 5 +++++ pkg/bindings/errors.go | 29 +++++++++++++++++++-------- pkg/bindings/pods/pods.go | 14 +++++++------ pkg/bindings/test/common_test.go | 17 +++++++++++++--- pkg/bindings/test/pods_test.go | 26 ++++++++++++++++++++++++ pkg/domain/infra/tunnel/containers.go | 2 +- pkg/domain/infra/tunnel/images.go | 2 +- pkg/domain/infra/tunnel/network.go | 2 +- pkg/domain/infra/tunnel/secrets.go | 4 ++-- pkg/domain/infra/tunnel/volumes.go | 2 +- pkg/errorhandling/errorhandling.go | 14 +++++++++++++ 11 files changed, 94 insertions(+), 23 deletions(-) diff --git a/pkg/bindings/connection.go b/pkg/bindings/connection.go index e2c46e481b..2fe86ca39b 100644 --- a/pkg/bindings/connection.go +++ b/pkg/bindings/connection.go @@ -379,6 +379,11 @@ func (h *APIResponse) IsClientError() bool { return h.Response.StatusCode/100 == 4 } +// IsConflictError returns true if the response code is 409 +func (h *APIResponse) IsConflictError() bool { + return h.Response.StatusCode == 409 +} + // IsServerError returns true if the response code is 5xx func (h *APIResponse) IsServerError() bool { return h.Response.StatusCode/100 == 5 diff --git a/pkg/bindings/errors.go b/pkg/bindings/errors.go index 9c311d9120..ec837b39c0 100644 --- a/pkg/bindings/errors.go +++ b/pkg/bindings/errors.go @@ -12,17 +12,22 @@ var ( ErrNotImplemented = errors.New("function not implemented") ) -func handleError(data []byte) error { - e := errorhandling.ErrorModel{} - if err := json.Unmarshal(data, &e); err != nil { +func handleError(data []byte, unmarshalErrorInto interface{}) error { + if err := json.Unmarshal(data, unmarshalErrorInto); err != nil { return err } - return e + return unmarshalErrorInto.(error) } // Process drains the response body, and processes the HTTP status code // Note: Closing the response.Body is left to the caller func (h APIResponse) Process(unmarshalInto interface{}) error { + return h.ProcessWithError(unmarshalInto, &errorhandling.ErrorModel{}) +} + +// Process drains the response body, and processes the HTTP status code +// Note: Closing the response.Body is left to the caller +func (h APIResponse) ProcessWithError(unmarshalInto interface{}, unmarshalErrorInto interface{}) error { data, err := ioutil.ReadAll(h.Response.Body) if err != nil { return errors.Wrap(err, "unable to process API response") @@ -33,14 +38,22 @@ func (h APIResponse) Process(unmarshalInto interface{}) error { } return nil } + + if h.IsConflictError() { + return handleError(data, unmarshalErrorInto) + } + // TODO should we add a debug here with the response code? - return handleError(data) + return handleError(data, &errorhandling.ErrorModel{}) } func CheckResponseCode(inError error) (int, error) { - e, ok := inError.(errorhandling.ErrorModel) - if !ok { + switch e := inError.(type) { + case *errorhandling.ErrorModel: + return e.Code(), nil + case *errorhandling.PodConflictErrorModel: + return e.Code(), nil + default: return -1, errors.New("error is not type ErrorModel") } - return e.Code(), nil } diff --git a/pkg/bindings/pods/pods.go b/pkg/bindings/pods/pods.go index a1a431a3b8..3b5832373a 100644 --- a/pkg/bindings/pods/pods.go +++ b/pkg/bindings/pods/pods.go @@ -9,6 +9,7 @@ import ( "github.com/containers/podman/v3/pkg/api/handlers" "github.com/containers/podman/v3/pkg/bindings" "github.com/containers/podman/v3/pkg/domain/entities" + "github.com/containers/podman/v3/pkg/errorhandling" jsoniter "github.com/json-iterator/go" ) @@ -97,7 +98,7 @@ func Kill(ctx context.Context, nameOrID string, options *KillOptions) (*entities } defer response.Body.Close() - return &report, response.Process(&report) + return &report, response.ProcessWithError(&report, &errorhandling.PodConflictErrorModel{}) } // Pause pauses all running containers in a given pod. @@ -117,7 +118,7 @@ func Pause(ctx context.Context, nameOrID string, options *PauseOptions) (*entiti } defer response.Body.Close() - return &report, response.Process(&report) + return &report, response.ProcessWithError(&report, &errorhandling.PodConflictErrorModel{}) } // Prune by default removes all non-running pods in local storage. @@ -184,7 +185,7 @@ func Restart(ctx context.Context, nameOrID string, options *RestartOptions) (*en } defer response.Body.Close() - return &report, response.Process(&report) + return &report, response.ProcessWithError(&report, &errorhandling.PodConflictErrorModel{}) } // Remove deletes a Pod from from local storage. The optional force parameter denotes @@ -232,7 +233,8 @@ func Start(ctx context.Context, nameOrID string, options *StartOptions) (*entiti report.Id = nameOrID return &report, nil } - return &report, response.Process(&report) + + return &report, response.ProcessWithError(&report, &errorhandling.PodConflictErrorModel{}) } // Stop stops all containers in a Pod. The optional timeout parameter can be @@ -260,7 +262,7 @@ func Stop(ctx context.Context, nameOrID string, options *StopOptions) (*entities report.Id = nameOrID return &report, nil } - return &report, response.Process(&report) + return &report, response.ProcessWithError(&report, &errorhandling.PodConflictErrorModel{}) } // Top gathers statistics about the running processes in a pod. The nameOrID can be a pod name @@ -316,7 +318,7 @@ func Unpause(ctx context.Context, nameOrID string, options *UnpauseOptions) (*en } defer response.Body.Close() - return &report, response.Process(&report) + return &report, response.ProcessWithError(&report, &errorhandling.PodConflictErrorModel{}) } // Stats display resource-usage statistics of one or more pods. diff --git a/pkg/bindings/test/common_test.go b/pkg/bindings/test/common_test.go index 91ebe21fca..d996595bfb 100644 --- a/pkg/bindings/test/common_test.go +++ b/pkg/bindings/test/common_test.go @@ -225,12 +225,23 @@ func (b *bindingTest) RunTopContainer(containerName *string, podName *string) (s // This method creates a pod with the given pod name. // Podname is an optional parameter func (b *bindingTest) Podcreate(name *string) { + b.PodcreateAndExpose(name, nil) +} + +// This method creates a pod with the given pod name and publish port. +// Podname is an optional parameter +// port is an optional parameter +func (b *bindingTest) PodcreateAndExpose(name *string, port *string) { + command := []string{"pod", "create"} if name != nil { podname := *name - b.runPodman([]string{"pod", "create", "--name", podname}).Wait(45) - } else { - b.runPodman([]string{"pod", "create"}).Wait(45) + command = append(command, "--name", podname) + } + if port != nil { + podport := *port + command = append(command, "--publish", podport) } + b.runPodman(command).Wait(45) } // StringInSlice returns a boolean based on whether a given diff --git a/pkg/bindings/test/pods_test.go b/pkg/bindings/test/pods_test.go index 5331cf4398..879d4d00dc 100644 --- a/pkg/bindings/test/pods_test.go +++ b/pkg/bindings/test/pods_test.go @@ -1,6 +1,7 @@ package test_bindings import ( + "fmt" "net/http" "strings" "time" @@ -9,7 +10,9 @@ import ( "github.com/containers/podman/v3/pkg/bindings" "github.com/containers/podman/v3/pkg/bindings/pods" "github.com/containers/podman/v3/pkg/domain/entities" + "github.com/containers/podman/v3/pkg/errorhandling" "github.com/containers/podman/v3/pkg/specgen" + "github.com/containers/podman/v3/utils" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/onsi/gomega/gexec" @@ -208,6 +211,29 @@ var _ = Describe("Podman pods", func() { } }) + It("start pod with port conflict", func() { + randomport, err := utils.GetRandomPort() + Expect(err).To(BeNil()) + + portPublish := fmt.Sprintf("%d:%d", randomport, randomport) + var podwithport string = "newpodwithport" + bt.PodcreateAndExpose(&podwithport, &portPublish) + + // Start pod and expose port 12345 + _, err = pods.Start(bt.conn, podwithport, nil) + Expect(err).To(BeNil()) + + // Start another pod and expose same port 12345 + var podwithport2 string = "newpodwithport2" + bt.PodcreateAndExpose(&podwithport2, &portPublish) + + _, err = pods.Start(bt.conn, podwithport2, nil) + Expect(err).ToNot(BeNil()) + code, _ := bindings.CheckResponseCode(err) + Expect(code).To(BeNumerically("==", http.StatusConflict)) + Expect(err).To(BeAssignableToTypeOf(&errorhandling.PodConflictErrorModel{})) + }) + It("start stop restart pod", func() { // Start an invalid pod _, err = pods.Start(bt.conn, "dummyName", nil) diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go index b638bfe24c..c4d62bd894 100644 --- a/pkg/domain/infra/tunnel/containers.go +++ b/pkg/domain/infra/tunnel/containers.go @@ -226,7 +226,7 @@ func (ic *ContainerEngine) ContainerInspect(ctx context.Context, namesOrIds []st for _, name := range namesOrIds { inspect, err := containers.Inspect(ic.ClientCtx, name, options) if err != nil { - errModel, ok := err.(errorhandling.ErrorModel) + errModel, ok := err.(*errorhandling.ErrorModel) if !ok { return nil, nil, err } diff --git a/pkg/domain/infra/tunnel/images.go b/pkg/domain/infra/tunnel/images.go index 9a746d68ce..ab2a93c75a 100644 --- a/pkg/domain/infra/tunnel/images.go +++ b/pkg/domain/infra/tunnel/images.go @@ -188,7 +188,7 @@ func (ir *ImageEngine) Inspect(ctx context.Context, namesOrIDs []string, opts en for _, i := range namesOrIDs { r, err := images.GetImage(ir.ClientCtx, i, options) if err != nil { - errModel, ok := err.(errorhandling.ErrorModel) + errModel, ok := err.(*errorhandling.ErrorModel) if !ok { return nil, nil, err } diff --git a/pkg/domain/infra/tunnel/network.go b/pkg/domain/infra/tunnel/network.go index 7e59e44c2a..7c183b1ac0 100644 --- a/pkg/domain/infra/tunnel/network.go +++ b/pkg/domain/infra/tunnel/network.go @@ -23,7 +23,7 @@ func (ic *ContainerEngine) NetworkInspect(ctx context.Context, namesOrIds []stri for _, name := range namesOrIds { report, err := network.Inspect(ic.ClientCtx, name, options) if err != nil { - errModel, ok := err.(errorhandling.ErrorModel) + errModel, ok := err.(*errorhandling.ErrorModel) if !ok { return nil, nil, err } diff --git a/pkg/domain/infra/tunnel/secrets.go b/pkg/domain/infra/tunnel/secrets.go index 6337c7fbe8..e5fa200bdc 100644 --- a/pkg/domain/infra/tunnel/secrets.go +++ b/pkg/domain/infra/tunnel/secrets.go @@ -28,7 +28,7 @@ func (ic *ContainerEngine) SecretInspect(ctx context.Context, nameOrIDs []string for _, name := range nameOrIDs { inspected, err := secrets.Inspect(ic.ClientCtx, name, nil) if err != nil { - errModel, ok := err.(errorhandling.ErrorModel) + errModel, ok := err.(*errorhandling.ErrorModel) if !ok { return nil, nil, err } @@ -67,7 +67,7 @@ func (ic *ContainerEngine) SecretRm(ctx context.Context, nameOrIDs []string, opt for _, name := range nameOrIDs { secret, err := secrets.Inspect(ic.ClientCtx, name, nil) if err != nil { - errModel, ok := err.(errorhandling.ErrorModel) + errModel, ok := err.(*errorhandling.ErrorModel) if !ok { return nil, err } diff --git a/pkg/domain/infra/tunnel/volumes.go b/pkg/domain/infra/tunnel/volumes.go index 2b2b2c2a1a..a3d9e1b6dd 100644 --- a/pkg/domain/infra/tunnel/volumes.go +++ b/pkg/domain/infra/tunnel/volumes.go @@ -56,7 +56,7 @@ func (ic *ContainerEngine) VolumeInspect(ctx context.Context, namesOrIds []strin for _, id := range namesOrIds { data, err := volumes.Inspect(ic.ClientCtx, id, nil) if err != nil { - errModel, ok := err.(errorhandling.ErrorModel) + errModel, ok := err.(*errorhandling.ErrorModel) if !ok { return nil, nil, err } diff --git a/pkg/errorhandling/errorhandling.go b/pkg/errorhandling/errorhandling.go index 6adbc9f344..fcb0f7881d 100644 --- a/pkg/errorhandling/errorhandling.go +++ b/pkg/errorhandling/errorhandling.go @@ -83,6 +83,12 @@ func Contains(err error, sub error) bool { return strings.Contains(err.Error(), sub.Error()) } +// PodConflictErrorModel is used in remote connections with podman +type PodConflictErrorModel struct { + Errs []string + Id string //nolint +} + // ErrorModel is used in remote connections with podman type ErrorModel struct { // API root cause formatted for automated parsing @@ -106,3 +112,11 @@ func (e ErrorModel) Cause() error { func (e ErrorModel) Code() int { return e.ResponseCode } + +func (e PodConflictErrorModel) Error() string { + return strings.Join(e.Errs, ",") +} + +func (e PodConflictErrorModel) Code() int { + return 409 +} From 18c322d1c05f776bf754c30091520c6d51a5cd4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20Trma=C4=8D?= Date: Thu, 21 Oct 2021 22:11:37 +0200 Subject: [PATCH 31/51] Use INTEGRATION_ROOT instead of current directory MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Should not change behavior, just to set a consistent precedent for code introduced in future commits. Signed-off-by: Miloslav Trmač --- test/e2e/trust_test.go | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/test/e2e/trust_test.go b/test/e2e/trust_test.go index 7f97f280ad..26b58737c1 100644 --- a/test/e2e/trust_test.go +++ b/test/e2e/trust_test.go @@ -14,7 +14,8 @@ import ( var _ = Describe("Podman trust", func() { var ( - tempdir string + tempdir string + err error podmanTest *PodmanTestIntegration ) @@ -38,11 +39,7 @@ var _ = Describe("Podman trust", func() { }) It("podman image trust show", func() { - path, err := os.Getwd() - if err != nil { - os.Exit(1) - } - session := podmanTest.Podman([]string{"image", "trust", "show", "--registrypath", filepath.Dir(path), "--policypath", filepath.Join(filepath.Dir(path), "policy.json")}) + session := podmanTest.Podman([]string{"image", "trust", "show", "--registrypath", filepath.Join(INTEGRATION_ROOT, "test"), "--policypath", filepath.Join(INTEGRATION_ROOT, "test/policy.json")}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) outArray := session.OutputToStringArray() From df736396e193df99be1977543187c013cba91643 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20Trma=C4=8D?= Date: Thu, 21 Oct 2021 22:19:23 +0200 Subject: [PATCH 32/51] Tighten the expected output of the "podman image trust show" test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ... to include all fields. Signed-off-by: Miloslav Trmač --- test/e2e/trust_test.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/e2e/trust_test.go b/test/e2e/trust_test.go index 26b58737c1..efb00cad5b 100644 --- a/test/e2e/trust_test.go +++ b/test/e2e/trust_test.go @@ -45,11 +45,11 @@ var _ = Describe("Podman trust", func() { outArray := session.OutputToStringArray() Expect(len(outArray)).To(Equal(3)) - // image order is not guaranteed. All we can do is check that - // these strings appear in output, we can't cross-check them. - Expect(session.OutputToString()).To(ContainSubstring("accept")) - Expect(session.OutputToString()).To(ContainSubstring("reject")) - Expect(session.OutputToString()).To(ContainSubstring("signed")) + // Repository order is not guaranteed. So, check that + // all expected lines appear in output; we also check total number of lines, so that handles all of them. + Expect(string(session.Out.Contents())).To(MatchRegexp(`(?m)^default\s+accept\s*$`)) + Expect(string(session.Out.Contents())).To(MatchRegexp(`(?m)^docker.io/library/hello-world\s+reject\s*$`)) + Expect(string(session.Out.Contents())).To(MatchRegexp(`(?m)^registry.access.redhat.com\s+signedBy\s+security@redhat.com, security@redhat.com\s+https://access.redhat.com/webassets/docker/content/sigstore\s*$`)) }) It("podman image trust set", func() { From df9e0fdcb055412d066cb240575cdf013ae281d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20Trma=C4=8D?= Date: Thu, 21 Oct 2021 22:32:34 +0200 Subject: [PATCH 33/51] Fix tests of podman image trust --raw and --json MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead using the OS-wide system default policy, use the one in this repo, and adjust the expected results (as well as making the test stricter). Signed-off-by: Miloslav Trmač --- test/e2e/trust_test.go | 44 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/test/e2e/trust_test.go b/test/e2e/trust_test.go index efb00cad5b..b591e1c023 100644 --- a/test/e2e/trust_test.go +++ b/test/e2e/trust_test.go @@ -73,24 +73,52 @@ var _ = Describe("Podman trust", func() { }) It("podman image trust show --json", func() { - session := podmanTest.Podman([]string{"image", "trust", "show", "--json"}) + session := podmanTest.Podman([]string{"image", "trust", "show", "--registrypath", filepath.Join(INTEGRATION_ROOT, "test"), "--policypath", filepath.Join(INTEGRATION_ROOT, "test/policy.json"), "--json"}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) Expect(session.IsJSONOutputValid()).To(BeTrue()) var teststruct []map[string]string json.Unmarshal(session.Out.Contents(), &teststruct) - Expect(teststruct[0]["name"]).To(Equal("* (default)")) - Expect(teststruct[0]["repo_name"]).To(Equal("default")) - Expect(teststruct[0]["type"]).To(Equal("accept")) - Expect(teststruct[1]["type"]).To(Equal("insecureAcceptAnything")) + Expect(len(teststruct)).To(Equal(3)) + // To ease comparison, group the unordered array of repos by repo (and we expect only one entry by repo, so order within groups doesn’t matter) + repoMap := map[string][]map[string]string{} + for _, e := range teststruct { + key := e["name"] + repoMap[key] = append(repoMap[key], e) + } + Expect(repoMap).To(Equal(map[string][]map[string]string{ + "* (default)": {{ + "name": "* (default)", + "repo_name": "default", + "sigstore": "", + "transport": "", + "type": "accept", + }}, + "docker.io/library/hello-world": {{ + "name": "docker.io/library/hello-world", + "repo_name": "docker.io/library/hello-world", + "sigstore": "", + "transport": "", + "type": "reject", + }}, + "registry.access.redhat.com": {{ + "name": "registry.access.redhat.com", + "repo_name": "registry.access.redhat.com", + "sigstore": "https://access.redhat.com/webassets/docker/content/sigstore", + "transport": "", + "type": "signedBy", + "gpg_id": "security@redhat.com, security@redhat.com", + }}, + })) }) It("podman image trust show --raw", func() { - session := podmanTest.Podman([]string{"image", "trust", "show", "--raw"}) + session := podmanTest.Podman([]string{"image", "trust", "show", "--policypath", filepath.Join(INTEGRATION_ROOT, "test/policy.json"), "--raw"}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) + contents, err := ioutil.ReadFile(filepath.Join(INTEGRATION_ROOT, "test/policy.json")) + Expect(err).ShouldNot(HaveOccurred()) Expect(session.IsJSONOutputValid()).To(BeTrue()) - Expect(session.OutputToString()).To(ContainSubstring("default")) - Expect(session.OutputToString()).To(ContainSubstring("insecureAcceptAnything")) + Expect(string(session.Out.Contents())).To(Equal(string(contents) + "\n")) }) }) From dd6551055a39eb338cdcc8691436aabc0aabf62d Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Tue, 2 Nov 2021 12:51:10 +0100 Subject: [PATCH 34/51] test: run --cgroups=split in new cgroup the --cgroups=split test changes the current cgroup as it creates a sub-cgroup. This can cause a race condition in tests that are reading the current cgroup. Closes: https://github.com/containers/podman/issues/11191 Signed-off-by: Giuseppe Scrivano --- test/e2e/common_test.go | 2 +- test/e2e/libpod_suite_remote_test.go | 16 +++++++++++++++- test/e2e/libpod_suite_test.go | 14 +++++++++++++- test/e2e/run_test.go | 4 ++-- test/utils/podmantest_test.go | 2 +- test/utils/utils.go | 16 ++++++++++------ 6 files changed, 42 insertions(+), 12 deletions(-) diff --git a/test/e2e/common_test.go b/test/e2e/common_test.go index 20ed72c591..dbf51f4e48 100644 --- a/test/e2e/common_test.go +++ b/test/e2e/common_test.go @@ -685,7 +685,7 @@ func SkipIfContainerized(reason string) { // PodmanAsUser is the exec call to podman on the filesystem with the specified uid/gid and environment func (p *PodmanTestIntegration) PodmanAsUser(args []string, uid, gid uint32, cwd string, env []string) *PodmanSessionIntegration { - podmanSession := p.PodmanAsUserBase(args, uid, gid, cwd, env, false, false, nil) + podmanSession := p.PodmanAsUserBase(args, uid, gid, cwd, env, false, false, nil, nil) return &PodmanSessionIntegration{podmanSession} } diff --git a/test/e2e/libpod_suite_remote_test.go b/test/e2e/libpod_suite_remote_test.go index 3115c246ff..ad511cc9e0 100644 --- a/test/e2e/libpod_suite_remote_test.go +++ b/test/e2e/libpod_suite_remote_test.go @@ -38,11 +38,25 @@ func (p *PodmanTestIntegration) Podman(args []string) *PodmanSessionIntegration return &PodmanSessionIntegration{podmanSession} } +// PodmanSystemdScope runs the podman command in a new systemd scope +func (p *PodmanTestIntegration) PodmanSystemdScope(args []string) *PodmanSessionIntegration { + var remoteArgs = []string{"--remote", "--url", p.RemoteSocket} + remoteArgs = append(remoteArgs, args...) + + wrapper := []string{"systemd-run", "--scope"} + if rootless.IsRootless() { + wrapper = []string{"systemd-run", "--scope", "--user"} + } + + podmanSession := p.PodmanAsUserBase(remoteArgs, 0, 0, "", nil, false, false, wrapper, nil) + return &PodmanSessionIntegration{podmanSession} +} + // PodmanExtraFiles is the exec call to podman on the filesystem and passes down extra files func (p *PodmanTestIntegration) PodmanExtraFiles(args []string, extraFiles []*os.File) *PodmanSessionIntegration { var remoteArgs = []string{"--remote", "--url", p.RemoteSocket} remoteArgs = append(remoteArgs, args...) - podmanSession := p.PodmanAsUserBase(remoteArgs, 0, 0, "", nil, false, false, extraFiles) + podmanSession := p.PodmanAsUserBase(remoteArgs, 0, 0, "", nil, false, false, nil, extraFiles) return &PodmanSessionIntegration{podmanSession} } diff --git a/test/e2e/libpod_suite_test.go b/test/e2e/libpod_suite_test.go index cc03ccc963..6d2d3fee8f 100644 --- a/test/e2e/libpod_suite_test.go +++ b/test/e2e/libpod_suite_test.go @@ -8,6 +8,8 @@ import ( "os" "path/filepath" "strings" + + "github.com/containers/podman/v3/pkg/rootless" ) func IsRemote() bool { @@ -23,9 +25,19 @@ func (p *PodmanTestIntegration) Podman(args []string) *PodmanSessionIntegration return &PodmanSessionIntegration{podmanSession} } +// PodmanSystemdScope runs the podman command in a new systemd scope +func (p *PodmanTestIntegration) PodmanSystemdScope(args []string) *PodmanSessionIntegration { + wrapper := []string{"systemd-run", "--scope"} + if rootless.IsRootless() { + wrapper = []string{"systemd-run", "--scope", "--user"} + } + podmanSession := p.PodmanAsUserBase(args, 0, 0, "", nil, false, false, wrapper, nil) + return &PodmanSessionIntegration{podmanSession} +} + // PodmanExtraFiles is the exec call to podman on the filesystem and passes down extra files func (p *PodmanTestIntegration) PodmanExtraFiles(args []string, extraFiles []*os.File) *PodmanSessionIntegration { - podmanSession := p.PodmanAsUserBase(args, 0, 0, "", nil, false, false, extraFiles) + podmanSession := p.PodmanAsUserBase(args, 0, 0, "", nil, false, false, nil, extraFiles) return &PodmanSessionIntegration{podmanSession} } diff --git a/test/e2e/run_test.go b/test/e2e/run_test.go index b6743f4b72..ca39989cda 100644 --- a/test/e2e/run_test.go +++ b/test/e2e/run_test.go @@ -1322,13 +1322,13 @@ USER mail`, BB) } } - container := podmanTest.Podman([]string{"run", "--rm", "--cgroups=split", ALPINE, "cat", "/proc/self/cgroup"}) + container := podmanTest.PodmanSystemdScope([]string{"run", "--rm", "--cgroups=split", ALPINE, "cat", "/proc/self/cgroup"}) container.WaitWithDefaultTimeout() Expect(container).Should(Exit(0)) checkLines(container.OutputToStringArray()) // check that --cgroups=split is honored also when a container runs in a pod - container = podmanTest.Podman([]string{"run", "--rm", "--pod", "new:split-test-pod", "--cgroups=split", ALPINE, "cat", "/proc/self/cgroup"}) + container = podmanTest.PodmanSystemdScope([]string{"run", "--rm", "--pod", "new:split-test-pod", "--cgroups=split", ALPINE, "cat", "/proc/self/cgroup"}) container.WaitWithDefaultTimeout() Expect(container).Should(Exit(0)) checkLines(container.OutputToStringArray()) diff --git a/test/utils/podmantest_test.go b/test/utils/podmantest_test.go index 9bd1c4a669..1bb9ecb6bc 100644 --- a/test/utils/podmantest_test.go +++ b/test/utils/podmantest_test.go @@ -23,7 +23,7 @@ var _ = Describe("PodmanTest test", func() { FakeOutputs["check"] = []string{"check"} os.Setenv("HOOK_OPTION", "hook_option") env := os.Environ() - session := podmanTest.PodmanAsUserBase([]string{"check"}, 1000, 1000, "", env, true, false, nil) + session := podmanTest.PodmanAsUserBase([]string{"check"}, 1000, 1000, "", env, true, false, nil, nil) os.Unsetenv("HOOK_OPTION") session.WaitWithDefaultTimeout() Expect(session.Command.Process).ShouldNot(BeNil()) diff --git a/test/utils/utils.go b/test/utils/utils.go index bfefc58ec8..d4d5e6e2f0 100644 --- a/test/utils/utils.go +++ b/test/utils/utils.go @@ -66,27 +66,31 @@ func (p *PodmanTest) MakeOptions(args []string, noEvents, noCache bool) []string // PodmanAsUserBase exec podman as user. uid and gid is set for credentials usage. env is used // to record the env for debugging -func (p *PodmanTest) PodmanAsUserBase(args []string, uid, gid uint32, cwd string, env []string, noEvents, noCache bool, extraFiles []*os.File) *PodmanSession { +func (p *PodmanTest) PodmanAsUserBase(args []string, uid, gid uint32, cwd string, env []string, noEvents, noCache bool, wrapper []string, extraFiles []*os.File) *PodmanSession { var command *exec.Cmd podmanOptions := p.MakeOptions(args, noEvents, noCache) podmanBinary := p.PodmanBinary if p.RemoteTest { podmanBinary = p.RemotePodmanBinary } + + runCmd := append(wrapper, podmanBinary) if p.RemoteTest { podmanOptions = append([]string{"--remote", "--url", p.RemoteSocket}, podmanOptions...) } if env == nil { - fmt.Printf("Running: %s %s\n", podmanBinary, strings.Join(podmanOptions, " ")) + fmt.Printf("Running: %s %s\n", strings.Join(runCmd, " "), strings.Join(podmanOptions, " ")) } else { - fmt.Printf("Running: (env: %v) %s %s\n", env, podmanBinary, strings.Join(podmanOptions, " ")) + fmt.Printf("Running: (env: %v) %s %s\n", env, strings.Join(runCmd, " "), strings.Join(podmanOptions, " ")) } if uid != 0 || gid != 0 { pythonCmd := fmt.Sprintf("import os; import sys; uid = %d; gid = %d; cwd = '%s'; os.setgid(gid); os.setuid(uid); os.chdir(cwd) if len(cwd)>0 else True; os.execv(sys.argv[1], sys.argv[1:])", gid, uid, cwd) - nsEnterOpts := append([]string{"-c", pythonCmd, podmanBinary}, podmanOptions...) + runCmd = append(runCmd, podmanOptions...) + nsEnterOpts := append([]string{"-c", pythonCmd}, runCmd...) command = exec.Command("python", nsEnterOpts...) } else { - command = exec.Command(podmanBinary, podmanOptions...) + runCmd = append(runCmd, podmanOptions...) + command = exec.Command(runCmd[0], runCmd[1:]...) } if env != nil { command.Env = env @@ -106,7 +110,7 @@ func (p *PodmanTest) PodmanAsUserBase(args []string, uid, gid uint32, cwd string // PodmanBase exec podman with default env. func (p *PodmanTest) PodmanBase(args []string, noEvents, noCache bool) *PodmanSession { - return p.PodmanAsUserBase(args, 0, 0, "", nil, noEvents, noCache, nil) + return p.PodmanAsUserBase(args, 0, 0, "", nil, noEvents, noCache, nil, nil) } // WaitForContainer waits on a started container From 718de67f33982e6cc59009b02b4b96c19842b921 Mon Sep 17 00:00:00 2001 From: Paul Holzinger Date: Thu, 4 Nov 2021 15:54:28 +0100 Subject: [PATCH 35/51] Fix bindings container log test The returned error was not checked, thus the test could hang forever since it blocks on the log channel. Also handle unexpectedEOF like EOF. Fixes #12176 Signed-off-by: Paul Holzinger --- pkg/bindings/containers/attach.go | 4 ++-- pkg/bindings/containers/logs.go | 2 +- pkg/bindings/test/containers_test.go | 7 ++++++- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/pkg/bindings/containers/attach.go b/pkg/bindings/containers/attach.go index 725d066486..32a8978d92 100644 --- a/pkg/bindings/containers/attach.go +++ b/pkg/bindings/containers/attach.go @@ -214,7 +214,7 @@ func Attach(ctx context.Context, nameOrID string, stdin io.Reader, stdout io.Wri // Read multiplexed channels and write to appropriate stream fd, l, err := DemuxHeader(socket, buffer) if err != nil { - if errors.Is(err, io.EOF) { + if errors.Is(err, io.EOF) || errors.Is(err, io.ErrUnexpectedEOF) { return nil } return err @@ -531,7 +531,7 @@ func ExecStartAndAttach(ctx context.Context, sessionID string, options *ExecStar // Read multiplexed channels and write to appropriate stream fd, l, err := DemuxHeader(socket, buffer) if err != nil { - if errors.Is(err, io.EOF) { + if errors.Is(err, io.EOF) || errors.Is(err, io.ErrUnexpectedEOF) { return nil } return err diff --git a/pkg/bindings/containers/logs.go b/pkg/bindings/containers/logs.go index 67db944872..37ffdf0a58 100644 --- a/pkg/bindings/containers/logs.go +++ b/pkg/bindings/containers/logs.go @@ -39,7 +39,7 @@ func Logs(ctx context.Context, nameOrID string, options *LogOptions, stdoutChan, for { fd, l, err := DemuxHeader(response.Body, buffer) if err != nil { - if errors.Is(err, io.EOF) { + if errors.Is(err, io.EOF) || errors.Is(err, io.ErrUnexpectedEOF) { return nil } return err diff --git a/pkg/bindings/test/containers_test.go b/pkg/bindings/test/containers_test.go index b9ed67255f..0f535bc317 100644 --- a/pkg/bindings/test/containers_test.go +++ b/pkg/bindings/test/containers_test.go @@ -259,6 +259,7 @@ var _ = Describe("Podman containers ", func() { _, err = bt.RunTopContainer(&name, nil) Expect(err).To(BeNil()) go func() { + defer GinkgoRecover() exitCode, err = containers.Wait(bt.conn, name, nil) errChan <- err close(errChan) @@ -281,6 +282,7 @@ var _ = Describe("Podman containers ", func() { _, err := bt.RunTopContainer(&name, nil) Expect(err).To(BeNil()) go func() { + defer GinkgoRecover() exitCode, err = containers.Wait(bt.conn, name, new(containers.WaitOptions).WithCondition([]define.ContainerStatus{pause})) errChan <- err close(errChan) @@ -366,7 +368,10 @@ var _ = Describe("Podman containers ", func() { opts := new(containers.LogOptions).WithStdout(true).WithFollow(true) go func() { - containers.Logs(bt.conn, r.ID, opts, stdoutChan, nil) + defer GinkgoRecover() + err := containers.Logs(bt.conn, r.ID, opts, stdoutChan, nil) + close(stdoutChan) + Expect(err).ShouldNot(HaveOccurred()) }() o := <-stdoutChan o = strings.TrimSpace(o) From b1ac02dcbbfd2a3f47955bf739fe03f83375a6c1 Mon Sep 17 00:00:00 2001 From: Nalin Dahyabhai Date: Thu, 4 Nov 2021 16:06:24 -0400 Subject: [PATCH 36/51] tweak a couple of flag descriptions in help output Descriptions of flags don't need to start with whitespace of their own. Signed-off-by: Nalin Dahyabhai --- cmd/podman/common/create.go | 2 +- cmd/podman/images/pull.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/podman/common/create.go b/cmd/podman/common/create.go index b3dfc49674..643f6728a1 100644 --- a/cmd/podman/common/create.go +++ b/cmd/podman/common/create.go @@ -426,7 +426,7 @@ func DefineCreateFlags(cmd *cobra.Command, cf *entities.ContainerCreateOptions, createFlags.StringVar( &cf.Variant, variantFlagName, "", - "Use _VARIANT_ instead of the running architecture variant for choosing images", + "Use `VARIANT` instead of the running architecture variant for choosing images", ) _ = cmd.RegisterFlagCompletionFunc(variantFlagName, completion.AutocompleteNone) diff --git a/cmd/podman/images/pull.go b/cmd/podman/images/pull.go index a4e3515db0..a990d16265 100644 --- a/cmd/podman/images/pull.go +++ b/cmd/podman/images/pull.go @@ -92,7 +92,7 @@ func pullFlags(cmd *cobra.Command) { _ = cmd.RegisterFlagCompletionFunc(osFlagName, completion.AutocompleteOS) variantFlagName := "variant" - flags.StringVar(&pullOptions.Variant, variantFlagName, "", " use VARIANT instead of the running architecture variant for choosing images") + flags.StringVar(&pullOptions.Variant, variantFlagName, "", "Use VARIANT instead of the running architecture variant for choosing images") _ = cmd.RegisterFlagCompletionFunc(variantFlagName, completion.AutocompleteNone) platformFlagName := "platform" From 93a3e720d794d8ae028075a20d92a4ab513d0051 Mon Sep 17 00:00:00 2001 From: Jhon Honce Date: Fri, 5 Nov 2021 10:12:32 -0700 Subject: [PATCH 37/51] Log Apache access_log-like entries at Info level [NO NEW TESTS NEEDED] Only log API access entries when --log-level set to Info or below. Fixes #12181 Signed-off-by: Jhon Honce --- pkg/api/server/handler_rid.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/pkg/api/server/handler_rid.go b/pkg/api/server/handler_rid.go index b624b99a62..7dcf436f78 100644 --- a/pkg/api/server/handler_rid.go +++ b/pkg/api/server/handler_rid.go @@ -2,6 +2,7 @@ package server import ( "fmt" + "io/ioutil" "net/http" "github.com/containers/podman/v3/pkg/api/types" @@ -15,7 +16,13 @@ import ( // and Apache style request logging func referenceIDHandler() mux.MiddlewareFunc { return func(h http.Handler) http.Handler { - return handlers.CombinedLoggingHandler(logrus.StandardLogger().Out, + // Only log Apache access_log-like entries at Info level or below + out := ioutil.Discard + if logrus.IsLevelEnabled(logrus.InfoLevel) { + out = logrus.StandardLogger().Out + } + + return handlers.CombinedLoggingHandler(out, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { rid := r.Header.Get("X-Reference-Id") if rid == "" { From 2dc8db77307a050cab9d030149be34e636f04657 Mon Sep 17 00:00:00 2001 From: Daniel J Walsh Date: Thu, 4 Nov 2021 04:14:12 -0700 Subject: [PATCH 38/51] Add some information about disabling SELinux when using system volumes A comment was made on internal mailing list about confusion on SELinux labeling of volumes. This PR makes it a little more clear about when you should or should not relabel. We need a similar comment in podman pod create, but it does not support --security-opt processing yet. Signed-off-by: Daniel J Walsh --- docs/source/markdown/podman-build.1.md | 8 ++++++++ docs/source/markdown/podman-create.1.md | 9 +++++++++ docs/source/markdown/podman-run.1.md | 9 +++++++++ 3 files changed, 26 insertions(+) diff --git a/docs/source/markdown/podman-build.1.md b/docs/source/markdown/podman-build.1.md index 0e65e02c9c..965f5319fb 100644 --- a/docs/source/markdown/podman-build.1.md +++ b/docs/source/markdown/podman-build.1.md @@ -774,6 +774,14 @@ content label. Shared volume labels allow all containers to read/write content. The `Z` option tells Podman to label the content with a private unshared label. Only the current container can use a private volume. +Note: Do not relabel system files and directories. Relabeling system content +might cause other confined services on your machine to fail. For these types +of containers, disabling SELinux separation is recommended. The option +`--security-opt label=disable` disables SELinux separation for the container. +For example, if a user wanted to volume mount their entire home directory into the build containers, they need to disable SELinux separation. + + $ podman build --security-opt label=disable -v $HOME:/home/user . + `Overlay Volume Mounts` The `:O` flag tells Podman to mount the directory from the host as a diff --git a/docs/source/markdown/podman-create.1.md b/docs/source/markdown/podman-create.1.md index d46400e310..7cbb71d850 100644 --- a/docs/source/markdown/podman-create.1.md +++ b/docs/source/markdown/podman-create.1.md @@ -1231,6 +1231,15 @@ content label. Shared volume labels allow all containers to read/write content. The `Z` option tells Podman to label the content with a private unshared label. Only the current container can use a private volume. +Note: Do not relabel system files and directories. Relabeling system content +might cause other confined services on your machine to fail. For these types +of containers we recommend that disable SELinux separation. The option +`--security-opt label=disable` disables SELinux separation for containers used in the build. +For example if a user wanted to volume mount their entire home directory into a +container, they need to disable SELinux separation. + + $ podman create --security-opt label=disable -v $HOME:/home/user fedora touch /home/user/file + `Overlay Volume Mounts` The `:O` flag tells Podman to mount the directory from the host as a diff --git a/docs/source/markdown/podman-run.1.md b/docs/source/markdown/podman-run.1.md index 6cda72952c..811bc725b3 100644 --- a/docs/source/markdown/podman-run.1.md +++ b/docs/source/markdown/podman-run.1.md @@ -1288,6 +1288,15 @@ share the volume content. As a result, Podman labels the content with a shared content label. Shared volume labels allow all containers to read/write content. The **Z** option tells Podman to label the content with a private unshared label. +Note: Do not relabel system files and directories. Relabeling system content +might cause other confined services on your machine to fail. For these types +of containers we recommend that disable SELinux separation. The option +`--security-opt label=disable` disables SELinux separation for the container. +For example if a user wanted to volume mount their entire home directory into a +container, they need to disable SELinux separation. + + $ podman run --security-opt label=disable -v $HOME:/home/user fedora touch /home/user/file + `Overlay Volume Mounts` The `:O` flag tells Podman to mount the directory from the host as a From c8b7ca2ba2ef9a57103b5c05e6e29b54b0c6fa48 Mon Sep 17 00:00:00 2001 From: Valentin Rothberg Date: Fri, 29 Oct 2021 10:28:38 +0200 Subject: [PATCH 39/51] pod/container create: resolve conflicts of generated names Address the TOCTOU when generating random names by having at most 10 attempts to assign a random name when creating a pod or container. [NO TESTS NEEDED] since I do not know a way to force a conflict with randomly generated names in a reasonable time frame. Fixes: #11735 Signed-off-by: Valentin Rothberg --- libpod/container_internal.go | 24 +++++++++++++++++++--- libpod/runtime_ctr.go | 9 -------- libpod/runtime_pod_linux.go | 40 +++++++++++++++++++++++------------- 3 files changed, 47 insertions(+), 26 deletions(-) diff --git a/libpod/container_internal.go b/libpod/container_internal.go index d71179017a..54d6b13039 100644 --- a/libpod/container_internal.go +++ b/libpod/container_internal.go @@ -479,9 +479,27 @@ func (c *Container) setupStorage(ctx context.Context) error { c.setupStorageMapping(&options.IDMappingOptions, &c.config.IDMappings) - containerInfo, err := c.runtime.storageService.CreateContainerStorage(ctx, c.runtime.imageContext, c.config.RootfsImageName, c.config.RootfsImageID, c.config.Name, c.config.ID, options) - if err != nil { - return errors.Wrapf(err, "error creating container storage") + // Unless the user has specified a name, use a randomly generated one. + // Note that name conflicts may occur (see #11735), so we need to loop. + generateName := c.config.Name == "" + var containerInfo ContainerInfo + var containerInfoErr error + for { + if generateName { + name, err := c.runtime.generateName() + if err != nil { + return err + } + c.config.Name = name + } + containerInfo, containerInfoErr = c.runtime.storageService.CreateContainerStorage(ctx, c.runtime.imageContext, c.config.RootfsImageName, c.config.RootfsImageID, c.config.Name, c.config.ID, options) + + if !generateName || errors.Cause(containerInfoErr) != storage.ErrDuplicateName { + break + } + } + if containerInfoErr != nil { + return errors.Wrapf(containerInfoErr, "error creating container storage") } c.config.IDMappings.UIDMap = containerInfo.UIDMap diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go index 7d3891f6e1..f27e854a46 100644 --- a/libpod/runtime_ctr.go +++ b/libpod/runtime_ctr.go @@ -322,15 +322,6 @@ func (r *Runtime) setupContainer(ctx context.Context, ctr *Container) (_ *Contai } } - if ctr.config.Name == "" { - name, err := r.generateName() - if err != nil { - return nil, err - } - - ctr.config.Name = name - } - // Check CGroup parent sanity, and set it if it was not set. // Only if we're actually configuring CGroups. if !ctr.config.NoCgroups { diff --git a/libpod/runtime_pod_linux.go b/libpod/runtime_pod_linux.go index 3a6098de84..de00eb8e05 100644 --- a/libpod/runtime_pod_linux.go +++ b/libpod/runtime_pod_linux.go @@ -43,18 +43,6 @@ func (r *Runtime) NewPod(ctx context.Context, p specgen.PodSpecGenerator, option } } - if pod.config.Name == "" { - name, err := r.generateName() - if err != nil { - return nil, err - } - pod.config.Name = name - } - - if p.InfraContainerSpec != nil && p.InfraContainerSpec.Hostname == "" { - p.InfraContainerSpec.Hostname = pod.config.Name - } - // Allocate a lock for the pod lock, err := r.lockManager.AllocateLock() if err != nil { @@ -131,9 +119,33 @@ func (r *Runtime) NewPod(ctx context.Context, p specgen.PodSpecGenerator, option logrus.Infof("Pod has an infra container, but shares no namespaces") } - if err := r.state.AddPod(pod); err != nil { - return nil, errors.Wrapf(err, "error adding pod to state") + // Unless the user has specified a name, use a randomly generated one. + // Note that name conflicts may occur (see #11735), so we need to loop. + generateName := pod.config.Name == "" + var addPodErr error + for { + if generateName { + name, err := r.generateName() + if err != nil { + return nil, err + } + pod.config.Name = name + } + + if p.InfraContainerSpec != nil && p.InfraContainerSpec.Hostname == "" { + p.InfraContainerSpec.Hostname = pod.config.Name + } + if addPodErr = r.state.AddPod(pod); addPodErr == nil { + return pod, nil + } + if !generateName || (errors.Cause(addPodErr) != define.ErrPodExists && errors.Cause(addPodErr) != define.ErrCtrExists) { + break + } + } + if addPodErr != nil { + return nil, errors.Wrapf(addPodErr, "error adding pod to state") } + return pod, nil } From fc1707dfe4288d0eb465a13f4dc025f779d829c5 Mon Sep 17 00:00:00 2001 From: Ed Santiago Date: Mon, 8 Nov 2021 13:44:03 -0700 Subject: [PATCH 40/51] Minor test tweaks - remove 'NO TESTS NEEDED' as a valid bypass string. Henceforth only 'NO NEW TESTS NEEDED' will work. - add a debugging aid for #11871, in which bodhi tests time out in nslookup. Signed-off-by: Ed Santiago --- contrib/cirrus/pr-should-include-tests | 8 +------- test/system/500-networking.bats | 7 +++++++ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/contrib/cirrus/pr-should-include-tests b/contrib/cirrus/pr-should-include-tests index 4b63293115..8103df41d7 100755 --- a/contrib/cirrus/pr-should-include-tests +++ b/contrib/cirrus/pr-should-include-tests @@ -12,9 +12,6 @@ fi if [[ "${CIRRUS_CHANGE_MESSAGE}" =~ NO.NEW.TESTS.NEEDED ]]; then exit 0 fi -if [[ "${CIRRUS_CHANGE_MESSAGE}" =~ NO.TESTS.NEEDED ]]; then - exit 0 -fi # HEAD should be good enough, but the CIRRUS envariable allows us to test head=${CIRRUS_CHANGE_IN_REPO:-HEAD} @@ -52,14 +49,11 @@ if [[ -z "$filtered_changes" ]]; then exit 0 fi -# One last chance: perhaps the developer included the magic '[NO (NEW) TESTS NEEDED]' +# One last chance: perhaps the developer included the magic '[NO NEW TESTS NEEDED]' # string in an amended commit. if git log --format=%B ${base}..${head} | fgrep '[NO NEW TESTS NEEDED]'; then exit 0 fi -if git log --format=%B ${base}..${head} | fgrep '[NO TESTS NEEDED]'; then - exit 0 -fi cat < Date: Tue, 9 Nov 2021 14:07:49 +1100 Subject: [PATCH 41/51] shm_lock: Handle ENOSPC better in AllocateSemaphore When starting a container libpod/runtime_pod_linux.go:NewPod calls libpod/lock/lock.go:AllocateLock ends up in here. If you exceed num_locks, in response to a "podman run ..." you will see: Error: error allocating lock for new container: no space left on device As noted inline, this error is technically true as it is talking about the SHM area, but for anyone who has not dug into the source (i.e. me, before a few hours ago :) your initial thought is going to be that your disk is full. I spent quite a bit of time trying to diagnose what disk, partition, overlay, etc. was filling up before I realised this was actually due to leaking from failing containers. This overrides this case to give a more explicit message that hopefully puts people on the right track to fixing this faster. You will now see: $ ./bin/podman run --rm -it fedora bash Error: error allocating lock for new container: allocation failed; exceeded num_locks (20) [NO NEW TESTS NEEDED] (just changes an existing error message) Signed-off-by: Ian Wienand --- libpod/lock/shm/shm_lock.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/libpod/lock/shm/shm_lock.go b/libpod/lock/shm/shm_lock.go index 322e92a8f6..fea02a619f 100644 --- a/libpod/lock/shm/shm_lock.go +++ b/libpod/lock/shm/shm_lock.go @@ -130,8 +130,17 @@ func (locks *SHMLocks) AllocateSemaphore() (uint32, error) { // semaphore indexes, and can still return error codes. retCode := C.allocate_semaphore(locks.lockStruct) if retCode < 0 { + var err = syscall.Errno(-1 * retCode) // Negative errno returned - return 0, syscall.Errno(-1 * retCode) + if errors.Is(err, syscall.ENOSPC) { + // ENOSPC expands to "no space left on device". While it is technically true + // that there's no room in the SHM inn for this lock, this tends to send normal people + // down the path of checking disk-space which is not actually their problem. + // Give a clue that it's actually due to num_locks filling up. + var errFull = errors.Errorf("allocation failed; exceeded num_locks (%d)", locks.maxLocks) + return uint32(retCode), errFull + } + return uint32(retCode), syscall.Errno(-1 * retCode) } return uint32(retCode), nil From e9f6e5194c491f01617763c02a0d8abd0cf02e79 Mon Sep 17 00:00:00 2001 From: Ian Wienand Date: Tue, 9 Nov 2021 13:40:18 +1100 Subject: [PATCH 42/51] Match .c files in Makefile Ensure that rebuilds happen when .c files are updated in the source tree. Signed-off-by: Ian Wienand --- Makefile | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index cf796ed3c6..d63cb45497 100644 --- a/Makefile +++ b/Makefile @@ -59,10 +59,11 @@ PKG_MANAGER ?= $(shell command -v dnf yum|head -n1) PRE_COMMIT = $(shell command -v bin/venv/bin/pre-commit ~/.local/bin/pre-commit pre-commit | head -n1) # This isn't what we actually build; it's a superset, used for target -# dependencies. Basically: all *.go files, except *_test.go, and except -# anything in a dot subdirectory. If any of these files is newer than -# our target (bin/podman{,-remote}), a rebuild is triggered. -SOURCES = $(shell find . -path './.*' -prune -o \( -name '*.go' -a ! -name '*_test.go' \) -print) +# dependencies. Basically: all *.go and *.c files, except *_test.go, +# and except anything in a dot subdirectory. If any of these files is +# newer than our target (bin/podman{,-remote}), a rebuild is +# triggered. +SOURCES = $(shell find . -path './.*' -prune -o \( \( -name '*.go' -o -name '*.c' \) -a ! -name '*_test.go' \) -print) BUILDFLAGS := -mod=vendor $(BUILDFLAGS) From e456873c02e023db1dc012fbf64e45a76ebc467f Mon Sep 17 00:00:00 2001 From: Sascha Grunert Date: Tue, 9 Nov 2021 09:41:42 +0100 Subject: [PATCH 43/51] Exclude already built sources for static build We now do not copy the `bin` directory to the target nix sources to avoid skipping the build because "everything is up to date". Fixes https://github.com/containers/podman/issues/12198 Signed-off-by: Sascha Grunert --- nix/default-arm64.nix | 3 ++- nix/default.nix | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/nix/default-arm64.nix b/nix/default-arm64.nix index 8868788ae1..a38cef04af 100644 --- a/nix/default-arm64.nix +++ b/nix/default-arm64.nix @@ -59,7 +59,8 @@ let self = with pkgs; buildGoModule rec { name = "podman"; - src = ./..; + src = builtins.filterSource + (path: type: !(type == "directory" && baseNameOf path == "bin")) ./..; vendorSha256 = null; doCheck = false; enableParallelBuilding = true; diff --git a/nix/default.nix b/nix/default.nix index 4d15532c22..9a4b372a46 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -57,7 +57,8 @@ let self = with pkgs; buildGoModule rec { name = "podman"; - src = ./..; + src = builtins.filterSource + (path: type: !(type == "directory" && baseNameOf path == "bin")) ./..; vendorSha256 = null; doCheck = false; enableParallelBuilding = true; From cedf1a3d43fbb1f0c40cd286ee6c50863560e627 Mon Sep 17 00:00:00 2001 From: Boaz Shuster Date: Sun, 7 Nov 2021 13:21:25 +0200 Subject: [PATCH 44/51] podman-generate-kube - remove empty structs from YAML [NO NEW TESTS NEEDED] Signed-off-by: Boaz Shuster --- libpod/kube.go | 78 +++++++++++++++++++++++++++++++- pkg/domain/infra/abi/generate.go | 3 +- 2 files changed, 77 insertions(+), 4 deletions(-) diff --git a/libpod/kube.go b/libpod/kube.go index d2ac157490..b34734513f 100644 --- a/libpod/kube.go +++ b/libpod/kube.go @@ -166,9 +166,83 @@ func (v *Volume) GenerateForKube() *v1.PersistentVolumeClaim { } } +// YAMLPodSpec represents the same k8s API core PodSpec struct with a small +// change and that is having Containers as a pointer to YAMLContainer. +// Because Go doesn't omit empty struct and we want to omit Status in YAML +// if it's empty. Fixes: GH-11998 +type YAMLPodSpec struct { + v1.PodSpec + Containers []*YAMLContainer `json:"containers"` +} + +// YAMLPod represents the same k8s API core Pod struct with a small +// change and that is having Spec as a pointer to YAMLPodSpec and +// Status as a pointer to k8s API core PodStatus. +// Because Go doesn't omit empty struct and we want to omit Status in YAML +// if it's empty. Fixes: GH-11998 +type YAMLPod struct { + v1.Pod + Spec *YAMLPodSpec `json:"spec,omitempty"` + Status *v1.PodStatus `json:"status,omitempty"` +} + +// YAMLService represents the same k8s API core Service struct with a small +// change and that is having Status as a pointer to k8s API core ServiceStatus. +// Because Go doesn't omit empty struct and we want to omit Status in YAML +// if it's empty. Fixes: GH-11998 +type YAMLService struct { + v1.Service + Status *v1.ServiceStatus `json:"status,omitempty"` +} + +// YAMLContainer represents the same k8s API core Container struct with a small +// change and that is having Resources as a pointer to k8s API core ResourceRequirements. +// Because Go doesn't omit empty struct and we want to omit Status in YAML +// if it's empty. Fixes: GH-11998 +type YAMLContainer struct { + v1.Container + Resources *v1.ResourceRequirements `json:"resources,omitempty"` +} + +// ConvertV1PodToYAMLPod takes k8s API core Pod and returns a pointer to YAMLPod +func ConvertV1PodToYAMLPod(pod *v1.Pod) *YAMLPod { + cs := []*YAMLContainer{} + for _, cc := range pod.Spec.Containers { + var res *v1.ResourceRequirements = nil + if len(cc.Resources.Limits) > 0 || len(cc.Resources.Requests) > 0 { + res = &cc.Resources + } + cs = append(cs, &YAMLContainer{Container: cc, Resources: res}) + } + mpo := &YAMLPod{Pod: *pod} + mpo.Spec = &YAMLPodSpec{PodSpec: (*pod).Spec, Containers: cs} + for _, ctr := range pod.Spec.Containers { + if ctr.SecurityContext == nil || ctr.SecurityContext.SELinuxOptions == nil { + continue + } + selinuxOpts := ctr.SecurityContext.SELinuxOptions + if selinuxOpts.User == "" && selinuxOpts.Role == "" && selinuxOpts.Type == "" && selinuxOpts.Level == "" { + ctr.SecurityContext.SELinuxOptions = nil + } + } + dnsCfg := pod.Spec.DNSConfig + if dnsCfg != nil && (len(dnsCfg.Nameservers)+len(dnsCfg.Searches)+len(dnsCfg.Options) > 0) { + mpo.Spec.DNSConfig = dnsCfg + } + status := pod.Status + if status.Phase != "" || len(status.Conditions) > 0 || + status.Message != "" || status.Reason != "" || + status.NominatedNodeName != "" || status.HostIP != "" || + status.PodIP != "" || status.StartTime != nil || + len(status.InitContainerStatuses) > 0 || len(status.ContainerStatuses) > 0 || status.QOSClass != "" || len(status.EphemeralContainerStatuses) > 0 { + mpo.Status = &status + } + return mpo +} + // GenerateKubeServiceFromV1Pod creates a v1 service object from a v1 pod object -func GenerateKubeServiceFromV1Pod(pod *v1.Pod, servicePorts []v1.ServicePort) v1.Service { - service := v1.Service{} +func GenerateKubeServiceFromV1Pod(pod *v1.Pod, servicePorts []v1.ServicePort) YAMLService { + service := YAMLService{} selector := make(map[string]string) selector["app"] = pod.Labels["app"] ports := servicePorts diff --git a/pkg/domain/infra/abi/generate.go b/pkg/domain/infra/abi/generate.go index 081a2464b7..a4d6bcf866 100644 --- a/pkg/domain/infra/abi/generate.go +++ b/pkg/domain/infra/abi/generate.go @@ -124,8 +124,7 @@ func (ic *ContainerEngine) GenerateKube(ctx context.Context, nameOrIDs []string, if err != nil { return nil, err } - - b, err := generateKubeYAML(po) + b, err := generateKubeYAML(libpod.ConvertV1PodToYAMLPod(po)) if err != nil { return nil, err } From 6770fede7112adb41db985972b8c198d2a809ceb Mon Sep 17 00:00:00 2001 From: Jindrich Novy Date: Wed, 13 Oct 2021 10:49:03 +0200 Subject: [PATCH 45/51] VOLUME must be declared after RUN chown command Podman and Docker will not commit changes via RUN command of a VOLUME directory, so we need to chown path first. Not doing do will cause: https://bugzilla.redhat.com/show_bug.cgi?id=2009266 Signed-off-by: Jindrich Novy Signed-off-by: Daniel J Walsh --- contrib/podmanimage/stable/Dockerfile | 9 +++++---- contrib/podmanimage/testing/Dockerfile | 9 +++++---- contrib/podmanimage/upstream/Dockerfile | 9 +++++---- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/contrib/podmanimage/stable/Dockerfile b/contrib/podmanimage/stable/Dockerfile index f980d15eda..7950269d2c 100644 --- a/contrib/podmanimage/stable/Dockerfile +++ b/contrib/podmanimage/stable/Dockerfile @@ -19,14 +19,15 @@ RUN useradd podman; \ echo podman:10000:5000 > /etc/subuid; \ echo podman:10000:5000 > /etc/subgid; -VOLUME /var/lib/containers -VOLUME /home/podman/.local/share/containers -RUN mkdir -p /home/podman/.local/share/containers +RUN mkdir -p /home/podman/.local/share/containers; chown podman:podman -R /home/podman ADD https://raw.githubusercontent.com/containers/libpod/master/contrib/podmanimage/stable/containers.conf /etc/containers/containers.conf ADD https://raw.githubusercontent.com/containers/libpod/master/contrib/podmanimage/stable/podman-containers.conf /home/podman/.config/containers/containers.conf -RUN chown podman:podman -R /home/podman +# Note VOLUME options must always happen after the chown call above +# RUN commands can not modify existing volumes +VOLUME /var/lib/containers +VOLUME /home/podman/.local/share/containers # chmod containers.conf and adjust storage.conf to enable Fuse storage. RUN chmod 644 /etc/containers/containers.conf; sed -i -e 's|^#mount_program|mount_program|g' -e '/additionalimage.*/a "/var/lib/shared",' -e 's|^mountopt[[:space:]]*=.*$|mountopt = "nodev,fsync=0"|g' /etc/containers/storage.conf diff --git a/contrib/podmanimage/testing/Dockerfile b/contrib/podmanimage/testing/Dockerfile index 58b11a20b9..03da058062 100644 --- a/contrib/podmanimage/testing/Dockerfile +++ b/contrib/podmanimage/testing/Dockerfile @@ -19,14 +19,15 @@ RUN useradd podman; \ echo podman:10000:5000 > /etc/subuid; \ echo podman:10000:5000 > /etc/subgid; -VOLUME /var/lib/containers -VOLUME /home/podman/.local/share/containers -RUN mkdir -p /home/podman/.local/share/containers +RUN mkdir -p /home/podman/.local/share/containers; chown podman:podman -R /home/podman ADD https://raw.githubusercontent.com/containers/libpod/master/contrib/podmanimage/stable/containers.conf /etc/containers/containers.conf ADD https://raw.githubusercontent.com/containers/libpod/master/contrib/podmanimage/stable/podman-containers.conf /home/podman/.config/containers/containers.conf -RUN chown podman:podman -R /home/podman +# Note VOLUME options must always happen after the chown call above +# RUN commands can not modify existing volumes +VOLUME /var/lib/containers +VOLUME /home/podman/.local/share/containers # chmod containers.conf and adjust storage.conf to enable Fuse storage. RUN chmod 644 /etc/containers/containers.conf; sed -i -e 's|^#mount_program|mount_program|g' -e '/additionalimage.*/a "/var/lib/shared",' -e 's|^mountopt[[:space:]]*=.*$|mountopt = "nodev,fsync=0"|g' /etc/containers/storage.conf diff --git a/contrib/podmanimage/upstream/Dockerfile b/contrib/podmanimage/upstream/Dockerfile index 75de947ea3..89ec6e39b5 100644 --- a/contrib/podmanimage/upstream/Dockerfile +++ b/contrib/podmanimage/upstream/Dockerfile @@ -68,14 +68,15 @@ RUN useradd podman; \ echo podman:10000:5000 > /etc/subuid; \ echo podman:10000:5000 > /etc/subgid; -VOLUME /var/lib/containers -VOLUME /home/podman/.local/share/containers -RUN mkdir -p /home/podman/.local/share/containers +RUN mkdir -p /home/podman/.local/share/containers; chown podman:podman -R /home/podman ADD https://raw.githubusercontent.com/containers/libpod/master/contrib/podmanimage/stable/containers.conf /etc/containers/containers.conf ADD https://raw.githubusercontent.com/containers/libpod/master/contrib/podmanimage/stable/podman-containers.conf /home/podman/.config/containers/containers.conf -RUN chown podman:podman -R /home/podman +# Note VOLUME options must always happen after the chown call above +# RUN commands can not modify existing volumes +VOLUME /var/lib/containers +VOLUME /home/podman/.local/share/containers # chmod containers.conf and adjust storage.conf to enable Fuse storage. RUN chmod 644 /etc/containers/containers.conf; sed -i -e 's|^#mount_program|mount_program|g' -e '/additionalimage.*/a "/var/lib/shared",' -e 's|^mountopt[[:space:]]*=.*$|mountopt = "nodev,fsync=0"|g' /etc/containers/storage.conf From c2fb170b87fc004bca47810b310ac9f709f2695f Mon Sep 17 00:00:00 2001 From: Paul Holzinger Date: Wed, 10 Nov 2021 20:54:01 +0100 Subject: [PATCH 46/51] Fix flake in upgrade tests The cni plugins need access to /run/cni and the dnsname plugin needs access to /run/containers. The race condition was basically that a `podman stop` could either do the cleanup itself or the spawned cleanup process would do the cleanup if it was fast enough. The `podman stop` is executed on the host while the podman cleanup process is executed in the "parent container". The parent container contains older plugins than on the host. The dnsname plugin before version 1.3 could error and this would prevent CNI from doing a proper cleanup. The plugin errors because it could not find its files in /run/containers. On my system the test always failed because the cleanup process was always faster than the stop process. However in the CI VMs the stop process was usually faster and so it failed only sometimes. Fixes #11558 Signed-off-by: Paul Holzinger --- test/upgrade/test-upgrade.bats | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/test/upgrade/test-upgrade.bats b/test/upgrade/test-upgrade.bats index 5cb302a85e..c9c44839ff 100644 --- a/test/upgrade/test-upgrade.bats +++ b/test/upgrade/test-upgrade.bats @@ -121,8 +121,15 @@ EOF # Clean up vestiges of previous run $PODMAN rm -f podman_parent || true - # Not entirely a NOP! This is just so we get /run/crun created on a CI VM - $PODMAN run --rm $OLD_PODMAN true + + local netname=testnet-$(random_string 10) + $PODMAN network create $netname + + # Not entirely a NOP! This is just so we get the /run/... mount points created on a CI VM + # --mac-address is needed to create /run/cni, --network is needed to create /run/containers for dnsname + $PODMAN run --rm --mac-address 78:28:a6:8d:24:8a --network $netname $OLD_PODMAN true + $PODMAN network rm -f $netname + # # Use new-podman to run the above script under old-podman. @@ -134,7 +141,8 @@ EOF # # mount /etc/containers/storage.conf to use the same storage settings as on the host # mount /dev/shm because the container locks are stored there - # mount /var/lib/cni and /etc/cni/net.d for cni networking + # mount /var/lib/cni, /run/cni and /etc/cni/net.d for cni networking + # mount /run/containers for the dnsname plugin # $PODMAN run -d --name podman_parent --pid=host \ --privileged \ @@ -145,6 +153,8 @@ EOF -v /dev/fuse:/dev/fuse \ -v /run/crun:/run/crun \ -v /run/netns:/run/netns:rshared \ + -v /run/containers:/run/containers \ + -v /run/cni:/run/cni \ -v /var/lib/cni:/var/lib/cni \ -v /etc/cni/net.d:/etc/cni/net.d \ -v /dev/shm:/dev/shm \ From 8b368b5e1bfbce3380a38078992429fed544c013 Mon Sep 17 00:00:00 2001 From: Yahav Itzhak Date: Sun, 7 Nov 2021 10:44:10 +0200 Subject: [PATCH 47/51] Fix Zsh completion command documentation Signed-off-by: yahavi --- docs/source/markdown/podman-completion.1.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/markdown/podman-completion.1.md b/docs/source/markdown/podman-completion.1.md index 6393323652..41f5043630 100644 --- a/docs/source/markdown/podman-completion.1.md +++ b/docs/source/markdown/podman-completion.1.md @@ -40,7 +40,7 @@ Shell completion needs to be already enabled in the environment. The following c **echo "autoload -U compinit; compinit" >> ~/.zshrc** To make it available for all zsh sessions run:\ -**podman completion -f "${fpath[1]}/_podman zsh"** +**podman completion -f "${fpath[1]}/_podman" zsh** Once the shell is reloaded the auto-completion should be working. From 6d9b1e4b8e7f72981cabcf576a8771ff458c0385 Mon Sep 17 00:00:00 2001 From: Matthew Heon Date: Fri, 12 Nov 2021 09:52:28 -0500 Subject: [PATCH 48/51] Fix partial log line handling with journald log driver Patch originally by Paul Holzinger (sourced from [1]). This is necessary to get the tests to pass in order to include a batch of other, related journald fixes in `podman logs`. [1] https://github.com/containers/podman/pull/12274#issuecomment-967168173 Signed-off-by: Matthew Heon --- libpod/container_log_linux.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/libpod/container_log_linux.go b/libpod/container_log_linux.go index 4029d0af77..b6b780bab9 100644 --- a/libpod/container_log_linux.go +++ b/libpod/container_log_linux.go @@ -140,6 +140,7 @@ func (c *Container) readFromJournal(ctx context.Context, options *logs.LogOption doTail = false } lastReadCursor := "" + partial := "" for { select { case <-ctx.Done(): @@ -229,6 +230,12 @@ func (c *Container) readFromJournal(ctx context.Context, options *logs.LogOption logrus.Errorf("Failed parse log line: %v", err) return } + if logLine.Partial() { + partial += logLine.Msg + continue + } + logLine.Msg = partial + logLine.Msg + partial = "" if doTail { tailQueue = append(tailQueue, logLine) continue From 1d6397e5c08a4edfbe0dc7f0ff437bb252f0c018 Mon Sep 17 00:00:00 2001 From: Matthew Heon Date: Thu, 11 Nov 2021 15:44:25 -0500 Subject: [PATCH 49/51] Add release notes for v3.4.2 Signed-off-by: Matthew Heon --- RELEASE_NOTES.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index e3d9445954..110de4376a 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,5 +1,24 @@ # Release Notes +## 3.4.2 +### Bugfixes +- Fixed a bug where `podman tag` could not tag manifest lists ([#12046](https://github.com/containers/podman/issues/12046)). +- Fixed a bug where built-in volumes specified by images would not be created correctly under some circumstances. +- Fixed a bug where, when using Podman Machine on OS X, containers in pods did not have working port forwarding from the host ([#12207](https://github.com/containers/podman/issues/12207)). +- Fixed a bug where the `podman network reload` command command on containers using the `slirp4netns` network mode and the `rootlessport` port forwarding driver would make an unnecessary attempt to restart `rootlessport` on containers that did not forward ports. +- Fixed a bug where the `podman generate kube` command would generate YAML including some unnecessary (set to default) fields (e.g. empty SELinux and DNS configuration blocks, and the `privileged` flag when set to false) ([#11995](https://github.com/containers/podman/issues/11995)). +- Fixed a bug where the `podman pod rm` command could, if interrupted at the right moment, leave a reference to an already-removed infra container behind ([#12034](https://github.com/containers/podman/issues/12034)). +- Fixed a bug where the `podman pod rm` command would not remove pods with more than one container if all containers save for the infra container were stopped unless `--force` was specified ([#11713](https://github.com/containers/podman/issues/11713)). +- Fixed a bug where the `--memory` flag to `podman run` and `podman create` did not accept a limit of 0 (which should specify unlimited memory) ([#12002](https://github.com/containers/podman/issues/12002)). +- Fixed a bug where the remote Podman client's `podman build` command could attempt to build a Dockerfile in the working directory of the `podman system service` instance instead of the Dockerfile specified by the user ([#12054](https://github.com/containers/podman/issues/12054)). +- Fixed a bug where the `podman logs --tail` command could function improperly (printing more output than requested) when the `journald` log driver was used. +- Fixed a bug where containers run using the `slirp4netns` network mode with IPv6 enabled would not have IPv6 connectivity until several seconds after they started ([#11062](https://github.com/containers/podman/issues/11062)). +- Fixed a bug where some Podman commands could cause an extra `dbus-daemon` process to be created ([#9727](https://github.com/containers/podman/issues/9727)). +- Fixed a bug where rootless Podman would sometimes print warnings about a failure to move the pause process into a given CGroup ([#12065](https://github.com/containers/podman/issues/12065)). +- Fixed a bug where the `checkpointed` field in `podman inspect` on a container was not set to false after a container was restored. +- Fixed a bug where the `podman system service` command would print overly-verbose logs about request IDs ([#12181](https://github.com/containers/podman/issues/12181)). +- Fixed a bug where Podman could, when creating a new container without a name explicitly specified by the user, sometimes use an auto-generated name already in use by another container if multiple containers were being created in parallel ([#11735](https://github.com/containers/podman/issues/11735)). + ## 3.4.1 ### Bugfixes - Fixed a bug where `podman machine init` could, under some circumstances, create invalid machine configurations which could not be started ([#11824](https://github.com/containers/podman/issues/11824)). From 2ad1fd3555de12de34e20898cc2ef901f08fe5ed Mon Sep 17 00:00:00 2001 From: Matthew Heon Date: Thu, 11 Nov 2021 15:46:13 -0500 Subject: [PATCH 50/51] Bump to v3.4.2 Signed-off-by: Matthew Heon --- version/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version/version.go b/version/version.go index e5d1f3d1cd..b980f375e0 100644 --- a/version/version.go +++ b/version/version.go @@ -27,7 +27,7 @@ const ( // NOTE: remember to bump the version at the top // of the top-level README.md file when this is // bumped. -var Version = semver.MustParse("3.4.2-dev") +var Version = semver.MustParse("3.4.2") // See https://docs.docker.com/engine/api/v1.40/ // libpod compat handlers are expected to honor docker API versions From 7c98d542b4c5ab0495f66a9179ae886e86cad273 Mon Sep 17 00:00:00 2001 From: Matthew Heon Date: Thu, 11 Nov 2021 15:46:45 -0500 Subject: [PATCH 51/51] Bump to v3.4.3-dev Signed-off-by: Matthew Heon --- contrib/spec/podman.spec.in | 2 +- version/version.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/contrib/spec/podman.spec.in b/contrib/spec/podman.spec.in index 683797cd0f..00f9ad6d01 100644 --- a/contrib/spec/podman.spec.in +++ b/contrib/spec/podman.spec.in @@ -36,7 +36,7 @@ Epoch: 99 %else Epoch: 0 %endif -Version: 3.4.2 +Version: 3.4.3 Release: #COMMITDATE#.git%{shortcommit0}%{?dist} Summary: Manage Pods, Containers and Container Images License: ASL 2.0 diff --git a/version/version.go b/version/version.go index b980f375e0..9dd8b9a834 100644 --- a/version/version.go +++ b/version/version.go @@ -27,7 +27,7 @@ const ( // NOTE: remember to bump the version at the top // of the top-level README.md file when this is // bumped. -var Version = semver.MustParse("3.4.2") +var Version = semver.MustParse("3.4.3-dev") // See https://docs.docker.com/engine/api/v1.40/ // libpod compat handlers are expected to honor docker API versions