summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOpenShift Merge Robot <openshift-merge-robot@users.noreply.github.com>2018-10-02 17:16:43 -0700
committerGitHub <noreply@github.com>2018-10-02 17:16:43 -0700
commitd5687946f6a0aa14a5326f26ca0ceca68588056f (patch)
tree888c74c05f061cda2f53829969634e31a0d41643
parentb63b1f9cb638db4bc3fdf69a50857b6d04efb6d7 (diff)
parent4f825f2e079c1cf3ec6c9fd2c5378ce2db18d4f0 (diff)
downloadpodman-d5687946f6a0aa14a5326f26ca0ceca68588056f.tar.gz
podman-d5687946f6a0aa14a5326f26ca0ceca68588056f.tar.bz2
podman-d5687946f6a0aa14a5326f26ca0ceca68588056f.zip
Merge pull request #1528 from baude/runlabel
Add container runlabel command
-rw-r--r--cmd/podman/container.go1
-rw-r--r--cmd/podman/runlabel.go188
-rw-r--r--cmd/podman/shared/funcs.go57
-rw-r--r--cmd/podman/shared/funcs_test.go89
-rw-r--r--commands.md1
-rw-r--r--completions/bash/podman30
-rw-r--r--docs/podman-container-runlabel.1.md102
-rw-r--r--libpod/image/image.go14
-rw-r--r--libpod/oci.go14
-rw-r--r--test/e2e/libpod_suite_test.go3
-rw-r--r--utils/utils.go5
11 files changed, 495 insertions, 9 deletions
diff --git a/cmd/podman/container.go b/cmd/podman/container.go
index b73fb7a94..82c1c824d 100644
--- a/cmd/podman/container.go
+++ b/cmd/podman/container.go
@@ -25,6 +25,7 @@ var (
restartCommand,
rmCommand,
runCommand,
+ runlabelCommand,
startCommand,
statsCommand,
stopCommand,
diff --git a/cmd/podman/runlabel.go b/cmd/podman/runlabel.go
new file mode 100644
index 000000000..c5dd98ee6
--- /dev/null
+++ b/cmd/podman/runlabel.go
@@ -0,0 +1,188 @@
+package main
+
+import (
+ "fmt"
+ "io"
+ "os"
+ "strings"
+
+ "github.com/containers/libpod/cmd/podman/libpodruntime"
+ "github.com/containers/libpod/cmd/podman/shared"
+ "github.com/containers/libpod/libpod/image"
+ "github.com/containers/libpod/utils"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+ "github.com/urfave/cli"
+)
+
+var (
+ runlabelFlags = []cli.Flag{
+ cli.StringFlag{
+ Name: "authfile",
+ Usage: "Path of the authentication file. Default is ${XDG_RUNTIME_DIR}/containers/auth.json",
+ },
+ cli.BoolFlag{
+ Name: "display",
+ Usage: "preview the command that `podman install` would execute",
+ },
+ cli.StringFlag{
+ Name: "cert-dir",
+ Usage: "`pathname` of a directory containing TLS certificates and keys",
+ },
+ cli.StringFlag{
+ Name: "creds",
+ Usage: "`credentials` (USERNAME:PASSWORD) to use for authenticating to a registry",
+ },
+ cli.StringFlag{
+ Name: "name",
+ Usage: "Assign a name to the container",
+ },
+ cli.StringFlag{
+ Name: "opt1",
+ Usage: "Optional parameter to pass for install",
+ Hidden: true,
+ },
+ cli.StringFlag{
+ Name: "opt2",
+ Usage: "Optional parameter to pass for install",
+ Hidden: true,
+ },
+ cli.StringFlag{
+ Name: "opt3",
+ Usage: "Optional parameter to pass for install",
+ Hidden: true,
+ },
+ cli.BoolFlag{
+ Name: "quiet, q",
+ Usage: "Suppress output information when installing images",
+ },
+ cli.BoolFlag{
+ Name: "pull, p",
+ Usage: "pull the image if it does not exist locally prior to executing the label contents",
+ },
+ cli.StringFlag{
+ Name: "signature-policy",
+ Usage: "`pathname` of signature policy file (not usually used)",
+ },
+ cli.BoolTFlag{
+ Name: "tls-verify",
+ Usage: "require HTTPS and verify certificates when contacting registries (default: true)",
+ },
+ }
+
+ runlabelDescription = `
+Executes a command as described by a container image label.
+`
+ runlabelCommand = cli.Command{
+ Name: "runlabel",
+ Usage: "Execute the command described by an image label",
+ Description: runlabelDescription,
+ Flags: runlabelFlags,
+ Action: runlabelCmd,
+ ArgsUsage: "",
+ OnUsageError: usageErrorHandler,
+ }
+)
+
+// installCmd gets the data from the command line and calls installImage
+// to copy an image from a registry to a local machine
+func runlabelCmd(c *cli.Context) error {
+ var (
+ imageName string
+ stdErr, stdOut io.Writer
+ stdIn io.Reader
+ newImage *image.Image
+ )
+
+ opts := make(map[string]string)
+ runtime, err := libpodruntime.GetRuntime(c)
+ if err != nil {
+ return errors.Wrapf(err, "could not get runtime")
+ }
+ defer runtime.Shutdown(false)
+
+ args := c.Args()
+ if len(args) == 0 {
+ logrus.Errorf("an image name must be specified")
+ return nil
+ }
+ if len(args) < 2 {
+ logrus.Errorf("the runlabel command requires at least 2 arguments")
+ return nil
+ }
+ if err := validateFlags(c, runlabelFlags); err != nil {
+ return err
+ }
+ if c.Bool("display") && c.Bool("quiet") {
+ return errors.Errorf("the display and quiet flags cannot be used together.")
+ }
+
+ pull := c.Bool("pull")
+ label := args[0]
+
+ runlabelImage := args[1]
+
+ if c.IsSet("opts1") {
+ opts["opts1"] = c.String("opts1")
+ }
+ if c.IsSet("opts2") {
+ opts["opts2"] = c.String("opts2")
+ }
+ if c.IsSet("opts3") {
+ opts["opts3"] = c.String("opts3")
+ }
+
+ ctx := getContext()
+ rtc := runtime.GetConfig()
+
+ stdErr = os.Stderr
+ stdOut = os.Stdout
+ stdIn = os.Stdin
+
+ if c.Bool("quiet") {
+ stdErr = nil
+ stdOut = nil
+ stdIn = nil
+ }
+
+ if pull {
+ newImage, err = runtime.ImageRuntime().New(ctx, runlabelImage, rtc.SignaturePolicyPath, "", stdOut, nil, image.SigningOptions{}, false, false)
+ } else {
+ newImage, err = runtime.ImageRuntime().NewFromLocal(runlabelImage)
+ }
+ if err != nil {
+ return errors.Wrapf(err, "unable to find image")
+ }
+
+ if len(newImage.Names()) < 1 {
+ imageName = newImage.ID()
+ } else {
+ imageName = newImage.Names()[0]
+ }
+
+ runLabel, err := newImage.GetLabel(ctx, label)
+ if err != nil {
+ return err
+ }
+
+ // If no label to execute, we return
+ if runLabel == "" {
+ return nil
+ }
+
+ // The user provided extra arguments that need to be tacked onto the label's command
+ if len(args) > 2 {
+ runLabel = fmt.Sprintf("%s %s", runLabel, strings.Join(args[2:], " "))
+ }
+
+ cmd := shared.GenerateCommand(runLabel, imageName, c.String("name"))
+ env := shared.GenerateRunEnvironment(c.String("name"), imageName, opts)
+
+ if !c.Bool("quiet") {
+ fmt.Printf("Command: %s\n", strings.Join(cmd, " "))
+ if c.Bool("display") {
+ return nil
+ }
+ }
+ return utils.ExecCmdWithStdStreams(stdIn, stdOut, stdErr, env, cmd[0], cmd[1:]...)
+}
diff --git a/cmd/podman/shared/funcs.go b/cmd/podman/shared/funcs.go
new file mode 100644
index 000000000..5c401634c
--- /dev/null
+++ b/cmd/podman/shared/funcs.go
@@ -0,0 +1,57 @@
+package shared
+
+import (
+ "fmt"
+ "os"
+ "strings"
+)
+
+// GenerateCommand takes a label (string) and converts it to an executable command
+func GenerateCommand(command, imageName, name string) []string {
+ var (
+ newCommand []string
+ )
+ if name == "" {
+ name = imageName
+ }
+ cmd := strings.Split(command, " ")
+ // Replace the first position of cmd with podman whether
+ // it is docker, /usr/bin/docker, or podman
+ newCommand = append(newCommand, "podman")
+ for _, arg := range cmd[1:] {
+ var newArg string
+ switch arg {
+ case "IMAGE":
+ newArg = imageName
+ case "IMAGE=IMAGE":
+ newArg = fmt.Sprintf("IMAGE=%s", imageName)
+ case "NAME":
+ newArg = name
+ case "NAME=NAME":
+ newArg = fmt.Sprintf("NAME=%s", name)
+ default:
+ newArg = arg
+ }
+ newCommand = append(newCommand, newArg)
+ }
+ return newCommand
+}
+
+// GenerateRunEnvironment merges the current environment variables with optional
+// environment variables provided by the user
+func GenerateRunEnvironment(name, imageName string, opts map[string]string) []string {
+ newEnv := os.Environ()
+ newEnv = append(newEnv, fmt.Sprintf("NAME=%s", name))
+ newEnv = append(newEnv, fmt.Sprintf("IMAGE=%s", imageName))
+
+ if opts["opt1"] != "" {
+ newEnv = append(newEnv, fmt.Sprintf("OPT1=%s", opts["opt1"]))
+ }
+ if opts["opt2"] != "" {
+ newEnv = append(newEnv, fmt.Sprintf("OPT2=%s", opts["opt2"]))
+ }
+ if opts["opt3"] != "" {
+ newEnv = append(newEnv, fmt.Sprintf("OPT3=%s", opts["opt3"]))
+ }
+ return newEnv
+}
diff --git a/cmd/podman/shared/funcs_test.go b/cmd/podman/shared/funcs_test.go
new file mode 100644
index 000000000..3d0ac005f
--- /dev/null
+++ b/cmd/podman/shared/funcs_test.go
@@ -0,0 +1,89 @@
+package shared
+
+import (
+ "strings"
+ "testing"
+
+ "github.com/containers/libpod/pkg/util"
+ "github.com/stretchr/testify/assert"
+)
+
+var (
+ name = "foo"
+ imageName = "bar"
+)
+
+func TestGenerateCommand(t *testing.T) {
+ inputCommand := "docker run -it --name NAME -e NAME=NAME -e IMAGE=IMAGE IMAGE echo install"
+ correctCommand := "podman run -it --name bar -e NAME=bar -e IMAGE=foo foo echo install"
+ newCommand := GenerateCommand(inputCommand, "foo", "bar")
+ assert.Equal(t, correctCommand, strings.Join(newCommand, " "))
+}
+
+func TestGenerateCommandPath(t *testing.T) {
+ inputCommand := "/usr/bin/docker run -it --name NAME -e NAME=NAME -e IMAGE=IMAGE IMAGE echo install"
+ correctCommand := "podman run -it --name bar -e NAME=bar -e IMAGE=foo foo echo install"
+ newCommand := GenerateCommand(inputCommand, "foo", "bar")
+ assert.Equal(t, correctCommand, strings.Join(newCommand, " "))
+}
+
+func TestGenerateCommandNoSetName(t *testing.T) {
+ inputCommand := "docker run -it --name NAME -e NAME=NAME -e IMAGE=IMAGE IMAGE echo install"
+ correctCommand := "podman run -it --name foo -e NAME=foo -e IMAGE=foo foo echo install"
+ newCommand := GenerateCommand(inputCommand, "foo", "")
+ assert.Equal(t, correctCommand, strings.Join(newCommand, " "))
+}
+
+func TestGenerateCommandNoName(t *testing.T) {
+ inputCommand := "docker run -it -e IMAGE=IMAGE IMAGE echo install"
+ correctCommand := "podman run -it -e IMAGE=foo foo echo install"
+ newCommand := GenerateCommand(inputCommand, "foo", "")
+ assert.Equal(t, correctCommand, strings.Join(newCommand, " "))
+}
+
+func TestGenerateCommandAlreadyPodman(t *testing.T) {
+ inputCommand := "podman run -it --name NAME -e NAME=NAME -e IMAGE=IMAGE IMAGE echo install"
+ correctCommand := "podman run -it --name bar -e NAME=bar -e IMAGE=foo foo echo install"
+ newCommand := GenerateCommand(inputCommand, "foo", "bar")
+ assert.Equal(t, correctCommand, strings.Join(newCommand, " "))
+}
+
+func TestGenerateRunEnvironment(t *testing.T) {
+ opts := make(map[string]string)
+ opts["opt1"] = "one"
+ opts["opt2"] = "two"
+ opts["opt3"] = "three"
+ envs := GenerateRunEnvironment(name, imageName, opts)
+ assert.True(t, util.StringInSlice("OPT1=one", envs))
+ assert.True(t, util.StringInSlice("OPT2=two", envs))
+ assert.True(t, util.StringInSlice("OPT3=three", envs))
+}
+
+func TestGenerateRunEnvironmentNoOpts(t *testing.T) {
+ opts := make(map[string]string)
+ envs := GenerateRunEnvironment(name, imageName, opts)
+ assert.False(t, util.StringInSlice("OPT1=", envs))
+ assert.False(t, util.StringInSlice("OPT2=", envs))
+ assert.False(t, util.StringInSlice("OPT3=", envs))
+}
+
+func TestGenerateRunEnvironmentSingleOpt(t *testing.T) {
+ opts := make(map[string]string)
+ opts["opt1"] = "one"
+ envs := GenerateRunEnvironment(name, imageName, opts)
+ assert.True(t, util.StringInSlice("OPT1=one", envs))
+ assert.False(t, util.StringInSlice("OPT2=", envs))
+ assert.False(t, util.StringInSlice("OPT3=", envs))
+}
+
+func TestGenerateRunEnvironmentName(t *testing.T) {
+ opts := make(map[string]string)
+ envs := GenerateRunEnvironment(name, imageName, opts)
+ assert.True(t, util.StringInSlice("NAME=foo", envs))
+}
+
+func TestGenerateRunEnvironmentImage(t *testing.T) {
+ opts := make(map[string]string)
+ envs := GenerateRunEnvironment(name, imageName, opts)
+ assert.True(t, util.StringInSlice("IMAGE=bar", envs))
+}
diff --git a/commands.md b/commands.md
index a0a97f9de..c84938e64 100644
--- a/commands.md
+++ b/commands.md
@@ -50,6 +50,7 @@
| [podman-rm(1)](/docs/podman-rm.1.md) | Removes one or more containers |[![...](/docs/play.png)](https://asciinema.org/a/7EMk22WrfGtKWmgHJX9Nze1Qp)|
| [podman-rmi(1)](/docs/podman-rmi.1.md) | Removes one or more images |[![...](/docs/play.png)](https://asciinema.org/a/133799)|
| [podman-run(1)](/docs/podman-run.1.md) | Run a command in a container ||
+| [podman-runlabel(1)](/docs/podman-container-runlabel.1.md) | Executes the command of a container image's label ||
| [podman-save(1)](/docs/podman-save.1.md) | Saves an image to an archive |[![...](/docs/play.png)](https://asciinema.org/a/kp8kOaexEhEa20P1KLZ3L5X4g)|
| [podman-search(1)](/docs/podman-search.1.md) | Search a registry for an image ||
| [podman-start(1)](/docs/podman-start.1.md) | Starts one or more containers
diff --git a/completions/bash/podman b/completions/bash/podman
index bdd5a34e2..f63bf4469 100644
--- a/completions/bash/podman
+++ b/completions/bash/podman
@@ -2086,6 +2086,36 @@ _podman_logout() {
_complete_ "$options_with_args" "$boolean_options"
}
+_podman_container_runlabel() {
+ local options_with_args="
+ --authfile
+ --cert-dir
+ --creds
+ --name
+ --signature-policy
+ "
+
+ local boolean_options="
+ --display
+ --help
+ -h
+ -p
+ --pull
+ -q
+ --quiet
+ --tls-verify
+ "
+
+ case "$cur" in
+ -*)
+ COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur"))
+ ;;
+ *)
+ __podman_complete_images --id
+ ;;
+ esac
+}
+
_podman_pod_create() {
local options_with_args="
--cgroup-parent
diff --git a/docs/podman-container-runlabel.1.md b/docs/podman-container-runlabel.1.md
new file mode 100644
index 000000000..889a5fb03
--- /dev/null
+++ b/docs/podman-container-runlabel.1.md
@@ -0,0 +1,102 @@
+% PODMAN(1) Podman Man Pages
+% Brent Baude
+% September 2018
+# NAME
+podman-container-runlabel - Execute Image Label Method
+
+# SYNOPSIS
+**podman container runlabel**
+[**-h**|**--help**]
+[**--display**]
+[**-n**][**--name**[=*NAME*]]
+[**-p**][[**--pull**]]
+[**--rootfs**=*ROOTFS*]
+[**--set**=*NAME*=*VALUE*]
+[**--storage**]
+LABEL IMAGE [ARG...]
+
+# DESCRIPTION
+**podman container runlabel** reads the provided `LABEL` field in the container
+IMAGE and executes the provided value for the label as a command. If this field does not
+exist, `podman container runlabel` will just exit.
+
+If the container image has a LABEL INSTALL instruction like the following:
+
+`LABEL INSTALL /usr/bin/podman run -t -i --rm \${OPT1} --privileged -v /:/host --net=host --ipc=host --pid=host -e HOST=/host -e NAME=\${NAME} -e IMAGE=\${IMAGE} -e CONFDIR=\/etc/${NAME} -e LOGDIR=/var/log/\${NAME} -e DATADIR=/var/lib/\${NAME} \${IMAGE} \${OPT2} /bin/install.sh \${OPT3}`
+
+`podman container runlabel` will set the following environment variables for use in the command:
+
+Note: Podman will always ensure that `podman` is the first argument of the command being executed.
+
+**NAME**
+The name specified via the command. NAME will be replaced with IMAGE if it is not specified.
+
+**IMAGE**
+Image name specified via the command.
+
+**SUDO_UID**
+The `SUDO_UID` environment variable. This is useful with the podman
+`-u` option for user space tools. If the environment variable is
+not available, the value of `/proc/self/loginuid` is used.
+
+**SUDO_GID**
+The `SUDO_GID` environment variable. This is useful with the podman
+`-u` option for user space tools. If the environment variable is
+not available, the default GID of the value for `SUDO_UID` is used.
+If this value is not available, the value of `/proc/self/loginuid`
+is used.
+
+Any additional arguments will be appended to the command.
+
+# OPTIONS:
+**--authfile**
+
+Path of the authentication file. Default is ${XDG_RUNTIME\_DIR}/containers/auth.json, which is set using `podman login`.
+If the authorization state is not found there, $HOME/.docker/config.json is checked, which is set using `docker login`.
+
+**--display**
+
+Display the label's value of the image having populated its environment variables.
+The runlabel command will not execute if --display is specified.
+
+**--cert-dir** *path*
+
+Use certificates at *path* (\*.crt, \*.cert, \*.key) to connect to the registry.
+Default certificates directory is _/etc/containers/certs.d_.
+
+**--creds**
+
+The [username[:password]] to use to authenticate with the registry if required.
+If one or both values are not supplied, a command line prompt will appear and the
+value can be entered. The password is entered without echo.
+
+**-h** **--help**
+Print usage statement
+
+**-n** **--name**=""
+ Use this name for creating content for the container. NAME will default to the IMAGENAME if it is not specified.
+
+**p** **--pull**
+ Pull the image if it cannot be found in local storage.
+
+**--quiet, -q**
+
+Suppress output information when pulling images
+
+**--signature-policy="PATHNAME"**
+
+Pathname of a signature policy file to use. It is not recommended that this
+option be used, as the default behavior of using the system-wide default policy
+(frequently */etc/containers/policy.json*) is most often preferred
+
+**--tls-verify**
+
+Require HTTPS and verify certificates when contacting registries (default: true). If explicitly set to true,
+then tls verification will be used, If set to false then tls verification will not be used. If not specified
+tls verification will be used unless the target registry is listed as an insecure registry in registries.conf
+
+## SEE ALSO
+podman(1)
+
+# HISTORY
+September 2018, Originally compiled by Brent Baude (bbaude at redhat dot com)
diff --git a/libpod/image/image.go b/libpod/image/image.go
index 197a83dc1..f39b1d78d 100644
--- a/libpod/image/image.go
+++ b/libpod/image/image.go
@@ -744,6 +744,20 @@ func (i *Image) Labels(ctx context.Context) (map[string]string, error) {
return imgInspect.Labels, nil
}
+// GetLabel Returns a case-insensitive match of a given label
+func (i *Image) GetLabel(ctx context.Context, label string) (string, error) {
+ imageLabels, err := i.Labels(ctx)
+ if err != nil {
+ return "", err
+ }
+ for k, v := range imageLabels {
+ if strings.ToLower(k) == strings.ToLower(label) {
+ return v, nil
+ }
+ }
+ return "", nil
+}
+
// Annotations returns the annotations of an image
func (i *Image) Annotations(ctx context.Context) (map[string]string, error) {
manifest, manifestType, err := i.Manifest(ctx)
diff --git a/libpod/oci.go b/libpod/oci.go
index 3838394cb..17f0630c4 100644
--- a/libpod/oci.go
+++ b/libpod/oci.go
@@ -535,7 +535,7 @@ func (r *OCIRuntime) updateContainerStatus(ctr *Container) error {
// Sets time the container was started, but does not save it.
func (r *OCIRuntime) startContainer(ctr *Container) error {
// TODO: streams should probably *not* be our STDIN/OUT/ERR - redirect to buffers?
- if err := utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, r.path, "start", ctr.ID()); err != nil {
+ if err := utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, nil, r.path, "start", ctr.ID()); err != nil {
return err
}
@@ -547,7 +547,7 @@ func (r *OCIRuntime) startContainer(ctr *Container) error {
// killContainer sends the given signal to the given container
func (r *OCIRuntime) killContainer(ctr *Container, signal uint) error {
logrus.Debugf("Sending signal %d to container %s", signal, ctr.ID())
- if err := utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, r.path, "kill", ctr.ID(), fmt.Sprintf("%d", signal)); err != nil {
+ if err := utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, nil, r.path, "kill", ctr.ID(), fmt.Sprintf("%d", signal)); err != nil {
return errors.Wrapf(err, "error sending signal to container %s", ctr.ID())
}
@@ -605,7 +605,7 @@ func (r *OCIRuntime) stopContainer(ctr *Container, timeout uint) error {
args = []string{"kill", "--all", ctr.ID(), "KILL"}
}
- if err := utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, r.path, args...); err != nil {
+ if err := utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, nil, r.path, args...); err != nil {
// Again, check if the container is gone. If it is, exit cleanly.
err := unix.Kill(ctr.state.PID, 0)
if err == unix.ESRCH {
@@ -631,12 +631,12 @@ func (r *OCIRuntime) deleteContainer(ctr *Container) error {
// pauseContainer pauses the given container
func (r *OCIRuntime) pauseContainer(ctr *Container) error {
- return utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, r.path, "pause", ctr.ID())
+ return utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, nil, r.path, "pause", ctr.ID())
}
// unpauseContainer unpauses the given container
func (r *OCIRuntime) unpauseContainer(ctr *Container) error {
- return utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, r.path, "resume", ctr.ID())
+ return utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, nil, r.path, "resume", ctr.ID())
}
// execContainer executes a command in a running container
@@ -740,7 +740,7 @@ func (r *OCIRuntime) execStopContainer(ctr *Container, timeout uint) error {
// Stop using SIGTERM by default
// Use SIGSTOP after a timeout
logrus.Debugf("Killing all processes in container %s with SIGTERM", ctr.ID())
- if err := utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, r.path, "kill", "--all", ctr.ID(), "TERM"); err != nil {
+ if err := utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, nil, r.path, "kill", "--all", ctr.ID(), "TERM"); err != nil {
return errors.Wrapf(err, "error sending SIGTERM to container %s processes", ctr.ID())
}
@@ -755,7 +755,7 @@ func (r *OCIRuntime) execStopContainer(ctr *Container, timeout uint) error {
// Send SIGKILL
logrus.Debugf("Killing all processes in container %s with SIGKILL", ctr.ID())
- if err := utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, r.path, "kill", "--all", ctr.ID(), "KILL"); err != nil {
+ if err := utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, nil, r.path, "kill", "--all", ctr.ID(), "KILL"); err != nil {
return errors.Wrapf(err, "error sending SIGKILL to container %s processes", ctr.ID())
}
diff --git a/test/e2e/libpod_suite_test.go b/test/e2e/libpod_suite_test.go
index a1e9ba57a..485b14ba5 100644
--- a/test/e2e/libpod_suite_test.go
+++ b/test/e2e/libpod_suite_test.go
@@ -31,7 +31,7 @@ var (
CGROUP_MANAGER = "systemd"
STORAGE_OPTIONS = "--storage-driver vfs"
ARTIFACT_DIR = "/tmp/.artifacts"
- CACHE_IMAGES = []string{ALPINE, BB, fedoraMinimal, nginx, redis, registry, infra}
+ CACHE_IMAGES = []string{ALPINE, BB, fedoraMinimal, nginx, redis, registry, infra, labels}
RESTORE_IMAGES = []string{ALPINE, BB}
ALPINE = "docker.io/library/alpine:latest"
BB = "docker.io/library/busybox:latest"
@@ -41,6 +41,7 @@ var (
redis = "docker.io/library/redis:alpine"
registry = "docker.io/library/registry:2"
infra = "k8s.gcr.io/pause:3.1"
+ labels = "quay.io/baude/alpine_labels:latest"
defaultWaitTimeout = 90
)
diff --git a/utils/utils.go b/utils/utils.go
index 9b7cebfea..c7c5ab5cf 100644
--- a/utils/utils.go
+++ b/utils/utils.go
@@ -29,11 +29,14 @@ func ExecCmd(name string, args ...string) (string, error) {
}
// ExecCmdWithStdStreams execute a command with the specified standard streams.
-func ExecCmdWithStdStreams(stdin io.Reader, stdout, stderr io.Writer, name string, args ...string) error {
+func ExecCmdWithStdStreams(stdin io.Reader, stdout, stderr io.Writer, env []string, name string, args ...string) error {
cmd := exec.Command(name, args...)
cmd.Stdin = stdin
cmd.Stdout = stdout
cmd.Stderr = stderr
+ if env != nil {
+ cmd.Env = env
+ }
err := cmd.Run()
if err != nil {