summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cirrus.yml16
-rw-r--r--Makefile4
-rw-r--r--RELEASE_NOTES.md11
-rw-r--r--changelog.txt17
-rw-r--r--cmd/podman/cliconfig/config.go1
-rw-r--r--cmd/podman/create.go2
-rw-r--r--cmd/podman/exec.go30
-rw-r--r--cmd/podman/rm.go3
-rw-r--r--cmd/podman/top.go2
-rwxr-xr-xcontrib/cirrus/integration_test.sh2
-rw-r--r--contrib/cirrus/lib.sh15
-rw-r--r--contrib/cirrus/packer/centos_setup.sh1
-rw-r--r--contrib/cirrus/packer/fedora_setup.sh1
-rw-r--r--contrib/cirrus/packer/rhel_setup.sh1
-rw-r--r--contrib/cirrus/packer/ubuntu_setup.sh1
-rwxr-xr-xcontrib/cirrus/setup_environment.sh4
-rw-r--r--docs/podman-exec.1.md4
-rw-r--r--libpod/container_api.go4
-rw-r--r--libpod/oci.go13
-rw-r--r--libpod/runtime.go25
-rw-r--r--pkg/adapter/containers.go23
-rw-r--r--pkg/logs/logs.go22
-rw-r--r--pkg/rootless/rootless_linux.go9
-rw-r--r--test/e2e/stop_test.go28
24 files changed, 183 insertions, 56 deletions
diff --git a/.cirrus.yml b/.cirrus.yml
index 4521866d1..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"
####
@@ -169,9 +169,9 @@ testing_task:
image_name: "${FEDORA_CACHE_IMAGE_NAME}"
image_name: "${PRIOR_FEDORA_CACHE_IMAGE_NAME}"
image_name: "${UBUNTU_CACHE_IMAGE_NAME}"
- image_name: "${PRIOR_RHEL_CACHE_IMAGE_NAME}"
- # TODO: tests fail
+ # TODO: Make these work (also optional_testing_task below)
+ # image_name: "${PRIOR_RHEL_CACHE_IMAGE_NAME}"
# image_name: "${RHEL_CACHE_IMAGE_NAME}"
# image_name: "${CENTOS_CACHE_IMAGE_NAME}"
@@ -206,9 +206,9 @@ optional_testing_task:
image_name: "${FEDORA_CACHE_IMAGE_NAME}"
image_name: "${PRIOR_FEDORA_CACHE_IMAGE_NAME}"
image_name: "${UBUNTU_CACHE_IMAGE_NAME}"
- image_name: "${PRIOR_RHEL_CACHE_IMAGE_NAME}"
- # TODO: Make these work (also build_images_task below)
+ # TODO: Make these work (also testing_task above)
# image_name: "${RHEL_CACHE_IMAGE_NAME}"
+ # image_name: "${PRIOR_RHEL_CACHE_IMAGE_NAME}"
# image_name: "${CENTOS_CACHE_IMAGE_NAME}"
timeout_in: 60m
diff --git a/Makefile b/Makefile
index 60fb3eda7..cb351f917 100644
--- a/Makefile
+++ b/Makefile
@@ -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/RELEASE_NOTES.md b/RELEASE_NOTES.md
index 67975730e..65a3f5eea 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -1,5 +1,16 @@
# Release Notes
+## 1.1.2
+### Bugfixes
+- Fixed a bug where the `podman image list`, `podman image rm`, and `podman container list` had broken global storage options
+- Fixed a bug where the `--label` option to `podman create` and `podman run` was missing the `-l` alias
+- Fixed a bug where running Podman with the `--config` flag would not set an appropriate default value for `tmp_dir` ([#2408](https://github.com/containers/libpod/issues/2408))
+- Fixed a bug where the `podman logs` command with the `--timestamps` flag produced unreadable output ([#2500](https://github.com/containers/libpod/issues/2500))
+- Fixed a bug where the `podman cp` command would automatically extract `.tar` files copied into the container ([#2509](https://github.com/containers/libpod/issues/2509))
+
+### Misc
+- The `podman container stop` command is now usable with the Podman remote client
+
## 1.1.1
### Bugfixes
- Fixed a bug where `podman container restore` was erroneously available as `podman restore` ([#2191](https://github.com/containers/libpod/issues/2191))
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/lib.sh b/contrib/cirrus/lib.sh
index 8be696933..acd2447c0 100644
--- a/contrib/cirrus/lib.sh
+++ b/contrib/cirrus/lib.sh
@@ -300,21 +300,6 @@ EOF
fi
}
-# Runs in testing VM, not image building
-install_testing_dependencies() {
- echo "Installing ginkgo, gomega, and easyjson into \$GOPATH=$GOPATH"
- req_env_var "
- GOPATH $GOPATH
- GOSRC $GOSRC
- "
- cd "$GOSRC"
- ooe.sh go get -u github.com/onsi/ginkgo/ginkgo
- ooe.sh install -D -m 755 "$GOPATH"/bin/ginkgo /usr/bin/
- ooe.sh go get github.com/onsi/gomega/...
- ooe.sh go get -u github.com/mailru/easyjson/...
- sudo install -D -m 755 "$GOPATH"/bin/easyjson /usr/bin/
-}
-
install_packer_copied_files(){
# Install cni config, policy and registry config
sudo install -D -m 755 /tmp/libpod/cni/87-podman-bridge.conflist \
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/contrib/cirrus/setup_environment.sh b/contrib/cirrus/setup_environment.sh
index 77c20d9bd..c3276bb6f 100755
--- a/contrib/cirrus/setup_environment.sh
+++ b/contrib/cirrus/setup_environment.sh
@@ -78,10 +78,6 @@ then
cd "${GOSRC}/"
source "$SCRIPT_BASE/lib.sh"
-
- # Only testing-VMs need deps installed, not image-builder VM
- echo "$CIRRUS_TASK_NAME" | grep -q 'image' || \
- install_testing_dependencies # must exist in $GOPATH
fi
record_timestamp "env. setup end"
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/adapter/containers.go b/pkg/adapter/containers.go
index 4975bea9c..fcce9bb86 100644
--- a/pkg/adapter/containers.go
+++ b/pkg/adapter/containers.go
@@ -10,6 +10,7 @@ import (
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/pkg/adapter/shortcuts"
"github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
)
// GetLatestContainer gets the latest Container and wraps it in an adapter Container
@@ -46,9 +47,10 @@ func (r *LocalRuntime) LookupContainer(idOrName string) (*Container, error) {
// StopContainers stops container(s) based on CLI inputs.
// Returns list of successful id(s), map of failed id(s) + error, or error not from container
func (r *LocalRuntime) StopContainers(ctx context.Context, cli *cliconfig.StopValues) ([]string, map[string]error, error) {
- timeout := uint(0)
- if cli.Flags().Changed("timeout") {
- timeout = uint(cli.Timeout)
+ var timeout *uint
+ if cli.Flags().Changed("timeout") || cli.Flags().Changed("time") {
+ t := uint(cli.Timeout)
+ timeout = &t
}
var (
@@ -62,11 +64,18 @@ func (r *LocalRuntime) StopContainers(ctx context.Context, cli *cliconfig.StopVa
}
for _, c := range ctrs {
- err := c.StopWithTimeout(timeout)
- if err != nil && errors.Cause(err) != libpod.ErrCtrStopped {
- failures[c.ID()] = err
- } else {
+ if timeout == nil {
+ t := c.StopTimeout()
+ timeout = &t
+ logrus.Debugf("Set timeout to container %s default (%d)", c.ID(), *timeout)
+ }
+ if err := c.StopWithTimeout(*timeout); err == nil {
ok = append(ok, c.ID())
+ } else if errors.Cause(err) == libpod.ErrCtrStopped {
+ ok = append(ok, c.ID())
+ logrus.Debugf("Container %s is already stopped", c.ID())
+ } else {
+ failures[c.ID()] = err
}
}
return ok, failures, nil
diff --git a/pkg/logs/logs.go b/pkg/logs/logs.go
index b104c592b..7fb5c7ea8 100644
--- a/pkg/logs/logs.go
+++ b/pkg/logs/logs.go
@@ -35,7 +35,10 @@ import (
const (
// timeFormat is the time format used in the log.
- timeFormat = time.RFC3339Nano
+ // It is a modified version of RFC3339Nano that guarantees trailing
+ // zeroes are not trimmed, taken from
+ // https://github.com/golang/go/issues/19635
+ timeFormat = "2006-01-02T15:04:05.000000000Z07:00"
)
// LogStreamType is the type of the stream in CRI container log.
@@ -277,10 +280,11 @@ func readLog(reader *bufio.Reader, opts *LogOptions) []string {
// logWriter controls the writing into the stream based on the log options.
type logWriter struct {
- stdout io.Writer
- stderr io.Writer
- opts *LogOptions
- remain int64
+ stdout io.Writer
+ stderr io.Writer
+ opts *LogOptions
+ remain int64
+ doAppend bool
}
// errMaximumWrite is returned when all bytes have been written.
@@ -309,9 +313,15 @@ func (w *logWriter) write(msg *logMessage) error {
return nil
}
line := msg.log
- if w.opts.Timestamps {
+ if w.opts.Timestamps && !w.doAppend {
prefix := append([]byte(msg.timestamp.Format(timeFormat)), delimiter[0])
line = append(prefix, line...)
+ if len(line) > 0 && line[len(line)-1] != '\n' {
+ w.doAppend = true
+ }
+ }
+ if w.doAppend && len(line) > 0 && line[len(line)-1] == '\n' {
+ w.doAppend = false
}
// If the line is longer than the remaining bytes, cut it.
if int64(len(line)) > w.remain {
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 {
diff --git a/test/e2e/stop_test.go b/test/e2e/stop_test.go
index eb680d2a1..cd0d804ee 100644
--- a/test/e2e/stop_test.go
+++ b/test/e2e/stop_test.go
@@ -82,7 +82,7 @@ var _ = Describe("Podman stop", func() {
Expect(session3.ExitCode()).To(Equal(0))
})
- It("podman stop all containers", func() {
+ It("podman stop all containers -t", func() {
session := podmanTest.RunTopContainer("test1")
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
@@ -107,6 +107,32 @@ var _ = Describe("Podman stop", func() {
Expect(output).To(ContainSubstring(cid3))
})
+ It("podman stop container --time", func() {
+ session := podmanTest.RunTopContainer("test4")
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ cid1 := session.OutputToString()
+
+ session = podmanTest.Podman([]string{"stop", "--time", "1", "test4"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ output := session.OutputToString()
+ Expect(output).To(ContainSubstring(cid1))
+ })
+
+ It("podman stop container --timeout", func() {
+ session := podmanTest.RunTopContainer("test5")
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ cid1 := session.OutputToString()
+
+ session = podmanTest.Podman([]string{"stop", "--timeout", "1", "test5"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ output := session.OutputToString()
+ Expect(output).To(ContainSubstring(cid1))
+ })
+
It("podman stop latest containers", func() {
session := podmanTest.RunTopContainer("test1")
session.WaitWithDefaultTimeout()