aboutsummaryrefslogtreecommitdiff
path: root/cmd
diff options
context:
space:
mode:
authorhaircommander <pehunt@redhat.com>2018-07-27 13:58:50 -0400
committerAtomic Bot <atomic-devel@projectatomic.io>2018-08-23 18:16:28 +0000
commitd5e690914dc78eca8664442e7677eb5004522bfd (patch)
tree3f7ed30e4302c871c16126a0032b8a3d51c46f98 /cmd
parent63dd200e7e47261454c7e55fed2ad972144e147f (diff)
downloadpodman-d5e690914dc78eca8664442e7677eb5004522bfd.tar.gz
podman-d5e690914dc78eca8664442e7677eb5004522bfd.tar.bz2
podman-d5e690914dc78eca8664442e7677eb5004522bfd.zip
Added option to share kernel namespaces in libpod and podman
A pause container is added to the pod if the user opts in. The default pause image and command can be overridden. Pause containers are ignored in ps unless the -a option is present. Pod inspect and pod ps show shared namespaces and pause container. A pause container can't be removed with podman rm, and a pod can be removed if it only has a pause container. Signed-off-by: haircommander <pehunt@redhat.com> Closes: #1187 Approved by: mheon
Diffstat (limited to 'cmd')
-rw-r--r--cmd/podman/create.go74
-rw-r--r--cmd/podman/libpodruntime/runtime.go9
-rw-r--r--cmd/podman/pod_create.go57
-rw-r--r--cmd/podman/pod_ps.go57
-rw-r--r--cmd/podman/ps.go16
5 files changed, 176 insertions, 37 deletions
diff --git a/cmd/podman/create.go b/cmd/podman/create.go
index 96934560f..d6bcea7bd 100644
--- a/cmd/podman/create.go
+++ b/cmd/podman/create.go
@@ -368,16 +368,6 @@ func parseCreateOpts(ctx context.Context, c *cli.Context, runtime *libpod.Runtim
tty := c.Bool("tty")
- pidMode := container.PidMode(c.String("pid"))
- if !cc.IsNS(string(pidMode)) && !pidMode.Valid() {
- return nil, errors.Errorf("--pid %q is not valid", c.String("pid"))
- }
-
- usernsMode := container.UsernsMode(c.String("userns"))
- if !cc.IsNS(string(usernsMode)) && !usernsMode.Valid() {
- return nil, errors.Errorf("--userns %q is not valid", c.String("userns"))
- }
-
if c.Bool("detach") && c.Bool("rm") {
return nil, errors.Errorf("--rm and --detach can not be specified together")
}
@@ -388,14 +378,62 @@ func parseCreateOpts(ctx context.Context, c *cli.Context, runtime *libpod.Runtim
return nil, errors.Errorf("--cpu-quota and --cpus cannot be set together")
}
- utsMode := container.UTSMode(c.String("uts"))
- if !cc.IsNS(string(utsMode)) && !utsMode.Valid() {
+ // Kernel Namespaces
+ var pod *libpod.Pod
+ if c.IsSet("pod") {
+ pod, err = runtime.LookupPod(c.String("pod"))
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ pidModeStr := c.String("pid")
+ if !c.IsSet("pid") && pod != nil && pod.SharesPID() {
+ pidModeStr = "pod"
+ }
+ pidMode := container.PidMode(pidModeStr)
+ if !cc.Valid(string(pidMode), pidMode) {
+ return nil, errors.Errorf("--pid %q is not valid", c.String("pid"))
+ }
+
+ usernsModeStr := c.String("userns")
+ if !c.IsSet("userns") && pod != nil && pod.SharesUser() {
+ usernsModeStr = "pod"
+ }
+ usernsMode := container.UsernsMode(usernsModeStr)
+ if !cc.Valid(string(usernsMode), usernsMode) {
+ return nil, errors.Errorf("--userns %q is not valid", c.String("userns"))
+ }
+
+ utsModeStr := c.String("uts")
+ if !c.IsSet("uts") && pod != nil && pod.SharesUTS() {
+ utsModeStr = "pod"
+ }
+ utsMode := container.UTSMode(utsModeStr)
+ if !cc.Valid(string(utsMode), utsMode) {
return nil, errors.Errorf("--uts %q is not valid", c.String("uts"))
}
- ipcMode := container.IpcMode(c.String("ipc"))
- if !cc.IsNS(string(ipcMode)) && !ipcMode.Valid() {
+
+ ipcModeStr := c.String("ipc")
+ if !c.IsSet("ipc") && pod != nil && pod.SharesIPC() {
+ ipcModeStr = "pod"
+ }
+ ipcMode := container.IpcMode(ipcModeStr)
+ if !cc.Valid(string(ipcMode), ipcMode) {
return nil, errors.Errorf("--ipc %q is not valid", ipcMode)
}
+ netModeStr := c.String("net")
+ if !c.IsSet("net") && pod != nil && pod.SharesNet() {
+ netModeStr = "pod"
+ }
+ // Make sure if network is set to container namespace, port binding is not also being asked for
+ netMode := container.NetworkMode(netModeStr)
+ if netMode.IsContainer() || cc.IsPod(netModeStr) {
+ if len(c.StringSlice("publish")) > 0 || c.Bool("publish-all") {
+ return nil, errors.Errorf("cannot set port bindings on an existing container network namespace")
+ }
+ }
+
shmDir := ""
if ipcMode.IsHost() {
shmDir = "/dev/shm"
@@ -534,14 +572,6 @@ func parseCreateOpts(ctx context.Context, c *cli.Context, runtime *libpod.Runtim
if err != nil {
return nil, errors.Wrapf(err, "unable to translate --shm-size")
}
- // Network
- netMode := container.NetworkMode(c.String("network"))
- // Make sure if network is set to container namespace, port binding is not also being asked for
- if netMode.IsContainer() {
- if len(c.StringSlice("publish")) > 0 || c.Bool("publish-all") {
- return nil, errors.Errorf("cannot set port bindings on an existing container network namespace")
- }
- }
// Verify the additional hosts are in correct format
for _, host := range c.StringSlice("add-host") {
diff --git a/cmd/podman/libpodruntime/runtime.go b/cmd/podman/libpodruntime/runtime.go
index e33b70e9a..af6be0602 100644
--- a/cmd/podman/libpodruntime/runtime.go
+++ b/cmd/podman/libpodruntime/runtime.go
@@ -124,5 +124,14 @@ func GetRuntimeWithStorageOpts(c *cli.Context, storageOpts *storage.StoreOptions
// TODO flag to set CNI plugins dir?
+ // Pod create options
+ if c.IsSet("pause-image") {
+ options = append(options, libpod.WithDefaultPauseImage(c.String("pause-image")))
+ }
+
+ if c.IsSet("pause-command") {
+ options = append(options, libpod.WithDefaultPauseCommand(c.String("pause-command")))
+ }
+
return libpod.NewRuntime(options...)
}
diff --git a/cmd/podman/pod_create.go b/cmd/podman/pod_create.go
index 568ace6e7..6975c9386 100644
--- a/cmd/podman/pod_create.go
+++ b/cmd/podman/pod_create.go
@@ -3,6 +3,7 @@ package main
import (
"fmt"
"os"
+ "strings"
"github.com/containers/libpod/cmd/podman/libpodruntime"
"github.com/containers/libpod/libpod"
@@ -11,6 +12,11 @@ import (
"github.com/urfave/cli"
)
+var (
+ // CRI-O default kernel namespaces
+ DefaultKernelNamespaces = "ipc,net,uts"
+)
+
var podCreateDescription = "Creates a new empty pod. The pod ID is then" +
" printed to stdout. You can then start it at any time with the" +
" podman pod start <pod_id> command. The pod will be created with the" +
@@ -33,10 +39,27 @@ var podCreateFlags = []cli.Flag{
Name: "name, n",
Usage: "Assign a name to the pod",
},
+ cli.BoolTFlag{
+ Name: "pause",
+ Usage: "Create a pause container associated with the pod to share namespaces with",
+ },
+ cli.StringFlag{
+ Name: "pause-image",
+ Usage: "The image of the pause container to associate with the pod",
+ },
+ cli.StringFlag{
+ Name: "pause-command",
+ Usage: "The command to run on the pause container when the pod is started",
+ },
cli.StringFlag{
Name: "pod-id-file",
Usage: "Write the pod ID to the file",
},
+ cli.StringFlag{
+ Name: "share",
+ Usage: "A comma deliminated list of kernel namespaces the pod will share",
+ Value: DefaultKernelNamespaces,
+ },
}
var podCreateCommand = cli.Command{
@@ -71,6 +94,9 @@ func podCreateCmd(c *cli.Context) error {
return errors.Wrapf(err, "unable to write pod id file %s", c.String("pod-id-file"))
}
}
+ if !c.BoolT("pause") && c.IsSet("share") && c.String("share") != "none" && c.String("share") != "" {
+ return errors.Errorf("You cannot share kernel namespaces on the pod level without a pause container")
+ }
if c.IsSet("cgroup-parent") {
options = append(options, libpod.WithPodCgroupParent(c.String("cgroup-parent")))
@@ -88,10 +114,39 @@ func podCreateCmd(c *cli.Context) error {
options = append(options, libpod.WithPodName(c.String("name")))
}
+ if c.BoolT("pause") {
+ options = append(options, libpod.WithPauseContainer())
+ for _, toShare := range strings.Split(c.String("share"), ",") {
+ switch toShare {
+ case "net":
+ options = append(options, libpod.WithPodNet())
+ case "mnt":
+ //options = append(options, libpod.WithPodMNT())
+ logrus.Debug("Mount Namespace sharing functionality not supported")
+ case "pid":
+ options = append(options, libpod.WithPodPID())
+ case "user":
+ // Note: more set up needs to be done before this doesn't error out a create.
+ logrus.Debug("User Namespace sharing functionality not supported")
+ case "ipc":
+ options = append(options, libpod.WithPodIPC())
+ case "uts":
+ options = append(options, libpod.WithPodUTS())
+ case "":
+ case "none":
+ continue
+ default:
+ return errors.Errorf("Invalid kernel namespace to share: %s. Options are: %s, or none", toShare, strings.Join(libpod.KernelNamespaces, ","))
+ }
+ }
+ }
+
// always have containers use pod cgroups
+ // User Opt out is not yet supported
options = append(options, libpod.WithPodCgroups())
- pod, err := runtime.NewPod(options...)
+ ctx := getContext()
+ pod, err := runtime.NewPod(ctx, options...)
if err != nil {
return err
}
diff --git a/cmd/podman/pod_ps.go b/cmd/podman/pod_ps.go
index 20beae53a..20cda1276 100644
--- a/cmd/podman/pod_ps.go
+++ b/cmd/podman/pod_ps.go
@@ -56,8 +56,9 @@ type podPsTemplateParams struct {
NumberOfContainers int
Status string
Cgroup string
- UsePodCgroup bool
ContainerInfo string
+ PauseContainerID string
+ SharedNamespaces string
}
// podPsJSONParams is used as a base structure for the psParams
@@ -73,7 +74,8 @@ type podPsJSONParams struct {
Status string `json:"status"`
CtrsInfo []podPsCtrInfo `json:"containerinfo,omitempty"`
Cgroup string `json:"cgroup,omitempty"`
- UsePodCgroup bool `json:"podcgroup,omitempty"`
+ PauseContainerID string `json:"pausecontainerid,omitempty"`
+ SharedNamespaces []string `json:"sharednamespaces,omitempty"`
}
// Type declaration and functions for sorting the pod PS output
@@ -111,10 +113,6 @@ func (a podPsSortedStatus) Less(i, j int) bool {
var (
podPsFlags = []cli.Flag{
cli.BoolFlag{
- Name: "cgroup",
- Usage: "Print the Cgroup information of the pod",
- },
- cli.BoolFlag{
Name: "ctr-names",
Usage: "Display the container names",
},
@@ -139,6 +137,10 @@ var (
Usage: "Show the latest pod created",
},
cli.BoolFlag{
+ Name: "namespace, ns",
+ Usage: "Display namespace information of the pod",
+ },
+ cli.BoolFlag{
Name: "no-trunc",
Usage: "Do not truncate pod and container IDs",
},
@@ -348,14 +350,15 @@ func genPodPsFormat(c *cli.Context) string {
format = formats.IDString
} else {
format = "table {{.ID}}\t{{.Name}}\t{{.Status}}\t{{.Created}}"
- if c.Bool("cgroup") {
- format += "\t{{.Cgroup}}\t{{.UsePodCgroup}}"
+ if c.Bool("namespace") {
+ format += "\t{{.Cgroup}}\t{{.SharedNamespaces}}"
}
if c.Bool("ctr-names") || c.Bool("ctr-ids") || c.Bool("ctr-status") {
format += "\t{{.ContainerInfo}}"
} else {
format += "\t{{.NumberOfContainers}}"
}
+ format += "\t{{.PauseContainerID}}"
}
return format
}
@@ -415,6 +418,7 @@ func getPodTemplateOutput(psParams []podPsJSONParams, opts podPsOptions) ([]podP
for _, psParam := range psParams {
podID := psParam.ID
+ pauseID := psParam.PauseContainerID
var ctrStr string
truncated := ""
@@ -424,6 +428,7 @@ func getPodTemplateOutput(psParams []podPsJSONParams, opts podPsOptions) ([]podP
psParam.CtrsInfo = psParam.CtrsInfo[:NUM_CTR_INFO]
truncated = "..."
}
+ pauseID = shortID(pauseID)
}
for _, ctrInfo := range psParam.CtrsInfo {
ctrStr += "[ "
@@ -449,9 +454,10 @@ func getPodTemplateOutput(psParams []podPsJSONParams, opts podPsOptions) ([]podP
Name: psParam.Name,
Status: psParam.Status,
NumberOfContainers: psParam.NumberOfContainers,
- UsePodCgroup: psParam.UsePodCgroup,
Cgroup: psParam.Cgroup,
ContainerInfo: ctrStr,
+ PauseContainerID: pauseID,
+ SharedNamespaces: strings.Join(psParam.SharedNamespaces, ","),
}
psOutput = append(psOutput, params)
@@ -460,6 +466,32 @@ func getPodTemplateOutput(psParams []podPsJSONParams, opts podPsOptions) ([]podP
return psOutput, nil
}
+func getSharedNamespaces(pod *libpod.Pod) []string {
+ var shared []string
+ if pod.SharesPID() {
+ shared = append(shared, "pid")
+ }
+ if pod.SharesNet() {
+ shared = append(shared, "net")
+ }
+ if pod.SharesMNT() {
+ shared = append(shared, "mnt")
+ }
+ if pod.SharesIPC() {
+ shared = append(shared, "ipc")
+ }
+ if pod.SharesUser() {
+ shared = append(shared, "user")
+ }
+ if pod.SharesCgroup() {
+ shared = append(shared, "cgroup")
+ }
+ if pod.SharesUTS() {
+ shared = append(shared, "uts")
+ }
+ return shared
+}
+
// getAndSortPodJSONOutput returns the container info in its raw, sorted form
func getAndSortPodJSONParams(pods []*libpod.Pod, opts podPsOptions, runtime *libpod.Runtime) ([]podPsJSONParams, error) {
var (
@@ -478,6 +510,10 @@ func getAndSortPodJSONParams(pods []*libpod.Pod, opts podPsOptions, runtime *lib
return nil, err
}
+ pauseContainerID, err := pod.PauseContainerID()
+ if err != nil {
+ return nil, err
+ }
for _, ctr := range ctrs {
batchInfo, err := shared.BatchContainerOp(ctr, bc_opts)
if err != nil {
@@ -508,9 +544,10 @@ func getAndSortPodJSONParams(pods []*libpod.Pod, opts podPsOptions, runtime *lib
Name: pod.Name(),
Status: status,
Cgroup: pod.CgroupParent(),
- UsePodCgroup: pod.UsePodCgroup(),
NumberOfContainers: ctrNum,
CtrsInfo: ctrsInfo,
+ SharedNamespaces: getSharedNamespaces(pod),
+ PauseContainerID: pauseContainerID,
}
psOutput = append(psOutput, params)
diff --git a/cmd/podman/ps.go b/cmd/podman/ps.go
index 3b53fe6f1..332416d14 100644
--- a/cmd/podman/ps.go
+++ b/cmd/podman/ps.go
@@ -44,6 +44,7 @@ type psTemplateParams struct {
User string
UTS string
Pod string
+ IsPause bool
}
// psJSONParams is used as a base structure for the psParams
@@ -71,6 +72,7 @@ type psJSONParams struct {
ContainerRunning bool `json:"ctrRunning"`
Namespaces *shared.Namespace `json:"namespace,omitempty"`
Pod string `json:"pod,omitempty"`
+ IsPause bool `json:"pause"`
}
// Type declaration and functions for sorting the PS output
@@ -216,7 +218,7 @@ func psCmd(c *cli.Context) error {
return errors.Errorf("too many arguments, ps takes no arguments")
}
- format := genPsFormat(c.String("format"), c.Bool("quiet"), c.Bool("size"), c.Bool("namespace"), c.Bool("pod"))
+ format := genPsFormat(c.String("format"), c.Bool("quiet"), c.Bool("size"), c.Bool("namespace"), c.Bool("pod"), c.Bool("all"))
opts := shared.PsOptions{
All: c.Bool("all"),
@@ -239,7 +241,8 @@ func psCmd(c *cli.Context) error {
// only get running containers
filterFuncs = append(filterFuncs, func(c *libpod.Container) bool {
state, _ := c.State()
- return state == libpod.ContainerStateRunning
+ // Don't return pause containers
+ return state == libpod.ContainerStateRunning && !c.IsPause()
})
}
@@ -417,7 +420,7 @@ func generateContainerFilterFuncs(filter, filterValue string, runtime *libpod.Ru
}
// generate the template based on conditions given
-func genPsFormat(format string, quiet, size, namespace, pod bool) string {
+func genPsFormat(format string, quiet, size, namespace, pod, pause bool) string {
if format != "" {
// "\t" from the command line is not being recognized as a tab
// replacing the string "\t" to a tab character if the user passes in "\t"
@@ -431,13 +434,16 @@ func genPsFormat(format string, quiet, size, namespace, pod bool) string {
podappend = "{{.Pod}}\t"
}
if namespace {
- return fmt.Sprintf("table {{.ID}}\t{{.Names}}\t%s{{.PID}}\t{{.Cgroup}}\t{{.IPC}}\t{{.MNT}}\t{{.NET}}\t{{.PIDNS}}\t{{.User}}\t{{.UTS}}\t", podappend)
+ return fmt.Sprintf("table {{.ID}}\t{{.Names}}\t%s{{.PID}}\t{{.Cgroup}}\t{{.IPC}}\t{{.MNT}}\t{{.NET}}\t{{.PIDNS}}\t{{.User}}\t{{.UTS}}", podappend)
}
format = "table {{.ID}}\t{{.Image}}\t{{.Command}}\t{{.Created}}\t{{.Status}}\t{{.Ports}}\t{{.Names}}\t"
format += podappend
if size {
format += "{{.Size}}\t"
}
+ if pause {
+ format += "{{.IsPause}}\t"
+ }
return format
}
@@ -572,6 +578,7 @@ func getTemplateOutput(psParams []psJSONParams, opts shared.PsOptions) ([]psTemp
Mounts: getMounts(psParam.Mounts, opts.NoTrunc),
PID: psParam.PID,
Pod: pod,
+ IsPause: psParam.IsPause,
}
if opts.Namespace {
@@ -628,6 +635,7 @@ func getAndSortJSONParams(containers []*libpod.Container, opts shared.PsOptions)
ContainerRunning: batchInfo.ConState == libpod.ContainerStateRunning,
Namespaces: ns,
Pod: ctr.PodID(),
+ IsPause: ctr.IsPause(),
}
psOutput = append(psOutput, params)