aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--cmd/podman/attach.go7
-rw-r--r--cmd/podman/build.go4
-rw-r--r--cmd/podman/checkpoint.go4
-rw-r--r--cmd/podman/create.go3
-rw-r--r--cmd/podman/diff.go4
-rw-r--r--cmd/podman/exec.go4
-rw-r--r--cmd/podman/export.go3
-rw-r--r--cmd/podman/import.go4
-rw-r--r--cmd/podman/kill.go4
-rw-r--r--cmd/podman/login.go2
-rw-r--r--cmd/podman/logout.go4
-rw-r--r--cmd/podman/pause.go4
-rw-r--r--cmd/podman/play_kube.go5
-rw-r--r--cmd/podman/pod_start.go4
-rw-r--r--cmd/podman/pod_stats.go4
-rw-r--r--cmd/podman/pod_stop.go4
-rw-r--r--cmd/podman/pod_top.go4
-rw-r--r--cmd/podman/ps.go4
-rw-r--r--cmd/podman/pull.go4
-rw-r--r--cmd/podman/push.go4
-rw-r--r--cmd/podman/rm.go4
-rw-r--r--cmd/podman/rmi.go4
-rw-r--r--cmd/podman/run.go11
-rw-r--r--cmd/podman/sign.go3
-rw-r--r--cmd/podman/start.go38
-rw-r--r--cmd/podman/stop.go4
-rw-r--r--cmd/podman/trust_set_show.go2
-rw-r--r--cmd/podman/umount.go4
-rw-r--r--cmd/podman/unpause.go3
-rw-r--r--cmd/podman/utils.go4
-rw-r--r--cmd/podman/volume_create.go4
-rw-r--r--cmd/podman/volume_inspect.go4
-rw-r--r--contrib/cirrus/packer/Makefile8
-rw-r--r--contrib/perftest/main.go2
-rw-r--r--docs/podman-exec.1.md8
-rw-r--r--docs/podman-pod-create.1.md4
-rw-r--r--docs/podman-run.1.md1
-rw-r--r--docs/podman-start.1.md7
-rw-r--r--docs/podman-stop.1.md6
-rw-r--r--libpod/container_api.go167
-rw-r--r--libpod/container_graph.go97
-rw-r--r--libpod/container_internal.go143
-rw-r--r--libpod/pod_internal.go96
-rw-r--r--libpod/runtime_pod_linux.go9
-rw-r--r--pkg/varlinkapi/containers.go2
-rw-r--r--test/e2e/e2e.coverprofile11
-rw-r--r--test/e2e/pod_infra_container_test.go51
-rw-r--r--test/trust_set_test.json8
49 files changed, 481 insertions, 305 deletions
diff --git a/.gitignore b/.gitignore
index c35cd3383..020621558 100644
--- a/.gitignore
+++ b/.gitignore
@@ -17,3 +17,4 @@ __pycache__
/cmd/podman/varlink/ioprojectatomicpodman.go
/cmd/podman/varlink/iopodman.go
.gopathok
+test/e2e/e2e.coverprofile
diff --git a/cmd/podman/attach.go b/cmd/podman/attach.go
index ed175bdf4..b70ff649c 100644
--- a/cmd/podman/attach.go
+++ b/cmd/podman/attach.go
@@ -22,7 +22,9 @@ var (
attachCommand.GlobalFlags = MainGlobalOpts
return attachCmd(&attachCommand)
},
- Example: "",
+ Example: `podman attach ctrID
+ podman attach 1234
+ podman attach --no-stdin foobar`,
}
)
@@ -74,7 +76,8 @@ func attachCmd(c *cliconfig.AttachValues) error {
inputStream = nil
}
- if err := startAttachCtr(ctr, os.Stdout, os.Stderr, inputStream, c.DetachKeys, c.SigProxy, false); err != nil && errors.Cause(err) != libpod.ErrDetach {
+ // If the container is in a pod, also set to recursively start dependencies
+ if err := startAttachCtr(ctr, os.Stdout, os.Stderr, inputStream, c.DetachKeys, c.SigProxy, false, ctr.PodID() != ""); err != nil && errors.Cause(err) != libpod.ErrDetach {
return errors.Wrapf(err, "error attaching to container %s", ctr.ID())
}
diff --git a/cmd/podman/build.go b/cmd/podman/build.go
index 30a734377..bb252f171 100644
--- a/cmd/podman/build.go
+++ b/cmd/podman/build.go
@@ -40,7 +40,9 @@ var (
buildCommand.NameSpaceResults = &namespaceValues
return buildCmd(&buildCommand)
},
- Example: "CONTEXT-DIRECTORY | URL",
+ Example: `podman build .
+ podman build --cert-dir ~/auth --creds=username:password -t imageName -f Dockerfile.simple .
+ podman build --layers --force-rm --tag imageName .`,
}
)
diff --git a/cmd/podman/checkpoint.go b/cmd/podman/checkpoint.go
index aa4034ccd..3484e8957 100644
--- a/cmd/podman/checkpoint.go
+++ b/cmd/podman/checkpoint.go
@@ -29,7 +29,9 @@ var (
checkpointCommand.GlobalFlags = MainGlobalOpts
return checkpointCmd(&checkpointCommand)
},
- Example: "CONTAINER-NAME [CONTAINER-NAME ...]",
+ Example: `podman checkpoint --keep ctrID
+ podman checkpoint --all
+ podman checkpoint --leave-running --latest`,
}
)
diff --git a/cmd/podman/create.go b/cmd/podman/create.go
index 7bfb070c7..e7efe7502 100644
--- a/cmd/podman/create.go
+++ b/cmd/podman/create.go
@@ -399,9 +399,6 @@ func parseCreateOpts(ctx context.Context, c *cliconfig.PodmanCommand, runtime *l
tty := c.Bool("tty")
- if c.Bool("detach") && c.Bool("rm") {
- return nil, errors.Errorf("--rm and --detach cannot be specified together")
- }
if c.Flag("cpu-period").Changed && c.Flag("cpus").Changed {
return nil, errors.Errorf("--cpu-period and --cpus cannot be set together")
}
diff --git a/cmd/podman/diff.go b/cmd/podman/diff.go
index 7d4cc1b58..e2d258ad4 100644
--- a/cmd/podman/diff.go
+++ b/cmd/podman/diff.go
@@ -46,7 +46,9 @@ var (
diffCommand.GlobalFlags = MainGlobalOpts
return diffCmd(&diffCommand)
},
- Example: "ID-NAME",
+ Example: `podman diff imageID
+ podman diff ctrID
+ podman diff --format json redis:alpine`,
}
)
diff --git a/cmd/podman/exec.go b/cmd/podman/exec.go
index 74808768e..9599be528 100644
--- a/cmd/podman/exec.go
+++ b/cmd/podman/exec.go
@@ -29,7 +29,9 @@ var (
execCommand.GlobalFlags = MainGlobalOpts
return execCmd(&execCommand)
},
- Example: "CONTAINER-NAME",
+ Example: `podman exec -it ctrID ls
+ podman exec -it -w /tmp myCtr pwd
+ podman exec --user root ctrID ls`,
}
)
diff --git a/cmd/podman/export.go b/cmd/podman/export.go
index 2ce8186a1..a593a4753 100644
--- a/cmd/podman/export.go
+++ b/cmd/podman/export.go
@@ -25,7 +25,8 @@ var (
exportCommand.GlobalFlags = MainGlobalOpts
return exportCmd(&exportCommand)
},
- Example: "CONTAINER",
+ Example: `podman export ctrID > myCtr.tar
+ podman export --output="myCtr.tar" ctrID`,
}
)
diff --git a/cmd/podman/import.go b/cmd/podman/import.go
index 32f79757b..053408ff3 100644
--- a/cmd/podman/import.go
+++ b/cmd/podman/import.go
@@ -25,7 +25,9 @@ var (
importCommand.GlobalFlags = MainGlobalOpts
return importCmd(&importCommand)
},
- Example: "TARBALL [REFERENCE]",
+ Example: `podman import http://example.com/ctr.tar url-image
+ cat ctr.tar | podman -q import --message "importing the ctr.tar tarball" - image-imported
+ cat ctr.tar | podman import -`,
}
)
diff --git a/cmd/podman/kill.go b/cmd/podman/kill.go
index d922cf721..1be4fa959 100644
--- a/cmd/podman/kill.go
+++ b/cmd/podman/kill.go
@@ -28,7 +28,9 @@ var (
killCommand.GlobalFlags = MainGlobalOpts
return killCmd(&killCommand)
},
- Example: "CONTAINER-NAME [CONTAINER-NAME ...]",
+ Example: `podman kill mywebserver
+ podman kill 860a4b23
+ podman kill --signal TERM ctrID`,
}
)
diff --git a/cmd/podman/login.go b/cmd/podman/login.go
index 3eacab54a..b02a4b3f9 100644
--- a/cmd/podman/login.go
+++ b/cmd/podman/login.go
@@ -112,7 +112,7 @@ func loginCmd(c *cliconfig.LoginValues) error {
}
// If no username and no password is specified, try to use existing ones.
- if c.Username == "" && password == "" {
+ if c.Username == "" && password == "" && userFromAuthFile != "" && passFromAuthFile != "" {
fmt.Println("Authenticating with existing credentials...")
if err := docker.CheckAuth(ctx, sc, userFromAuthFile, passFromAuthFile, server); err == nil {
fmt.Println("Existing credentials are valid. Already logged in to", server)
diff --git a/cmd/podman/logout.go b/cmd/podman/logout.go
index 5fecf814e..4108887f0 100644
--- a/cmd/podman/logout.go
+++ b/cmd/podman/logout.go
@@ -22,7 +22,9 @@ var (
logoutCommand.GlobalFlags = MainGlobalOpts
return logoutCmd(&logoutCommand)
},
- Example: "REGISTRY",
+ Example: `podman logout docker.io
+ podman logout --authfile authdir/myauths.json docker.io
+ podman logout --all`,
}
)
diff --git a/cmd/podman/pause.go b/cmd/podman/pause.go
index a840cbe49..94bb0edfe 100644
--- a/cmd/podman/pause.go
+++ b/cmd/podman/pause.go
@@ -28,7 +28,9 @@ var (
pauseCommand.GlobalFlags = MainGlobalOpts
return pauseCmd(&pauseCommand)
},
- Example: "CONTAINER-NAME [CONTAINER-NAME ...]",
+ Example: `podman pause mywebserver
+ podman pause 860a4b23
+ podman stop -a`,
}
)
diff --git a/cmd/podman/play_kube.go b/cmd/podman/play_kube.go
index 4ecd30cd4..9fc06dde9 100644
--- a/cmd/podman/play_kube.go
+++ b/cmd/podman/play_kube.go
@@ -37,7 +37,8 @@ var (
playKubeCommand.GlobalFlags = MainGlobalOpts
return playKubeYAMLCmd(&playKubeCommand)
},
- Example: "Kubernetes YAML file",
+ Example: `podman play kube demo.yml
+ podman play kube --cert-dir /mycertsdir --tls-verify=true --quiet myWebPod`,
}
)
@@ -154,7 +155,7 @@ func playKubeYAMLCmd(c *cliconfig.KubePlayValues) error {
// start the containers
for _, ctr := range containers {
- if err := ctr.Start(ctx); err != nil {
+ if err := ctr.Start(ctx, false); err != nil {
// Making this a hard failure here to avoid a mess
// the other containers are in created status
return err
diff --git a/cmd/podman/pod_start.go b/cmd/podman/pod_start.go
index 829fe2107..d093c51cf 100644
--- a/cmd/podman/pod_start.go
+++ b/cmd/podman/pod_start.go
@@ -26,7 +26,9 @@ var (
podStartCommand.GlobalFlags = MainGlobalOpts
return podStartCmd(&podStartCommand)
},
- Example: "POD-NAME [POD-NAME ...]",
+ Example: `podman pod start podID
+ podman pod start --latest
+ podman pod start --all`,
}
)
diff --git a/cmd/podman/pod_stats.go b/cmd/podman/pod_stats.go
index 7afab6be9..b1779532f 100644
--- a/cmd/podman/pod_stats.go
+++ b/cmd/podman/pod_stats.go
@@ -32,7 +32,9 @@ var (
podStatsCommand.GlobalFlags = MainGlobalOpts
return podStatsCmd(&podStatsCommand)
},
- Example: "[POD_NAME_OR_ID]",
+ Example: `podman stats -a --no-stream
+ podman stats --no-reset ctrID
+ podman stats --no-stream --format "table {{.ID}} {{.Name}} {{.MemUsage}}" ctrID`,
}
)
diff --git a/cmd/podman/pod_stop.go b/cmd/podman/pod_stop.go
index 80082045d..a9237347e 100644
--- a/cmd/podman/pod_stop.go
+++ b/cmd/podman/pod_stop.go
@@ -27,7 +27,9 @@ var (
podStopCommand.GlobalFlags = MainGlobalOpts
return podStopCmd(&podStopCommand)
},
- Example: "POD-NAME [POD-NAME ...]",
+ Example: `podman pod stop mywebserverpod
+ podman pod stop --latest
+ podman pod stop --timeout 0 490eb 3557fb`,
}
)
diff --git a/cmd/podman/pod_top.go b/cmd/podman/pod_top.go
index 411c782bd..790118496 100644
--- a/cmd/podman/pod_top.go
+++ b/cmd/podman/pod_top.go
@@ -33,7 +33,9 @@ the latest pod.
podTopCommand.GlobalFlags = MainGlobalOpts
return podTopCmd(&podTopCommand)
},
- Example: "POD-NAME [format descriptors]",
+ Example: `podman top ctrID
+ podman top --latest
+ podman top --latest pid seccomp args %C`,
}
)
diff --git a/cmd/podman/ps.go b/cmd/podman/ps.go
index 949f78a34..482e423b7 100644
--- a/cmd/podman/ps.go
+++ b/cmd/podman/ps.go
@@ -166,7 +166,9 @@ var (
psCommand.GlobalFlags = MainGlobalOpts
return psCmd(&psCommand)
},
- Example: "",
+ Example: `podman ps -a
+ podman ps -a --format "{{.ID}} {{.Image}} {{.Labels}} {{.Mounts}}"
+ podman ps --size --sort names`,
}
)
diff --git a/cmd/podman/pull.go b/cmd/podman/pull.go
index 6e060d6f5..859228cbd 100644
--- a/cmd/podman/pull.go
+++ b/cmd/podman/pull.go
@@ -36,7 +36,9 @@ specified, the image with the 'latest' tag (if it exists) is pulled
pullCommand.GlobalFlags = MainGlobalOpts
return pullCmd(&pullCommand)
},
- Example: "",
+ Example: `podman pull imageName
+ podman pull --cert-dir image/certs --authfile temp-auths/myauths.json docker://docker.io/myrepo/finaltest
+ podman pull fedora:latest`,
}
)
diff --git a/cmd/podman/push.go b/cmd/podman/push.go
index bbe8a4027..881d8cebc 100644
--- a/cmd/podman/push.go
+++ b/cmd/podman/push.go
@@ -34,7 +34,9 @@ var (
pushCommand.GlobalFlags = MainGlobalOpts
return pushCmd(&pushCommand)
},
- Example: "IMAGE DESTINATION",
+ Example: `podman push imageID docker://registry.example.com/repository:tag
+ podman push imageID oci-archive:/path/to/layout:image:tag
+ podman push --authfile temp-auths/myauths.json alpine docker://docker.io/myrepo/alpine`,
}
)
diff --git a/cmd/podman/rm.go b/cmd/podman/rm.go
index d170e5357..2e5fe1dc0 100644
--- a/cmd/podman/rm.go
+++ b/cmd/podman/rm.go
@@ -28,7 +28,9 @@ Running containers will not be removed without the -f option.
rmCommand.GlobalFlags = MainGlobalOpts
return rmCmd(&rmCommand)
},
- Example: "",
+ Example: `podman rm imageID
+ podman rm mywebserver myflaskserver 860a4b23
+ podman rm --force --all`,
}
)
diff --git a/cmd/podman/rmi.go b/cmd/podman/rmi.go
index c5bd1e190..fb27772f5 100644
--- a/cmd/podman/rmi.go
+++ b/cmd/podman/rmi.go
@@ -23,7 +23,9 @@ var (
rmiCommand.GlobalFlags = MainGlobalOpts
return rmiCmd(&rmiCommand)
},
- Example: "IMAGE-NAME-OR-ID [...]",
+ Example: `podman rmi imageID
+ podman rmi --force alpine
+ podman rmi c4dfb1609ee2 93fd78260bd1 c0ed59d05ff7`,
}
)
diff --git a/cmd/podman/run.go b/cmd/podman/run.go
index 64f8b6856..ff4c3b418 100644
--- a/cmd/podman/run.go
+++ b/cmd/podman/run.go
@@ -30,7 +30,9 @@ var (
runCommand.GlobalFlags = MainGlobalOpts
return runCmd(&runCommand)
},
- Example: "IMAGE [COMMAND [ARG...]]",
+ Example: `podman run imageID ls -alF /etc
+ podman run --net=host imageID dnf -y install java
+ podman run --volume /var/hostdir:/var/ctrdir -i -t fedora /bin/bash`,
}
)
@@ -72,7 +74,8 @@ func runCmd(c *cliconfig.RunValues) error {
ctx := getContext()
// Handle detached start
if createConfig.Detach {
- if err := ctr.Start(ctx); err != nil {
+ // if the container was created as part of a pod, also start its dependencies, if any.
+ if err := ctr.Start(ctx, c.IsSet("pod")); err != nil {
// This means the command did not exist
exitCode = 127
if strings.Index(err.Error(), "permission denied") > -1 {
@@ -117,7 +120,8 @@ func runCmd(c *cliconfig.RunValues) error {
}
}
}
- if err := startAttachCtr(ctr, outputStream, errorStream, inputStream, c.String("detach-keys"), c.Bool("sig-proxy"), true); err != nil {
+ // if the container was created as part of a pod, also start its dependencies, if any.
+ if err := startAttachCtr(ctr, outputStream, errorStream, inputStream, c.String("detach-keys"), c.Bool("sig-proxy"), true, c.IsSet("pod")); err != nil {
// We've manually detached from the container
// Do not perform cleanup, or wait for container exit code
// Just exit immediately
@@ -125,7 +129,6 @@ func runCmd(c *cliconfig.RunValues) error {
exitCode = 0
return nil
}
-
// This means the command did not exist
exitCode = 127
if strings.Index(err.Error(), "permission denied") > -1 {
diff --git a/cmd/podman/sign.go b/cmd/podman/sign.go
index ac0d985f5..6e8f9ee95 100644
--- a/cmd/podman/sign.go
+++ b/cmd/podman/sign.go
@@ -32,7 +32,8 @@ var (
signCommand.GlobalFlags = MainGlobalOpts
return signCmd(&signCommand)
},
- Example: "IMAGE-NAME [IMAGE-NAME ...]",
+ Example: `podman sign --sign-by mykey imageID
+ podman sign --sign-by mykey --directory ./mykeydir imageID`,
}
)
diff --git a/cmd/podman/start.go b/cmd/podman/start.go
index 3a606d662..f3639cb23 100644
--- a/cmd/podman/start.go
+++ b/cmd/podman/start.go
@@ -1,14 +1,12 @@
package main
import (
- "encoding/json"
"fmt"
"os"
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/cmd/podman/libpodruntime"
"github.com/containers/libpod/libpod"
- cc "github.com/containers/libpod/pkg/spec"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
@@ -30,7 +28,9 @@ var (
startCommand.GlobalFlags = MainGlobalOpts
return startCmd(&startCommand)
},
- Example: "CONTAINER-NAME [CONTAINER-NAME ...]",
+ Example: `podman start --latest
+ podman start 860a4b231279 5421ab43b45
+ podman start --interactive --attach imageID`,
}
)
@@ -107,7 +107,8 @@ func startCmd(c *cliconfig.StartValues) error {
}
// attach to the container and also start it not already running
- err = startAttachCtr(ctr, os.Stdout, os.Stderr, inputStream, c.DetachKeys, sigProxy, !ctrRunning)
+ // If the container is in a pod, also set to recursively start dependencies
+ err = startAttachCtr(ctr, os.Stdout, os.Stderr, inputStream, c.DetachKeys, sigProxy, !ctrRunning, ctr.PodID() != "")
if errors.Cause(err) == libpod.ErrDetach {
// User manually detached
// Exit cleanly immediately
@@ -124,31 +125,30 @@ func startCmd(c *cliconfig.StartValues) error {
}
if ecode, err := ctr.Wait(); err != nil {
- logrus.Errorf("unable to get exit code of container %s: %q", ctr.ID(), err)
+ if errors.Cause(err) == libpod.ErrNoSuchCtr {
+ // The container may have been removed
+ // Go looking for an exit file
+ ctrExitCode, err := readExitFile(runtime.GetConfig().TmpDir, ctr.ID())
+ if err != nil {
+ logrus.Errorf("Cannot get exit code: %v", err)
+ exitCode = 127
+ } else {
+ exitCode = ctrExitCode
+ }
+ }
} else {
exitCode = int(ecode)
}
- return ctr.Cleanup(ctx)
+ return nil
}
if ctrRunning {
fmt.Println(ctr.ID())
continue
}
// Handle non-attach start
- if err := ctr.Start(ctx); err != nil {
- var createArtifact cc.CreateConfig
- artifact, artifactErr := ctr.GetArtifact("create-config")
- if artifactErr == nil {
- if jsonErr := json.Unmarshal(artifact, &createArtifact); jsonErr != nil {
- logrus.Errorf("unable to detect if container %s should be deleted", ctr.ID())
- }
- if createArtifact.Rm {
- if rmErr := runtime.RemoveContainer(ctx, ctr, true, false); rmErr != nil {
- logrus.Errorf("unable to remove container %s after it failed to start", ctr.ID())
- }
- }
- }
+ // If the container is in a pod, also set to recursively start dependencies
+ if err := ctr.Start(ctx, ctr.PodID() != ""); err != nil {
if lastError != nil {
fmt.Fprintln(os.Stderr, lastError)
}
diff --git a/cmd/podman/stop.go b/cmd/podman/stop.go
index 134d8a069..15c3984f4 100644
--- a/cmd/podman/stop.go
+++ b/cmd/podman/stop.go
@@ -31,7 +31,9 @@ var (
stopCommand.GlobalFlags = MainGlobalOpts
return stopCmd(&stopCommand)
},
- Example: "CONTAINER-NAME [CONTAINER-NAME ...]",
+ Example: `podman stop ctrID
+ podman stop --latest
+ podman stop --timeout 2 mywebserver 6e534f14da9d`,
}
)
diff --git a/cmd/podman/trust_set_show.go b/cmd/podman/trust_set_show.go
index f3d1cadce..0a4783d0a 100644
--- a/cmd/podman/trust_set_show.go
+++ b/cmd/podman/trust_set_show.go
@@ -26,7 +26,7 @@ var (
Use: "set",
Short: "Set default trust policy or a new trust policy for a registry",
Long: setTrustDescription,
- Example: "default | REGISTRY[/REPOSITORY]",
+ Example: "",
RunE: func(cmd *cobra.Command, args []string) error {
setTrustCommand.InputArgs = args
setTrustCommand.GlobalFlags = MainGlobalOpts
diff --git a/cmd/podman/umount.go b/cmd/podman/umount.go
index 20ea410c2..afa0e86db 100644
--- a/cmd/podman/umount.go
+++ b/cmd/podman/umount.go
@@ -31,7 +31,9 @@ An unmount can be forced with the --force flag.
umountCommand.GlobalFlags = MainGlobalOpts
return umountCmd(&umountCommand)
},
- Example: "CONTAINER-NAME-OR-ID",
+ Example: `podman umount ctrID
+ podman umount ctrID1 ctrID2 ctrID3
+ podman umount --all`,
}
)
diff --git a/cmd/podman/unpause.go b/cmd/podman/unpause.go
index c8f85cfd3..efd9a20a3 100644
--- a/cmd/podman/unpause.go
+++ b/cmd/podman/unpause.go
@@ -29,7 +29,8 @@ var (
unpauseCommand.GlobalFlags = MainGlobalOpts
return unpauseCmd(&unpauseCommand)
},
- Example: "CONTAINER-NAME [CONTAINER-NAME ...]",
+ Example: `podman unpause ctrID
+ podman unpause --all`,
}
)
diff --git a/cmd/podman/utils.go b/cmd/podman/utils.go
index 744d010d5..c76e7f2a4 100644
--- a/cmd/podman/utils.go
+++ b/cmd/podman/utils.go
@@ -20,7 +20,7 @@ type RawTtyFormatter struct {
}
// Start (if required) and attach to a container
-func startAttachCtr(ctr *libpod.Container, stdout, stderr, stdin *os.File, detachKeys string, sigProxy bool, startContainer bool) error {
+func startAttachCtr(ctr *libpod.Container, stdout, stderr, stdin *os.File, detachKeys string, sigProxy bool, startContainer bool, recursive bool) error {
ctx := context.Background()
resize := make(chan remotecommand.TerminalSize)
@@ -76,7 +76,7 @@ func startAttachCtr(ctr *libpod.Container, stdout, stderr, stdin *os.File, detac
return ctr.Attach(streams, detachKeys, resize)
}
- attachChan, err := ctr.StartAndAttach(getContext(), streams, detachKeys, resize)
+ attachChan, err := ctr.StartAndAttach(getContext(), streams, detachKeys, resize, recursive)
if err != nil {
return err
}
diff --git a/cmd/podman/volume_create.go b/cmd/podman/volume_create.go
index fe5d69e0b..6c8a78922 100644
--- a/cmd/podman/volume_create.go
+++ b/cmd/podman/volume_create.go
@@ -26,7 +26,9 @@ be created at.`
volumeCreateCommand.GlobalFlags = MainGlobalOpts
return volumeCreateCmd(&volumeCreateCommand)
},
- Example: "[VOLUME-NAME]",
+ Example: `podman volume create myvol
+ podman volume create
+ podman volume create --label foo=bar myvol`,
}
)
diff --git a/cmd/podman/volume_inspect.go b/cmd/podman/volume_inspect.go
index 928ef37d0..3b4ba51d5 100644
--- a/cmd/podman/volume_inspect.go
+++ b/cmd/podman/volume_inspect.go
@@ -24,7 +24,9 @@ from JSON to a Go template.
volumeInspectCommand.GlobalFlags = MainGlobalOpts
return volumeInspectCmd(&volumeInspectCommand)
},
- Example: "[VOLUME-NAME ...]",
+ Example: `podman volume inspect myvol
+ podman volume inspect --all
+ podman volume inspect --format "{{.Driver}} {{.Scope}}" myvol`,
}
)
diff --git a/contrib/cirrus/packer/Makefile b/contrib/cirrus/packer/Makefile
index 0a783e979..91a1dfeef 100644
--- a/contrib/cirrus/packer/Makefile
+++ b/contrib/cirrus/packer/Makefile
@@ -4,7 +4,9 @@
# e.g for names see libpod_images.yml
PACKER_VER ?= 1.3.2
-PACKER_DIST_FILENAME := packer_${PACKER_VER}_linux_amd64.zip
+GOARCH=$(shell go env GOARCH)
+ARCH=$(uname -m)
+PACKER_DIST_FILENAME := packer_${PACKER_VER}_linux_${GOARCH}.zip
# Only needed for libpod_base_images target
TIMESTAMP := $(shell date +%s)
@@ -30,7 +32,7 @@ ${PACKER_DIST_FILENAME}:
packer: ${PACKER_DIST_FILENAME}
@curl -L --silent --show-error \
https://releases.hashicorp.com/packer/${PACKER_VER}/packer_${PACKER_VER}_SHA256SUMS \
- | grep 'linux_amd64' > /tmp/packer_sha256sums
+ | grep linux_${GOARCH} > /tmp/packer_sha256sums
@sha256sum --check /tmp/packer_sha256sums
@unzip -o ${PACKER_DIST_FILENAME}
@touch --reference=Makefile ${PACKER_DIST_FILENAME}
@@ -93,7 +95,7 @@ endif
-var GOSRC=$(GOSRC) \
-var PACKER_BASE=$(PACKER_BASE) \
-var SCRIPT_BASE=$(SCRIPT_BASE) \
- -var RHEL_BASE_IMAGE_NAME=$(shell basename $(RHEL_IMAGE_FILE) | tr -d '[[:space:]]' | sed -r -e 's/\.x86_64\.raw\.xz//' | tr '[[:upper:]]' '[[:lower:]]' | tr '[[:punct:]]' '-') \
+ -var RHEL_BASE_IMAGE_NAME=$(shell basename $(RHEL_IMAGE_FILE) | tr -d '[[:space:]]' | sed -r -e 's/\.${ARCH}\.raw\.xz//' | tr '[[:upper:]]' '[[:lower:]]' | tr '[[:punct:]]' '-') \
-var RHEL_IMAGE_FILE=$(RHEL_IMAGE_FILE) \
-var RHEL_CSUM_FILE=$(RHEL_CSUM_FILE) \
-var 'RHSM_COMMAND=$(RHSM_COMMAND)' \
diff --git a/contrib/perftest/main.go b/contrib/perftest/main.go
index c0a91209f..237f4f6e6 100644
--- a/contrib/perftest/main.go
+++ b/contrib/perftest/main.go
@@ -201,7 +201,7 @@ func runSingleThreadedStressTest(ctx context.Context, client *libpod.Runtime, im
// Start container
startStartTime := time.Now()
- err = ctr.Start(ctx)
+ err = ctr.Start(ctx, false)
if err != nil {
return nil, err
}
diff --git a/docs/podman-exec.1.md b/docs/podman-exec.1.md
index 77317b0ca..6f464a8f2 100644
--- a/docs/podman-exec.1.md
+++ b/docs/podman-exec.1.md
@@ -4,7 +4,7 @@
podman\-exec - Execute a command in a running container
## SYNOPSIS
-**podman exec** *container* [*options*] [*command* [*arg* ...]]
+**podman exec** [*options*] *container* [*command* [*arg* ...]]
## DESCRIPTION
**podman exec** executes a command in a running container.
@@ -46,6 +46,12 @@ The default working directory for running binaries within a container is the roo
The image developer can set a different default with the WORKDIR instruction, which can be overridden
when creating the container.
+## EXAMPLES
+
+$ podman exec -it ctrID ls
+$ podman exec -it -w /tmp myCtr pwd
+$ podman exec --user root ctrID ls
+
## SEE ALSO
podman(1), podman-run(1)
diff --git a/docs/podman-pod-create.1.md b/docs/podman-pod-create.1.md
index a63b12d73..06f962849 100644
--- a/docs/podman-pod-create.1.md
+++ b/docs/podman-pod-create.1.md
@@ -10,8 +10,8 @@ podman\-pod\-create - Create a new pod
Creates an empty pod, or unit of multiple containers, and prepares it to have
containers added to it. The pod id is printed to STDOUT. You can then use
-**podman create --pod <pod_id|pod_name> ...** to add containers to the pod, and
-**podman pod start <pod_id|pod_name>** to start the pod.
+**podman create --pod \<pod_id|pod_name\> ...** to add containers to the pod, and
+**podman pod start \<pod_id|pod_name\>** to start the pod.
## OPTIONS
diff --git a/docs/podman-run.1.md b/docs/podman-run.1.md
index cef9a6e8a..b928f61f5 100644
--- a/docs/podman-run.1.md
+++ b/docs/podman-run.1.md
@@ -449,6 +449,7 @@ Tune the container's pids limit. Set `-1` to have unlimited pids for the contain
Run container in an existing pod. If you want podman to make the pod for you, preference the pod name with `new:`.
To make a pod with more granular options, use the `podman pod create` command before creating a container.
+If a container is run with a pod, and the pod has an infra-container, the infra-container will be started before the container is.
**--privileged**=*true*|*false*
diff --git a/docs/podman-start.1.md b/docs/podman-start.1.md
index f16a20efa..786936721 100644
--- a/docs/podman-start.1.md
+++ b/docs/podman-start.1.md
@@ -8,7 +8,7 @@ podman\-start - Start one or more containers
## DESCRIPTION
Start one or more containers. You may use container IDs or names as input. The *attach* and *interactive*
-options cannot be used to override the *--tty** and *--interactive* options from when the container
+options cannot be used to override the *--tty* and *--interactive* options from when the container
was created. If you attempt to start a running container with the *--attach* option, podman will simply
attach to the container.
@@ -33,6 +33,7 @@ Attach container's STDIN. The default is false.
Instead of providing the container name or ID, use the last created container. If you use methods other than Podman
to run containers such as CRI-O, the last started container could be from either of those methods.
+
**--sig-proxy**=*true*|*false*
Proxy received signals to the process (non-TTY mode only). SIGCHLD, SIGSTOP, and SIGKILL are not proxied. The default is *true* when attaching, *false* otherwise.
@@ -41,9 +42,9 @@ Proxy received signals to the process (non-TTY mode only). SIGCHLD, SIGSTOP, and
podman start mywebserver
-podman start 860a4b23 5421ab4
+podman start 860a4b231279 5421ab43b45
-podman start -i -a 860a4b23
+podman start --interactive --attach 860a4b231279
podman start -i -l
diff --git a/docs/podman-stop.1.md b/docs/podman-stop.1.md
index 813f0ef9e..e36265d5e 100644
--- a/docs/podman-stop.1.md
+++ b/docs/podman-stop.1.md
@@ -32,11 +32,11 @@ Timeout to wait before forcibly stopping the container
podman stop mywebserver
-podman stop 860a4b23
+podman stop 860a4b235279
-podman stop mywebserver 860a4b23
+podman stop mywebserver 860a4b235279
-podman stop --timeout 2 860a4b23
+podman stop --timeout 2 860a4b235279
podman stop -a
diff --git a/libpod/container_api.go b/libpod/container_api.go
index 149867759..abe0df610 100644
--- a/libpod/container_api.go
+++ b/libpod/container_api.go
@@ -7,7 +7,6 @@ import (
"io/ioutil"
"os"
"strconv"
- "strings"
"time"
"github.com/containers/libpod/libpod/driver"
@@ -38,24 +37,15 @@ func (c *Container) Init(ctx context.Context) (err error) {
return errors.Wrapf(ErrCtrExists, "container %s has already been created in runtime", c.ID())
}
- notRunning, err := c.checkDependenciesRunning()
- if err != nil {
- return errors.Wrapf(err, "error checking dependencies for container %s", c.ID())
- }
- if len(notRunning) > 0 {
- depString := strings.Join(notRunning, ",")
- return errors.Wrapf(ErrCtrStateInvalid, "some dependencies of container %s are not started: %s", c.ID(), depString)
+ // don't recursively start
+ if err := c.checkDependenciesAndHandleError(ctx); err != nil {
+ return err
}
- defer func() {
- if err != nil {
- if err2 := c.cleanup(ctx); err2 != nil {
- logrus.Errorf("error cleaning up container %s: %v", c.ID(), err2)
- }
- }
- }()
-
if err := c.prepare(); err != nil {
+ if err2 := c.cleanup(ctx); err2 != nil {
+ logrus.Errorf("error cleaning up container %s: %v", c.ID(), err2)
+ }
return err
}
@@ -68,13 +58,14 @@ func (c *Container) Init(ctx context.Context) (err error) {
return c.init(ctx)
}
-// Start starts a container
-// Start can start configured, created or stopped containers
+// Start starts a container.
+// Start can start configured, created or stopped containers.
// For configured containers, the container will be initialized first, then
-// started
+// started.
// Stopped containers will be deleted and re-created in runc, undergoing a fresh
-// Init()
-func (c *Container) Start(ctx context.Context) (err error) {
+// Init().
+// If recursive is set, Start will also start all containers this container depends on.
+func (c *Container) Start(ctx context.Context, recursive bool) (err error) {
if !c.batched {
c.lock.Lock()
defer c.lock.Unlock()
@@ -83,64 +74,26 @@ func (c *Container) Start(ctx context.Context) (err error) {
return err
}
}
-
- // Container must be created or stopped to be started
- if !(c.state.State == ContainerStateConfigured ||
- c.state.State == ContainerStateCreated ||
- c.state.State == ContainerStateStopped ||
- c.state.State == ContainerStateExited) {
- return errors.Wrapf(ErrCtrStateInvalid, "container %s must be in Created or Stopped state to be started", c.ID())
- }
-
- notRunning, err := c.checkDependenciesRunning()
- if err != nil {
- return errors.Wrapf(err, "error checking dependencies for container %s", c.ID())
- }
- if len(notRunning) > 0 {
- depString := strings.Join(notRunning, ",")
- return errors.Wrapf(ErrCtrStateInvalid, "some dependencies of container %s are not started: %s", c.ID(), depString)
- }
-
- defer func() {
- if err != nil {
- if err2 := c.cleanup(ctx); err2 != nil {
- logrus.Errorf("error cleaning up container %s: %v", c.ID(), err2)
- }
- }
- }()
-
- if err := c.prepare(); err != nil {
+ if err := c.prepareToStart(ctx, recursive); err != nil {
return err
}
- if c.state.State == ContainerStateStopped {
- // Reinitialize the container if we need to
- if err := c.reinit(ctx); err != nil {
- return err
- }
- } else if c.state.State == ContainerStateConfigured ||
- c.state.State == ContainerStateExited {
- // Or initialize it if necessary
- if err := c.init(ctx); err != nil {
- return err
- }
- }
-
// Start the container
return c.start()
}
-// StartAndAttach starts a container and attaches to it
-// StartAndAttach can start configured, created or stopped containers
+// StartAndAttach starts a container and attaches to it.
+// StartAndAttach can start configured, created or stopped containers.
// For configured containers, the container will be initialized first, then
-// started
+// started.
// Stopped containers will be deleted and re-created in runc, undergoing a fresh
-// Init()
+// Init().
// If successful, an error channel will be returned containing the result of the
// attach call.
// The channel will be closed automatically after the result of attach has been
-// sent
-func (c *Container) StartAndAttach(ctx context.Context, streams *AttachStreams, keys string, resize <-chan remotecommand.TerminalSize) (attachResChan <-chan error, err error) {
+// sent.
+// If recursive is set, StartAndAttach will also start all containers this container depends on.
+func (c *Container) StartAndAttach(ctx context.Context, streams *AttachStreams, keys string, resize <-chan remotecommand.TerminalSize, recursive bool) (attachResChan <-chan error, err error) {
if !c.batched {
c.lock.Lock()
defer c.lock.Unlock()
@@ -150,48 +103,10 @@ func (c *Container) StartAndAttach(ctx context.Context, streams *AttachStreams,
}
}
- // Container must be created or stopped to be started
- if !(c.state.State == ContainerStateConfigured ||
- c.state.State == ContainerStateCreated ||
- c.state.State == ContainerStateStopped ||
- c.state.State == ContainerStateExited) {
- return nil, errors.Wrapf(ErrCtrStateInvalid, "container %s must be in Created or Stopped state to be started", c.ID())
- }
-
- notRunning, err := c.checkDependenciesRunning()
- if err != nil {
- return nil, errors.Wrapf(err, "error checking dependencies for container %s", c.ID())
- }
- if len(notRunning) > 0 {
- depString := strings.Join(notRunning, ",")
- return nil, errors.Wrapf(ErrCtrStateInvalid, "some dependencies of container %s are not started: %s", c.ID(), depString)
- }
-
- defer func() {
- if err != nil {
- if err2 := c.cleanup(ctx); err2 != nil {
- logrus.Errorf("error cleaning up container %s: %v", c.ID(), err2)
- }
- }
- }()
-
- if err := c.prepare(); err != nil {
+ if err := c.prepareToStart(ctx, recursive); err != nil {
return nil, err
}
- if c.state.State == ContainerStateStopped {
- // Reinitialize the container if we need to
- if err := c.reinit(ctx); err != nil {
- return nil, err
- }
- } else if c.state.State == ContainerStateConfigured ||
- c.state.State == ContainerStateExited {
- // Or initialize it if necessary
- if err := c.init(ctx); err != nil {
- return nil, err
- }
- }
-
attachChan := make(chan error)
// Attach to the container before starting it
@@ -205,6 +120,24 @@ func (c *Container) StartAndAttach(ctx context.Context, streams *AttachStreams,
return attachChan, nil
}
+// RestartWithTimeout restarts a running container and takes a given timeout in uint
+func (c *Container) RestartWithTimeout(ctx context.Context, timeout uint) (err error) {
+ if !c.batched {
+ c.lock.Lock()
+ defer c.lock.Unlock()
+
+ if err := c.syncContainer(); err != nil {
+ return err
+ }
+ }
+
+ if err = c.checkDependenciesAndHandleError(ctx); err != nil {
+ return err
+ }
+
+ return c.restartWithTimeout(ctx, timeout)
+}
+
// Stop uses the container's stop signal (or SIGTERM if no signal was specified)
// to stop the container, and if it has not stopped after container's stop
// timeout, SIGKILL is used to attempt to forcibly stop the container
@@ -730,28 +663,6 @@ func (c *Container) Sync() error {
return nil
}
-// RestartWithTimeout restarts a running container and takes a given timeout in uint
-func (c *Container) RestartWithTimeout(ctx context.Context, timeout uint) (err error) {
- if !c.batched {
- c.lock.Lock()
- defer c.lock.Unlock()
-
- if err := c.syncContainer(); err != nil {
- return err
- }
- }
-
- notRunning, err := c.checkDependenciesRunning()
- if err != nil {
- return errors.Wrapf(err, "error checking dependencies for container %s", c.ID())
- }
- if len(notRunning) > 0 {
- depString := strings.Join(notRunning, ",")
- return errors.Wrapf(ErrCtrStateInvalid, "some dependencies of container %s are not started: %s", c.ID(), depString)
- }
- return c.restartWithTimeout(ctx, timeout)
-}
-
// Refresh refreshes a container's state in the database, restarting the
// container if it is running
func (c *Container) Refresh(ctx context.Context) error {
diff --git a/libpod/container_graph.go b/libpod/container_graph.go
index 44a1f1736..da93be77d 100644
--- a/libpod/container_graph.go
+++ b/libpod/container_graph.go
@@ -1,6 +1,9 @@
package libpod
import (
+ "context"
+ "strings"
+
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
@@ -169,3 +172,97 @@ func detectCycles(graph *containerGraph) (bool, error) {
return false, nil
}
+
+// Visit a node on a container graph and start the container, or set an error if
+// a dependency failed to start. if restart is true, startNode will restart the node instead of starting it.
+func startNode(ctx context.Context, node *containerNode, setError bool, ctrErrors map[string]error, ctrsVisited map[string]bool, restart bool) {
+ // First, check if we have already visited the node
+ if ctrsVisited[node.id] {
+ return
+ }
+
+ // If setError is true, a dependency of us failed
+ // Mark us as failed and recurse
+ if setError {
+ // Mark us as visited, and set an error
+ ctrsVisited[node.id] = true
+ ctrErrors[node.id] = errors.Wrapf(ErrCtrStateInvalid, "a dependency of container %s failed to start", node.id)
+
+ // Hit anyone who depends on us, and set errors on them too
+ for _, successor := range node.dependedOn {
+ startNode(ctx, successor, true, ctrErrors, ctrsVisited, restart)
+ }
+
+ return
+ }
+
+ // Have all our dependencies started?
+ // If not, don't visit the node yet
+ depsVisited := true
+ for _, dep := range node.dependsOn {
+ depsVisited = depsVisited && ctrsVisited[dep.id]
+ }
+ if !depsVisited {
+ // Don't visit us yet, all dependencies are not up
+ // We'll hit the dependencies eventually, and when we do it will
+ // recurse here
+ return
+ }
+
+ // Going to try to start the container, mark us as visited
+ ctrsVisited[node.id] = true
+
+ ctrErrored := false
+
+ // Check if dependencies are running
+ // Graph traversal means we should have started them
+ // But they could have died before we got here
+ // Does not require that the container be locked, we only need to lock
+ // the dependencies
+ depsStopped, err := node.container.checkDependenciesRunning()
+ if err != nil {
+ ctrErrors[node.id] = err
+ ctrErrored = true
+ } else if len(depsStopped) > 0 {
+ // Our dependencies are not running
+ depsList := strings.Join(depsStopped, ",")
+ ctrErrors[node.id] = errors.Wrapf(ErrCtrStateInvalid, "the following dependencies of container %s are not running: %s", node.id, depsList)
+ ctrErrored = true
+ }
+
+ // Lock before we start
+ node.container.lock.Lock()
+
+ // Sync the container to pick up current state
+ if !ctrErrored {
+ if err := node.container.syncContainer(); err != nil {
+ ctrErrored = true
+ ctrErrors[node.id] = err
+ }
+ }
+
+ // Start the container (only if it is not running)
+ if !ctrErrored {
+ if !restart && node.container.state.State != ContainerStateRunning {
+ if err := node.container.initAndStart(ctx); err != nil {
+ ctrErrored = true
+ ctrErrors[node.id] = err
+ }
+ }
+ if restart && node.container.state.State != ContainerStatePaused && node.container.state.State != ContainerStateUnknown {
+ if err := node.container.restartWithTimeout(ctx, node.container.config.StopTimeout); err != nil {
+ ctrErrored = true
+ ctrErrors[node.id] = err
+ }
+ }
+ }
+
+ node.container.lock.Unlock()
+
+ // Recurse to anyone who depends on us and start them
+ for _, successor := range node.dependedOn {
+ startNode(ctx, successor, ctrErrored, ctrErrors, ctrsVisited, restart)
+ }
+
+ return
+}
diff --git a/libpod/container_internal.go b/libpod/container_internal.go
index b2ebad777..a54613443 100644
--- a/libpod/container_internal.go
+++ b/libpod/container_internal.go
@@ -559,6 +559,149 @@ func (c *Container) save() error {
return nil
}
+// Checks the container is in the right state, then initializes the container in preparation to start the container.
+// If recursive is true, each of the containers dependencies will be started.
+// Otherwise, this function will return with error if there are dependencies of this container that aren't running.
+func (c *Container) prepareToStart(ctx context.Context, recursive bool) (err error) {
+ // Container must be created or stopped to be started
+ if !(c.state.State == ContainerStateConfigured ||
+ c.state.State == ContainerStateCreated ||
+ c.state.State == ContainerStateStopped ||
+ c.state.State == ContainerStateExited) {
+ return errors.Wrapf(ErrCtrStateInvalid, "container %s must be in Created or Stopped state to be started", c.ID())
+ }
+
+ if !recursive {
+ if err := c.checkDependenciesAndHandleError(ctx); err != nil {
+ return err
+ }
+ } else {
+ if err := c.startDependencies(ctx); err != nil {
+ return err
+ }
+ }
+
+ defer func() {
+ if err != nil {
+ if err2 := c.cleanup(ctx); err2 != nil {
+ logrus.Errorf("error cleaning up container %s: %v", c.ID(), err2)
+ }
+ }
+ }()
+
+ if err := c.prepare(); err != nil {
+ return err
+ }
+
+ if c.state.State == ContainerStateStopped {
+ // Reinitialize the container if we need to
+ if err := c.reinit(ctx); err != nil {
+ return err
+ }
+ } else if c.state.State == ContainerStateConfigured ||
+ c.state.State == ContainerStateExited {
+ // Or initialize it if necessary
+ if err := c.init(ctx); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// checks dependencies are running and prints a helpful message
+func (c *Container) checkDependenciesAndHandleError(ctx context.Context) error {
+ notRunning, err := c.checkDependenciesRunning()
+ if err != nil {
+ return errors.Wrapf(err, "error checking dependencies for container %s", c.ID())
+ }
+ if len(notRunning) > 0 {
+ depString := strings.Join(notRunning, ",")
+ return errors.Wrapf(ErrCtrStateInvalid, "some dependencies of container %s are not started: %s", c.ID(), depString)
+ }
+
+ return nil
+}
+
+// Recursively start all dependencies of a container so the container can be started.
+func (c *Container) startDependencies(ctx context.Context) error {
+ depCtrIDs := c.Dependencies()
+ if len(depCtrIDs) == 0 {
+ return nil
+ }
+
+ depVisitedCtrs := make(map[string]*Container)
+ if err := c.getAllDependencies(depVisitedCtrs); err != nil {
+ return errors.Wrapf(err, "error starting dependency for container %s", c.ID())
+ }
+
+ // Because of how Go handles passing slices through functions, a slice cannot grow between function calls
+ // without clunky syntax. Circumnavigate this by translating the map to a slice for buildContainerGraph
+ depCtrs := make([]*Container, 0)
+ for _, ctr := range depVisitedCtrs {
+ depCtrs = append(depCtrs, ctr)
+ }
+
+ // Build a dependency graph of containers
+ graph, err := buildContainerGraph(depCtrs)
+ if err != nil {
+ return errors.Wrapf(err, "error generating dependency graph for container %s", c.ID())
+ }
+
+ ctrErrors := make(map[string]error)
+ // reset ctrsVisisted for next round of recursion
+ ctrsVisited := make(map[string]bool)
+
+ // If there are no containers without dependencies, we can't start
+ // Error out
+ if len(graph.noDepNodes) == 0 {
+ return errors.Wrapf(ErrNoSuchCtr, "All dependencies have dependencies of %s", c.ID())
+ }
+
+ // Traverse the graph beginning at nodes with no dependencies
+ for _, node := range graph.noDepNodes {
+ startNode(ctx, node, false, ctrErrors, ctrsVisited, true)
+ }
+
+ if len(ctrErrors) > 0 {
+ logrus.Errorf("error starting some container dependencies")
+ for _, e := range ctrErrors {
+ logrus.Errorf("%q", e)
+ }
+ return errors.Wrapf(ErrInternal, "error starting some containers")
+ }
+ return nil
+}
+
+// getAllDependencies is a precursor to starting dependencies.
+// To start a container with all of its dependencies, we need to recursively find all dependencies
+// a container has, as well as each of those containers' dependencies, and so on
+// To do so, keep track of containers already visisted (so there aren't redundant state lookups),
+// and recursively search until we have reached the leafs of every dependency node.
+// Since we need to start all dependencies for our original container to successfully start, we propegate any errors
+// in looking up dependencies.
+// Note: this function is currently meant as a robust solution to a narrow problem: start an infra-container when
+// a container in the pod is run. It has not been tested for performance past one level, so expansion of recursive start
+// must be tested first.
+func (c *Container) getAllDependencies(visited map[string]*Container) error {
+ depIDs := c.Dependencies()
+ if len(depIDs) == 0 {
+ return nil
+ }
+ for _, depID := range depIDs {
+ if _, ok := visited[depID]; !ok {
+ dep, err := c.runtime.state.LookupContainer(depID)
+ if err != nil {
+ return err
+ }
+ visited[depID] = dep
+ if err := dep.getAllDependencies(visited); err != nil {
+ return err
+ }
+ }
+ }
+ return nil
+}
+
// Check if a container's dependencies are running
// Returns a []string containing the IDs of dependencies that are not running
func (c *Container) checkDependenciesRunning() ([]string, error) {
diff --git a/libpod/pod_internal.go b/libpod/pod_internal.go
index 0f1f115e8..25e4e77d7 100644
--- a/libpod/pod_internal.go
+++ b/libpod/pod_internal.go
@@ -1,10 +1,8 @@
package libpod
import (
- "context"
"fmt"
"path/filepath"
- "strings"
"time"
"github.com/containers/storage/pkg/stringid"
@@ -85,97 +83,3 @@ func (p *Pod) refresh() error {
// Save changes
return p.save()
}
-
-// Visit a node on a container graph and start the container, or set an error if
-// a dependency failed to start. if restart is true, startNode will restart the node instead of starting it.
-func startNode(ctx context.Context, node *containerNode, setError bool, ctrErrors map[string]error, ctrsVisited map[string]bool, restart bool) {
- // First, check if we have already visited the node
- if ctrsVisited[node.id] {
- return
- }
-
- // If setError is true, a dependency of us failed
- // Mark us as failed and recurse
- if setError {
- // Mark us as visited, and set an error
- ctrsVisited[node.id] = true
- ctrErrors[node.id] = errors.Wrapf(ErrCtrStateInvalid, "a dependency of container %s failed to start", node.id)
-
- // Hit anyone who depends on us, and set errors on them too
- for _, successor := range node.dependedOn {
- startNode(ctx, successor, true, ctrErrors, ctrsVisited, restart)
- }
-
- return
- }
-
- // Have all our dependencies started?
- // If not, don't visit the node yet
- depsVisited := true
- for _, dep := range node.dependsOn {
- depsVisited = depsVisited && ctrsVisited[dep.id]
- }
- if !depsVisited {
- // Don't visit us yet, all dependencies are not up
- // We'll hit the dependencies eventually, and when we do it will
- // recurse here
- return
- }
-
- // Going to try to start the container, mark us as visited
- ctrsVisited[node.id] = true
-
- ctrErrored := false
-
- // Check if dependencies are running
- // Graph traversal means we should have started them
- // But they could have died before we got here
- // Does not require that the container be locked, we only need to lock
- // the dependencies
- depsStopped, err := node.container.checkDependenciesRunning()
- if err != nil {
- ctrErrors[node.id] = err
- ctrErrored = true
- } else if len(depsStopped) > 0 {
- // Our dependencies are not running
- depsList := strings.Join(depsStopped, ",")
- ctrErrors[node.id] = errors.Wrapf(ErrCtrStateInvalid, "the following dependencies of container %s are not running: %s", node.id, depsList)
- ctrErrored = true
- }
-
- // Lock before we start
- node.container.lock.Lock()
-
- // Sync the container to pick up current state
- if !ctrErrored {
- if err := node.container.syncContainer(); err != nil {
- ctrErrored = true
- ctrErrors[node.id] = err
- }
- }
-
- // Start the container (only if it is not running)
- if !ctrErrored {
- if !restart && node.container.state.State != ContainerStateRunning {
- if err := node.container.initAndStart(ctx); err != nil {
- ctrErrored = true
- ctrErrors[node.id] = err
- }
- }
- if restart && node.container.state.State != ContainerStatePaused && node.container.state.State != ContainerStateUnknown {
- if err := node.container.restartWithTimeout(ctx, node.container.config.StopTimeout); err != nil {
- ctrErrored = true
- ctrErrors[node.id] = err
- }
- }
- }
-
- node.container.lock.Unlock()
-
- // Recurse to anyone who depends on us and start them
- for _, successor := range node.dependedOn {
- startNode(ctx, successor, ctrErrored, ctrErrors, ctrsVisited, restart)
- }
-
- return
-}
diff --git a/libpod/runtime_pod_linux.go b/libpod/runtime_pod_linux.go
index c6d497c0c..c378d18e4 100644
--- a/libpod/runtime_pod_linux.go
+++ b/libpod/runtime_pod_linux.go
@@ -117,15 +117,6 @@ func (r *Runtime) NewPod(ctx context.Context, options ...PodCreateOption) (*Pod,
if err := pod.save(); err != nil {
return nil, err
}
-
- // Once the pod infra container has been created, we start it
- if err := ctr.Start(ctx); err != nil {
- // If the infra container does not start, we need to tear the pod down.
- if err2 := r.removePod(ctx, pod, true, true); err2 != nil {
- logrus.Errorf("Error removing pod after infra container failed to start: %v", err2)
- }
- return nil, errors.Wrapf(err, "error starting Infra Container")
- }
}
return pod, nil
diff --git a/pkg/varlinkapi/containers.go b/pkg/varlinkapi/containers.go
index 8a52efa61..7345a1dd8 100644
--- a/pkg/varlinkapi/containers.go
+++ b/pkg/varlinkapi/containers.go
@@ -260,7 +260,7 @@ func (i *LibpodAPI) StartContainer(call iopodman.VarlinkCall, name string) error
if state == libpod.ContainerStateRunning || state == libpod.ContainerStatePaused {
return call.ReplyErrorOccurred("container is already running or paused")
}
- if err := ctr.Start(getContext()); err != nil {
+ if err := ctr.Start(getContext(), false); err != nil {
return call.ReplyErrorOccurred(err.Error())
}
return call.ReplyStartContainer(ctr.ID())
diff --git a/test/e2e/e2e.coverprofile b/test/e2e/e2e.coverprofile
new file mode 100644
index 000000000..b5382604f
--- /dev/null
+++ b/test/e2e/e2e.coverprofile
@@ -0,0 +1,11 @@
+mode: atomic
+github.com/containers/libpod/test/e2e/pod_pod_namespaces.go:14.46,21.20 2 1
+github.com/containers/libpod/test/e2e/pod_pod_namespaces.go:31.2,31.19 1 1
+github.com/containers/libpod/test/e2e/pod_pod_namespaces.go:38.2,38.53 1 1
+github.com/containers/libpod/test/e2e/pod_pod_namespaces.go:65.2,65.52 1 1
+github.com/containers/libpod/test/e2e/pod_pod_namespaces.go:21.20,23.17 2 2
+github.com/containers/libpod/test/e2e/pod_pod_namespaces.go:26.3,28.36 3 2
+github.com/containers/libpod/test/e2e/pod_pod_namespaces.go:23.17,25.4 1 0
+github.com/containers/libpod/test/e2e/pod_pod_namespaces.go:31.19,36.3 4 2
+github.com/containers/libpod/test/e2e/pod_pod_namespaces.go:38.53,63.3 20 1
+github.com/containers/libpod/test/e2e/pod_pod_namespaces.go:65.52,90.3 20 1
diff --git a/test/e2e/pod_infra_container_test.go b/test/e2e/pod_infra_container_test.go
index 161bf7f9c..ed5002ca7 100644
--- a/test/e2e/pod_infra_container_test.go
+++ b/test/e2e/pod_infra_container_test.go
@@ -309,4 +309,55 @@ var _ = Describe("Podman pod create", func() {
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
})
+
+ It("podman run in pod starts infra", func() {
+ session := podmanTest.Podman([]string{"pod", "create"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ podID := session.OutputToString()
+
+ result := podmanTest.Podman([]string{"ps", "-aq"})
+ result.WaitWithDefaultTimeout()
+ Expect(result.ExitCode()).To(Equal(0))
+ infraID := result.OutputToString()
+
+ result = podmanTest.Podman([]string{"run", "--pod", podID, "-d", ALPINE, "top"})
+ result.WaitWithDefaultTimeout()
+ Expect(result.ExitCode()).To(Equal(0))
+
+ result = podmanTest.Podman([]string{"ps", "-aq"})
+ result.WaitWithDefaultTimeout()
+ Expect(result.ExitCode()).To(Equal(0))
+ Expect(len(result.OutputToStringArray())).Should(BeNumerically(">", 0))
+
+ Expect(result.OutputToString()).To(ContainSubstring(infraID))
+ })
+
+ It("podman start in pod starts infra", func() {
+ session := podmanTest.Podman([]string{"pod", "create"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ podID := session.OutputToString()
+
+ result := podmanTest.Podman([]string{"ps", "-aq"})
+ result.WaitWithDefaultTimeout()
+ Expect(result.ExitCode()).To(Equal(0))
+ infraID := result.OutputToString()
+
+ result = podmanTest.Podman([]string{"create", "--pod", podID, ALPINE, "ls"})
+ result.WaitWithDefaultTimeout()
+ Expect(result.ExitCode()).To(Equal(0))
+ ctrID := result.OutputToString()
+
+ result = podmanTest.Podman([]string{"start", ctrID})
+ result.WaitWithDefaultTimeout()
+ Expect(result.ExitCode()).To(Equal(0))
+
+ result = podmanTest.Podman([]string{"ps", "-aq"})
+ result.WaitWithDefaultTimeout()
+ Expect(result.ExitCode()).To(Equal(0))
+ Expect(len(result.OutputToStringArray())).Should(BeNumerically(">", 0))
+
+ Expect(result.OutputToString()).To(ContainSubstring(infraID))
+ })
})
diff --git a/test/trust_set_test.json b/test/trust_set_test.json
new file mode 100644
index 000000000..661e65922
--- /dev/null
+++ b/test/trust_set_test.json
@@ -0,0 +1,8 @@
+{
+ "default": [
+ {
+ "type": "insecureAcceptAnything"
+ }
+ ],
+ "transports": null
+} \ No newline at end of file