diff options
-rw-r--r-- | .cirrus.yml | 3 | ||||
-rw-r--r-- | cmd/podman/generate/systemd.go | 2 | ||||
-rw-r--r-- | docs/source/markdown/podman-cp.1.md | 2 | ||||
-rw-r--r-- | docs/source/markdown/podman-generate-systemd.1.md | 2 | ||||
-rw-r--r-- | libpod/container_internal_linux.go | 12 | ||||
-rw-r--r-- | libpod/oci_conmon_exec_linux.go | 3 | ||||
-rw-r--r-- | libpod/oci_conmon_linux.go | 44 | ||||
-rw-r--r-- | pkg/systemd/generate/containers.go | 2 | ||||
-rw-r--r-- | test/system/250-systemd.bats | 42 |
9 files changed, 86 insertions, 26 deletions
diff --git a/.cirrus.yml b/.cirrus.yml index f39e599ba..5087a00eb 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -423,6 +423,9 @@ apiv2_test_task: depends_on: - validate gce_instance: *standardvm + # Test is normally pretty quick, about 10-minutes. If it hangs, + # don't make developers wait the full 1-hour timeout. + timeout_in: 20m env: <<: *stdenvars TEST_FLAVOR: apiv2 diff --git a/cmd/podman/generate/systemd.go b/cmd/podman/generate/systemd.go index 5461f1f6a..b76a71f0d 100644 --- a/cmd/podman/generate/systemd.go +++ b/cmd/podman/generate/systemd.go @@ -50,7 +50,7 @@ func init() { timeFlagName := "time" flags.UintVarP(&systemdTimeout, timeFlagName, "t", containerConfig.Engine.StopTimeout, "Stop timeout override") _ = systemdCmd.RegisterFlagCompletionFunc(timeFlagName, completion.AutocompleteNone) - flags.BoolVarP(&systemdOptions.New, "new", "", false, "Create a new container instead of starting an existing one") + flags.BoolVarP(&systemdOptions.New, "new", "", false, "Create a new container or pod instead of starting an existing one") flags.BoolVarP(&systemdOptions.NoHeader, "no-header", "", false, "Skip header generation") containerPrefixFlagName := "container-prefix" diff --git a/docs/source/markdown/podman-cp.1.md b/docs/source/markdown/podman-cp.1.md index 79edf26ed..1929bed1f 100644 --- a/docs/source/markdown/podman-cp.1.md +++ b/docs/source/markdown/podman-cp.1.md @@ -52,6 +52,8 @@ Using `-` as the **src_path** streams the contents of `STDIN` as a tar archive. Note that `podman cp` ignores permission errors when copying from a running rootless container. The TTY devices inside a rootless container are owned by the host's root user and hence cannot be read inside the container's user namespace. +Further note that `podman cp` does not support globbing (e.g., `cp dir/*.txt`). If you want to copy multiple files from the host to the container you may use xargs(1) or find(1) (or similar tools for chaining commands) in conjunction with `podman cp`. If you want to copy multiple files from the container to the host, you may use `podman mount CONTAINER` and operate on the returned mount point instead (see ALTERNATIVES below). + ## OPTIONS #### **--archive**, **-a**=**true** | *false* diff --git a/docs/source/markdown/podman-generate-systemd.1.md b/docs/source/markdown/podman-generate-systemd.1.md index 357120381..8393aec11 100644 --- a/docs/source/markdown/podman-generate-systemd.1.md +++ b/docs/source/markdown/podman-generate-systemd.1.md @@ -32,6 +32,8 @@ Use the name of the container for the start, stop, and description in the unit f Using this flag will yield unit files that do not expect containers and pods to exist. Instead, new containers and pods are created based on their configuration files. The unit files are created best effort and may need to be further edited; please review the generated files carefully before using them in production. +Note that `--new` only works on containers and pods created directly via Podman (i.e., `podman [container] {create,run}` or `podman pod create`). It does not work on containers or pods created via the REST API or via `podman play kube`. + #### **--no-header** Do not generate the header including meta data such as the Podman version and the timestamp. diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go index b624f44ac..847122929 100644 --- a/libpod/container_internal_linux.go +++ b/libpod/container_internal_linux.go @@ -773,6 +773,18 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) { } } + // Pass down the LISTEN_* environment (see #10443). + for _, key := range []string{"LISTEN_PID", "LISTEN_FDS", "LISTEN_FDNAMES"} { + if val, ok := os.LookupEnv(key); ok { + // Force the PID to `1` since we cannot rely on (all + // versions of) all runtimes to do it for us. + if key == "LISTEN_PID" { + val = "1" + } + g.AddProcessEnv(key, val) + } + } + return g.Config, nil } diff --git a/libpod/oci_conmon_exec_linux.go b/libpod/oci_conmon_exec_linux.go index 85ae95097..5a7677b04 100644 --- a/libpod/oci_conmon_exec_linux.go +++ b/libpod/oci_conmon_exec_linux.go @@ -438,7 +438,7 @@ func (r *ConmonOCIRuntime) startExec(c *Container, sessionID string, options *Ex // } // } - conmonEnv, extraFiles := r.configureConmonEnv(c, runtimeDir) + conmonEnv := r.configureConmonEnv(c, runtimeDir) var filesToClose []*os.File if options.PreserveFDs > 0 { @@ -456,7 +456,6 @@ func (r *ConmonOCIRuntime) startExec(c *Container, sessionID string, options *Ex execCmd.Env = append(execCmd.Env, conmonEnv...) execCmd.ExtraFiles = append(execCmd.ExtraFiles, childSyncPipe, childStartPipe, childAttachPipe) - execCmd.ExtraFiles = append(execCmd.ExtraFiles, extraFiles...) execCmd.Dir = c.execBundlePath(sessionID) execCmd.SysProcAttr = &syscall.SysProcAttr{ Setpgid: true, diff --git a/libpod/oci_conmon_linux.go b/libpod/oci_conmon_linux.go index c14911980..353e6af71 100644 --- a/libpod/oci_conmon_linux.go +++ b/libpod/oci_conmon_linux.go @@ -34,7 +34,6 @@ import ( "github.com/containers/podman/v3/utils" "github.com/containers/storage/pkg/homedir" pmount "github.com/containers/storage/pkg/mount" - "github.com/coreos/go-systemd/v22/activation" "github.com/coreos/go-systemd/v22/daemon" spec "github.com/opencontainers/runtime-spec/specs-go" "github.com/opencontainers/selinux/go-selinux" @@ -66,7 +65,6 @@ type ConmonOCIRuntime struct { supportsJSON bool supportsKVM bool supportsNoCgroups bool - sdNotify bool enableKeyring bool } @@ -105,7 +103,6 @@ func newConmonOCIRuntime(name string, paths []string, conmonPath string, runtime runtime.logSizeMax = runtimeCfg.Containers.LogSizeMax runtime.noPivot = runtimeCfg.Engine.NoPivotRoot runtime.reservePorts = runtimeCfg.Engine.EnablePortReservation - runtime.sdNotify = runtimeCfg.Engine.SDNotify runtime.enableKeyring = runtimeCfg.Containers.EnableKeyring // TODO: probe OCI runtime for feature and enable automatically if @@ -1050,8 +1047,22 @@ func (r *ConmonOCIRuntime) createOCIContainer(ctr *Container, restoreOptions *Co } } - if ctr.config.PreserveFDs > 0 { - args = append(args, formatRuntimeOpts("--preserve-fds", fmt.Sprintf("%d", ctr.config.PreserveFDs))...) + // Pass down the LISTEN_* environment (see #10443). + preserveFDs := ctr.config.PreserveFDs + if val := os.Getenv("LISTEN_FDS"); val != "" { + if ctr.config.PreserveFDs > 0 { + logrus.Warnf("Ignoring LISTEN_FDS to preserve custom user-specified FDs") + } else { + fds, err := strconv.Atoi(val) + if err != nil { + return fmt.Errorf("converting LISTEN_FDS=%s: %w", val, err) + } + preserveFDs = uint(fds) + } + } + + if preserveFDs > 0 { + args = append(args, formatRuntimeOpts("--preserve-fds", fmt.Sprintf("%d", preserveFDs))...) } if restoreOptions != nil { @@ -1104,11 +1115,11 @@ func (r *ConmonOCIRuntime) createOCIContainer(ctr *Container, restoreOptions *Co } // 0, 1 and 2 are stdin, stdout and stderr - conmonEnv, envFiles := r.configureConmonEnv(ctr, runtimeDir) + conmonEnv := r.configureConmonEnv(ctr, runtimeDir) var filesToClose []*os.File - if ctr.config.PreserveFDs > 0 { - for fd := 3; fd < int(3+ctr.config.PreserveFDs); fd++ { + if preserveFDs > 0 { + for fd := 3; fd < int(3+preserveFDs); fd++ { f := os.NewFile(uintptr(fd), fmt.Sprintf("fd-%d", fd)) filesToClose = append(filesToClose, f) cmd.ExtraFiles = append(cmd.ExtraFiles, f) @@ -1118,10 +1129,9 @@ func (r *ConmonOCIRuntime) createOCIContainer(ctr *Container, restoreOptions *Co cmd.Env = r.conmonEnv // we don't want to step on users fds they asked to preserve // Since 0-2 are used for stdio, start the fds we pass in at preserveFDs+3 - cmd.Env = append(cmd.Env, fmt.Sprintf("_OCI_SYNCPIPE=%d", ctr.config.PreserveFDs+3), fmt.Sprintf("_OCI_STARTPIPE=%d", ctr.config.PreserveFDs+4)) + cmd.Env = append(cmd.Env, fmt.Sprintf("_OCI_SYNCPIPE=%d", preserveFDs+3), fmt.Sprintf("_OCI_STARTPIPE=%d", preserveFDs+4)) cmd.Env = append(cmd.Env, conmonEnv...) cmd.ExtraFiles = append(cmd.ExtraFiles, childSyncPipe, childStartPipe) - cmd.ExtraFiles = append(cmd.ExtraFiles, envFiles...) if r.reservePorts && !rootless.IsRootless() && !ctr.config.NetMode.IsSlirp4netns() { ports, err := bindPorts(ctr.config.PortMappings) @@ -1225,7 +1235,7 @@ func (r *ConmonOCIRuntime) createOCIContainer(ctr *Container, restoreOptions *Co // configureConmonEnv gets the environment values to add to conmon's exec struct // TODO this may want to be less hardcoded/more configurable in the future -func (r *ConmonOCIRuntime) configureConmonEnv(ctr *Container, runtimeDir string) ([]string, []*os.File) { +func (r *ConmonOCIRuntime) configureConmonEnv(ctr *Container, runtimeDir string) []string { var env []string for _, e := range os.Environ() { if strings.HasPrefix(e, "LC_") { @@ -1240,17 +1250,7 @@ func (r *ConmonOCIRuntime) configureConmonEnv(ctr *Container, runtimeDir string) env = append(env, fmt.Sprintf("HOME=%s", home)) } - extraFiles := make([]*os.File, 0) - if !r.sdNotify { - if listenfds, ok := os.LookupEnv("LISTEN_FDS"); ok { - env = append(env, fmt.Sprintf("LISTEN_FDS=%s", listenfds), "LISTEN_PID=1") - fds := activation.Files(false) - extraFiles = append(extraFiles, fds...) - } - } else { - logrus.Debug("disabling SD notify") - } - return env, extraFiles + return env } // sharedConmonArgs takes common arguments for exec and create/restore and formats them for the conmon CLI diff --git a/pkg/systemd/generate/containers.go b/pkg/systemd/generate/containers.go index 931f13972..188926115 100644 --- a/pkg/systemd/generate/containers.go +++ b/pkg/systemd/generate/containers.go @@ -155,7 +155,7 @@ func generateContainerInfo(ctr *libpod.Container, options entities.GenerateSyste if config.CreateCommand != nil { createCommand = config.CreateCommand } else if options.New { - return nil, errors.Errorf("cannot use --new on container %q: no create command found", ctr.ID()) + return nil, errors.Errorf("cannot use --new on container %q: no create command found: only works on containers created directly with podman but not via REST API", ctr.ID()) } nameOrID, serviceName := containerServiceName(ctr, options) diff --git a/test/system/250-systemd.bats b/test/system/250-systemd.bats index 5d4ae4cb1..08fad5e7c 100644 --- a/test/system/250-systemd.bats +++ b/test/system/250-systemd.bats @@ -136,4 +136,46 @@ function service_cleanup() { service_cleanup } +function set_listen_env() { + export LISTEN_PID="100" LISTEN_FDS="1" LISTEN_FDNAMES="listen_fdnames" +} + +function unset_listen_env() { + unset LISTEN_PID LISTEN_FDS LISTEN_FDNAMES +} + +function check_listen_env() { + local stdenv="$1" + local context="$2" + if is_remote; then + is "$output" "$stdenv" "LISTEN Environment did not pass: $context" + else + is "$output" "$stdenv +LISTEN_PID=1 +LISTEN_FDS=1 +LISTEN_FDNAMES=listen_fdnames" "LISTEN Environment passed: $context" + fi +} + +@test "podman pass LISTEN environment " { + # Note that `--hostname=host1` makes sure that all containers have the same + # environment. + run_podman run --hostname=host1 --rm $IMAGE printenv + stdenv=$output + + # podman run + set_listen_env + run_podman run --hostname=host1 --rm $IMAGE printenv + unset_listen_env + check_listen_env "$stdenv" "podman run" + + # podman start + run_podman create --hostname=host1 --rm $IMAGE printenv + cid="$output" + set_listen_env + run_podman start --attach $cid + unset_listen_env + check_listen_env "$stdenv" "podman start" +} + # vim: filetype=sh |