summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhaircommander <pehunt@redhat.com>2018-07-27 13:58:50 -0400
committerAtomic Bot <atomic-devel@projectatomic.io>2018-08-23 18:16:28 +0000
commitd5e690914dc78eca8664442e7677eb5004522bfd (patch)
tree3f7ed30e4302c871c16126a0032b8a3d51c46f98
parent63dd200e7e47261454c7e55fed2ad972144e147f (diff)
downloadpodman-d5e690914dc78eca8664442e7677eb5004522bfd.tar.gz
podman-d5e690914dc78eca8664442e7677eb5004522bfd.tar.bz2
podman-d5e690914dc78eca8664442e7677eb5004522bfd.zip
Added option to share kernel namespaces in libpod and podman
A pause container is added to the pod if the user opts in. The default pause image and command can be overridden. Pause containers are ignored in ps unless the -a option is present. Pod inspect and pod ps show shared namespaces and pause container. A pause container can't be removed with podman rm, and a pod can be removed if it only has a pause container. Signed-off-by: haircommander <pehunt@redhat.com> Closes: #1187 Approved by: mheon
-rw-r--r--cmd/podman/create.go74
-rw-r--r--cmd/podman/libpodruntime/runtime.go9
-rw-r--r--cmd/podman/pod_create.go57
-rw-r--r--cmd/podman/pod_ps.go57
-rw-r--r--cmd/podman/ps.go16
-rw-r--r--completions/bash/podman4
-rw-r--r--docs/podman-pod-create.1.md20
-rw-r--r--libpod.conf6
-rw-r--r--libpod/container.go22
-rw-r--r--libpod/container_ffjson.go485
-rw-r--r--libpod/container_inspect.go1
-rw-r--r--libpod/container_internal.go35
-rw-r--r--libpod/container_internal_linux.go49
-rw-r--r--libpod/options.go280
-rw-r--r--libpod/pod.go95
-rw-r--r--libpod/pod_api.go7
-rw-r--r--libpod/pod_ffjson.go745
-rw-r--r--libpod/pod_internal.go1
-rw-r--r--libpod/runtime.go11
-rw-r--r--libpod/runtime_ctr.go42
-rw-r--r--libpod/runtime_pod.go10
-rw-r--r--libpod/runtime_pod_linux.go49
-rw-r--r--libpod/runtime_pod_pause_linux.go60
-rw-r--r--libpod/runtime_pod_unsupported.go2
-rw-r--r--pkg/inspect/inspect.go1
-rw-r--r--pkg/spec/createconfig.go17
-rw-r--r--pkg/spec/parse.go17
-rw-r--r--pkg/spec/spec.go6
-rw-r--r--pkg/varlinkapi/pods.go2
-rw-r--r--test/e2e/libpod_suite_test.go15
-rw-r--r--test/e2e/pod_create_test.go28
-rw-r--r--test/e2e/pod_inspect_test.go8
-rw-r--r--test/e2e/pod_kill_test.go61
-rw-r--r--test/e2e/pod_pause_container_test.go285
-rw-r--r--test/e2e/pod_pause_test.go29
-rw-r--r--test/e2e/pod_ps_test.go98
-rw-r--r--test/e2e/pod_restart_test.go54
-rw-r--r--test/e2e/pod_rm_test.go72
-rw-r--r--test/e2e/pod_start_test.go58
-rw-r--r--test/e2e/pod_stop_test.go58
-rw-r--r--test/e2e/ps_test.go8
41 files changed, 2569 insertions, 385 deletions
diff --git a/cmd/podman/create.go b/cmd/podman/create.go
index 96934560f..d6bcea7bd 100644
--- a/cmd/podman/create.go
+++ b/cmd/podman/create.go
@@ -368,16 +368,6 @@ func parseCreateOpts(ctx context.Context, c *cli.Context, runtime *libpod.Runtim
tty := c.Bool("tty")
- pidMode := container.PidMode(c.String("pid"))
- if !cc.IsNS(string(pidMode)) && !pidMode.Valid() {
- return nil, errors.Errorf("--pid %q is not valid", c.String("pid"))
- }
-
- usernsMode := container.UsernsMode(c.String("userns"))
- if !cc.IsNS(string(usernsMode)) && !usernsMode.Valid() {
- return nil, errors.Errorf("--userns %q is not valid", c.String("userns"))
- }
-
if c.Bool("detach") && c.Bool("rm") {
return nil, errors.Errorf("--rm and --detach can not be specified together")
}
@@ -388,14 +378,62 @@ func parseCreateOpts(ctx context.Context, c *cli.Context, runtime *libpod.Runtim
return nil, errors.Errorf("--cpu-quota and --cpus cannot be set together")
}
- utsMode := container.UTSMode(c.String("uts"))
- if !cc.IsNS(string(utsMode)) && !utsMode.Valid() {
+ // Kernel Namespaces
+ var pod *libpod.Pod
+ if c.IsSet("pod") {
+ pod, err = runtime.LookupPod(c.String("pod"))
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ pidModeStr := c.String("pid")
+ if !c.IsSet("pid") && pod != nil && pod.SharesPID() {
+ pidModeStr = "pod"
+ }
+ pidMode := container.PidMode(pidModeStr)
+ if !cc.Valid(string(pidMode), pidMode) {
+ return nil, errors.Errorf("--pid %q is not valid", c.String("pid"))
+ }
+
+ usernsModeStr := c.String("userns")
+ if !c.IsSet("userns") && pod != nil && pod.SharesUser() {
+ usernsModeStr = "pod"
+ }
+ usernsMode := container.UsernsMode(usernsModeStr)
+ if !cc.Valid(string(usernsMode), usernsMode) {
+ return nil, errors.Errorf("--userns %q is not valid", c.String("userns"))
+ }
+
+ utsModeStr := c.String("uts")
+ if !c.IsSet("uts") && pod != nil && pod.SharesUTS() {
+ utsModeStr = "pod"
+ }
+ utsMode := container.UTSMode(utsModeStr)
+ if !cc.Valid(string(utsMode), utsMode) {
return nil, errors.Errorf("--uts %q is not valid", c.String("uts"))
}
- ipcMode := container.IpcMode(c.String("ipc"))
- if !cc.IsNS(string(ipcMode)) && !ipcMode.Valid() {
+
+ ipcModeStr := c.String("ipc")
+ if !c.IsSet("ipc") && pod != nil && pod.SharesIPC() {
+ ipcModeStr = "pod"
+ }
+ ipcMode := container.IpcMode(ipcModeStr)
+ if !cc.Valid(string(ipcMode), ipcMode) {
return nil, errors.Errorf("--ipc %q is not valid", ipcMode)
}
+ netModeStr := c.String("net")
+ if !c.IsSet("net") && pod != nil && pod.SharesNet() {
+ netModeStr = "pod"
+ }
+ // Make sure if network is set to container namespace, port binding is not also being asked for
+ netMode := container.NetworkMode(netModeStr)
+ if netMode.IsContainer() || cc.IsPod(netModeStr) {
+ if len(c.StringSlice("publish")) > 0 || c.Bool("publish-all") {
+ return nil, errors.Errorf("cannot set port bindings on an existing container network namespace")
+ }
+ }
+
shmDir := ""
if ipcMode.IsHost() {
shmDir = "/dev/shm"
@@ -534,14 +572,6 @@ func parseCreateOpts(ctx context.Context, c *cli.Context, runtime *libpod.Runtim
if err != nil {
return nil, errors.Wrapf(err, "unable to translate --shm-size")
}
- // Network
- netMode := container.NetworkMode(c.String("network"))
- // Make sure if network is set to container namespace, port binding is not also being asked for
- if netMode.IsContainer() {
- if len(c.StringSlice("publish")) > 0 || c.Bool("publish-all") {
- return nil, errors.Errorf("cannot set port bindings on an existing container network namespace")
- }
- }
// Verify the additional hosts are in correct format
for _, host := range c.StringSlice("add-host") {
diff --git a/cmd/podman/libpodruntime/runtime.go b/cmd/podman/libpodruntime/runtime.go
index e33b70e9a..af6be0602 100644
--- a/cmd/podman/libpodruntime/runtime.go
+++ b/cmd/podman/libpodruntime/runtime.go
@@ -124,5 +124,14 @@ func GetRuntimeWithStorageOpts(c *cli.Context, storageOpts *storage.StoreOptions
// TODO flag to set CNI plugins dir?
+ // Pod create options
+ if c.IsSet("pause-image") {
+ options = append(options, libpod.WithDefaultPauseImage(c.String("pause-image")))
+ }
+
+ if c.IsSet("pause-command") {
+ options = append(options, libpod.WithDefaultPauseCommand(c.String("pause-command")))
+ }
+
return libpod.NewRuntime(options...)
}
diff --git a/cmd/podman/pod_create.go b/cmd/podman/pod_create.go
index 568ace6e7..6975c9386 100644
--- a/cmd/podman/pod_create.go
+++ b/cmd/podman/pod_create.go
@@ -3,6 +3,7 @@ package main
import (
"fmt"
"os"
+ "strings"
"github.com/containers/libpod/cmd/podman/libpodruntime"
"github.com/containers/libpod/libpod"
@@ -11,6 +12,11 @@ import (
"github.com/urfave/cli"
)
+var (
+ // CRI-O default kernel namespaces
+ DefaultKernelNamespaces = "ipc,net,uts"
+)
+
var podCreateDescription = "Creates a new empty pod. The pod ID is then" +
" printed to stdout. You can then start it at any time with the" +
" podman pod start <pod_id> command. The pod will be created with the" +
@@ -33,10 +39,27 @@ var podCreateFlags = []cli.Flag{
Name: "name, n",
Usage: "Assign a name to the pod",
},
+ cli.BoolTFlag{
+ Name: "pause",
+ Usage: "Create a pause container associated with the pod to share namespaces with",
+ },
+ cli.StringFlag{
+ Name: "pause-image",
+ Usage: "The image of the pause container to associate with the pod",
+ },
+ cli.StringFlag{
+ Name: "pause-command",
+ Usage: "The command to run on the pause container when the pod is started",
+ },
cli.StringFlag{
Name: "pod-id-file",
Usage: "Write the pod ID to the file",
},
+ cli.StringFlag{
+ Name: "share",
+ Usage: "A comma deliminated list of kernel namespaces the pod will share",
+ Value: DefaultKernelNamespaces,
+ },
}
var podCreateCommand = cli.Command{
@@ -71,6 +94,9 @@ func podCreateCmd(c *cli.Context) error {
return errors.Wrapf(err, "unable to write pod id file %s", c.String("pod-id-file"))
}
}
+ if !c.BoolT("pause") && c.IsSet("share") && c.String("share") != "none" && c.String("share") != "" {
+ return errors.Errorf("You cannot share kernel namespaces on the pod level without a pause container")
+ }
if c.IsSet("cgroup-parent") {
options = append(options, libpod.WithPodCgroupParent(c.String("cgroup-parent")))
@@ -88,10 +114,39 @@ func podCreateCmd(c *cli.Context) error {
options = append(options, libpod.WithPodName(c.String("name")))
}
+ if c.BoolT("pause") {
+ options = append(options, libpod.WithPauseContainer())
+ for _, toShare := range strings.Split(c.String("share"), ",") {
+ switch toShare {
+ case "net":
+ options = append(options, libpod.WithPodNet())
+ case "mnt":
+ //options = append(options, libpod.WithPodMNT())
+ logrus.Debug("Mount Namespace sharing functionality not supported")
+ case "pid":
+ options = append(options, libpod.WithPodPID())
+ case "user":
+ // Note: more set up needs to be done before this doesn't error out a create.
+ logrus.Debug("User Namespace sharing functionality not supported")
+ case "ipc":
+ options = append(options, libpod.WithPodIPC())
+ case "uts":
+ options = append(options, libpod.WithPodUTS())
+ case "":
+ case "none":
+ continue
+ default:
+ return errors.Errorf("Invalid kernel namespace to share: %s. Options are: %s, or none", toShare, strings.Join(libpod.KernelNamespaces, ","))
+ }
+ }
+ }
+
// always have containers use pod cgroups
+ // User Opt out is not yet supported
options = append(options, libpod.WithPodCgroups())
- pod, err := runtime.NewPod(options...)
+ ctx := getContext()
+ pod, err := runtime.NewPod(ctx, options...)
if err != nil {
return err
}
diff --git a/cmd/podman/pod_ps.go b/cmd/podman/pod_ps.go
index 20beae53a..20cda1276 100644
--- a/cmd/podman/pod_ps.go
+++ b/cmd/podman/pod_ps.go
@@ -56,8 +56,9 @@ type podPsTemplateParams struct {
NumberOfContainers int
Status string
Cgroup string
- UsePodCgroup bool
ContainerInfo string
+ PauseContainerID string
+ SharedNamespaces string
}
// podPsJSONParams is used as a base structure for the psParams
@@ -73,7 +74,8 @@ type podPsJSONParams struct {
Status string `json:"status"`
CtrsInfo []podPsCtrInfo `json:"containerinfo,omitempty"`
Cgroup string `json:"cgroup,omitempty"`
- UsePodCgroup bool `json:"podcgroup,omitempty"`
+ PauseContainerID string `json:"pausecontainerid,omitempty"`
+ SharedNamespaces []string `json:"sharednamespaces,omitempty"`
}
// Type declaration and functions for sorting the pod PS output
@@ -111,10 +113,6 @@ func (a podPsSortedStatus) Less(i, j int) bool {
var (
podPsFlags = []cli.Flag{
cli.BoolFlag{
- Name: "cgroup",
- Usage: "Print the Cgroup information of the pod",
- },
- cli.BoolFlag{
Name: "ctr-names",
Usage: "Display the container names",
},
@@ -139,6 +137,10 @@ var (
Usage: "Show the latest pod created",
},
cli.BoolFlag{
+ Name: "namespace, ns",
+ Usage: "Display namespace information of the pod",
+ },
+ cli.BoolFlag{
Name: "no-trunc",
Usage: "Do not truncate pod and container IDs",
},
@@ -348,14 +350,15 @@ func genPodPsFormat(c *cli.Context) string {
format = formats.IDString
} else {
format = "table {{.ID}}\t{{.Name}}\t{{.Status}}\t{{.Created}}"
- if c.Bool("cgroup") {
- format += "\t{{.Cgroup}}\t{{.UsePodCgroup}}"
+ if c.Bool("namespace") {
+ format += "\t{{.Cgroup}}\t{{.SharedNamespaces}}"
}
if c.Bool("ctr-names") || c.Bool("ctr-ids") || c.Bool("ctr-status") {
format += "\t{{.ContainerInfo}}"
} else {
format += "\t{{.NumberOfContainers}}"
}
+ format += "\t{{.PauseContainerID}}"
}
return format
}
@@ -415,6 +418,7 @@ func getPodTemplateOutput(psParams []podPsJSONParams, opts podPsOptions) ([]podP
for _, psParam := range psParams {
podID := psParam.ID
+ pauseID := psParam.PauseContainerID
var ctrStr string
truncated := ""
@@ -424,6 +428,7 @@ func getPodTemplateOutput(psParams []podPsJSONParams, opts podPsOptions) ([]podP
psParam.CtrsInfo = psParam.CtrsInfo[:NUM_CTR_INFO]
truncated = "..."
}
+ pauseID = shortID(pauseID)
}
for _, ctrInfo := range psParam.CtrsInfo {
ctrStr += "[ "
@@ -449,9 +454,10 @@ func getPodTemplateOutput(psParams []podPsJSONParams, opts podPsOptions) ([]podP
Name: psParam.Name,
Status: psParam.Status,
NumberOfContainers: psParam.NumberOfContainers,
- UsePodCgroup: psParam.UsePodCgroup,
Cgroup: psParam.Cgroup,
ContainerInfo: ctrStr,
+ PauseContainerID: pauseID,
+ SharedNamespaces: strings.Join(psParam.SharedNamespaces, ","),
}
psOutput = append(psOutput, params)
@@ -460,6 +466,32 @@ func getPodTemplateOutput(psParams []podPsJSONParams, opts podPsOptions) ([]podP
return psOutput, nil
}
+func getSharedNamespaces(pod *libpod.Pod) []string {
+ var shared []string
+ if pod.SharesPID() {
+ shared = append(shared, "pid")
+ }
+ if pod.SharesNet() {
+ shared = append(shared, "net")
+ }
+ if pod.SharesMNT() {
+ shared = append(shared, "mnt")
+ }
+ if pod.SharesIPC() {
+ shared = append(shared, "ipc")
+ }
+ if pod.SharesUser() {
+ shared = append(shared, "user")
+ }
+ if pod.SharesCgroup() {
+ shared = append(shared, "cgroup")
+ }
+ if pod.SharesUTS() {
+ shared = append(shared, "uts")
+ }
+ return shared
+}
+
// getAndSortPodJSONOutput returns the container info in its raw, sorted form
func getAndSortPodJSONParams(pods []*libpod.Pod, opts podPsOptions, runtime *libpod.Runtime) ([]podPsJSONParams, error) {
var (
@@ -478,6 +510,10 @@ func getAndSortPodJSONParams(pods []*libpod.Pod, opts podPsOptions, runtime *lib
return nil, err
}
+ pauseContainerID, err := pod.PauseContainerID()
+ if err != nil {
+ return nil, err
+ }
for _, ctr := range ctrs {
batchInfo, err := shared.BatchContainerOp(ctr, bc_opts)
if err != nil {
@@ -508,9 +544,10 @@ func getAndSortPodJSONParams(pods []*libpod.Pod, opts podPsOptions, runtime *lib
Name: pod.Name(),
Status: status,
Cgroup: pod.CgroupParent(),
- UsePodCgroup: pod.UsePodCgroup(),
NumberOfContainers: ctrNum,
CtrsInfo: ctrsInfo,
+ SharedNamespaces: getSharedNamespaces(pod),
+ PauseContainerID: pauseContainerID,
}
psOutput = append(psOutput, params)
diff --git a/cmd/podman/ps.go b/cmd/podman/ps.go
index 3b53fe6f1..332416d14 100644
--- a/cmd/podman/ps.go
+++ b/cmd/podman/ps.go
@@ -44,6 +44,7 @@ type psTemplateParams struct {
User string
UTS string
Pod string
+ IsPause bool
}
// psJSONParams is used as a base structure for the psParams
@@ -71,6 +72,7 @@ type psJSONParams struct {
ContainerRunning bool `json:"ctrRunning"`
Namespaces *shared.Namespace `json:"namespace,omitempty"`
Pod string `json:"pod,omitempty"`
+ IsPause bool `json:"pause"`
}
// Type declaration and functions for sorting the PS output
@@ -216,7 +218,7 @@ func psCmd(c *cli.Context) error {
return errors.Errorf("too many arguments, ps takes no arguments")
}
- format := genPsFormat(c.String("format"), c.Bool("quiet"), c.Bool("size"), c.Bool("namespace"), c.Bool("pod"))
+ format := genPsFormat(c.String("format"), c.Bool("quiet"), c.Bool("size"), c.Bool("namespace"), c.Bool("pod"), c.Bool("all"))
opts := shared.PsOptions{
All: c.Bool("all"),
@@ -239,7 +241,8 @@ func psCmd(c *cli.Context) error {
// only get running containers
filterFuncs = append(filterFuncs, func(c *libpod.Container) bool {
state, _ := c.State()
- return state == libpod.ContainerStateRunning
+ // Don't return pause containers
+ return state == libpod.ContainerStateRunning && !c.IsPause()
})
}
@@ -417,7 +420,7 @@ func generateContainerFilterFuncs(filter, filterValue string, runtime *libpod.Ru
}
// generate the template based on conditions given
-func genPsFormat(format string, quiet, size, namespace, pod bool) string {
+func genPsFormat(format string, quiet, size, namespace, pod, pause bool) string {
if format != "" {
// "\t" from the command line is not being recognized as a tab
// replacing the string "\t" to a tab character if the user passes in "\t"
@@ -431,13 +434,16 @@ func genPsFormat(format string, quiet, size, namespace, pod bool) string {
podappend = "{{.Pod}}\t"
}
if namespace {
- return fmt.Sprintf("table {{.ID}}\t{{.Names}}\t%s{{.PID}}\t{{.Cgroup}}\t{{.IPC}}\t{{.MNT}}\t{{.NET}}\t{{.PIDNS}}\t{{.User}}\t{{.UTS}}\t", podappend)
+ return fmt.Sprintf("table {{.ID}}\t{{.Names}}\t%s{{.PID}}\t{{.Cgroup}}\t{{.IPC}}\t{{.MNT}}\t{{.NET}}\t{{.PIDNS}}\t{{.User}}\t{{.UTS}}", podappend)
}
format = "table {{.ID}}\t{{.Image}}\t{{.Command}}\t{{.Created}}\t{{.Status}}\t{{.Ports}}\t{{.Names}}\t"
format += podappend
if size {
format += "{{.Size}}\t"
}
+ if pause {
+ format += "{{.IsPause}}\t"
+ }
return format
}
@@ -572,6 +578,7 @@ func getTemplateOutput(psParams []psJSONParams, opts shared.PsOptions) ([]psTemp
Mounts: getMounts(psParam.Mounts, opts.NoTrunc),
PID: psParam.PID,
Pod: pod,
+ IsPause: psParam.IsPause,
}
if opts.Namespace {
@@ -628,6 +635,7 @@ func getAndSortJSONParams(containers []*libpod.Container, opts shared.PsOptions)
ContainerRunning: batchInfo.ConState == libpod.ContainerStateRunning,
Namespaces: ns,
Pod: ctr.PodID(),
+ IsPause: ctr.IsPause(),
}
psOutput = append(psOutput, params)
diff --git a/completions/bash/podman b/completions/bash/podman
index 2bf175982..7aa85053c 100644
--- a/completions/bash/podman
+++ b/completions/bash/podman
@@ -2077,6 +2077,9 @@ _podman_logout() {
_podman_pod_create() {
local options_with_args="
--cgroup-parent
+ --share
+ --pause-command
+ --pause-image
--podidfile
--label-file
--label
@@ -2085,6 +2088,7 @@ _podman_pod_create() {
"
local boolean_options="
+ --pause
"
_complete_ "$options_with_args" "$boolean_options"
}
diff --git a/docs/podman-pod-create.1.md b/docs/podman-pod-create.1.md
index 495c6934a..063dbc918 100644
--- a/docs/podman-pod-create.1.md
+++ b/docs/podman-pod-create.1.md
@@ -39,6 +39,22 @@ Read in a line delimited file of labels
Assign a name to the pod
+**--pause**
+
+Create a pause container and associate it with the pod. A pause container is a lightweight container used to coordinate the shared kernel namespace of a pod. Default: true
+
+**--pause-command**=""
+
+The command that will be run to start the pause container. Default: "/pause"
+
+**--pause-image**=""
+
+The image that will be created for the pause container. Default: "k8s.gcr.io/pause:3.1"
+
+**--share**=""
+
+A comma deliminated list of kernel namespaces to share. If none or "" is specified, no namespaces will be shared. The namespaces to choose from are ipc, net, pid, user, uts.
+
The operator can identify a pod in three ways:
UUID long identifier (“f78375b1c487e03c9438c729345e54db9d20cfa2ac1fc3494b6eb60872e74778”)
UUID short identifier (“f78375b1c487”)
@@ -53,6 +69,10 @@ for it. The name is useful any place you need to identify a pod.
# podman pod create --name test
+# podman pod create --pause=false
+
+# podman pod create --pause-command /top
+
## SEE ALSO
podman-pod(1)
diff --git a/libpod.conf b/libpod.conf
index cef5a12d8..9de42caf2 100644
--- a/libpod.conf
+++ b/libpod.conf
@@ -65,3 +65,9 @@ cni_plugin_dir = [
# The default namespace is "", which corresponds to no namespace. When no
# namespace is set, all containers and pods are visible.
#namespace = ""
+
+# Default pause image name for pod pause containers
+pause_image = "k8s.gcr.io/pause:3.1"
+
+# Default command to run the pause container
+pause_command = "/pause"
diff --git a/libpod/container.go b/libpod/container.go
index b79258c43..2e2d29899 100644
--- a/libpod/container.go
+++ b/libpod/container.go
@@ -252,6 +252,19 @@ type ContainerConfig struct {
UTSNsCtr string `json:"utsNsCtr,omitempty"`
CgroupNsCtr string `json:"cgroupNsCtr,omitempty"`
+ // Whether container shares an NS with the pod
+ // NetNsPod conflicts with the CreateNetNS bool
+ // {namespace}NsPod conflicts with {namespace}NsCtr
+ // The pause container will be considered dependencies of the given container
+ // It must be started before the given container is started
+ IPCNsPod bool `json:"ipcNsPod,omitempty"`
+ MountNsPod bool `json:"mountNsPod,omitempty"`
+ NetNsPod bool `json:"netNsPod,omitempty"`
+ PIDNsPod bool `json:"pidNsPod,omitempty"`
+ UserNsPod bool `json:"userNsPod,omitempty"`
+ UTSNsPod bool `json:"utsNsPod,omitempty"`
+ CgroupNsPod bool `json:"cgroupNsPod,omitempty"`
+
// IDs of dependency containers.
// These containers must be started before this container is started.
Dependencies []string
@@ -328,6 +341,10 @@ type ContainerConfig struct {
// LocalVolumes are the built-in volumes we get from the --volumes-from flag
// It picks up the built-in volumes of the container used by --volumes-from
LocalVolumes []string
+
+ // IsPause is a bool indicating whether this container is a pause container used for
+ // sharing kernel namespaces in a pod
+ IsPause bool `json:"pause"`
}
// ContainerStatus returns a string representation for users
@@ -956,3 +973,8 @@ func (c *Container) RootGID() int {
}
return 0
}
+
+// IsPause returns whether the container is a pause container
+func (c *Container) IsPause() bool {
+ return c.config.IsPause
+}
diff --git a/libpod/container_ffjson.go b/libpod/container_ffjson.go
index d843beb48..02dc10e68 100644
--- a/libpod/container_ffjson.go
+++ b/libpod/container_ffjson.go
@@ -194,6 +194,62 @@ func (j *ContainerConfig) MarshalJSONBuf(buf fflib.EncodingBuffer) error {
fflib.WriteJsonString(buf, string(j.CgroupNsCtr))
buf.WriteByte(',')
}
+ if j.IPCNsPod != false {
+ if j.IPCNsPod {
+ buf.WriteString(`"ipcNsPod":true`)
+ } else {
+ buf.WriteString(`"ipcNsPod":false`)
+ }
+ buf.WriteByte(',')
+ }
+ if j.MountNsPod != false {
+ if j.MountNsPod {
+ buf.WriteString(`"mountNsPod":true`)
+ } else {
+ buf.WriteString(`"mountNsPod":false`)
+ }
+ buf.WriteByte(',')
+ }
+ if j.NetNsPod != false {
+ if j.NetNsPod {
+ buf.WriteString(`"netNsPod":true`)
+ } else {
+ buf.WriteString(`"netNsPod":false`)
+ }
+ buf.WriteByte(',')
+ }
+ if j.PIDNsPod != false {
+ if j.PIDNsPod {
+ buf.WriteString(`"pidNsPod":true`)
+ } else {
+ buf.WriteString(`"pidNsPod":false`)
+ }
+ buf.WriteByte(',')
+ }
+ if j.UserNsPod != false {
+ if j.UserNsPod {
+ buf.WriteString(`"userNsPod":true`)
+ } else {
+ buf.WriteString(`"userNsPod":false`)
+ }
+ buf.WriteByte(',')
+ }
+ if j.UTSNsPod != false {
+ if j.UTSNsPod {
+ buf.WriteString(`"utsNsPod":true`)
+ } else {
+ buf.WriteString(`"utsNsPod":false`)
+ }
+ buf.WriteByte(',')
+ }
+ if j.CgroupNsPod != false {
+ if j.CgroupNsPod {
+ buf.WriteString(`"cgroupNsPod":true`)
+ } else {
+ buf.WriteString(`"cgroupNsPod":false`)
+ }
+ buf.WriteByte(',')
+ }
buf.WriteString(`"Dependencies":`)
if j.Dependencies != nil {
buf.WriteString(`[`)
@@ -461,6 +517,11 @@ func (j *ContainerConfig) MarshalJSONBuf(buf fflib.EncodingBuffer) error {
} else {
buf.WriteString(`null`)
}
+ if j.IsPause {
+ buf.WriteString(`,"pause":true`)
+ } else {
+ buf.WriteString(`,"pause":false`)
+ }
buf.WriteByte('}')
return nil
}
@@ -521,6 +582,20 @@ const (
ffjtContainerConfigCgroupNsCtr
+ ffjtContainerConfigIPCNsPod
+
+ ffjtContainerConfigMountNsPod
+
+ ffjtContainerConfigNetNsPod
+
+ ffjtContainerConfigPIDNsPod
+
+ ffjtContainerConfigUserNsPod
+
+ ffjtContainerConfigUTSNsPod
+
+ ffjtContainerConfigCgroupNsPod
+
ffjtContainerConfigDependencies
ffjtContainerConfigCreateNetNS
@@ -564,6 +639,8 @@ const (
ffjtContainerConfigExitCommand
ffjtContainerConfigLocalVolumes
+
+ ffjtContainerConfigIsPause
)
var ffjKeyContainerConfigSpec = []byte("spec")
@@ -618,6 +695,20 @@ var ffjKeyContainerConfigUTSNsCtr = []byte("utsNsCtr")
var ffjKeyContainerConfigCgroupNsCtr = []byte("cgroupNsCtr")
+var ffjKeyContainerConfigIPCNsPod = []byte("ipcNsPod")
+
+var ffjKeyContainerConfigMountNsPod = []byte("mountNsPod")
+
+var ffjKeyContainerConfigNetNsPod = []byte("netNsPod")
+
+var ffjKeyContainerConfigPIDNsPod = []byte("pidNsPod")
+
+var ffjKeyContainerConfigUserNsPod = []byte("userNsPod")
+
+var ffjKeyContainerConfigUTSNsPod = []byte("utsNsPod")
+
+var ffjKeyContainerConfigCgroupNsPod = []byte("cgroupNsPod")
+
var ffjKeyContainerConfigDependencies = []byte("Dependencies")
var ffjKeyContainerConfigCreateNetNS = []byte("createNetNS")
@@ -662,6 +753,8 @@ var ffjKeyContainerConfigExitCommand = []byte("exitCommand")
var ffjKeyContainerConfigLocalVolumes = []byte("LocalVolumes")
+var ffjKeyContainerConfigIsPause = []byte("pause")
+
// UnmarshalJSON umarshall json - template of ffjson
func (j *ContainerConfig) UnmarshalJSON(input []byte) error {
fs := fflib.NewFFLexer(input)
@@ -770,6 +863,11 @@ mainparse:
state = fflib.FFParse_want_colon
goto mainparse
+ } else if bytes.Equal(ffjKeyContainerConfigCgroupNsPod, kn) {
+ currentKey = ffjtContainerConfigCgroupNsPod
+ state = fflib.FFParse_want_colon
+ goto mainparse
+
} else if bytes.Equal(ffjKeyContainerConfigCreateNetNS, kn) {
currentKey = ffjtContainerConfigCreateNetNS
state = fflib.FFParse_want_colon
@@ -864,6 +962,11 @@ mainparse:
currentKey = ffjtContainerConfigIPCNsCtr
state = fflib.FFParse_want_colon
goto mainparse
+
+ } else if bytes.Equal(ffjKeyContainerConfigIPCNsPod, kn) {
+ currentKey = ffjtContainerConfigIPCNsPod
+ state = fflib.FFParse_want_colon
+ goto mainparse
}
case 'l':
@@ -890,6 +993,11 @@ mainparse:
currentKey = ffjtContainerConfigMountNsCtr
state = fflib.FFParse_want_colon
goto mainparse
+
+ } else if bytes.Equal(ffjKeyContainerConfigMountNsPod, kn) {
+ currentKey = ffjtContainerConfigMountNsPod
+ state = fflib.FFParse_want_colon
+ goto mainparse
}
case 'n':
@@ -909,6 +1017,11 @@ mainparse:
state = fflib.FFParse_want_colon
goto mainparse
+ } else if bytes.Equal(ffjKeyContainerConfigNetNsPod, kn) {
+ currentKey = ffjtContainerConfigNetNsPod
+ state = fflib.FFParse_want_colon
+ goto mainparse
+
} else if bytes.Equal(ffjKeyContainerConfigNetworks, kn) {
currentKey = ffjtContainerConfigNetworks
state = fflib.FFParse_want_colon
@@ -932,6 +1045,11 @@ mainparse:
state = fflib.FFParse_want_colon
goto mainparse
+ } else if bytes.Equal(ffjKeyContainerConfigPIDNsPod, kn) {
+ currentKey = ffjtContainerConfigPIDNsPod
+ state = fflib.FFParse_want_colon
+ goto mainparse
+
} else if bytes.Equal(ffjKeyContainerConfigPortMappings, kn) {
currentKey = ffjtContainerConfigPortMappings
state = fflib.FFParse_want_colon
@@ -941,6 +1059,11 @@ mainparse:
currentKey = ffjtContainerConfigPostConfigureNetNS
state = fflib.FFParse_want_colon
goto mainparse
+
+ } else if bytes.Equal(ffjKeyContainerConfigIsPause, kn) {
+ currentKey = ffjtContainerConfigIsPause
+ state = fflib.FFParse_want_colon
+ goto mainparse
}
case 'r':
@@ -1011,6 +1134,16 @@ mainparse:
state = fflib.FFParse_want_colon
goto mainparse
+ } else if bytes.Equal(ffjKeyContainerConfigUserNsPod, kn) {
+ currentKey = ffjtContainerConfigUserNsPod
+ state = fflib.FFParse_want_colon
+ goto mainparse
+
+ } else if bytes.Equal(ffjKeyContainerConfigUTSNsPod, kn) {
+ currentKey = ffjtContainerConfigUTSNsPod
+ state = fflib.FFParse_want_colon
+ goto mainparse
+
} else if bytes.Equal(ffjKeyContainerConfigUserVolumes, kn) {
currentKey = ffjtContainerConfigUserVolumes
state = fflib.FFParse_want_colon
@@ -1019,6 +1152,12 @@ mainparse:
}
+ if fflib.EqualFoldRight(ffjKeyContainerConfigIsPause, kn) {
+ currentKey = ffjtContainerConfigIsPause
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
if fflib.EqualFoldRight(ffjKeyContainerConfigLocalVolumes, kn) {
currentKey = ffjtContainerConfigLocalVolumes
state = fflib.FFParse_want_colon
@@ -1151,6 +1290,48 @@ mainparse:
goto mainparse
}
+ if fflib.EqualFoldRight(ffjKeyContainerConfigCgroupNsPod, kn) {
+ currentKey = ffjtContainerConfigCgroupNsPod
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ if fflib.EqualFoldRight(ffjKeyContainerConfigUTSNsPod, kn) {
+ currentKey = ffjtContainerConfigUTSNsPod
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ if fflib.EqualFoldRight(ffjKeyContainerConfigUserNsPod, kn) {
+ currentKey = ffjtContainerConfigUserNsPod
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ if fflib.EqualFoldRight(ffjKeyContainerConfigPIDNsPod, kn) {
+ currentKey = ffjtContainerConfigPIDNsPod
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ if fflib.EqualFoldRight(ffjKeyContainerConfigNetNsPod, kn) {
+ currentKey = ffjtContainerConfigNetNsPod
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ if fflib.EqualFoldRight(ffjKeyContainerConfigMountNsPod, kn) {
+ currentKey = ffjtContainerConfigMountNsPod
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ if fflib.EqualFoldRight(ffjKeyContainerConfigIPCNsPod, kn) {
+ currentKey = ffjtContainerConfigIPCNsPod
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
if fflib.EqualFoldRight(ffjKeyContainerConfigCgroupNsCtr, kn) {
currentKey = ffjtContainerConfigCgroupNsCtr
state = fflib.FFParse_want_colon
@@ -1402,6 +1583,27 @@ mainparse:
case ffjtContainerConfigCgroupNsCtr:
goto handle_CgroupNsCtr
+ case ffjtContainerConfigIPCNsPod:
+ goto handle_IPCNsPod
+
+ case ffjtContainerConfigMountNsPod:
+ goto handle_MountNsPod
+
+ case ffjtContainerConfigNetNsPod:
+ goto handle_NetNsPod
+
+ case ffjtContainerConfigPIDNsPod:
+ goto handle_PIDNsPod
+
+ case ffjtContainerConfigUserNsPod:
+ goto handle_UserNsPod
+
+ case ffjtContainerConfigUTSNsPod:
+ goto handle_UTSNsPod
+
+ case ffjtContainerConfigCgroupNsPod:
+ goto handle_CgroupNsPod
+
case ffjtContainerConfigDependencies:
goto handle_Dependencies
@@ -1468,6 +1670,9 @@ mainparse:
case ffjtContainerConfigLocalVolumes:
goto handle_LocalVolumes
+ case ffjtContainerConfigIsPause:
+ goto handle_IsPause
+
case ffjtContainerConfignosuchkey:
err = fs.SkipField(tok)
if err != nil {
@@ -2264,6 +2469,251 @@ handle_CgroupNsCtr:
state = fflib.FFParse_after_value
goto mainparse
+handle_IPCNsPod:
+
+ /* handler: j.IPCNsPod type=bool kind=bool quoted=false*/
+
+ {
+ if tok != fflib.FFTok_bool && tok != fflib.FFTok_null {
+ return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for bool", tok))
+ }
+ }
+
+ {
+ if tok == fflib.FFTok_null {
+
+ } else {
+ tmpb := fs.Output.Bytes()
+
+ if bytes.Compare([]byte{'t', 'r', 'u', 'e'}, tmpb) == 0 {
+
+ j.IPCNsPod = true
+
+ } else if bytes.Compare([]byte{'f', 'a', 'l', 's', 'e'}, tmpb) == 0 {
+
+ j.IPCNsPod = false
+
+ } else {
+ err = errors.New("unexpected bytes for true/false value")
+ return fs.WrapErr(err)
+ }
+
+ }
+ }
+
+ state = fflib.FFParse_after_value
+ goto mainparse
+
+handle_MountNsPod:
+
+ /* handler: j.MountNsPod type=bool kind=bool quoted=false*/
+
+ {
+ if tok != fflib.FFTok_bool && tok != fflib.FFTok_null {
+ return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for bool", tok))
+ }
+ }
+
+ {
+ if tok == fflib.FFTok_null {
+
+ } else {
+ tmpb := fs.Output.Bytes()
+
+ if bytes.Compare([]byte{'t', 'r', 'u', 'e'}, tmpb) == 0 {
+
+ j.MountNsPod = true
+
+ } else if bytes.Compare([]byte{'f', 'a', 'l', 's', 'e'}, tmpb) == 0 {
+
+ j.MountNsPod = false
+
+ } else {
+ err = errors.New("unexpected bytes for true/false value")
+ return fs.WrapErr(err)
+ }
+
+ }
+ }
+
+ state = fflib.FFParse_after_value
+ goto mainparse
+
+handle_NetNsPod:
+
+ /* handler: j.NetNsPod type=bool kind=bool quoted=false*/
+
+ {
+ if tok != fflib.FFTok_bool && tok != fflib.FFTok_null {
+ return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for bool", tok))
+ }
+ }
+
+ {
+ if tok == fflib.FFTok_null {
+
+ } else {
+ tmpb := fs.Output.Bytes()
+
+ if bytes.Compare([]byte{'t', 'r', 'u', 'e'}, tmpb) == 0 {
+
+ j.NetNsPod = true
+
+ } else if bytes.Compare([]byte{'f', 'a', 'l', 's', 'e'}, tmpb) == 0 {
+
+ j.NetNsPod = false
+
+ } else {
+ err = errors.New("unexpected bytes for true/false value")
+ return fs.WrapErr(err)
+ }
+
+ }
+ }
+
+ state = fflib.FFParse_after_value
+ goto mainparse
+
+handle_PIDNsPod:
+
+ /* handler: j.PIDNsPod type=bool kind=bool quoted=false*/
+
+ {
+ if tok != fflib.FFTok_bool && tok != fflib.FFTok_null {
+ return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for bool", tok))
+ }
+ }
+
+ {
+ if tok == fflib.FFTok_null {
+
+ } else {
+ tmpb := fs.Output.Bytes()
+
+ if bytes.Compare([]byte{'t', 'r', 'u', 'e'}, tmpb) == 0 {
+
+ j.PIDNsPod = true
+
+ } else if bytes.Compare([]byte{'f', 'a', 'l', 's', 'e'}, tmpb) == 0 {
+
+ j.PIDNsPod = false
+
+ } else {
+ err = errors.New("unexpected bytes for true/false value")
+ return fs.WrapErr(err)
+ }
+
+ }
+ }
+
+ state = fflib.FFParse_after_value
+ goto mainparse
+
+handle_UserNsPod:
+
+ /* handler: j.UserNsPod type=bool kind=bool quoted=false*/
+
+ {
+ if tok != fflib.FFTok_bool && tok != fflib.FFTok_null {
+ return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for bool", tok))
+ }
+ }
+
+ {
+ if tok == fflib.FFTok_null {
+
+ } else {
+ tmpb := fs.Output.Bytes()
+
+ if bytes.Compare([]byte{'t', 'r', 'u', 'e'}, tmpb) == 0 {
+
+ j.UserNsPod = true
+
+ } else if bytes.Compare([]byte{'f', 'a', 'l', 's', 'e'}, tmpb) == 0 {
+
+ j.UserNsPod = false
+
+ } else {
+ err = errors.New("unexpected bytes for true/false value")
+ return fs.WrapErr(err)
+ }
+
+ }
+ }
+
+ state = fflib.FFParse_after_value
+ goto mainparse
+
+handle_UTSNsPod:
+
+ /* handler: j.UTSNsPod type=bool kind=bool quoted=false*/
+
+ {
+ if tok != fflib.FFTok_bool && tok != fflib.FFTok_null {
+ return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for bool", tok))
+ }
+ }
+
+ {
+ if tok == fflib.FFTok_null {
+
+ } else {
+ tmpb := fs.Output.Bytes()
+
+ if bytes.Compare([]byte{'t', 'r', 'u', 'e'}, tmpb) == 0 {
+
+ j.UTSNsPod = true
+
+ } else if bytes.Compare([]byte{'f', 'a', 'l', 's', 'e'}, tmpb) == 0 {
+
+ j.UTSNsPod = false
+
+ } else {
+ err = errors.New("unexpected bytes for true/false value")
+ return fs.WrapErr(err)
+ }
+
+ }
+ }
+
+ state = fflib.FFParse_after_value
+ goto mainparse
+
+handle_CgroupNsPod:
+
+ /* handler: j.CgroupNsPod type=bool kind=bool quoted=false*/
+
+ {
+ if tok != fflib.FFTok_bool && tok != fflib.FFTok_null {
+ return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for bool", tok))
+ }
+ }
+
+ {
+ if tok == fflib.FFTok_null {
+
+ } else {
+ tmpb := fs.Output.Bytes()
+
+ if bytes.Compare([]byte{'t', 'r', 'u', 'e'}, tmpb) == 0 {
+
+ j.CgroupNsPod = true
+
+ } else if bytes.Compare([]byte{'f', 'a', 'l', 's', 'e'}, tmpb) == 0 {
+
+ j.CgroupNsPod = false
+
+ } else {
+ err = errors.New("unexpected bytes for true/false value")
+ return fs.WrapErr(err)
+ }
+
+ }
+ }
+
+ state = fflib.FFParse_after_value
+ goto mainparse
+
handle_Dependencies:
/* handler: j.Dependencies type=[]string kind=slice quoted=false*/
@@ -3523,6 +3973,41 @@ handle_LocalVolumes:
state = fflib.FFParse_after_value
goto mainparse
+handle_IsPause:
+
+ /* handler: j.IsPause type=bool kind=bool quoted=false*/
+
+ {
+ if tok != fflib.FFTok_bool && tok != fflib.FFTok_null {
+ return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for bool", tok))
+ }
+ }
+
+ {
+ if tok == fflib.FFTok_null {
+
+ } else {
+ tmpb := fs.Output.Bytes()
+
+ if bytes.Compare([]byte{'t', 'r', 'u', 'e'}, tmpb) == 0 {
+
+ j.IsPause = true
+
+ } else if bytes.Compare([]byte{'f', 'a', 'l', 's', 'e'}, tmpb) == 0 {
+
+ j.IsPause = false
+
+ } else {
+ err = errors.New("unexpected bytes for true/false value")
+ return fs.WrapErr(err)
+ }
+
+ }
+ }
+
+ state = fflib.FFParse_after_value
+ goto mainparse
+
wantedvalue:
return fs.WrapErr(fmt.Errorf("wanted value token, but got token: %v", tok))
wrongtokenerror:
diff --git a/libpod/container_inspect.go b/libpod/container_inspect.go
index a7ee911a6..18a8b9b83 100644
--- a/libpod/container_inspect.go
+++ b/libpod/container_inspect.go
@@ -104,6 +104,7 @@ func (c *Container) getContainerInspectData(size bool, driverData *inspect.Data)
IPv6Gateway: "",
MacAddress: "", // TODO
},
+ IsPause: c.IsPause(),
}
// Copy port mappings into network settings
diff --git a/libpod/container_internal.go b/libpod/container_internal.go
index 32036ca7a..e276e0194 100644
--- a/libpod/container_internal.go
+++ b/libpod/container_internal.go
@@ -11,7 +11,6 @@ import (
"path/filepath"
"strings"
"syscall"
- "time"
"github.com/containers/libpod/pkg/chrootuser"
"github.com/containers/libpod/pkg/hooks"
@@ -23,13 +22,11 @@ import (
"github.com/containers/storage/pkg/archive"
"github.com/containers/storage/pkg/chrootarchive"
"github.com/containers/storage/pkg/mount"
- "github.com/containers/storage/pkg/stringid"
spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/opencontainers/runtime-tools/generate"
"github.com/opencontainers/selinux/go-selinux/label"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
- "github.com/ulule/deepcopier"
"golang.org/x/text/language"
)
@@ -174,38 +171,6 @@ func (c *Container) syncContainer() error {
return nil
}
-// Make a new container
-func newContainer(rspec *spec.Spec, lockDir string) (*Container, error) {
- if rspec == nil {
- return nil, errors.Wrapf(ErrInvalidArg, "must provide a valid runtime spec to create container")
- }
-
- ctr := new(Container)
- ctr.config = new(ContainerConfig)
- ctr.state = new(containerState)
-
- ctr.config.ID = stringid.GenerateNonCryptoID()
-
- ctr.config.Spec = new(spec.Spec)
- deepcopier.Copy(rspec).To(ctr.config.Spec)
- ctr.config.CreatedTime = time.Now()
-
- ctr.config.ShmSize = DefaultShmSize
-
- ctr.state.BindMounts = make(map[string]string)
-
- // Path our lock file will reside at
- lockPath := filepath.Join(lockDir, ctr.config.ID)
- // Grab a lockfile at the given path
- lock, err := storage.GetLockfile(lockPath)
- if err != nil {
- return nil, errors.Wrapf(err, "error creating lockfile for new container")
- }
- ctr.lock = lock
-
- return ctr, nil
-}
-
// Create container root filesystem for use
func (c *Container) setupStorage(ctx context.Context) error {
if !c.valid {
diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go
index ba02c9f5a..efd808b57 100644
--- a/libpod/container_internal_linux.go
+++ b/libpod/container_internal_linux.go
@@ -168,42 +168,91 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
}
}
+ var podInfraContainer string
+ if c.config.Pod != "" {
+ pod, err := c.runtime.state.LookupPod(c.config.Pod)
+ if err != nil {
+ return nil, err
+ }
+ if pod.SharesNamespaces() {
+ if err := pod.updatePod(); err != nil {
+ return nil, err
+ }
+ podInfraContainer = pod.state.PauseContainerID
+ }
+ }
+
// Add shared namespaces from other containers
if c.config.IPCNsCtr != "" {
if err := c.addNamespaceContainer(&g, IPCNS, c.config.IPCNsCtr, spec.IPCNamespace); err != nil {
return nil, err
}
}
+ if c.config.IPCNsPod && podInfraContainer != "" {
+ if err := c.addNamespaceContainer(&g, IPCNS, podInfraContainer, spec.IPCNamespace); err != nil {
+ return nil, err
+ }
+ }
if c.config.MountNsCtr != "" {
if err := c.addNamespaceContainer(&g, MountNS, c.config.MountNsCtr, spec.MountNamespace); err != nil {
return nil, err
}
}
+ if c.config.MountNsPod && podInfraContainer != "" {
+ if err := c.addNamespaceContainer(&g, MountNS, podInfraContainer, spec.MountNamespace); err != nil {
+ return nil, err
+ }
+ }
if c.config.NetNsCtr != "" {
if err := c.addNamespaceContainer(&g, NetNS, c.config.NetNsCtr, spec.NetworkNamespace); err != nil {
return nil, err
}
}
+ if c.config.NetNsPod && podInfraContainer != "" {
+ if err := c.addNamespaceContainer(&g, NetNS, podInfraContainer, spec.NetworkNamespace); err != nil {
+ return nil, err
+ }
+ }
if c.config.PIDNsCtr != "" {
if err := c.addNamespaceContainer(&g, PIDNS, c.config.PIDNsCtr, string(spec.PIDNamespace)); err != nil {
return nil, err
}
}
+ if c.config.PIDNsPod && podInfraContainer != "" {
+ if err := c.addNamespaceContainer(&g, PIDNS, podInfraContainer, string(spec.PIDNamespace)); err != nil {
+ return nil, err
+ }
+ }
if c.config.UserNsCtr != "" {
if err := c.addNamespaceContainer(&g, UserNS, c.config.UserNsCtr, spec.UserNamespace); err != nil {
return nil, err
}
}
+ if c.config.UserNsPod && podInfraContainer != "" {
+ if err := c.addNamespaceContainer(&g, UserNS, podInfraContainer, spec.UserNamespace); err != nil {
+ return nil, err
+ }
+ }
if c.config.UTSNsCtr != "" {
if err := c.addNamespaceContainer(&g, UTSNS, c.config.UTSNsCtr, spec.UTSNamespace); err != nil {
return nil, err
}
}
+ if c.config.UTSNsPod && podInfraContainer != "" {
+ if err := c.addNamespaceContainer(&g, UTSNS, podInfraContainer, spec.UTSNamespace); err != nil {
+ return nil, err
+ }
+ }
if c.config.CgroupNsCtr != "" {
if err := c.addNamespaceContainer(&g, CgroupNS, c.config.CgroupNsCtr, spec.CgroupNamespace); err != nil {
return nil, err
}
}
+ if c.config.CgroupNsPod && podInfraContainer != "" {
+ if err := c.addNamespaceContainer(&g, CgroupNS, podInfraContainer, spec.CgroupNamespace); err != nil {
+ return nil, err
+ }
+ }
if c.config.Rootfs == "" {
if err := idtools.MkdirAllAs(c.state.RealMountpoint, 0700, c.RootUID(), c.RootGID()); err != nil {
diff --git a/libpod/options.go b/libpod/options.go
index 7bb4a3632..c5e32d20e 100644
--- a/libpod/options.go
+++ b/libpod/options.go
@@ -304,6 +304,37 @@ func WithNamespace(ns string) RuntimeOption {
}
}
+// WithDefaultPauseImage sets the pause image for libpod.
+// A pause image is used for inter-container kernel
+// namespace sharing within a pod. Typically, a pause
+// container is lightweight and is there to reap
+// zombie processes within its pid namespace.
+func WithDefaultPauseImage(img string) RuntimeOption {
+ return func(rt *Runtime) error {
+ if rt.valid {
+ return ErrRuntimeFinalized
+ }
+
+ rt.config.PauseImage = img
+
+ return nil
+ }
+}
+
+// WithDefaultPauseCommand sets the command to
+// run on pause container start up.
+func WithDefaultPauseCommand(cmd string) RuntimeOption {
+ return func(rt *Runtime) error {
+ if rt.valid {
+ return ErrRuntimeFinalized
+ }
+
+ rt.config.PauseCommand = cmd
+
+ return nil
+ }
+}
+
// Container Creation Options
// WithShmDir sets the directory that should be mounted on /dev/shm.
@@ -518,6 +549,132 @@ func WithExitCommand(exitCommand []string) CtrCreateOption {
}
}
+// WithIPCNSFromPod indicates the the container should join the IPC namespace of
+// its pod
+func WithIPCNSFromPod() CtrCreateOption {
+ return func(ctr *Container) error {
+ if ctr.valid {
+ return ErrCtrFinalized
+ }
+
+ if ctr.config.Pod == "" {
+ return errors.Wrapf(ErrInvalidArg, "container is not a member of any pod")
+ }
+
+ ctr.config.IPCNsPod = true
+
+ return nil
+ }
+}
+
+// WithMountNSFromPod indicates the the container should join the Mount namespace of
+// its pod
+func WithMountNSFromPod() CtrCreateOption {
+ return func(ctr *Container) error {
+ if ctr.valid {
+ return ErrCtrFinalized
+ }
+
+ if ctr.config.Pod == "" {
+ return errors.Wrapf(ErrInvalidArg, "container is not a member of any pod")
+ }
+
+ ctr.config.MountNsPod = true
+
+ return nil
+ }
+}
+
+// WithNetNSFromPod indicates the the container should join the network namespace of
+// its pod
+func WithNetNSFromPod() CtrCreateOption {
+ return func(ctr *Container) error {
+ if ctr.valid {
+ return ErrCtrFinalized
+ }
+
+ if ctr.config.Pod == "" {
+ return errors.Wrapf(ErrInvalidArg, "container is not a member of any pod")
+ }
+
+ ctr.config.NetNsPod = true
+
+ return nil
+ }
+}
+
+// WithPIDNSFromPod indicates the the container should join the PID namespace of
+// its pod
+func WithPIDNSFromPod() CtrCreateOption {
+ return func(ctr *Container) error {
+ if ctr.valid {
+ return ErrCtrFinalized
+ }
+
+ if ctr.config.Pod == "" {
+ return errors.Wrapf(ErrInvalidArg, "container is not a member of any pod")
+ }
+
+ ctr.config.PIDNsPod = true
+
+ return nil
+ }
+}
+
+// WithUTSNSFromPod indicates the the container should join the UTS namespace of
+// its pod
+func WithUTSNSFromPod() CtrCreateOption {
+ return func(ctr *Container) error {
+ if ctr.valid {
+ return ErrCtrFinalized
+ }
+
+ if ctr.config.Pod == "" {
+ return errors.Wrapf(ErrInvalidArg, "container is not a member of any pod")
+ }
+
+ ctr.config.UTSNsPod = true
+
+ return nil
+ }
+}
+
+// WithUserNSFromPod indicates the the container should join the User namespace of
+// its pod
+func WithUserNSFromPod() CtrCreateOption {
+ return func(ctr *Container) error {
+ if ctr.valid {
+ return ErrCtrFinalized
+ }
+
+ if ctr.config.Pod == "" {
+ return errors.Wrapf(ErrInvalidArg, "container is not a member of any pod")
+ }
+
+ ctr.config.UserNsPod = true
+
+ return nil
+ }
+}
+
+// WithCgroupNSFromPod indicates the the container should join the Cgroup namespace of
+// its pod
+func WithCgroupNSFromPod() CtrCreateOption {
+ return func(ctr *Container) error {
+ if ctr.valid {
+ return ErrCtrFinalized
+ }
+
+ if ctr.config.Pod == "" {
+ return errors.Wrapf(ErrInvalidArg, "container is not a member of any pod")
+ }
+
+ ctr.config.CgroupNsPod = true
+
+ return nil
+ }
+}
+
// WithIPCNSFrom indicates the the container should join the IPC namespace of
// the given container.
// If the container has joined a pod, it can only join the namespaces of
@@ -999,6 +1156,20 @@ func WithCtrNamespace(ns string) CtrCreateOption {
}
}
+// withIsPause sets the container to be a pause container. This means the container will be sometimes hidden
+// and expected to be the first container in the pod.
+func withIsPause() CtrCreateOption {
+ return func(ctr *Container) error {
+ if ctr.valid {
+ return ErrCtrFinalized
+ }
+
+ ctr.config.IsPause = true
+
+ return nil
+ }
+}
+
// Pod Creation Options
// WithPodName sets the name of the pod.
@@ -1080,3 +1251,112 @@ func WithPodNamespace(ns string) PodCreateOption {
return nil
}
}
+
+// WithPodIPC tells containers in this pod to use the ipc namespace
+// created for this pod.
+// Containers in a pod will inherit the kernel namespaces from the
+// first container added.
+func WithPodIPC() PodCreateOption {
+ return func(pod *Pod) error {
+ if pod.valid {
+ return ErrPodFinalized
+ }
+
+ pod.config.UsePodIPC = true
+
+ return nil
+ }
+}
+
+// WithPodNet tells containers in this pod to use the network namespace
+// created for this pod.
+// Containers in a pod will inherit the kernel namespaces from the
+// first container added.
+func WithPodNet() PodCreateOption {
+ return func(pod *Pod) error {
+ if pod.valid {
+ return ErrPodFinalized
+ }
+
+ pod.config.UsePodNet = true
+
+ return nil
+ }
+}
+
+// WithPodMNT tells containers in this pod to use the mount namespace
+// created for this pod.
+// Containers in a pod will inherit the kernel namespaces from the
+// first container added.
+func WithPodMNT() PodCreateOption {
+ return func(pod *Pod) error {
+ if pod.valid {
+ return ErrPodFinalized
+ }
+
+ pod.config.UsePodMNT = true
+
+ return nil
+ }
+}
+
+// WithPodUser tells containers in this pod to use the user namespace
+// created for this pod.
+// Containers in a pod will inherit the kernel namespaces from the
+// first container added.
+func WithPodUser() PodCreateOption {
+ return func(pod *Pod) error {
+ if pod.valid {
+ return ErrPodFinalized
+ }
+
+ pod.config.UsePodUser = true
+
+ return nil
+ }
+}
+
+// WithPodPID tells containers in this pod to use the pid namespace
+// created for this pod.
+// Containers in a pod will inherit the kernel namespaces from the
+// first container added.
+func WithPodPID() PodCreateOption {
+ return func(pod *Pod) error {
+ if pod.valid {
+ return ErrPodFinalized
+ }
+
+ pod.config.UsePodPID = true
+
+ return nil
+ }
+}
+
+// WithPodUTS tells containers in this pod to use the uts namespace
+// created for this pod.
+// Containers in a pod will inherit the kernel namespaces from the
+// first container added.
+func WithPodUTS() PodCreateOption {
+ return func(pod *Pod) error {
+ if pod.valid {
+ return ErrPodFinalized
+ }
+
+ pod.config.UsePodUTS = true
+
+ return nil
+ }
+}
+
+// WithPauseContainer tells the pod to create a pause container
+func WithPauseContainer() PodCreateOption {
+ return func(pod *Pod) error {
+ if pod.valid {
+ return ErrPodFinalized
+ }
+
+ pod.config.PauseContainer.HasPauseContainer = true
+
+ return nil
+ }
+}
diff --git a/libpod/pod.go b/libpod/pod.go
index 666480aa8..e70cd9138 100644
--- a/libpod/pod.go
+++ b/libpod/pod.go
@@ -7,6 +7,11 @@ import (
"github.com/pkg/errors"
)
+var (
+ // KernelNamespaces is a list of the kernel namespaces a pod can share
+ KernelNamespaces = []string{"ipc", "net", "pid", "user", "mnt", "uts", "cgroup"}
+)
+
// Pod represents a group of containers that are managed together.
// Any operations on a Pod that access state must begin with a call to
// updatePod().
@@ -18,6 +23,7 @@ import (
// function takes the pod lock and accesses any part of state, it should
// updatePod() immediately after locking.
// ffjson: skip
+// Pod represents a group of containers that may share namespaces
type Pod struct {
config *PodConfig
state *podState
@@ -38,11 +44,23 @@ type PodConfig struct {
Labels map[string]string `json:"labels"`
// CgroupParent contains the pod's CGroup parent
CgroupParent string `json:"cgroupParent"`
+
// UsePodCgroup indicates whether the pod will create its own CGroup and
// join containers to it.
// If true, all containers joined to the pod will use the pod cgroup as
// their cgroup parent, and cannot set a different cgroup parent
- UsePodCgroup bool `json:"usePodCgroup"`
+ UsePodCgroup bool `json:"sharesCgroup,omitempty"`
+
+ // The following UsePod{kernelNamespace} indicate whether the containers
+ // in the pod will inherit the namespace from the first container in the pod.
+ UsePodPID bool `json:"sharesPid,omitempty"`
+ UsePodIPC bool `json:"sharesIpc,omitempty"`
+ UsePodNet bool `json:"sharesNet,omitempty"`
+ UsePodMNT bool `json:"sharesMnt,omitempty"`
+ UsePodUser bool `json:"sharesUser,omitempty"`
+ UsePodUTS bool `json:"sharesUts,omitempty"`
+
+ PauseContainer *PauseContainerConfig `json:"pauseConfig"`
// Time pod was created
CreatedTime time.Time `json:"created"`
@@ -52,6 +70,9 @@ type PodConfig struct {
type podState struct {
// CgroupPath is the path to the pod's CGroup
CgroupPath string `json:"cgroupPath"`
+ // PauseContainerID is the container that holds pod namespace information
+ // Most often a pause container
+ PauseContainerID string
}
// PodInspect represents the data we want to display for
@@ -64,7 +85,8 @@ type PodInspect struct {
// PodInspectState contains inspect data on the pod's state
type PodInspectState struct {
- CgroupPath string `json:"cgroupPath"`
+ CgroupPath string `json:"cgroupPath"`
+ PauseContainerID string `json:"pauseContainerID"`
}
// PodContainerInfo keeps information on a container in a pod
@@ -73,6 +95,11 @@ type PodContainerInfo struct {
State string `json:"state"`
}
+// PauseContainerConfig is the configuration for the pod's pause container
+type PauseContainerConfig struct {
+ HasPauseContainer bool `json:"makePauseContainer"`
+}
+
// ID retrieves the pod's ID
func (p *Pod) ID() string {
return p.config.ID
@@ -109,9 +136,45 @@ func (p *Pod) CgroupParent() string {
return p.config.CgroupParent
}
-// UsePodCgroup returns whether containers in the pod will default to this pod's
+// SharesPID returns whether containers in pod
+// default to use PID namespace of first container in pod
+func (p *Pod) SharesPID() bool {
+ return p.config.UsePodPID
+}
+
+// SharesIPC returns whether containers in pod
+// default to use IPC namespace of first container in pod
+func (p *Pod) SharesIPC() bool {
+ return p.config.UsePodIPC
+}
+
+// SharesNet returns whether containers in pod
+// default to use network namespace of first container in pod
+func (p *Pod) SharesNet() bool {
+ return p.config.UsePodNet
+}
+
+// SharesMNT returns whether containers in pod
+// default to use PID namespace of first container in pod
+func (p *Pod) SharesMNT() bool {
+ return p.config.UsePodMNT
+}
+
+// SharesUser returns whether containers in pod
+// default to use user namespace of first container in pod
+func (p *Pod) SharesUser() bool {
+ return p.config.UsePodUser
+}
+
+// SharesUTS returns whether containers in pod
+// default to use UTS namespace of first container in pod
+func (p *Pod) SharesUTS() bool {
+ return p.config.UsePodUTS
+}
+
+// SharesCgroup returns whether containers in the pod will default to this pod's
// cgroup instead of the default libpod parent
-func (p *Pod) UsePodCgroup() bool {
+func (p *Pod) SharesCgroup() bool {
return p.config.UsePodCgroup
}
@@ -161,6 +224,30 @@ func (p *Pod) allContainers() ([]*Container, error) {
return p.runtime.state.PodContainers(p)
}
+// HasPauseContainer returns whether the pod will create a pause container
+func (p *Pod) HasPauseContainer() bool {
+ return p.config.PauseContainer.HasPauseContainer
+}
+
+// SharesNamespaces checks if the pod has any kernel namespaces set as shared. A pause container will not be
+// created if no kernel namespaces are shared.
+func (p *Pod) SharesNamespaces() bool {
+ return p.SharesPID() || p.SharesIPC() || p.SharesNet() || p.SharesMNT() || p.SharesUser() || p.SharesUTS()
+}
+
+// PauseContainerID returns a the pause container ID for a pod.
+// If the container returned is "", the pod has no pause container.
+func (p *Pod) PauseContainerID() (string, error) {
+ p.lock.Lock()
+ defer p.lock.Unlock()
+
+ if err := p.updatePod(); err != nil {
+ return "", err
+ }
+
+ return p.state.PauseContainerID, nil
+}
+
// TODO add pod batching
// Lock pod to avoid lock contention
// Store and lock all containers (no RemoveContainer in batch guarantees cache will not become stale)
diff --git a/libpod/pod_api.go b/libpod/pod_api.go
index d1e19063c..096c9b513 100644
--- a/libpod/pod_api.go
+++ b/libpod/pod_api.go
@@ -426,13 +426,18 @@ func (p *Pod) Inspect() (*PodInspect, error) {
}
podContainers = append(podContainers, pc)
}
+ pauseContainerID := p.state.PauseContainerID
+ if err != nil {
+ return &PodInspect{}, err
+ }
config := new(PodConfig)
deepcopier.Copy(p.config).To(config)
inspectData := PodInspect{
Config: config,
State: &PodInspectState{
- CgroupPath: p.state.CgroupPath,
+ CgroupPath: p.state.CgroupPath,
+ PauseContainerID: pauseContainerID,
},
Containers: podContainers,
}
diff --git a/libpod/pod_ffjson.go b/libpod/pod_ffjson.go
index 36b1cf08f..a2030bb4c 100644
--- a/libpod/pod_ffjson.go
+++ b/libpod/pod_ffjson.go
@@ -12,6 +12,212 @@ import (
)
// MarshalJSON marshal bytes to json - template
+func (j *PauseContainerConfig) MarshalJSON() ([]byte, error) {
+ var buf fflib.Buffer
+ if j == nil {
+ buf.WriteString("null")
+ return buf.Bytes(), nil
+ }
+ err := j.MarshalJSONBuf(&buf)
+ if err != nil {
+ return nil, err
+ }
+ return buf.Bytes(), nil
+}
+
+// MarshalJSONBuf marshal buff to json - template
+func (j *PauseContainerConfig) MarshalJSONBuf(buf fflib.EncodingBuffer) error {
+ if j == nil {
+ buf.WriteString("null")
+ return nil
+ }
+ var err error
+ var obj []byte
+ _ = obj
+ _ = err
+ if j.HasPauseContainer {
+ buf.WriteString(`{"makePauseContainer":true`)
+ } else {
+ buf.WriteString(`{"makePauseContainer":false`)
+ }
+ buf.WriteByte('}')
+ return nil
+}
+
+const (
+ ffjtPauseContainerConfigbase = iota
+ ffjtPauseContainerConfignosuchkey
+
+ ffjtPauseContainerConfigHasPauseContainer
+)
+
+var ffjKeyPauseContainerConfigHasPauseContainer = []byte("makePauseContainer")
+
+// UnmarshalJSON umarshall json - template of ffjson
+func (j *PauseContainerConfig) UnmarshalJSON(input []byte) error {
+ fs := fflib.NewFFLexer(input)
+ return j.UnmarshalJSONFFLexer(fs, fflib.FFParse_map_start)
+}
+
+// UnmarshalJSONFFLexer fast json unmarshall - template ffjson
+func (j *PauseContainerConfig) UnmarshalJSONFFLexer(fs *fflib.FFLexer, state fflib.FFParseState) error {
+ var err error
+ currentKey := ffjtPauseContainerConfigbase
+ _ = currentKey
+ tok := fflib.FFTok_init
+ wantedTok := fflib.FFTok_init
+
+mainparse:
+ for {
+ tok = fs.Scan()
+ // println(fmt.Sprintf("debug: tok: %v state: %v", tok, state))
+ if tok == fflib.FFTok_error {
+ goto tokerror
+ }
+
+ switch state {
+
+ case fflib.FFParse_map_start:
+ if tok != fflib.FFTok_left_bracket {
+ wantedTok = fflib.FFTok_left_bracket
+ goto wrongtokenerror
+ }
+ state = fflib.FFParse_want_key
+ continue
+
+ case fflib.FFParse_after_value:
+ if tok == fflib.FFTok_comma {
+ state = fflib.FFParse_want_key
+ } else if tok == fflib.FFTok_right_bracket {
+ goto done
+ } else {
+ wantedTok = fflib.FFTok_comma
+ goto wrongtokenerror
+ }
+
+ case fflib.FFParse_want_key:
+ // json {} ended. goto exit. woo.
+ if tok == fflib.FFTok_right_bracket {
+ goto done
+ }
+ if tok != fflib.FFTok_string {
+ wantedTok = fflib.FFTok_string
+ goto wrongtokenerror
+ }
+
+ kn := fs.Output.Bytes()
+ if len(kn) <= 0 {
+ // "" case. hrm.
+ currentKey = ffjtPauseContainerConfignosuchkey
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ } else {
+ switch kn[0] {
+
+ case 'm':
+
+ if bytes.Equal(ffjKeyPauseContainerConfigHasPauseContainer, kn) {
+ currentKey = ffjtPauseContainerConfigHasPauseContainer
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ }
+
+ if fflib.EqualFoldRight(ffjKeyPauseContainerConfigHasPauseContainer, kn) {
+ currentKey = ffjtPauseContainerConfigHasPauseContainer
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ currentKey = ffjtPauseContainerConfignosuchkey
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ case fflib.FFParse_want_colon:
+ if tok != fflib.FFTok_colon {
+ wantedTok = fflib.FFTok_colon
+ goto wrongtokenerror
+ }
+ state = fflib.FFParse_want_value
+ continue
+ case fflib.FFParse_want_value:
+
+ if tok == fflib.FFTok_left_brace || tok == fflib.FFTok_left_bracket || tok == fflib.FFTok_integer || tok == fflib.FFTok_double || tok == fflib.FFTok_string || tok == fflib.FFTok_bool || tok == fflib.FFTok_null {
+ switch currentKey {
+
+ case ffjtPauseContainerConfigHasPauseContainer:
+ goto handle_HasPauseContainer
+
+ case ffjtPauseContainerConfignosuchkey:
+ err = fs.SkipField(tok)
+ if err != nil {
+ return fs.WrapErr(err)
+ }
+ state = fflib.FFParse_after_value
+ goto mainparse
+ }
+ } else {
+ goto wantedvalue
+ }
+ }
+ }
+
+handle_HasPauseContainer:
+
+ /* handler: j.HasPauseContainer type=bool kind=bool quoted=false*/
+
+ {
+ if tok != fflib.FFTok_bool && tok != fflib.FFTok_null {
+ return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for bool", tok))
+ }
+ }
+
+ {
+ if tok == fflib.FFTok_null {
+
+ } else {
+ tmpb := fs.Output.Bytes()
+
+ if bytes.Compare([]byte{'t', 'r', 'u', 'e'}, tmpb) == 0 {
+
+ j.HasPauseContainer = true
+
+ } else if bytes.Compare([]byte{'f', 'a', 'l', 's', 'e'}, tmpb) == 0 {
+
+ j.HasPauseContainer = false
+
+ } else {
+ err = errors.New("unexpected bytes for true/false value")
+ return fs.WrapErr(err)
+ }
+
+ }
+ }
+
+ state = fflib.FFParse_after_value
+ goto mainparse
+
+wantedvalue:
+ return fs.WrapErr(fmt.Errorf("wanted value token, but got token: %v", tok))
+wrongtokenerror:
+ return fs.WrapErr(fmt.Errorf("ffjson: wanted token: %v, but got token: %v output=%s", wantedTok, tok, fs.Output.String()))
+tokerror:
+ if fs.BigError != nil {
+ return fs.WrapErr(fs.BigError)
+ }
+ err = fs.Error.ToError()
+ if err != nil {
+ return fs.WrapErr(err)
+ }
+ panic("ffjson-generated: unreachable, please report bug.")
+done:
+
+ return nil
+}
+
+// MarshalJSON marshal bytes to json - template
func (j *PodConfig) MarshalJSON() ([]byte, error) {
var buf fflib.Buffer
if j == nil {
@@ -60,10 +266,76 @@ func (j *PodConfig) MarshalJSONBuf(buf fflib.EncodingBuffer) error {
}
buf.WriteString(`,"cgroupParent":`)
fflib.WriteJsonString(buf, string(j.CgroupParent))
- if j.UsePodCgroup {
- buf.WriteString(`,"usePodCgroup":true`)
+ buf.WriteByte(',')
+ if j.UsePodCgroup != false {
+ if j.UsePodCgroup {
+ buf.WriteString(`"sharesCgroup":true`)
+ } else {
+ buf.WriteString(`"sharesCgroup":false`)
+ }
+ buf.WriteByte(',')
+ }
+ if j.UsePodPID != false {
+ if j.UsePodPID {
+ buf.WriteString(`"sharesPid":true`)
+ } else {
+ buf.WriteString(`"sharesPid":false`)
+ }
+ buf.WriteByte(',')
+ }
+ if j.UsePodIPC != false {
+ if j.UsePodIPC {
+ buf.WriteString(`"sharesIpc":true`)
+ } else {
+ buf.WriteString(`"sharesIpc":false`)
+ }
+ buf.WriteByte(',')
+ }
+ if j.UsePodNet != false {
+ if j.UsePodNet {
+ buf.WriteString(`"sharesNet":true`)
+ } else {
+ buf.WriteString(`"sharesNet":false`)
+ }
+ buf.WriteByte(',')
+ }
+ if j.UsePodMNT != false {
+ if j.UsePodMNT {
+ buf.WriteString(`"sharesMnt":true`)
+ } else {
+ buf.WriteString(`"sharesMnt":false`)
+ }
+ buf.WriteByte(',')
+ }
+ if j.UsePodUser != false {
+ if j.UsePodUser {
+ buf.WriteString(`"sharesUser":true`)
+ } else {
+ buf.WriteString(`"sharesUser":false`)
+ }
+ buf.WriteByte(',')
+ }
+ if j.UsePodUTS != false {
+ if j.UsePodUTS {
+ buf.WriteString(`"sharesUts":true`)
+ } else {
+ buf.WriteString(`"sharesUts":false`)
+ }
+ buf.WriteByte(',')
+ }
+ if j.PauseContainer != nil {
+ buf.WriteString(`"pauseConfig":`)
+
+ {
+
+ err = j.PauseContainer.MarshalJSONBuf(buf)
+ if err != nil {
+ return err
+ }
+
+ }
} else {
- buf.WriteString(`,"usePodCgroup":false`)
+ buf.WriteString(`"pauseConfig":null`)
}
buf.WriteString(`,"created":`)
@@ -96,6 +368,20 @@ const (
ffjtPodConfigUsePodCgroup
+ ffjtPodConfigUsePodPID
+
+ ffjtPodConfigUsePodIPC
+
+ ffjtPodConfigUsePodNet
+
+ ffjtPodConfigUsePodMNT
+
+ ffjtPodConfigUsePodUser
+
+ ffjtPodConfigUsePodUTS
+
+ ffjtPodConfigPauseContainer
+
ffjtPodConfigCreatedTime
)
@@ -109,7 +395,21 @@ var ffjKeyPodConfigLabels = []byte("labels")
var ffjKeyPodConfigCgroupParent = []byte("cgroupParent")
-var ffjKeyPodConfigUsePodCgroup = []byte("usePodCgroup")
+var ffjKeyPodConfigUsePodCgroup = []byte("sharesCgroup")
+
+var ffjKeyPodConfigUsePodPID = []byte("sharesPid")
+
+var ffjKeyPodConfigUsePodIPC = []byte("sharesIpc")
+
+var ffjKeyPodConfigUsePodNet = []byte("sharesNet")
+
+var ffjKeyPodConfigUsePodMNT = []byte("sharesMnt")
+
+var ffjKeyPodConfigUsePodUser = []byte("sharesUser")
+
+var ffjKeyPodConfigUsePodUTS = []byte("sharesUts")
+
+var ffjKeyPodConfigPauseContainer = []byte("pauseConfig")
var ffjKeyPodConfigCreatedTime = []byte("created")
@@ -216,12 +516,50 @@ mainparse:
goto mainparse
}
- case 'u':
+ case 'p':
+
+ if bytes.Equal(ffjKeyPodConfigPauseContainer, kn) {
+ currentKey = ffjtPodConfigPauseContainer
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ case 's':
if bytes.Equal(ffjKeyPodConfigUsePodCgroup, kn) {
currentKey = ffjtPodConfigUsePodCgroup
state = fflib.FFParse_want_colon
goto mainparse
+
+ } else if bytes.Equal(ffjKeyPodConfigUsePodPID, kn) {
+ currentKey = ffjtPodConfigUsePodPID
+ state = fflib.FFParse_want_colon
+ goto mainparse
+
+ } else if bytes.Equal(ffjKeyPodConfigUsePodIPC, kn) {
+ currentKey = ffjtPodConfigUsePodIPC
+ state = fflib.FFParse_want_colon
+ goto mainparse
+
+ } else if bytes.Equal(ffjKeyPodConfigUsePodNet, kn) {
+ currentKey = ffjtPodConfigUsePodNet
+ state = fflib.FFParse_want_colon
+ goto mainparse
+
+ } else if bytes.Equal(ffjKeyPodConfigUsePodMNT, kn) {
+ currentKey = ffjtPodConfigUsePodMNT
+ state = fflib.FFParse_want_colon
+ goto mainparse
+
+ } else if bytes.Equal(ffjKeyPodConfigUsePodUser, kn) {
+ currentKey = ffjtPodConfigUsePodUser
+ state = fflib.FFParse_want_colon
+ goto mainparse
+
+ } else if bytes.Equal(ffjKeyPodConfigUsePodUTS, kn) {
+ currentKey = ffjtPodConfigUsePodUTS
+ state = fflib.FFParse_want_colon
+ goto mainparse
}
}
@@ -232,6 +570,48 @@ mainparse:
goto mainparse
}
+ if fflib.EqualFoldRight(ffjKeyPodConfigPauseContainer, kn) {
+ currentKey = ffjtPodConfigPauseContainer
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ if fflib.EqualFoldRight(ffjKeyPodConfigUsePodUTS, kn) {
+ currentKey = ffjtPodConfigUsePodUTS
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ if fflib.EqualFoldRight(ffjKeyPodConfigUsePodUser, kn) {
+ currentKey = ffjtPodConfigUsePodUser
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ if fflib.EqualFoldRight(ffjKeyPodConfigUsePodMNT, kn) {
+ currentKey = ffjtPodConfigUsePodMNT
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ if fflib.EqualFoldRight(ffjKeyPodConfigUsePodNet, kn) {
+ currentKey = ffjtPodConfigUsePodNet
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ if fflib.EqualFoldRight(ffjKeyPodConfigUsePodIPC, kn) {
+ currentKey = ffjtPodConfigUsePodIPC
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ if fflib.EqualFoldRight(ffjKeyPodConfigUsePodPID, kn) {
+ currentKey = ffjtPodConfigUsePodPID
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
if fflib.EqualFoldRight(ffjKeyPodConfigUsePodCgroup, kn) {
currentKey = ffjtPodConfigUsePodCgroup
state = fflib.FFParse_want_colon
@@ -303,6 +683,27 @@ mainparse:
case ffjtPodConfigUsePodCgroup:
goto handle_UsePodCgroup
+ case ffjtPodConfigUsePodPID:
+ goto handle_UsePodPID
+
+ case ffjtPodConfigUsePodIPC:
+ goto handle_UsePodIPC
+
+ case ffjtPodConfigUsePodNet:
+ goto handle_UsePodNet
+
+ case ffjtPodConfigUsePodMNT:
+ goto handle_UsePodMNT
+
+ case ffjtPodConfigUsePodUser:
+ goto handle_UsePodUser
+
+ case ffjtPodConfigUsePodUTS:
+ goto handle_UsePodUTS
+
+ case ffjtPodConfigPauseContainer:
+ goto handle_PauseContainer
+
case ffjtPodConfigCreatedTime:
goto handle_CreatedTime
@@ -564,6 +965,242 @@ handle_UsePodCgroup:
state = fflib.FFParse_after_value
goto mainparse
+handle_UsePodPID:
+
+ /* handler: j.UsePodPID type=bool kind=bool quoted=false*/
+
+ {
+ if tok != fflib.FFTok_bool && tok != fflib.FFTok_null {
+ return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for bool", tok))
+ }
+ }
+
+ {
+ if tok == fflib.FFTok_null {
+
+ } else {
+ tmpb := fs.Output.Bytes()
+
+ if bytes.Compare([]byte{'t', 'r', 'u', 'e'}, tmpb) == 0 {
+
+ j.UsePodPID = true
+
+ } else if bytes.Compare([]byte{'f', 'a', 'l', 's', 'e'}, tmpb) == 0 {
+
+ j.UsePodPID = false
+
+ } else {
+ err = errors.New("unexpected bytes for true/false value")
+ return fs.WrapErr(err)
+ }
+
+ }
+ }
+
+ state = fflib.FFParse_after_value
+ goto mainparse
+
+handle_UsePodIPC:
+
+ /* handler: j.UsePodIPC type=bool kind=bool quoted=false*/
+
+ {
+ if tok != fflib.FFTok_bool && tok != fflib.FFTok_null {
+ return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for bool", tok))
+ }
+ }
+
+ {
+ if tok == fflib.FFTok_null {
+
+ } else {
+ tmpb := fs.Output.Bytes()
+
+ if bytes.Compare([]byte{'t', 'r', 'u', 'e'}, tmpb) == 0 {
+
+ j.UsePodIPC = true
+
+ } else if bytes.Compare([]byte{'f', 'a', 'l', 's', 'e'}, tmpb) == 0 {
+
+ j.UsePodIPC = false
+
+ } else {
+ err = errors.New("unexpected bytes for true/false value")
+ return fs.WrapErr(err)
+ }
+
+ }
+ }
+
+ state = fflib.FFParse_after_value
+ goto mainparse
+
+handle_UsePodNet:
+
+ /* handler: j.UsePodNet type=bool kind=bool quoted=false*/
+
+ {
+ if tok != fflib.FFTok_bool && tok != fflib.FFTok_null {
+ return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for bool", tok))
+ }
+ }
+
+ {
+ if tok == fflib.FFTok_null {
+
+ } else {
+ tmpb := fs.Output.Bytes()
+
+ if bytes.Compare([]byte{'t', 'r', 'u', 'e'}, tmpb) == 0 {
+
+ j.UsePodNet = true
+
+ } else if bytes.Compare([]byte{'f', 'a', 'l', 's', 'e'}, tmpb) == 0 {
+
+ j.UsePodNet = false
+
+ } else {
+ err = errors.New("unexpected bytes for true/false value")
+ return fs.WrapErr(err)
+ }
+
+ }
+ }
+
+ state = fflib.FFParse_after_value
+ goto mainparse
+
+handle_UsePodMNT:
+
+ /* handler: j.UsePodMNT type=bool kind=bool quoted=false*/
+
+ {
+ if tok != fflib.FFTok_bool && tok != fflib.FFTok_null {
+ return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for bool", tok))
+ }
+ }
+
+ {
+ if tok == fflib.FFTok_null {
+
+ } else {
+ tmpb := fs.Output.Bytes()
+
+ if bytes.Compare([]byte{'t', 'r', 'u', 'e'}, tmpb) == 0 {
+
+ j.UsePodMNT = true
+
+ } else if bytes.Compare([]byte{'f', 'a', 'l', 's', 'e'}, tmpb) == 0 {
+
+ j.UsePodMNT = false
+
+ } else {
+ err = errors.New("unexpected bytes for true/false value")
+ return fs.WrapErr(err)
+ }
+
+ }
+ }
+
+ state = fflib.FFParse_after_value
+ goto mainparse
+
+handle_UsePodUser:
+
+ /* handler: j.UsePodUser type=bool kind=bool quoted=false*/
+
+ {
+ if tok != fflib.FFTok_bool && tok != fflib.FFTok_null {
+ return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for bool", tok))
+ }
+ }
+
+ {
+ if tok == fflib.FFTok_null {
+
+ } else {
+ tmpb := fs.Output.Bytes()
+
+ if bytes.Compare([]byte{'t', 'r', 'u', 'e'}, tmpb) == 0 {
+
+ j.UsePodUser = true
+
+ } else if bytes.Compare([]byte{'f', 'a', 'l', 's', 'e'}, tmpb) == 0 {
+
+ j.UsePodUser = false
+
+ } else {
+ err = errors.New("unexpected bytes for true/false value")
+ return fs.WrapErr(err)
+ }
+
+ }
+ }
+
+ state = fflib.FFParse_after_value
+ goto mainparse
+
+handle_UsePodUTS:
+
+ /* handler: j.UsePodUTS type=bool kind=bool quoted=false*/
+
+ {
+ if tok != fflib.FFTok_bool && tok != fflib.FFTok_null {
+ return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for bool", tok))
+ }
+ }
+
+ {
+ if tok == fflib.FFTok_null {
+
+ } else {
+ tmpb := fs.Output.Bytes()
+
+ if bytes.Compare([]byte{'t', 'r', 'u', 'e'}, tmpb) == 0 {
+
+ j.UsePodUTS = true
+
+ } else if bytes.Compare([]byte{'f', 'a', 'l', 's', 'e'}, tmpb) == 0 {
+
+ j.UsePodUTS = false
+
+ } else {
+ err = errors.New("unexpected bytes for true/false value")
+ return fs.WrapErr(err)
+ }
+
+ }
+ }
+
+ state = fflib.FFParse_after_value
+ goto mainparse
+
+handle_PauseContainer:
+
+ /* handler: j.PauseContainer type=libpod.PauseContainerConfig kind=struct quoted=false*/
+
+ {
+ if tok == fflib.FFTok_null {
+
+ j.PauseContainer = nil
+
+ } else {
+
+ if j.PauseContainer == nil {
+ j.PauseContainer = new(PauseContainerConfig)
+ }
+
+ err = j.PauseContainer.UnmarshalJSONFFLexer(fs, fflib.FFParse_want_key)
+ if err != nil {
+ return err
+ }
+ }
+ state = fflib.FFParse_after_value
+ }
+
+ state = fflib.FFParse_after_value
+ goto mainparse
+
handle_CreatedTime:
/* handler: j.CreatedTime type=time.Time kind=struct quoted=false*/
@@ -1586,6 +2223,8 @@ func (j *PodInspectState) MarshalJSONBuf(buf fflib.EncodingBuffer) error {
_ = err
buf.WriteString(`{"cgroupPath":`)
fflib.WriteJsonString(buf, string(j.CgroupPath))
+ buf.WriteString(`,"pauseContainerID":`)
+ fflib.WriteJsonString(buf, string(j.PauseContainerID))
buf.WriteByte('}')
return nil
}
@@ -1595,10 +2234,14 @@ const (
ffjtPodInspectStatenosuchkey
ffjtPodInspectStateCgroupPath
+
+ ffjtPodInspectStatePauseContainerID
)
var ffjKeyPodInspectStateCgroupPath = []byte("cgroupPath")
+var ffjKeyPodInspectStatePauseContainerID = []byte("pauseContainerID")
+
// UnmarshalJSON umarshall json - template of ffjson
func (j *PodInspectState) UnmarshalJSON(input []byte) error {
fs := fflib.NewFFLexer(input)
@@ -1668,6 +2311,20 @@ mainparse:
goto mainparse
}
+ case 'p':
+
+ if bytes.Equal(ffjKeyPodInspectStatePauseContainerID, kn) {
+ currentKey = ffjtPodInspectStatePauseContainerID
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ }
+
+ if fflib.EqualFoldRight(ffjKeyPodInspectStatePauseContainerID, kn) {
+ currentKey = ffjtPodInspectStatePauseContainerID
+ state = fflib.FFParse_want_colon
+ goto mainparse
}
if fflib.SimpleLetterEqualFold(ffjKeyPodInspectStateCgroupPath, kn) {
@@ -1696,6 +2353,9 @@ mainparse:
case ffjtPodInspectStateCgroupPath:
goto handle_CgroupPath
+ case ffjtPodInspectStatePauseContainerID:
+ goto handle_PauseContainerID
+
case ffjtPodInspectStatenosuchkey:
err = fs.SkipField(tok)
if err != nil {
@@ -1736,6 +2396,32 @@ handle_CgroupPath:
state = fflib.FFParse_after_value
goto mainparse
+handle_PauseContainerID:
+
+ /* handler: j.PauseContainerID type=string kind=string quoted=false*/
+
+ {
+
+ {
+ if tok != fflib.FFTok_string && tok != fflib.FFTok_null {
+ return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for string", tok))
+ }
+ }
+
+ if tok == fflib.FFTok_null {
+
+ } else {
+
+ outBuf := fs.Output.Bytes()
+
+ j.PauseContainerID = string(string(outBuf))
+
+ }
+ }
+
+ state = fflib.FFParse_after_value
+ goto mainparse
+
wantedvalue:
return fs.WrapErr(fmt.Errorf("wanted value token, but got token: %v", tok))
wrongtokenerror:
@@ -1780,6 +2466,8 @@ func (j *podState) MarshalJSONBuf(buf fflib.EncodingBuffer) error {
_ = err
buf.WriteString(`{"cgroupPath":`)
fflib.WriteJsonString(buf, string(j.CgroupPath))
+ buf.WriteString(`,"PauseContainerID":`)
+ fflib.WriteJsonString(buf, string(j.PauseContainerID))
buf.WriteByte('}')
return nil
}
@@ -1789,10 +2477,14 @@ const (
ffjtpodStatenosuchkey
ffjtpodStateCgroupPath
+
+ ffjtpodStatePauseContainerID
)
var ffjKeypodStateCgroupPath = []byte("cgroupPath")
+var ffjKeypodStatePauseContainerID = []byte("PauseContainerID")
+
// UnmarshalJSON umarshall json - template of ffjson
func (j *podState) UnmarshalJSON(input []byte) error {
fs := fflib.NewFFLexer(input)
@@ -1854,6 +2546,14 @@ mainparse:
} else {
switch kn[0] {
+ case 'P':
+
+ if bytes.Equal(ffjKeypodStatePauseContainerID, kn) {
+ currentKey = ffjtpodStatePauseContainerID
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
case 'c':
if bytes.Equal(ffjKeypodStateCgroupPath, kn) {
@@ -1864,6 +2564,12 @@ mainparse:
}
+ if fflib.EqualFoldRight(ffjKeypodStatePauseContainerID, kn) {
+ currentKey = ffjtpodStatePauseContainerID
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
if fflib.SimpleLetterEqualFold(ffjKeypodStateCgroupPath, kn) {
currentKey = ffjtpodStateCgroupPath
state = fflib.FFParse_want_colon
@@ -1890,6 +2596,9 @@ mainparse:
case ffjtpodStateCgroupPath:
goto handle_CgroupPath
+ case ffjtpodStatePauseContainerID:
+ goto handle_PauseContainerID
+
case ffjtpodStatenosuchkey:
err = fs.SkipField(tok)
if err != nil {
@@ -1930,6 +2639,32 @@ handle_CgroupPath:
state = fflib.FFParse_after_value
goto mainparse
+handle_PauseContainerID:
+
+ /* handler: j.PauseContainerID type=string kind=string quoted=false*/
+
+ {
+
+ {
+ if tok != fflib.FFTok_string && tok != fflib.FFTok_null {
+ return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for string", tok))
+ }
+ }
+
+ if tok == fflib.FFTok_null {
+
+ } else {
+
+ outBuf := fs.Output.Bytes()
+
+ j.PauseContainerID = string(string(outBuf))
+
+ }
+ }
+
+ state = fflib.FFParse_after_value
+ goto mainparse
+
wantedvalue:
return fs.WrapErr(fmt.Errorf("wanted value token, but got token: %v", tok))
wrongtokenerror:
diff --git a/libpod/pod_internal.go b/libpod/pod_internal.go
index 1ba4487ab..fb0b68906 100644
--- a/libpod/pod_internal.go
+++ b/libpod/pod_internal.go
@@ -20,6 +20,7 @@ func newPod(lockDir string, runtime *Runtime) (*Pod, error) {
pod.config.ID = stringid.GenerateNonCryptoID()
pod.config.Labels = make(map[string]string)
pod.config.CreatedTime = time.Now()
+ pod.config.PauseContainer = new(PauseContainerConfig)
pod.state = new(podState)
pod.runtime = runtime
diff --git a/libpod/runtime.go b/libpod/runtime.go
index 73f516cd5..7e006b1fc 100644
--- a/libpod/runtime.go
+++ b/libpod/runtime.go
@@ -56,6 +56,11 @@ const (
// configuration file. If OverrideConfigPath exists, it will be used in
// place of the configuration file pointed to by ConfigPath.
OverrideConfigPath = "/etc/containers/libpod.conf"
+
+ // DefaultPauseImage to use for pause container
+ DefaultPauseImage = "k8s.gcr.io/pause:3.1"
+ // DefaultPauseCommand to be run in a pause container
+ DefaultPauseCommand = "/pause"
)
// A RuntimeOption is a functional option which alters the Runtime created by
@@ -152,6 +157,10 @@ type RuntimeConfig struct {
// and all containers and pods will be visible.
// The default namespace is "".
Namespace string `toml:"namespace,omitempty"`
+ // PauseImage is the image a pod pause container will use to manage namespaces
+ PauseImage string `toml:"pause_image"`
+ // PauseCommand is the command run to start up a pod pause container
+ PauseCommand string `toml:"pause_command"`
}
var (
@@ -186,6 +195,8 @@ var (
NoPivotRoot: false,
CNIConfigDir: "/etc/cni/net.d/",
CNIPluginDir: []string{"/usr/libexec/cni", "/usr/lib/cni", "/opt/cni/bin"},
+ PauseCommand: DefaultPauseCommand,
+ PauseImage: DefaultPauseImage,
}
)
diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go
index 051b3e85e..1aca559de 100644
--- a/libpod/runtime_ctr.go
+++ b/libpod/runtime_ctr.go
@@ -8,9 +8,12 @@ import (
"strings"
"time"
+ "github.com/containers/storage"
+ "github.com/containers/storage/pkg/stringid"
spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
+ "github.com/ulule/deepcopier"
)
// CtrRemoveTimeout is the default number of seconds to wait after stopping a container
@@ -35,11 +38,37 @@ func (r *Runtime) NewContainer(ctx context.Context, rSpec *spec.Spec, options ..
if !r.valid {
return nil, ErrRuntimeStopped
}
+ return r.newContainer(ctx, rSpec, options...)
+}
+
+func (r *Runtime) newContainer(ctx context.Context, rSpec *spec.Spec, options ...CtrCreateOption) (c *Container, err error) {
+ if rSpec == nil {
+ return nil, errors.Wrapf(ErrInvalidArg, "must provide a valid runtime spec to create container")
+ }
+
+ ctr := new(Container)
+ ctr.config = new(ContainerConfig)
+ ctr.state = new(containerState)
+
+ ctr.config.ID = stringid.GenerateNonCryptoID()
+
+ ctr.config.Spec = new(spec.Spec)
+ deepcopier.Copy(rSpec).To(ctr.config.Spec)
+ ctr.config.CreatedTime = time.Now()
+
+ ctr.config.ShmSize = DefaultShmSize
+
+ ctr.state.BindMounts = make(map[string]string)
- ctr, err := newContainer(rSpec, r.lockDir)
+ // Path our lock file will reside at
+ lockPath := filepath.Join(r.lockDir, ctr.config.ID)
+ // Grab a lockfile at the given path
+ lock, err := storage.GetLockfile(lockPath)
if err != nil {
- return nil, err
+ return nil, errors.Wrapf(err, "error creating lockfile for new container")
}
+ ctr.lock = lock
+
ctr.config.StopTimeout = CtrRemoveTimeout
// Set namespace based on current runtime namespace
@@ -59,6 +88,7 @@ func (r *Runtime) NewContainer(ctx context.Context, rSpec *spec.Spec, options ..
ctr.runtime = r
var pod *Pod
+
if ctr.config.Pod != "" {
// Get the pod from state
pod, err = r.state.Pod(ctr.config.Pod)
@@ -194,6 +224,14 @@ func (r *Runtime) removeContainer(ctx context.Context, c *Container, force bool)
// Lock the pod while we're removing container
pod.lock.Lock()
defer pod.lock.Unlock()
+ if err := pod.updatePod(); err != nil {
+ return err
+ }
+
+ pauseID := pod.state.PauseContainerID
+ if c.ID() == pauseID {
+ return errors.Errorf("a pause container cannot be removed without removing pod %s", pod.ID())
+ }
}
c.lock.Lock()
diff --git a/libpod/runtime_pod.go b/libpod/runtime_pod.go
index 280699b79..19e32d1b0 100644
--- a/libpod/runtime_pod.go
+++ b/libpod/runtime_pod.go
@@ -26,6 +26,16 @@ type PodFilter func(*Pod) bool
// being removed
// Otherwise, the pod will not be removed if any containers are running
func (r *Runtime) RemovePod(ctx context.Context, p *Pod, removeCtrs, force bool) error {
+ r.lock.Lock()
+ defer r.lock.Unlock()
+
+ if !r.valid {
+ return ErrRuntimeStopped
+ }
+
+ p.lock.Lock()
+ defer p.lock.Unlock()
+
return r.removePod(ctx, p, removeCtrs, force)
}
diff --git a/libpod/runtime_pod_linux.go b/libpod/runtime_pod_linux.go
index 3592c2fee..eff15be76 100644
--- a/libpod/runtime_pod_linux.go
+++ b/libpod/runtime_pod_linux.go
@@ -15,7 +15,7 @@ import (
)
// NewPod makes a new, empty pod
-func (r *Runtime) NewPod(options ...PodCreateOption) (*Pod, error) {
+func (r *Runtime) NewPod(ctx context.Context, options ...PodCreateOption) (*Pod, error) {
r.lock.Lock()
defer r.lock.Unlock()
@@ -87,38 +87,42 @@ func (r *Runtime) NewPod(options ...PodCreateOption) (*Pod, error) {
if pod.config.UsePodCgroup {
logrus.Debugf("Got pod cgroup as %s", pod.state.CgroupPath)
}
+ if pod.HasPauseContainer() != pod.SharesNamespaces() {
+ return nil, errors.Errorf("Pods must have a pause container to share namespaces")
+ }
if err := r.state.AddPod(pod); err != nil {
return nil, errors.Wrapf(err, "error adding pod to state")
}
+ if pod.HasPauseContainer() {
+ ctr, err := r.createPauseContainer(ctx, pod)
+ if err != nil {
+ // Tear down pod, as it is assumed a the pod will contain
+ // a pause container, and it does not.
+ if err2 := r.removePod(ctx, pod, true, true); err2 != nil {
+ logrus.Errorf("Error removing pod after pause container creation failure: %v", err2)
+ }
+ return nil, errors.Wrapf(err, "error adding Pause Container")
+ }
+ pod.state.PauseContainerID = ctr.ID()
+ if err := pod.save(); err != nil {
+ return nil, err
+ }
+ }
+
return pod, nil
}
func (r *Runtime) removePod(ctx context.Context, p *Pod, removeCtrs, force bool) error {
- r.lock.Lock()
- defer r.lock.Unlock()
-
- if !r.valid {
- return ErrRuntimeStopped
- }
-
if !p.valid {
if ok, _ := r.state.HasPod(p.ID()); !ok {
- // Pod was either already removed, or never existed to
- // begin with
+ // Pod probably already removed
+ // Or was never in the runtime to begin with
return nil
}
}
- p.lock.Lock()
- defer p.lock.Unlock()
-
- // Force a pod update
- if err := p.updatePod(); err != nil {
- return err
- }
-
ctrs, err := r.state.PodContainers(p)
if err != nil {
return err
@@ -126,6 +130,15 @@ func (r *Runtime) removePod(ctx context.Context, p *Pod, removeCtrs, force bool)
numCtrs := len(ctrs)
+ // If the only container in the pod is the pause container, remove the pod and container unconditionally.
+ if err := p.updatePod(); err != nil {
+ return err
+ }
+ pauseCtrID := p.state.PauseContainerID
+ if numCtrs == 1 && ctrs[0].ID() == pauseCtrID {
+ removeCtrs = true
+ force = true
+ }
if !removeCtrs && numCtrs > 0 {
return errors.Wrapf(ErrCtrExists, "pod %s contains containers and cannot be removed", p.ID())
}
diff --git a/libpod/runtime_pod_pause_linux.go b/libpod/runtime_pod_pause_linux.go
new file mode 100644
index 000000000..41bf8b041
--- /dev/null
+++ b/libpod/runtime_pod_pause_linux.go
@@ -0,0 +1,60 @@
+// +build linux
+
+package libpod
+
+import (
+ "context"
+
+ "github.com/containers/libpod/libpod/image"
+ "github.com/opencontainers/runtime-tools/generate"
+)
+
+const (
+ // IDTruncLength is the length of the pod's id that will be used to make the
+ // pause container name
+ IDTruncLength = 12
+)
+
+func (r *Runtime) makePauseContainer(ctx context.Context, p *Pod, imgName, imgID string) (*Container, error) {
+
+ // Set up generator for pause container defaults
+ g, err := generate.New("linux")
+ if err != nil {
+ return nil, err
+ }
+
+ g.SetRootReadonly(true)
+ g.SetProcessArgs([]string{r.config.PauseCommand})
+
+ containerName := p.ID()[:IDTruncLength] + "-infra"
+ var options []CtrCreateOption
+ options = append(options, r.WithPod(p))
+ options = append(options, WithRootFSFromImage(imgID, imgName, false))
+ options = append(options, WithName(containerName))
+ options = append(options, withIsPause())
+
+ return r.newContainer(ctx, g.Config, options...)
+}
+
+// createPauseContainer wrap creates a pause container for a pod.
+// A pause container becomes the basis for kernel namespace sharing between
+// containers in the pod.
+func (r *Runtime) createPauseContainer(ctx context.Context, p *Pod) (*Container, error) {
+ if !r.valid {
+ return nil, ErrRuntimeStopped
+ }
+
+ newImage, err := r.ImageRuntime().New(ctx, r.config.PauseImage, "", "", nil, nil, image.SigningOptions{}, false, false)
+ if err != nil {
+ return nil, err
+ }
+
+ data, err := newImage.Inspect(ctx)
+ if err != nil {
+ return nil, err
+ }
+ imageName := newImage.Names()[0]
+ imageID := data.ID
+
+ return r.makePauseContainer(ctx, p, imageName, imageID)
+}
diff --git a/libpod/runtime_pod_unsupported.go b/libpod/runtime_pod_unsupported.go
index 7cecb7c56..d2629d5ab 100644
--- a/libpod/runtime_pod_unsupported.go
+++ b/libpod/runtime_pod_unsupported.go
@@ -7,7 +7,7 @@ import (
)
// NewPod makes a new, empty pod
-func (r *Runtime) NewPod(options ...PodCreateOption) (*Pod, error) {
+func (r *Runtime) NewPod(ctx context.Context, options ...PodCreateOption) (*Pod, error) {
return nil, ErrOSNotSupported
}
diff --git a/pkg/inspect/inspect.go b/pkg/inspect/inspect.go
index d2c9e79a5..be3818db8 100644
--- a/pkg/inspect/inspect.go
+++ b/pkg/inspect/inspect.go
@@ -170,6 +170,7 @@ type ContainerInspectData struct {
NetworkSettings *NetworkSettings `json:"NetworkSettings"` //TODO
ExitCommand []string `json:"ExitCommand"`
Namespace string `json:"Namespace"`
+ IsPause bool `json:"IsPause"`
}
// ContainerInspectState represents the state of a container.
diff --git a/pkg/spec/createconfig.go b/pkg/spec/createconfig.go
index 6df6fb480..dd1cd5833 100644
--- a/pkg/spec/createconfig.go
+++ b/pkg/spec/createconfig.go
@@ -364,6 +364,9 @@ func (c *CreateConfig) GetContainerCreateOptions(runtime *libpod.Runtime) ([]lib
networks := make([]string, 0)
userNetworks := c.NetMode.UserDefined()
+ if IsPod(userNetworks) {
+ userNetworks = ""
+ }
if userNetworks != "" {
for _, netName := range strings.Split(userNetworks, ",") {
if netName == "" {
@@ -381,6 +384,8 @@ func (c *CreateConfig) GetContainerCreateOptions(runtime *libpod.Runtime) ([]lib
return nil, errors.Wrapf(err, "container %q not found", c.NetMode.ConnectedContainer())
}
options = append(options, libpod.WithNetNSFrom(connectedCtr))
+ } else if IsPod(string(c.NetMode)) {
+ options = append(options, libpod.WithNetNSFromPod())
} else if !c.NetMode.IsHost() && !c.NetMode.IsNone() {
isRootless := rootless.IsRootless()
postConfigureNetNS := isRootless || (len(c.IDMappings.UIDMap) > 0 || len(c.IDMappings.GIDMap) > 0) && !c.UsernsMode.IsHost()
@@ -398,6 +403,10 @@ func (c *CreateConfig) GetContainerCreateOptions(runtime *libpod.Runtime) ([]lib
options = append(options, libpod.WithPIDNSFrom(connectedCtr))
}
+ if IsPod(string(c.PidMode)) {
+ options = append(options, libpod.WithPIDNSFromPod())
+ }
+
if c.IpcMode.IsContainer() {
connectedCtr, err := c.Runtime.LookupContainer(c.IpcMode.Container())
if err != nil {
@@ -406,7 +415,15 @@ func (c *CreateConfig) GetContainerCreateOptions(runtime *libpod.Runtime) ([]lib
options = append(options, libpod.WithIPCNSFrom(connectedCtr))
}
+ if IsPod(string(c.IpcMode)) {
+ options = append(options, libpod.WithIPCNSFromPod())
+ }
+
+ if IsPod(string(c.UtsMode)) {
+ options = append(options, libpod.WithUTSNSFromPod())
+ }
+ // TODO: MNT, USER, CGROUP
options = append(options, libpod.WithStopSignal(c.StopSignal))
options = append(options, libpod.WithStopTimeout(c.StopTimeout))
if len(c.DNSSearch) > 0 {
diff --git a/pkg/spec/parse.go b/pkg/spec/parse.go
index d34e10760..4cdc62de6 100644
--- a/pkg/spec/parse.go
+++ b/pkg/spec/parse.go
@@ -18,12 +18,29 @@ func (w *weightDevice) String() string {
return fmt.Sprintf("%s:%d", w.path, w.weight)
}
+// LinuxNS is a struct that contains namespace information
+// It implemented Valid to show it is a valid namespace
+type LinuxNS interface {
+ Valid() bool
+}
+
// IsNS returns if the specified string has a ns: prefix
func IsNS(s string) bool {
parts := strings.SplitN(s, ":", 2)
return len(parts) > 1 && parts[0] == "ns"
}
+// IsPod returns if the specified string is pod
+func IsPod(s string) bool {
+ return s == "pod"
+}
+
+// Valid checks the validity of a linux namespace
+// s should be the string representation of ns
+func Valid(s string, ns LinuxNS) bool {
+ return IsPod(s) || IsNS(s) || ns.Valid()
+}
+
// NS is the path to the namespace to join.
func NS(s string) string {
parts := strings.SplitN(s, ":", 2)
diff --git a/pkg/spec/spec.go b/pkg/spec/spec.go
index 7323b2d2b..8d8a07a2e 100644
--- a/pkg/spec/spec.go
+++ b/pkg/spec/spec.go
@@ -349,6 +349,9 @@ func addPidNS(config *CreateConfig, g *generate.Generator) error {
if pidMode.IsContainer() {
logrus.Debug("using container pidmode")
}
+ if IsPod(string(pidMode)) {
+ logrus.Debug("using pod pidmode")
+ }
return nil
}
@@ -384,6 +387,9 @@ func addNetNS(config *CreateConfig, g *generate.Generator) error {
} else if IsNS(string(netMode)) {
logrus.Debug("Using ns netmode")
return g.AddOrReplaceLinuxNamespace(spec.NetworkNamespace, NS(string(netMode)))
+ } else if IsPod(string(netMode)) {
+ logrus.Debug("Using pod netmode, unless pod is not sharing")
+ return nil
} else if netMode.IsUserDefined() {
logrus.Debug("Using user defined netmode")
return nil
diff --git a/pkg/varlinkapi/pods.go b/pkg/varlinkapi/pods.go
index 9e49ab687..6252d815b 100644
--- a/pkg/varlinkapi/pods.go
+++ b/pkg/varlinkapi/pods.go
@@ -23,7 +23,7 @@ func (i *LibpodAPI) CreatePod(call iopodman.VarlinkCall, create iopodman.PodCrea
}
options = append(options, libpod.WithPodCgroups())
- pod, err := i.Runtime.NewPod(options...)
+ pod, err := i.Runtime.NewPod(getContext(), options...)
if err != nil {
return call.ReplyErrorOccurred(err.Error())
}
diff --git a/test/e2e/libpod_suite_test.go b/test/e2e/libpod_suite_test.go
index 466f79ae9..019ba9377 100644
--- a/test/e2e/libpod_suite_test.go
+++ b/test/e2e/libpod_suite_test.go
@@ -32,7 +32,7 @@ var (
CGROUP_MANAGER = "systemd"
STORAGE_OPTIONS = "--storage-driver vfs"
ARTIFACT_DIR = "/tmp/.artifacts"
- CACHE_IMAGES = []string{ALPINE, BB, fedoraMinimal, nginx, redis, registry}
+ CACHE_IMAGES = []string{ALPINE, BB, fedoraMinimal, nginx, redis, registry, pause}
RESTORE_IMAGES = []string{ALPINE, BB}
ALPINE = "docker.io/library/alpine:latest"
BB = "docker.io/library/busybox:latest"
@@ -41,6 +41,7 @@ var (
nginx = "quay.io/baude/alpine_nginx:latest"
redis = "docker.io/library/redis:alpine"
registry = "docker.io/library/registry:2"
+ pause = "k8s.gcr.io/pause:3.1"
defaultWaitTimeout = 90
)
@@ -422,6 +423,18 @@ func (p *PodmanTest) RestoreAllArtifacts() error {
return nil
}
+// CreatePod creates a pod with no pause container
+// it optionally takes a pod name
+func (p *PodmanTest) CreatePod(name string) (*PodmanSession, int, string) {
+ var podmanArgs = []string{"pod", "create", "--pause=false", "--share", ""}
+ if name != "" {
+ podmanArgs = append(podmanArgs, "--name", name)
+ }
+ session := p.Podman(podmanArgs)
+ session.WaitWithDefaultTimeout()
+ return session, session.ExitCode(), session.OutputToString()
+}
+
//RunTopContainer runs a simple container in the background that
// runs top. If the name passed != "", it will have a name
func (p *PodmanTest) RunTopContainer(name string) *PodmanSession {
diff --git a/test/e2e/pod_create_test.go b/test/e2e/pod_create_test.go
index a81751c41..4cf685ce2 100644
--- a/test/e2e/pod_create_test.go
+++ b/test/e2e/pod_create_test.go
@@ -32,23 +32,20 @@ var _ = Describe("Podman pod create", func() {
})
It("podman create pod", func() {
- session := podmanTest.Podman([]string{"pod", "create"})
- session.WaitWithDefaultTimeout()
- cid := session.OutputToString()
- Expect(session.ExitCode()).To(Equal(0))
+ _, ec, podID := podmanTest.CreatePod("")
+ Expect(ec).To(Equal(0))
check := podmanTest.Podman([]string{"pod", "ps", "-q", "--no-trunc"})
check.WaitWithDefaultTimeout()
- match, _ := check.GrepString(cid)
+ match, _ := check.GrepString(podID)
Expect(match).To(BeTrue())
Expect(len(check.OutputToStringArray())).To(Equal(1))
})
It("podman create pod with name", func() {
name := "test"
- session := podmanTest.Podman([]string{"pod", "create", "--name", name})
- session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
+ _, ec, _ := podmanTest.CreatePod(name)
+ Expect(ec).To(Equal(0))
check := podmanTest.Podman([]string{"pod", "ps", "--no-trunc"})
check.WaitWithDefaultTimeout()
@@ -58,13 +55,11 @@ var _ = Describe("Podman pod create", func() {
It("podman create pod with doubled name", func() {
name := "test"
- session := podmanTest.Podman([]string{"pod", "create", "--name", name})
- session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
+ _, ec, _ := podmanTest.CreatePod(name)
+ Expect(ec).To(Equal(0))
- session = podmanTest.Podman([]string{"pod", "create", "--name", name})
- session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Not(Equal(1)))
+ _, ec2, _ := podmanTest.CreatePod(name)
+ Expect(ec2).To(Not(Equal(0)))
check := podmanTest.Podman([]string{"pod", "ps", "-q"})
check.WaitWithDefaultTimeout()
@@ -77,9 +72,8 @@ var _ = Describe("Podman pod create", func() {
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- session = podmanTest.Podman([]string{"pod", "create", "--name", name})
- session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Not(Equal(1)))
+ _, ec, _ := podmanTest.CreatePod(name)
+ Expect(ec).To(Not(Equal(0)))
check := podmanTest.Podman([]string{"pod", "ps", "-q"})
check.WaitWithDefaultTimeout()
diff --git a/test/e2e/pod_inspect_test.go b/test/e2e/pod_inspect_test.go
index b5c2bd1be..667e59f38 100644
--- a/test/e2e/pod_inspect_test.go
+++ b/test/e2e/pod_inspect_test.go
@@ -38,12 +38,10 @@ var _ = Describe("Podman pod inspect", func() {
})
It("podman inspect a pod", func() {
- session := podmanTest.Podman([]string{"pod", "create"})
- session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
- podid := session.OutputToString()
+ _, ec, podid := podmanTest.CreatePod("")
+ Expect(ec).To(Equal(0))
- session = podmanTest.RunTopContainerInPod("", podid)
+ session := podmanTest.RunTopContainerInPod("", podid)
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
diff --git a/test/e2e/pod_kill_test.go b/test/e2e/pod_kill_test.go
index 427fb63b3..b29fe1e17 100644
--- a/test/e2e/pod_kill_test.go
+++ b/test/e2e/pod_kill_test.go
@@ -38,12 +38,10 @@ var _ = Describe("Podman pod kill", func() {
})
It("podman pod kill a pod by id", func() {
- session := podmanTest.Podman([]string{"pod", "create"})
- session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
- podid := session.OutputToString()
+ _, ec, podid := podmanTest.CreatePod("")
+ Expect(ec).To(Equal(0))
- session = podmanTest.RunTopContainerInPod("", podid)
+ session := podmanTest.RunTopContainerInPod("", podid)
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
@@ -58,12 +56,10 @@ var _ = Describe("Podman pod kill", func() {
})
It("podman pod kill a pod by id with TERM", func() {
- session := podmanTest.Podman([]string{"pod", "create"})
- session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
- podid := session.OutputToString()
+ _, ec, podid := podmanTest.CreatePod("")
+ Expect(ec).To(Equal(0))
- session = podmanTest.RunTopContainerInPod("", podid)
+ session := podmanTest.RunTopContainerInPod("", podid)
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
@@ -74,12 +70,10 @@ var _ = Describe("Podman pod kill", func() {
})
It("podman pod kill a pod by name", func() {
- session := podmanTest.Podman([]string{"pod", "create", "--name", "test1"})
- session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
- podid := session.OutputToString()
+ _, ec, podid := podmanTest.CreatePod("test1")
+ Expect(ec).To(Equal(0))
- session = podmanTest.RunTopContainerInPod("", podid)
+ session := podmanTest.RunTopContainerInPod("", podid)
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
@@ -90,12 +84,10 @@ var _ = Describe("Podman pod kill", func() {
})
It("podman pod kill a pod by id with a bogus signal", func() {
- session := podmanTest.Podman([]string{"pod", "create", "--name", "test1"})
- session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
- podid := session.OutputToString()
+ _, ec, podid := podmanTest.CreatePod("test1")
+ Expect(ec).To(Equal(0))
- session = podmanTest.RunTopContainerInPod("", podid)
+ session := podmanTest.RunTopContainerInPod("", podid)
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
@@ -106,19 +98,15 @@ var _ = Describe("Podman pod kill", func() {
})
It("podman pod kill latest pod", func() {
- session := podmanTest.Podman([]string{"pod", "create", "--name", "test1"})
- session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
- podid := session.OutputToString()
+ _, ec, podid := podmanTest.CreatePod("")
+ Expect(ec).To(Equal(0))
- session = podmanTest.RunTopContainerInPod("", podid)
+ session := podmanTest.RunTopContainerInPod("", podid)
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- session = podmanTest.Podman([]string{"pod", "create", "--name", "test2"})
- session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
- podid2 := session.OutputToString()
+ _, ec, podid2 := podmanTest.CreatePod("")
+ Expect(ec).To(Equal(0))
session = podmanTest.RunTopContainerInPod("", podid2)
session.WaitWithDefaultTimeout()
@@ -135,12 +123,10 @@ var _ = Describe("Podman pod kill", func() {
})
It("podman pod kill all", func() {
- session := podmanTest.Podman([]string{"pod", "create", "--name", "test1"})
- session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
- podid := session.OutputToString()
+ _, ec, podid := podmanTest.CreatePod("")
+ Expect(ec).To(Equal(0))
- session = podmanTest.RunTopContainerInPod("", podid)
+ session := podmanTest.RunTopContainerInPod("", podid)
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
@@ -148,10 +134,8 @@ var _ = Describe("Podman pod kill", func() {
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- session = podmanTest.Podman([]string{"pod", "create", "--name", "test2"})
- session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
- podid2 := session.OutputToString()
+ _, ec, podid2 := podmanTest.CreatePod("")
+ Expect(ec).To(Equal(0))
session = podmanTest.RunTopContainerInPod("", podid2)
session.WaitWithDefaultTimeout()
@@ -159,6 +143,7 @@ var _ = Describe("Podman pod kill", func() {
result := podmanTest.Podman([]string{"pod", "kill", "-a"})
result.WaitWithDefaultTimeout()
+ fmt.Println(result.OutputToString(), result.ErrorToString())
Expect(result.ExitCode()).To(Equal(0))
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
})
diff --git a/test/e2e/pod_pause_container_test.go b/test/e2e/pod_pause_container_test.go
new file mode 100644
index 000000000..09a1c18d0
--- /dev/null
+++ b/test/e2e/pod_pause_container_test.go
@@ -0,0 +1,285 @@
+package integration
+
+import (
+ "fmt"
+ "os"
+ "strconv"
+
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+)
+
+var _ = Describe("Podman pod create", func() {
+ var (
+ tempdir string
+ err error
+ podmanTest PodmanTest
+ )
+
+ BeforeEach(func() {
+ tempdir, err = CreateTempDirInTempDir()
+ if err != nil {
+ os.Exit(1)
+ }
+ podmanTest = PodmanCreate(tempdir)
+ podmanTest.RestoreAllArtifacts()
+ podmanTest.RestoreArtifact(pause)
+ })
+
+ AfterEach(func() {
+ podmanTest.CleanupPod()
+ f := CurrentGinkgoTestDescription()
+ timedResult := fmt.Sprintf("Test: %s completed in %f seconds", f.TestText, f.Duration.Seconds())
+ GinkgoWriter.Write([]byte(timedResult))
+ })
+
+ It("podman create pause container", func() {
+ session := podmanTest.Podman([]string{"pod", "create"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ podID := session.OutputToString()
+
+ check := podmanTest.Podman([]string{"pod", "ps", "-q", "--no-trunc"})
+ check.WaitWithDefaultTimeout()
+ match, _ := check.GrepString(podID)
+ Expect(match).To(BeTrue())
+ Expect(len(check.OutputToStringArray())).To(Equal(1))
+
+ check = podmanTest.Podman([]string{"ps", "-qa", "--no-trunc"})
+ check.WaitWithDefaultTimeout()
+ Expect(len(check.OutputToStringArray())).To(Equal(1))
+ })
+
+ It("podman start pause container", func() {
+ session := podmanTest.Podman([]string{"pod", "create"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ podID := session.OutputToString()
+
+ session = podmanTest.Podman([]string{"pod", "start", podID})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ check := podmanTest.Podman([]string{"ps", "-qa", "--no-trunc", "--filter", "status=running"})
+ check.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ Expect(len(check.OutputToStringArray())).To(Equal(1))
+ })
+
+ It("podman pause container namespaces", func() {
+ session := podmanTest.Podman([]string{"pod", "create"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ podID := session.OutputToString()
+
+ session = podmanTest.Podman([]string{"pod", "start", podID})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session = podmanTest.RunTopContainerInPod("", podID)
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ check := podmanTest.Podman([]string{"ps", "-a", "--no-trunc", "--ns", "--format", "{{.IPC}} {{.NET}}"})
+ check.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ Expect(len(check.OutputToStringArray())).To(Equal(2))
+ Expect(check.OutputToStringArray()[0]).To(Equal(check.OutputToStringArray()[1]))
+
+ })
+
+ It("podman pod correctly sets up NetNS", func() {
+ session := podmanTest.Podman([]string{"pod", "create", "--share", "net"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ podID := session.OutputToString()
+
+ session = podmanTest.Podman([]string{"pod", "start", podID})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ podmanTest.RestoreArtifact(nginx)
+ session = podmanTest.Podman([]string{"run", "-d", "--pod", podID, nginx})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ podmanTest.RestoreArtifact(fedoraMinimal)
+ session = podmanTest.Podman([]string{"run", "--pod", podID, fedoraMinimal, "curl", "localhost:80"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session = podmanTest.Podman([]string{"run", fedoraMinimal, "curl", "localhost"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Not(Equal(0)))
+ })
+
+ It("podman pod correctly sets up PIDNS", func() {
+ session := podmanTest.Podman([]string{"pod", "create", "--share", "pid", "--name", "test-pod"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ podID := session.OutputToString()
+
+ session = podmanTest.Podman([]string{"pod", "start", podID})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session = podmanTest.RunTopContainerInPod("test-ctr", podID)
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ check := podmanTest.Podman([]string{"top", "test-ctr", "pid"})
+ check.WaitWithDefaultTimeout()
+ Expect(check.ExitCode()).To(Equal(0))
+ PIDs := check.OutputToStringArray()
+ Expect(len(PIDs)).To(Equal(4))
+
+ ctrPID, _ := strconv.Atoi(PIDs[1])
+ pausePID, _ := strconv.Atoi(PIDs[2])
+ Expect(ctrPID).To(BeNumerically("<", pausePID))
+ })
+
+ It("podman pod doesn't share PIDNS if requested to not", func() {
+ session := podmanTest.Podman([]string{"pod", "create", "--share", "net", "--name", "test-pod"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ podID := session.OutputToString()
+
+ session = podmanTest.Podman([]string{"pod", "start", podID})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session = podmanTest.RunTopContainerInPod("test-ctr", podID)
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ check := podmanTest.Podman([]string{"top", "test-ctr", "pid"})
+ check.WaitWithDefaultTimeout()
+ Expect(check.ExitCode()).To(Equal(0))
+ ctrTop := check.OutputToStringArray()
+
+ check = podmanTest.Podman([]string{"top", podID[:12] + "-infra", "pid"})
+ check.WaitWithDefaultTimeout()
+ Expect(check.ExitCode()).To(Equal(0))
+ pauseTop := check.OutputToStringArray()
+
+ ctrPID, _ := strconv.Atoi(ctrTop[1])
+ pausePID, _ := strconv.Atoi(pauseTop[1])
+ Expect(ctrPID).To(Equal(pausePID))
+ })
+
+ It("podman pod container can override pod net NS", func() {
+ session := podmanTest.Podman([]string{"pod", "create", "--share", "net"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ podID := session.OutputToString()
+
+ session = podmanTest.Podman([]string{"pod", "start", podID})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ podmanTest.RestoreArtifact(nginx)
+ session = podmanTest.Podman([]string{"run", "-d", "--pod", podID, nginx})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ podmanTest.RestoreArtifact(fedoraMinimal)
+ session = podmanTest.Podman([]string{"run", "--pod", podID, "--network", "bridge", fedoraMinimal, "curl", "localhost"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Not(Equal(0)))
+ })
+
+ It("podman pod container can override pod pid NS", func() {
+ session := podmanTest.Podman([]string{"pod", "create", "--share", "pid"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ podID := session.OutputToString()
+
+ session = podmanTest.Podman([]string{"pod", "start", podID})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session = podmanTest.Podman([]string{"run", "--pod", podID, "--pid", "host", "-d", ALPINE, "top"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ check := podmanTest.Podman([]string{"ps", "-a", "--ns", "--format", "{{.PIDNS}}"})
+ check.WaitWithDefaultTimeout()
+ Expect(check.ExitCode()).To(Equal(0))
+ outputArray := check.OutputToStringArray()
+ Expect(len(outputArray)).To(Equal(2))
+
+ PID1 := outputArray[0]
+ PID2 := outputArray[1]
+ Expect(PID1).To(Not(Equal(PID2)))
+ })
+
+ It("podman pod container can override pod not sharing pid", func() {
+ session := podmanTest.Podman([]string{"pod", "create", "--share", "net"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ podID := session.OutputToString()
+
+ session = podmanTest.Podman([]string{"pod", "start", podID})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session = podmanTest.Podman([]string{"run", "--pod", podID, "--pid", "pod", "-d", ALPINE, "top"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ check := podmanTest.Podman([]string{"ps", "-a", "--ns", "--format", "{{.PIDNS}}"})
+ check.WaitWithDefaultTimeout()
+ Expect(check.ExitCode()).To(Equal(0))
+ outputArray := check.OutputToStringArray()
+ Expect(len(outputArray)).To(Equal(2))
+
+ PID1 := outputArray[0]
+ PID2 := outputArray[1]
+ Expect(PID1).To(Equal(PID2))
+ })
+
+ It("podman pod container can override pod ipc NS", func() {
+ session := podmanTest.Podman([]string{"pod", "create", "--share", "ipc"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ podID := session.OutputToString()
+
+ session = podmanTest.Podman([]string{"pod", "start", podID})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session = podmanTest.Podman([]string{"run", "--pod", podID, "--ipc", "host", "-d", ALPINE, "top"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ check := podmanTest.Podman([]string{"ps", "-a", "--ns", "--format", "{{.IPC}}"})
+ check.WaitWithDefaultTimeout()
+ Expect(check.ExitCode()).To(Equal(0))
+ outputArray := check.OutputToStringArray()
+ Expect(len(outputArray)).To(Equal(2))
+
+ PID1 := outputArray[0]
+ PID2 := outputArray[1]
+ Expect(PID1).To(Not(Equal(PID2)))
+ })
+
+ It("podman pod pause container deletion", func() {
+ session := podmanTest.Podman([]string{"pod", "create", "--share", "ipc"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ podID := session.OutputToString()
+
+ session = podmanTest.Podman([]string{"ps", "-aq"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ pauseID := session.OutputToString()
+
+ session = podmanTest.Podman([]string{"rm", pauseID})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Not(Equal(0)))
+
+ session = podmanTest.Podman([]string{"pod", "rm", podID})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ })
+})
diff --git a/test/e2e/pod_pause_test.go b/test/e2e/pod_pause_test.go
index 6a5afe73b..384cbfcb7 100644
--- a/test/e2e/pod_pause_test.go
+++ b/test/e2e/pod_pause_test.go
@@ -46,10 +46,8 @@ var _ = Describe("Podman pod pause", func() {
})
It("podman pod pause a created pod by id", func() {
- session := podmanTest.Podman([]string{"pod", "create"})
- session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
- podid := session.OutputToString()
+ _, ec, podid := podmanTest.CreatePod("")
+ Expect(ec).To(Equal(0))
result := podmanTest.Podman([]string{"pod", "pause", podid})
result.WaitWithDefaultTimeout()
@@ -57,12 +55,10 @@ var _ = Describe("Podman pod pause", func() {
})
It("podman pod pause a running pod by id", func() {
- session := podmanTest.Podman([]string{"pod", "create"})
- session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
- podid := session.OutputToString()
+ _, ec, podid := podmanTest.CreatePod("")
+ Expect(ec).To(Equal(0))
- session = podmanTest.RunTopContainerInPod("", podid)
+ session := podmanTest.RunTopContainerInPod("", podid)
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
@@ -80,12 +76,10 @@ var _ = Describe("Podman pod pause", func() {
})
It("podman unpause a running pod by id", func() {
- session := podmanTest.Podman([]string{"pod", "create"})
- session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
- podid := session.OutputToString()
+ _, ec, podid := podmanTest.CreatePod("")
+ Expect(ec).To(Equal(0))
- session = podmanTest.RunTopContainerInPod("", podid)
+ session := podmanTest.RunTopContainerInPod("", podid)
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
@@ -97,11 +91,10 @@ var _ = Describe("Podman pod pause", func() {
})
It("podman pod pause a running pod by name", func() {
- session := podmanTest.Podman([]string{"pod", "create", "--name", "test1"})
- session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
+ _, ec, _ := podmanTest.CreatePod("test1")
+ Expect(ec).To(Equal(0))
- session = podmanTest.RunTopContainerInPod("", "test1")
+ session := podmanTest.RunTopContainerInPod("", "test1")
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
diff --git a/test/e2e/pod_ps_test.go b/test/e2e/pod_ps_test.go
index 4e2995917..b48cb9578 100644
--- a/test/e2e/pod_ps_test.go
+++ b/test/e2e/pod_ps_test.go
@@ -39,12 +39,10 @@ var _ = Describe("Podman ps", func() {
})
It("podman pod ps default", func() {
- session := podmanTest.Podman([]string{"pod", "create"})
- session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
+ _, ec, podid := podmanTest.CreatePod("")
+ Expect(ec).To(Equal(0))
- podid := session.OutputToString()
- session = podmanTest.RunTopContainerInPod("", podid)
+ session := podmanTest.RunTopContainerInPod("", podid)
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
@@ -55,12 +53,10 @@ var _ = Describe("Podman ps", func() {
})
It("podman pod ps quiet flag", func() {
- session := podmanTest.Podman([]string{"pod", "create"})
- session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
+ _, ec, podid := podmanTest.CreatePod("")
+ Expect(ec).To(Equal(0))
- podid := session.OutputToString()
- _, ec, _ := podmanTest.RunLsContainerInPod("", podid)
+ _, ec, _ = podmanTest.RunLsContainerInPod("", podid)
Expect(ec).To(Equal(0))
result := podmanTest.Podman([]string{"pod", "ps", "-q"})
@@ -71,14 +67,12 @@ var _ = Describe("Podman ps", func() {
})
It("podman pod ps no-trunc", func() {
- session := podmanTest.Podman([]string{"pod", "create"})
- session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
-
- podid := session.OutputToString()
- _, ec, _ := podmanTest.RunLsContainerInPod("", podid)
+ _, ec, podid := podmanTest.CreatePod("")
Expect(ec).To(Equal(0))
+ _, ec2, _ := podmanTest.RunLsContainerInPod("", podid)
+ Expect(ec2).To(Equal(0))
+
result := podmanTest.Podman([]string{"pod", "ps", "-q", "--no-trunc"})
result.WaitWithDefaultTimeout()
Expect(result.ExitCode()).To(Equal(0))
@@ -87,17 +81,11 @@ var _ = Describe("Podman ps", func() {
})
It("podman pod ps latest", func() {
- session := podmanTest.Podman([]string{"pod", "create"})
- session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
-
- podid1 := session.OutputToString()
-
- session = podmanTest.Podman([]string{"pod", "create"})
- session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
+ _, ec, podid1 := podmanTest.CreatePod("")
+ Expect(ec).To(Equal(0))
- podid2 := session.OutputToString()
+ _, ec2, podid2 := podmanTest.CreatePod("")
+ Expect(ec2).To(Equal(0))
result := podmanTest.Podman([]string{"pod", "ps", "-q", "--no-trunc", "--latest"})
result.WaitWithDefaultTimeout()
@@ -106,11 +94,10 @@ var _ = Describe("Podman ps", func() {
Expect(result.OutputToString()).To(Not(ContainSubstring(podid1)))
})
It("podman pod ps id filter flag", func() {
- session := podmanTest.Podman([]string{"pod", "create"})
- session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
+ _, ec, podid := podmanTest.CreatePod("")
+ Expect(ec).To(Equal(0))
- result := podmanTest.Podman([]string{"pod", "ps", "--filter", fmt.Sprintf("id=%s", session.OutputToString())})
+ result := podmanTest.Podman([]string{"pod", "ps", "--filter", fmt.Sprintf("id=%s", podid)})
result.WaitWithDefaultTimeout()
Expect(result.ExitCode()).To(Equal(0))
})
@@ -123,19 +110,16 @@ var _ = Describe("Podman ps", func() {
})
It("podman pod ps --sort by name", func() {
- session := podmanTest.Podman([]string{"pod", "create"})
- session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
+ _, ec, _ := podmanTest.CreatePod("")
+ Expect(ec).To(Equal(0))
- session = podmanTest.Podman([]string{"pod", "create"})
- session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
+ _, ec2, _ := podmanTest.CreatePod("")
+ Expect(ec2).To(Equal(0))
- session = podmanTest.Podman([]string{"pod", "create"})
- session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
+ _, ec3, _ := podmanTest.CreatePod("")
+ Expect(ec3).To(Equal(0))
- session = podmanTest.Podman([]string{"pod", "ps", "--sort=name", "--format", "{{.Name}}"})
+ session := podmanTest.Podman([]string{"pod", "ps", "--sort=name", "--format", "{{.Name}}"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
@@ -146,16 +130,14 @@ var _ = Describe("Podman ps", func() {
})
It("podman pod ps --ctr-names", func() {
- session := podmanTest.Podman([]string{"pod", "create"})
- session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
- podid := session.OutputToString()
+ _, ec, podid := podmanTest.CreatePod("")
+ Expect(ec).To(Equal(0))
- session = podmanTest.RunTopContainerInPod("test1", podid)
+ session := podmanTest.RunTopContainerInPod("test1", podid)
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- _, ec, _ := podmanTest.RunLsContainerInPod("test2", podid)
+ _, ec, _ = podmanTest.RunLsContainerInPod("test2", podid)
Expect(ec).To(Equal(0))
session = podmanTest.Podman([]string{"pod", "ps", "--format={{.ContainerInfo}}", "--ctr-names"})
@@ -166,22 +148,18 @@ var _ = Describe("Podman ps", func() {
})
It("podman pod ps filter ctr attributes", func() {
- session := podmanTest.Podman([]string{"pod", "create"})
- session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
- podid1 := session.OutputToString()
+ _, ec, podid1 := podmanTest.CreatePod("")
+ Expect(ec).To(Equal(0))
- session = podmanTest.RunTopContainerInPod("test1", podid1)
+ session := podmanTest.RunTopContainerInPod("test1", podid1)
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- session = podmanTest.Podman([]string{"pod", "create"})
- session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
- podid2 := session.OutputToString()
+ _, ec2, podid2 := podmanTest.CreatePod("")
+ Expect(ec2).To(Equal(0))
- _, ec, cid := podmanTest.RunLsContainerInPod("test2", podid2)
- Expect(ec).To(Equal(0))
+ _, ec3, cid := podmanTest.RunLsContainerInPod("test2", podid2)
+ Expect(ec3).To(Equal(0))
session = podmanTest.Podman([]string{"pod", "ps", "-q", "--no-trunc", "--filter", "ctr-names=test1"})
session.WaitWithDefaultTimeout()
@@ -195,10 +173,8 @@ var _ = Describe("Podman ps", func() {
Expect(session.OutputToString()).To(ContainSubstring(podid2))
Expect(session.OutputToString()).To(Not(ContainSubstring(podid1)))
- session = podmanTest.Podman([]string{"pod", "create"})
- session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
- podid3 := session.OutputToString()
+ _, ec3, podid3 := podmanTest.CreatePod("")
+ Expect(ec3).To(Equal(0))
session = podmanTest.Podman([]string{"pod", "ps", "-q", "--no-trunc", "--filter", "ctr-number=1"})
session.WaitWithDefaultTimeout()
diff --git a/test/e2e/pod_restart_test.go b/test/e2e/pod_restart_test.go
index 86132c04f..e486f8791 100644
--- a/test/e2e/pod_restart_test.go
+++ b/test/e2e/pod_restart_test.go
@@ -38,22 +38,19 @@ var _ = Describe("Podman pod restart", func() {
})
It("podman pod restart single empty pod", func() {
- session := podmanTest.Podman([]string{"pod", "create"})
- session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
- cid := session.OutputToString()
+ _, ec, podid := podmanTest.CreatePod("")
+ Expect(ec).To(Equal(0))
- session = podmanTest.Podman([]string{"pod", "restart", cid})
+ session := podmanTest.Podman([]string{"pod", "restart", podid})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(125))
})
It("podman pod restart single pod by name", func() {
- session := podmanTest.Podman([]string{"pod", "create", "--name", "foobar99"})
- session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
+ _, ec, _ := podmanTest.CreatePod("foobar99")
+ Expect(ec).To(Equal(0))
- session = podmanTest.RunTopContainerInPod("test1", "foobar99")
+ session := podmanTest.RunTopContainerInPod("test1", "foobar99")
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
@@ -70,15 +67,15 @@ var _ = Describe("Podman pod restart", func() {
})
It("podman pod restart multiple pods", func() {
- session := podmanTest.Podman([]string{"pod", "create", "--name", "foobar99"})
- session.WaitWithDefaultTimeout()
+ _, ec, _ := podmanTest.CreatePod("foobar99")
+ Expect(ec).To(Equal(0))
- session = podmanTest.RunTopContainerInPod("test1", "foobar99")
+ session := podmanTest.RunTopContainerInPod("test1", "foobar99")
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- session2 := podmanTest.Podman([]string{"pod", "create", "--name", "foobar100"})
- session2.WaitWithDefaultTimeout()
+ _, ec, _ = podmanTest.CreatePod("foobar100")
+ Expect(ec).To(Equal(0))
session = podmanTest.RunTopContainerInPod("test2", "foobar100")
session.WaitWithDefaultTimeout()
@@ -108,15 +105,15 @@ var _ = Describe("Podman pod restart", func() {
})
It("podman pod restart all pods", func() {
- session := podmanTest.Podman([]string{"pod", "create", "--name", "foobar99"})
- session.WaitWithDefaultTimeout()
+ _, ec, _ := podmanTest.CreatePod("foobar99")
+ Expect(ec).To(Equal(0))
- session = podmanTest.RunTopContainerInPod("test1", "foobar99")
+ session := podmanTest.RunTopContainerInPod("test1", "foobar99")
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- session2 := podmanTest.Podman([]string{"pod", "create", "--name", "foobar100"})
- session2.WaitWithDefaultTimeout()
+ _, ec, _ = podmanTest.CreatePod("foobar100")
+ Expect(ec).To(Equal(0))
session = podmanTest.RunTopContainerInPod("test2", "foobar100")
session.WaitWithDefaultTimeout()
@@ -136,15 +133,15 @@ var _ = Describe("Podman pod restart", func() {
})
It("podman pod restart latest pod", func() {
- session := podmanTest.Podman([]string{"pod", "create", "--name", "foobar99"})
- session.WaitWithDefaultTimeout()
+ _, ec, _ := podmanTest.CreatePod("foobar99")
+ Expect(ec).To(Equal(0))
- session = podmanTest.RunTopContainerInPod("test1", "foobar99")
+ session := podmanTest.RunTopContainerInPod("test1", "foobar99")
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- session2 := podmanTest.Podman([]string{"pod", "create", "--name", "foobar100"})
- session2.WaitWithDefaultTimeout()
+ _, ec, _ = podmanTest.CreatePod("foobar100")
+ Expect(ec).To(Equal(0))
session = podmanTest.RunTopContainerInPod("test2", "foobar100")
session.WaitWithDefaultTimeout()
@@ -164,15 +161,14 @@ var _ = Describe("Podman pod restart", func() {
})
It("podman pod restart multiple pods with bogus", func() {
- session := podmanTest.Podman([]string{"pod", "create", "--name", "foobar99"})
- session.WaitWithDefaultTimeout()
- cid1 := session.OutputToString()
+ _, ec, podid1 := podmanTest.CreatePod("foobar99")
+ Expect(ec).To(Equal(0))
- session = podmanTest.RunTopContainerInPod("", "foobar99")
+ session := podmanTest.RunTopContainerInPod("", "foobar99")
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- session = podmanTest.Podman([]string{"pod", "restart", cid1, "doesnotexist"})
+ session = podmanTest.Podman([]string{"pod", "restart", podid1, "doesnotexist"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(125))
})
diff --git a/test/e2e/pod_rm_test.go b/test/e2e/pod_rm_test.go
index 1ce0d18c7..09002e954 100644
--- a/test/e2e/pod_rm_test.go
+++ b/test/e2e/pod_rm_test.go
@@ -32,9 +32,8 @@ var _ = Describe("Podman pod rm", func() {
})
It("podman pod rm empty pod", func() {
- session := podmanTest.Podman([]string{"pod", "create"})
- session.WaitWithDefaultTimeout()
- podid := session.OutputToString()
+ _, ec, podid := podmanTest.CreatePod("")
+ Expect(ec).To(Equal(0))
result := podmanTest.Podman([]string{"pod", "rm", podid})
result.WaitWithDefaultTimeout()
@@ -42,13 +41,11 @@ var _ = Describe("Podman pod rm", func() {
})
It("podman pod rm latest pod", func() {
- session := podmanTest.Podman([]string{"pod", "create"})
- session.WaitWithDefaultTimeout()
- podid := session.OutputToString()
+ _, ec, podid := podmanTest.CreatePod("")
+ Expect(ec).To(Equal(0))
- session = podmanTest.Podman([]string{"pod", "create"})
- session.WaitWithDefaultTimeout()
- podid2 := session.OutputToString()
+ _, ec2, podid2 := podmanTest.CreatePod("")
+ Expect(ec2).To(Equal(0))
result := podmanTest.Podman([]string{"pod", "rm", "--latest"})
result.WaitWithDefaultTimeout()
@@ -62,14 +59,11 @@ var _ = Describe("Podman pod rm", func() {
})
It("podman pod rm doesn't remove a pod with a container", func() {
- session := podmanTest.Podman([]string{"pod", "create"})
- session.WaitWithDefaultTimeout()
-
- podid := session.OutputToString()
+ _, ec, podid := podmanTest.CreatePod("")
+ Expect(ec).To(Equal(0))
- session = podmanTest.Podman([]string{"create", "--pod", podid, ALPINE, "ls"})
- session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
+ _, ec2, _ := podmanTest.RunLsContainerInPod("", podid)
+ Expect(ec2).To(Equal(0))
result := podmanTest.Podman([]string{"pod", "rm", podid})
result.WaitWithDefaultTimeout()
@@ -81,12 +75,10 @@ var _ = Describe("Podman pod rm", func() {
})
It("podman pod rm -f does remove a running container", func() {
- session := podmanTest.Podman([]string{"pod", "create"})
- session.WaitWithDefaultTimeout()
+ _, ec, podid := podmanTest.CreatePod("")
+ Expect(ec).To(Equal(0))
- podid := session.OutputToString()
-
- session = podmanTest.Podman([]string{"run", "-d", "--pod", podid, ALPINE, "top"})
+ session := podmanTest.RunTopContainerInPod("", podid)
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
@@ -100,15 +92,13 @@ var _ = Describe("Podman pod rm", func() {
})
It("podman pod rm -a doesn't remove a running container", func() {
- session := podmanTest.Podman([]string{"pod", "create"})
- session.WaitWithDefaultTimeout()
+ _, ec, podid1 := podmanTest.CreatePod("")
+ Expect(ec).To(Equal(0))
- podid1 := session.OutputToString()
+ _, ec, _ = podmanTest.CreatePod("")
+ Expect(ec).To(Equal(0))
- session = podmanTest.Podman([]string{"pod", "create"})
- session.WaitWithDefaultTimeout()
-
- session = podmanTest.Podman([]string{"run", "-d", "--pod", podid1, ALPINE, "top"})
+ session := podmanTest.RunTopContainerInPod("", podid1)
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
@@ -127,20 +117,16 @@ var _ = Describe("Podman pod rm", func() {
})
It("podman pod rm -fa removes everything", func() {
- session := podmanTest.Podman([]string{"pod", "create"})
- session.WaitWithDefaultTimeout()
-
- podid1 := session.OutputToString()
-
- session = podmanTest.Podman([]string{"pod", "create"})
- session.WaitWithDefaultTimeout()
+ _, ec, podid1 := podmanTest.CreatePod("")
+ Expect(ec).To(Equal(0))
- podid2 := session.OutputToString()
+ _, ec, podid2 := podmanTest.CreatePod("")
+ Expect(ec).To(Equal(0))
- session = podmanTest.Podman([]string{"pod", "create"})
- session.WaitWithDefaultTimeout()
+ _, ec, _ = podmanTest.CreatePod("")
+ Expect(ec).To(Equal(0))
- session = podmanTest.Podman([]string{"run", "-d", "--pod", podid1, ALPINE, "top"})
+ session := podmanTest.RunTopContainerInPod("", podid1)
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
@@ -148,12 +134,12 @@ var _ = Describe("Podman pod rm", func() {
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- session = podmanTest.Podman([]string{"run", "-d", "--pod", podid2, ALPINE, "ls"})
- session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
+ _, ec, _ = podmanTest.RunLsContainerInPod("", podid2)
+ Expect(ec).To(Equal(0))
- session = podmanTest.Podman([]string{"run", "-d", "--pod", podid2, ALPINE, "top"})
+ session = podmanTest.RunTopContainerInPod("", podid2)
session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
result := podmanTest.Podman([]string{"pod", "rm", "-fa"})
result.WaitWithDefaultTimeout()
diff --git a/test/e2e/pod_start_test.go b/test/e2e/pod_start_test.go
index 17296c4b3..9d2ea9b26 100644
--- a/test/e2e/pod_start_test.go
+++ b/test/e2e/pod_start_test.go
@@ -38,22 +38,19 @@ var _ = Describe("Podman pod start", func() {
})
It("podman pod start single empty pod", func() {
- session := podmanTest.Podman([]string{"pod", "create"})
- session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
- cid := session.OutputToString()
+ _, ec, podid := podmanTest.CreatePod("")
+ Expect(ec).To(Equal(0))
- session = podmanTest.Podman([]string{"pod", "start", cid})
+ session := podmanTest.Podman([]string{"pod", "start", podid})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(125))
})
It("podman pod start single pod by name", func() {
- session := podmanTest.Podman([]string{"pod", "create", "--name", "foobar99"})
- session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
+ _, ec, _ := podmanTest.CreatePod("foobar99")
+ Expect(ec).To(Equal(0))
- session = podmanTest.Podman([]string{"create", "--pod", "foobar99", ALPINE, "ls"})
+ session := podmanTest.Podman([]string{"create", "--pod", "foobar99", ALPINE, "ls"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
@@ -63,38 +60,36 @@ var _ = Describe("Podman pod start", func() {
})
It("podman pod start multiple pods", func() {
- session := podmanTest.Podman([]string{"pod", "create", "--name", "foobar99"})
- session.WaitWithDefaultTimeout()
- cid1 := session.OutputToString()
+ _, ec, podid1 := podmanTest.CreatePod("foobar99")
+ Expect(ec).To(Equal(0))
- session = podmanTest.Podman([]string{"create", "--pod", "foobar99", ALPINE, "top"})
+ session := podmanTest.Podman([]string{"create", "--pod", "foobar99", ALPINE, "top"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- session2 := podmanTest.Podman([]string{"pod", "create", "--name", "foobar100"})
- session2.WaitWithDefaultTimeout()
- cid2 := session2.OutputToString()
+ _, ec2, podid2 := podmanTest.CreatePod("foobar100")
+ Expect(ec2).To(Equal(0))
session = podmanTest.Podman([]string{"create", "--pod", "foobar100", ALPINE, "top"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- session = podmanTest.Podman([]string{"pod", "start", cid1, cid2})
+ session = podmanTest.Podman([]string{"pod", "start", podid1, podid2})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(2))
})
It("podman pod start all pods", func() {
- session := podmanTest.Podman([]string{"pod", "create", "--name", "foobar99"})
- session.WaitWithDefaultTimeout()
+ _, ec, _ := podmanTest.CreatePod("foobar99")
+ Expect(ec).To(Equal(0))
- session = podmanTest.Podman([]string{"create", "--pod", "foobar99", ALPINE, "top"})
+ session := podmanTest.Podman([]string{"create", "--pod", "foobar99", ALPINE, "top"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- session2 := podmanTest.Podman([]string{"pod", "create", "--name", "foobar100"})
- session2.WaitWithDefaultTimeout()
+ _, ec, _ = podmanTest.CreatePod("foobar100")
+ Expect(ec).To(Equal(0))
session = podmanTest.Podman([]string{"create", "--pod", "foobar100", ALPINE, "top"})
session.WaitWithDefaultTimeout()
@@ -107,15 +102,15 @@ var _ = Describe("Podman pod start", func() {
})
It("podman pod start latest pod", func() {
- session := podmanTest.Podman([]string{"pod", "create", "--name", "foobar99"})
- session.WaitWithDefaultTimeout()
+ _, ec, _ := podmanTest.CreatePod("foobar99")
+ Expect(ec).To(Equal(0))
- session = podmanTest.Podman([]string{"create", "--pod", "foobar99", ALPINE, "top"})
+ session := podmanTest.Podman([]string{"create", "--pod", "foobar99", ALPINE, "top"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- session2 := podmanTest.Podman([]string{"pod", "create", "--name", "foobar100"})
- session2.WaitWithDefaultTimeout()
+ _, ec, _ = podmanTest.CreatePod("foobar100")
+ Expect(ec).To(Equal(0))
session = podmanTest.Podman([]string{"create", "--pod", "foobar100", ALPINE, "top"})
session.WaitWithDefaultTimeout()
@@ -128,15 +123,14 @@ var _ = Describe("Podman pod start", func() {
})
It("podman pod start multiple pods with bogus", func() {
- session := podmanTest.Podman([]string{"pod", "create", "--name", "foobar99"})
- session.WaitWithDefaultTimeout()
- cid1 := session.OutputToString()
+ _, ec, podid := podmanTest.CreatePod("foobar99")
+ Expect(ec).To(Equal(0))
- session = podmanTest.Podman([]string{"create", "--pod", "foobar99", ALPINE, "top"})
+ session := podmanTest.Podman([]string{"create", "--pod", "foobar99", ALPINE, "top"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- session = podmanTest.Podman([]string{"pod", "start", cid1, "doesnotexist"})
+ session = podmanTest.Podman([]string{"pod", "start", podid, "doesnotexist"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(125))
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
diff --git a/test/e2e/pod_stop_test.go b/test/e2e/pod_stop_test.go
index 0eb41b696..32f8559ad 100644
--- a/test/e2e/pod_stop_test.go
+++ b/test/e2e/pod_stop_test.go
@@ -38,22 +38,19 @@ var _ = Describe("Podman pod stop", func() {
})
It("podman pod stop single empty pod", func() {
- session := podmanTest.Podman([]string{"pod", "create"})
- session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
- cid := session.OutputToString()
+ _, ec, podid := podmanTest.CreatePod("")
+ Expect(ec).To(Equal(0))
- session = podmanTest.Podman([]string{"pod", "stop", cid})
+ session := podmanTest.Podman([]string{"pod", "stop", podid})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
})
It("podman pod stop single pod by name", func() {
- session := podmanTest.Podman([]string{"pod", "create", "--name", "foobar99"})
- session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
+ _, ec, _ := podmanTest.CreatePod("foobar99")
+ Expect(ec).To(Equal(0))
- session = podmanTest.RunTopContainerInPod("", "foobar99")
+ session := podmanTest.RunTopContainerInPod("", "foobar99")
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
@@ -64,38 +61,36 @@ var _ = Describe("Podman pod stop", func() {
})
It("podman pod stop multiple pods", func() {
- session := podmanTest.Podman([]string{"pod", "create", "--name", "foobar99"})
- session.WaitWithDefaultTimeout()
- cid1 := session.OutputToString()
+ _, ec, podid1 := podmanTest.CreatePod("foobar99")
+ Expect(ec).To(Equal(0))
- session = podmanTest.RunTopContainerInPod("", "foobar99")
+ session := podmanTest.RunTopContainerInPod("", "foobar99")
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- session2 := podmanTest.Podman([]string{"pod", "create", "--name", "foobar100"})
- session2.WaitWithDefaultTimeout()
- cid2 := session2.OutputToString()
+ _, ec2, podid2 := podmanTest.CreatePod("foobar100")
+ Expect(ec2).To(Equal(0))
session = podmanTest.RunTopContainerInPod("", "foobar100")
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- session = podmanTest.Podman([]string{"pod", "stop", cid1, cid2})
+ session = podmanTest.Podman([]string{"pod", "stop", podid1, podid2})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
})
It("podman pod stop all pods", func() {
- session := podmanTest.Podman([]string{"pod", "create", "--name", "foobar99"})
- session.WaitWithDefaultTimeout()
+ _, ec, _ := podmanTest.CreatePod("foobar99")
+ Expect(ec).To(Equal(0))
- session = podmanTest.RunTopContainerInPod("", "foobar99")
+ session := podmanTest.RunTopContainerInPod("", "foobar99")
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- session2 := podmanTest.Podman([]string{"pod", "create", "--name", "foobar100"})
- session2.WaitWithDefaultTimeout()
+ _, ec, _ = podmanTest.CreatePod("foobar100")
+ Expect(ec).To(Equal(0))
session = podmanTest.RunTopContainerInPod("", "foobar100")
session.WaitWithDefaultTimeout()
@@ -108,15 +103,15 @@ var _ = Describe("Podman pod stop", func() {
})
It("podman pod stop latest pod", func() {
- session := podmanTest.Podman([]string{"pod", "create", "--name", "foobar99"})
- session.WaitWithDefaultTimeout()
+ _, ec, _ := podmanTest.CreatePod("foobar99")
+ Expect(ec).To(Equal(0))
- session = podmanTest.RunTopContainerInPod("", "foobar99")
+ session := podmanTest.RunTopContainerInPod("", "foobar99")
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- session2 := podmanTest.Podman([]string{"pod", "create", "--name", "foobar100"})
- session2.WaitWithDefaultTimeout()
+ _, ec, _ = podmanTest.CreatePod("foobar100")
+ Expect(ec).To(Equal(0))
session = podmanTest.RunTopContainerInPod("", "foobar100")
session.WaitWithDefaultTimeout()
@@ -129,15 +124,14 @@ var _ = Describe("Podman pod stop", func() {
})
It("podman pod stop multiple pods with bogus", func() {
- session := podmanTest.Podman([]string{"pod", "create", "--name", "foobar99"})
- session.WaitWithDefaultTimeout()
- cid1 := session.OutputToString()
+ _, ec, podid1 := podmanTest.CreatePod("foobar99")
+ Expect(ec).To(Equal(0))
- session = podmanTest.RunTopContainerInPod("", "foobar99")
+ session := podmanTest.RunTopContainerInPod("", "foobar99")
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- session = podmanTest.Podman([]string{"pod", "stop", cid1, "doesnotexist"})
+ session = podmanTest.Podman([]string{"pod", "stop", podid1, "doesnotexist"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(125))
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
diff --git a/test/e2e/ps_test.go b/test/e2e/ps_test.go
index 5dfb385a8..f5d79193b 100644
--- a/test/e2e/ps_test.go
+++ b/test/e2e/ps_test.go
@@ -248,12 +248,10 @@ var _ = Describe("Podman ps", func() {
})
It("podman --pod", func() {
- session := podmanTest.Podman([]string{"pod", "create"})
- session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
- podid := session.OutputToString()
+ _, ec, podid := podmanTest.CreatePod("")
+ Expect(ec).To(Equal(0))
- session = podmanTest.RunTopContainerInPod("", podid)
+ session := podmanTest.RunTopContainerInPod("", podid)
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))