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
This commit is contained in:
haircommander 2018-07-27 13:58:50 -04:00 committed by Atomic Bot
parent 63dd200e7e
commit d5e690914d
41 changed files with 2575 additions and 391 deletions

View file

@ -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") {

View file

@ -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...)
}

View file

@ -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
}

View file

@ -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
@ -110,10 +112,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",
@ -138,6 +136,10 @@ var (
Name: "latest, l",
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)

View file

@ -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)

View file

@ -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"
}

View file

@ -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)

View file

@ -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"

View file

@ -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
}

View file

@ -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:

View file

@ -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

View file

@ -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 {

View file

@ -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 {

View file

@ -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
}
}

View file

@ -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)

View file

@ -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,
}

View file

@ -11,6 +11,212 @@ import (
fflib "github.com/pquerna/ffjson/fflib/v1"
)
// 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
@ -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:

View file

@ -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

View file

@ -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,
}
)

View file

@ -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...)
}
ctr, err := newContainer(rSpec, r.lockDir)
if err != nil {
return nil, err
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)
// 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, 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()

View file

@ -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)
}

View file

@ -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())
}

View file

@ -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)
}

View file

@ -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
}

View file

@ -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.

View file

@ -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 {

View file

@ -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)

View file

@ -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

View file

@ -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())
}

View file

@ -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 {

View file

@ -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()

View file

@ -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))

View file

@ -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,23 +123,19 @@ var _ = Describe("Podman pod kill", func() {
})
It("podman pod kill all", func() {
session := podmanTest.Podman([]string{"pod", "create", "--name", "test1"})
_, ec, podid := podmanTest.CreatePod("")
Expect(ec).To(Equal(0))
session := podmanTest.RunTopContainerInPod("", podid)
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
podid := session.OutputToString()
session = podmanTest.RunTopContainerInPod("", podid)
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
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()
@ -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))
})

View file

@ -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))
})
})

View file

@ -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))

View file

@ -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))
_, ec, podid1 := podmanTest.CreatePod("")
Expect(ec).To(Equal(0))
podid1 := session.OutputToString()
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))
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,23 +148,19 @@ 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()
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()
_, ec, cid := podmanTest.RunLsContainerInPod("test2", podid2)
_, ec, podid1 := podmanTest.CreatePod("")
Expect(ec).To(Equal(0))
session := podmanTest.RunTopContainerInPod("test1", podid1)
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
_, ec2, podid2 := podmanTest.CreatePod("")
Expect(ec2).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()
Expect(session.ExitCode()).To(Equal(0))
@ -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()

View file

@ -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))
})

View file

@ -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()
_, ec, podid := podmanTest.CreatePod("")
Expect(ec).To(Equal(0))
podid := session.OutputToString()
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()
_, ec, podid1 := podmanTest.CreatePod("")
Expect(ec).To(Equal(0))
podid1 := 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))
podid2 := session.OutputToString()
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))
@ -148,13 +134,13 @@ var _ = Describe("Podman pod rm", func() {
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
session = podmanTest.Podman([]string{"run", "-d", "--pod", podid2, ALPINE, "ls"})
_, ec, _ = podmanTest.RunLsContainerInPod("", podid2)
Expect(ec).To(Equal(0))
session = podmanTest.RunTopContainerInPod("", podid2)
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
session = podmanTest.Podman([]string{"run", "-d", "--pod", podid2, ALPINE, "top"})
session.WaitWithDefaultTimeout()
result := podmanTest.Podman([]string{"pod", "rm", "-fa"})
result.WaitWithDefaultTimeout()
Expect(result.ExitCode()).To(Equal(0))

View file

@ -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))

View file

@ -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))

View file

@ -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))