diff options
-rw-r--r-- | .cirrus.yml | 8 | ||||
-rw-r--r-- | Makefile | 4 | ||||
-rw-r--r-- | changelog.txt | 17 | ||||
-rw-r--r-- | cmd/podman/cliconfig/config.go | 1 | ||||
-rw-r--r-- | cmd/podman/create.go | 2 | ||||
-rw-r--r-- | cmd/podman/exec.go | 30 | ||||
-rw-r--r-- | cmd/podman/rm.go | 3 | ||||
-rw-r--r-- | cmd/podman/top.go | 2 | ||||
-rwxr-xr-x | contrib/cirrus/integration_test.sh | 2 | ||||
-rw-r--r-- | contrib/cirrus/packer/centos_setup.sh | 1 | ||||
-rw-r--r-- | contrib/cirrus/packer/fedora_setup.sh | 1 | ||||
-rw-r--r-- | contrib/cirrus/packer/rhel_setup.sh | 1 | ||||
-rw-r--r-- | contrib/cirrus/packer/ubuntu_setup.sh | 1 | ||||
-rw-r--r-- | docs/podman-exec.1.md | 4 | ||||
-rw-r--r-- | libpod/container_api.go | 4 | ||||
-rw-r--r-- | libpod/oci.go | 13 | ||||
-rw-r--r-- | libpod/runtime.go | 25 | ||||
-rw-r--r-- | pkg/rootless/rootless_linux.go | 9 |
18 files changed, 109 insertions, 19 deletions
diff --git a/.cirrus.yml b/.cirrus.yml index cc8f11f7b..b473980ea 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -27,11 +27,11 @@ env: #### #### Cache-image names to test with ### - FEDORA_CACHE_IMAGE_NAME: "fedora-29-libpod-7f4cd1f7" - PRIOR_FEDORA_CACHE_IMAGE_NAME: "fedora-28-libpod-7f4cd1f7" - UBUNTU_CACHE_IMAGE_NAME: "ubuntu-18-libpod-84514d8b" + FEDORA_CACHE_IMAGE_NAME: "fedora-29-libpod-d6d53e40" + PRIOR_FEDORA_CACHE_IMAGE_NAME: "fedora-28-libpod-d6d53e40" + UBUNTU_CACHE_IMAGE_NAME: "ubuntu-18-libpod-d6d53e40" # RHEL_CACHE_IMAGE_NAME: "rhel-8-notready" - PRIOR_RHEL_CACHE_IMAGE_NAME: "rhel-7-libpod-7f4cd1f7" + PRIOR_RHEL_CACHE_IMAGE_NAME: "rhel-7-libpod-d6d53e40" # CENTOS_CACHE_IMAGE_NAME: "centos-7-notready" #### @@ -1,6 +1,6 @@ GO ?= go DESTDIR ?= / -EPOCH_TEST_COMMIT ?= cabfc9b6fb16c5b55d70140182496bbe129f6a4b +EPOCH_TEST_COMMIT ?= 4b80517b6a638ff06f8ad432f0f0f5839283d058 HEAD ?= HEAD CHANGELOG_BASE ?= HEAD~ CHANGELOG_TARGET ?= HEAD @@ -44,7 +44,7 @@ LIBSECCOMP_COMMIT := release-2.3 # Rarely if ever should integration tests take more than 50min, # caller may override in special circumstances if needed. -GINKGOTIMEOUT ?= -timeout=50m +GINKGOTIMEOUT ?= -timeout=90m # If GOPATH not specified, use one in the local directory ifeq ($(GOPATH),) diff --git a/changelog.txt b/changelog.txt index 9dd0ae2d1..7db579f3a 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,20 @@ +- Changelog for v1.1.2 (2019-03-04) + * Fix #2521 + * Update release notes for v1.1.2 + * Change timestamp format for podman logs + * Don't extract tar file in podman cp + * runtime: fill a proper default tmpdir when --config is used + * Add additional defense against 0-length log segfaults + * When logging with timestamps, append only until newline + * Ensure that each log line is newline-terminated + * A few more usage-message tweaks + * Add missing short flag -l for run/create + * Fix aliased commands to actually work + * Support podman-remote stop container(s) + * Add tests to make sure podman container and podman image commands work + * Bump gitvalidation epoch + * Bump to v1.2.0-dev + - Changelog for v1.1.1 (2019-03-01) * Update release notes for v1.1.1 * Pull image for runlabel if not local diff --git a/cmd/podman/cliconfig/config.go b/cmd/podman/cliconfig/config.go index 702e20040..ea99aafc2 100644 --- a/cmd/podman/cliconfig/config.go +++ b/cmd/podman/cliconfig/config.go @@ -100,6 +100,7 @@ type ExecValues struct { User string Latest bool Workdir string + PreserveFDs int } type ImageExistsValues struct { diff --git a/cmd/podman/create.go b/cmd/podman/create.go index 95cb732d9..129c886b2 100644 --- a/cmd/podman/create.go +++ b/cmd/podman/create.go @@ -869,7 +869,7 @@ func joinOrCreateRootlessUserNamespace(createConfig *cc.CreateConfig, runtime *l } return false, -1, errors.Errorf("dependency container %s is not running", ctr.ID()) } - return rootless.JoinNS(uint(pid)) + return rootless.JoinNS(uint(pid), 0) } } return rootless.BecomeRootInUserNS() diff --git a/cmd/podman/exec.go b/cmd/podman/exec.go index 4917fb606..32a6e4bb5 100644 --- a/cmd/podman/exec.go +++ b/cmd/podman/exec.go @@ -4,7 +4,9 @@ import ( "fmt" "github.com/containers/libpod/cmd/podman/cliconfig" "github.com/spf13/cobra" + "io/ioutil" "os" + "strconv" "github.com/containers/libpod/cmd/podman/libpodruntime" "github.com/containers/libpod/libpod" @@ -47,6 +49,7 @@ func init() { flags.BoolVarP(&execCommand.Tty, "tty", "t", false, "Allocate a pseudo-TTY. The default is false") flags.StringVarP(&execCommand.User, "user", "u", "", "Sets the username or UID used and optionally the groupname or GID for the specified command") + flags.IntVar(&execCommand.PreserveFDs, "preserve-fds", 0, "Pass N additional file descriptors to the container") flags.StringVarP(&execCommand.Workdir, "workdir", "w", "", "Working directory inside the container") markFlagHiddenForRemoteClient("latest", flags) } @@ -82,11 +85,34 @@ func execCmd(c *cliconfig.ExecValues) error { return errors.Wrapf(err, "unable to exec into %s", args[0]) } + if c.PreserveFDs > 0 { + entries, err := ioutil.ReadDir("/proc/self/fd") + if err != nil { + return errors.Wrapf(err, "unable to read /proc/self/fd") + } + m := make(map[int]bool) + for _, e := range entries { + i, err := strconv.Atoi(e.Name()) + if err != nil { + if err != nil { + return errors.Wrapf(err, "cannot parse %s in /proc/self/fd", e.Name()) + } + } + m[i] = true + } + for i := 3; i < 3+c.PreserveFDs; i++ { + if _, found := m[i]; !found { + return errors.New("invalid --preserve-fds=N specified. Not enough FDs available") + } + } + + } + pid, err := ctr.PID() if err != nil { return err } - became, ret, err := rootless.JoinNS(uint(pid)) + became, ret, err := rootless.JoinNS(uint(pid), c.PreserveFDs) if err != nil { return err } @@ -113,5 +139,5 @@ func execCmd(c *cliconfig.ExecValues) error { streams.AttachError = true streams.AttachInput = true - return ctr.Exec(c.Tty, c.Privileged, envs, cmd, c.User, c.Workdir, streams) + return ctr.Exec(c.Tty, c.Privileged, envs, cmd, c.User, c.Workdir, streams, c.PreserveFDs) } diff --git a/cmd/podman/rm.go b/cmd/podman/rm.go index 61b049840..d23f8228c 100644 --- a/cmd/podman/rm.go +++ b/cmd/podman/rm.go @@ -80,6 +80,9 @@ func rmCmd(c *cliconfig.RmValues) error { return err } if err != nil { + if errors.Cause(err) == libpod.ErrNoSuchCtr { + exitCode = 1 + } fmt.Println(err.Error()) } } diff --git a/cmd/podman/top.go b/cmd/podman/top.go index cdf270fa7..d96402f1a 100644 --- a/cmd/podman/top.go +++ b/cmd/podman/top.go @@ -108,7 +108,7 @@ func topCmd(c *cliconfig.TopValues) error { if err != nil { return err } - became, ret, err := rootless.JoinNS(uint(pid)) + became, ret, err := rootless.JoinNS(uint(pid), 0) if err != nil { return err } diff --git a/contrib/cirrus/integration_test.sh b/contrib/cirrus/integration_test.sh index 0fd86dfdc..58c8af289 100755 --- a/contrib/cirrus/integration_test.sh +++ b/contrib/cirrus/integration_test.sh @@ -19,7 +19,7 @@ case "${OS_RELEASE_ID}-${OS_RELEASE_VER}" in ubuntu-18) make install PREFIX=/usr ETCDIR=/etc make test-binaries - SKIP_USERNS=1 make localintegration GINKGOTIMEOUT=90m + SKIP_USERNS=1 make localintegration ;; fedora-29) ;& # Continue to the next item fedora-28) ;& diff --git a/contrib/cirrus/packer/centos_setup.sh b/contrib/cirrus/packer/centos_setup.sh index 923f2563b..d947a1d7f 100644 --- a/contrib/cirrus/packer/centos_setup.sh +++ b/contrib/cirrus/packer/centos_setup.sh @@ -27,6 +27,7 @@ ooe.sh sudo yum -y install centos-release-scl epel-release ooe.sh sudo yum -y install \ PyYAML \ atomic-registries \ + bats \ btrfs-progs-devel \ bzip2 \ device-mapper-devel \ diff --git a/contrib/cirrus/packer/fedora_setup.sh b/contrib/cirrus/packer/fedora_setup.sh index de7ad4506..84aee7667 100644 --- a/contrib/cirrus/packer/fedora_setup.sh +++ b/contrib/cirrus/packer/fedora_setup.sh @@ -26,6 +26,7 @@ ooe.sh sudo dnf update -y ooe.sh sudo dnf install -y \ atomic-registries \ + bats \ btrfs-progs-devel \ bzip2 \ device-mapper-devel \ diff --git a/contrib/cirrus/packer/rhel_setup.sh b/contrib/cirrus/packer/rhel_setup.sh index ac6866a57..20be97f9b 100644 --- a/contrib/cirrus/packer/rhel_setup.sh +++ b/contrib/cirrus/packer/rhel_setup.sh @@ -33,6 +33,7 @@ ooe.sh sudo yum -y update ooe.sh sudo yum -y install \ PyYAML \ atomic-registries \ + bats \ btrfs-progs-devel \ bzip2 \ device-mapper-devel \ diff --git a/contrib/cirrus/packer/ubuntu_setup.sh b/contrib/cirrus/packer/ubuntu_setup.sh index 5b7e1d714..24f1cce21 100644 --- a/contrib/cirrus/packer/ubuntu_setup.sh +++ b/contrib/cirrus/packer/ubuntu_setup.sh @@ -38,6 +38,7 @@ ooe.sh sudo -E apt-get -qq install \ apparmor \ autoconf \ automake \ + bats \ bison \ btrfs-tools \ build-essential \ diff --git a/docs/podman-exec.1.md b/docs/podman-exec.1.md index 14088b468..b74713b0b 100644 --- a/docs/podman-exec.1.md +++ b/docs/podman-exec.1.md @@ -26,6 +26,10 @@ to run containers such as CRI-O, the last started container could be from eithe The latest option is not supported on the remote client. +**--preserve-fds=N** + +Pass down to the process N additional file descriptors (in addition to 0, 1, 2). The total FDs will be 3+N. + **--privileged** Give the process extended Linux capabilities when running the command in container. diff --git a/libpod/container_api.go b/libpod/container_api.go index 6bef3c47d..4a76e1434 100644 --- a/libpod/container_api.go +++ b/libpod/container_api.go @@ -204,7 +204,7 @@ func (c *Container) Kill(signal uint) error { // Exec starts a new process inside the container // TODO investigate allowing exec without attaching -func (c *Container) Exec(tty, privileged bool, env, cmd []string, user, workDir string, streams *AttachStreams) error { +func (c *Container) Exec(tty, privileged bool, env, cmd []string, user, workDir string, streams *AttachStreams, preserveFDs int) error { var capList []string locked := false @@ -266,7 +266,7 @@ func (c *Container) Exec(tty, privileged bool, env, cmd []string, user, workDir logrus.Debugf("Creating new exec session in container %s with session id %s", c.ID(), sessionID) - execCmd, err := c.runtime.ociRuntime.execContainer(c, cmd, capList, env, tty, workDir, hostUser, sessionID, streams) + execCmd, err := c.runtime.ociRuntime.execContainer(c, cmd, capList, env, tty, workDir, hostUser, sessionID, streams, preserveFDs) if err != nil { return errors.Wrapf(err, "error exec %s", c.ID()) } diff --git a/libpod/oci.go b/libpod/oci.go index 2b3cc5db5..2cbf25699 100644 --- a/libpod/oci.go +++ b/libpod/oci.go @@ -733,7 +733,7 @@ func (r *OCIRuntime) unpauseContainer(ctr *Container) error { // TODO: Add --detach support // TODO: Convert to use conmon // TODO: add --pid-file and use that to generate exec session tracking -func (r *OCIRuntime) execContainer(c *Container, cmd, capAdd, env []string, tty bool, cwd, user, sessionID string, streams *AttachStreams) (*exec.Cmd, error) { +func (r *OCIRuntime) execContainer(c *Container, cmd, capAdd, env []string, tty bool, cwd, user, sessionID string, streams *AttachStreams, preserveFDs int) (*exec.Cmd, error) { if len(cmd) == 0 { return nil, errors.Wrapf(ErrInvalidArg, "must provide a command to execute") } @@ -770,6 +770,9 @@ func (r *OCIRuntime) execContainer(c *Container, cmd, capAdd, env []string, tty args = append(args, "--user", user) } + if preserveFDs > 0 { + args = append(args, fmt.Sprintf("--preserve-fds=%d", preserveFDs)) + } if c.config.Spec.Process.NoNewPrivileges { args = append(args, "--no-new-privs") } @@ -806,6 +809,14 @@ func (r *OCIRuntime) execContainer(c *Container, cmd, capAdd, env []string, tty return nil, errors.Wrapf(err, "cannot start container %s", c.ID()) } + if preserveFDs > 0 { + for fd := 3; fd < 3+preserveFDs; fd++ { + // These fds were passed down to the runtime. Close them + // and not interfere + os.NewFile(uintptr(fd), fmt.Sprintf("fd-%d", fd)).Close() + } + } + return execCmd, nil } diff --git a/libpod/runtime.go b/libpod/runtime.go index 112b6820a..482cd9d73 100644 --- a/libpod/runtime.go +++ b/libpod/runtime.go @@ -333,7 +333,7 @@ func NewRuntime(options ...RuntimeOption) (runtime *Runtime, err error) { storageConf, err := util.GetDefaultStoreOptions() if err != nil { - return nil, errors.Wrapf(err, "error retrieving rootless storage config") + return nil, errors.Wrapf(err, "error retrieving storage config") } runtime.config.StorageConfig = storageConf runtime.config.StaticDir = filepath.Join(storageConf.GraphRoot, "libpod") @@ -365,8 +365,7 @@ func NewRuntime(options ...RuntimeOption) (runtime *Runtime, err error) { // containers/image uses XDG_RUNTIME_DIR to locate the auth file. // So make sure the env variable is set. - err = SetXdgRuntimeDir(runtimeDir) - if err != nil { + if err := SetXdgRuntimeDir(runtimeDir); err != nil { return nil, errors.Wrapf(err, "cannot set XDG_RUNTIME_DIR") } @@ -475,13 +474,31 @@ func NewRuntimeFromConfig(configPath string, options ...RuntimeOption) (runtime // Set three fields not in the TOML config runtime.config.StateType = defaultRuntimeConfig.StateType runtime.config.OCIRuntime = defaultRuntimeConfig.OCIRuntime - runtime.config.StorageConfig = storage.StoreOptions{} + + storageConf, err := util.GetDefaultStoreOptions() + if err != nil { + return nil, errors.Wrapf(err, "error retrieving storage config") + } + runtime.config.StorageConfig = storageConf + runtime.config.StaticDir = filepath.Join(storageConf.GraphRoot, "libpod") + runtime.config.VolumePath = filepath.Join(storageConf.GraphRoot, "volumes") tmpDir, err := getDefaultTmpDir() if err != nil { return nil, err } runtime.config.TmpDir = tmpDir + if rootless.IsRootless() { + runtimeDir, err := util.GetRootlessRuntimeDir() + if err != nil { + return nil, err + } + // containers/image uses XDG_RUNTIME_DIR to locate the auth file. + // So make sure the env variable is set. + if err := SetXdgRuntimeDir(runtimeDir); err != nil { + return nil, errors.Wrapf(err, "cannot set XDG_RUNTIME_DIR") + } + } // Check to see if the given configuration file exists if _, err := os.Stat(configPath); err != nil { diff --git a/pkg/rootless/rootless_linux.go b/pkg/rootless/rootless_linux.go index 98692707f..55fba900e 100644 --- a/pkg/rootless/rootless_linux.go +++ b/pkg/rootless/rootless_linux.go @@ -102,7 +102,7 @@ func tryMappingTool(tool string, pid int, hostID int, mappings []idtools.IDMap) // JoinNS re-exec podman in a new userNS and join the user namespace of the specified // PID. -func JoinNS(pid uint) (bool, int, error) { +func JoinNS(pid uint, preserveFDs int) (bool, int, error) { if os.Geteuid() == 0 || os.Getenv("_LIBPOD_USERNS_CONFIGURED") != "" { return false, -1, nil } @@ -117,6 +117,13 @@ func JoinNS(pid uint) (bool, int, error) { if int(pidC) < 0 { return false, -1, errors.Errorf("cannot re-exec process") } + if preserveFDs > 0 { + for fd := 3; fd < 3+preserveFDs; fd++ { + // These fds were passed down to the runtime. Close them + // and not interfere + os.NewFile(uintptr(fd), fmt.Sprintf("fd-%d", fd)).Close() + } + } ret := C.reexec_in_user_namespace_wait(pidC) if ret < 0 { |