summaryrefslogtreecommitdiff
path: root/libpod
diff options
context:
space:
mode:
Diffstat (limited to 'libpod')
-rw-r--r--libpod/container.go22
-rw-r--r--libpod/container_ffjson.go485
-rw-r--r--libpod/container_inspect.go1
-rw-r--r--libpod/container_internal.go35
-rw-r--r--libpod/container_internal_linux.go49
-rw-r--r--libpod/options.go280
-rw-r--r--libpod/pod.go95
-rw-r--r--libpod/pod_api.go7
-rw-r--r--libpod/pod_ffjson.go745
-rw-r--r--libpod/pod_internal.go1
-rw-r--r--libpod/runtime.go11
-rw-r--r--libpod/runtime_ctr.go42
-rw-r--r--libpod/runtime_pod.go10
-rw-r--r--libpod/runtime_pod_linux.go49
-rw-r--r--libpod/runtime_pod_pause_linux.go60
-rw-r--r--libpod/runtime_pod_unsupported.go2
16 files changed, 1828 insertions, 66 deletions
diff --git a/libpod/container.go b/libpod/container.go
index b79258c43..2e2d29899 100644
--- a/libpod/container.go
+++ b/libpod/container.go
@@ -252,6 +252,19 @@ type ContainerConfig struct {
UTSNsCtr string `json:"utsNsCtr,omitempty"`
CgroupNsCtr string `json:"cgroupNsCtr,omitempty"`
+ // Whether container shares an NS with the pod
+ // NetNsPod conflicts with the CreateNetNS bool
+ // {namespace}NsPod conflicts with {namespace}NsCtr
+ // The pause container will be considered dependencies of the given container
+ // It must be started before the given container is started
+ IPCNsPod bool `json:"ipcNsPod,omitempty"`
+ MountNsPod bool `json:"mountNsPod,omitempty"`
+ NetNsPod bool `json:"netNsPod,omitempty"`
+ PIDNsPod bool `json:"pidNsPod,omitempty"`
+ UserNsPod bool `json:"userNsPod,omitempty"`
+ UTSNsPod bool `json:"utsNsPod,omitempty"`
+ CgroupNsPod bool `json:"cgroupNsPod,omitempty"`
+
// IDs of dependency containers.
// These containers must be started before this container is started.
Dependencies []string
@@ -328,6 +341,10 @@ type ContainerConfig struct {
// LocalVolumes are the built-in volumes we get from the --volumes-from flag
// It picks up the built-in volumes of the container used by --volumes-from
LocalVolumes []string
+
+ // IsPause is a bool indicating whether this container is a pause container used for
+ // sharing kernel namespaces in a pod
+ IsPause bool `json:"pause"`
}
// ContainerStatus returns a string representation for users
@@ -956,3 +973,8 @@ func (c *Container) RootGID() int {
}
return 0
}
+
+// IsPause returns whether the container is a pause container
+func (c *Container) IsPause() bool {
+ return c.config.IsPause
+}
diff --git a/libpod/container_ffjson.go b/libpod/container_ffjson.go
index d843beb48..02dc10e68 100644
--- a/libpod/container_ffjson.go
+++ b/libpod/container_ffjson.go
@@ -194,6 +194,62 @@ func (j *ContainerConfig) MarshalJSONBuf(buf fflib.EncodingBuffer) error {
fflib.WriteJsonString(buf, string(j.CgroupNsCtr))
buf.WriteByte(',')
}
+ if j.IPCNsPod != false {
+ if j.IPCNsPod {
+ buf.WriteString(`"ipcNsPod":true`)
+ } else {
+ buf.WriteString(`"ipcNsPod":false`)
+ }
+ buf.WriteByte(',')
+ }
+ if j.MountNsPod != false {
+ if j.MountNsPod {
+ buf.WriteString(`"mountNsPod":true`)
+ } else {
+ buf.WriteString(`"mountNsPod":false`)
+ }
+ buf.WriteByte(',')
+ }
+ if j.NetNsPod != false {
+ if j.NetNsPod {
+ buf.WriteString(`"netNsPod":true`)
+ } else {
+ buf.WriteString(`"netNsPod":false`)
+ }
+ buf.WriteByte(',')
+ }
+ if j.PIDNsPod != false {
+ if j.PIDNsPod {
+ buf.WriteString(`"pidNsPod":true`)
+ } else {
+ buf.WriteString(`"pidNsPod":false`)
+ }
+ buf.WriteByte(',')
+ }
+ if j.UserNsPod != false {
+ if j.UserNsPod {
+ buf.WriteString(`"userNsPod":true`)
+ } else {
+ buf.WriteString(`"userNsPod":false`)
+ }
+ buf.WriteByte(',')
+ }
+ if j.UTSNsPod != false {
+ if j.UTSNsPod {
+ buf.WriteString(`"utsNsPod":true`)
+ } else {
+ buf.WriteString(`"utsNsPod":false`)
+ }
+ buf.WriteByte(',')
+ }
+ if j.CgroupNsPod != false {
+ if j.CgroupNsPod {
+ buf.WriteString(`"cgroupNsPod":true`)
+ } else {
+ buf.WriteString(`"cgroupNsPod":false`)
+ }
+ buf.WriteByte(',')
+ }
buf.WriteString(`"Dependencies":`)
if j.Dependencies != nil {
buf.WriteString(`[`)
@@ -461,6 +517,11 @@ func (j *ContainerConfig) MarshalJSONBuf(buf fflib.EncodingBuffer) error {
} else {
buf.WriteString(`null`)
}
+ if j.IsPause {
+ buf.WriteString(`,"pause":true`)
+ } else {
+ buf.WriteString(`,"pause":false`)
+ }
buf.WriteByte('}')
return nil
}
@@ -521,6 +582,20 @@ const (
ffjtContainerConfigCgroupNsCtr
+ ffjtContainerConfigIPCNsPod
+
+ ffjtContainerConfigMountNsPod
+
+ ffjtContainerConfigNetNsPod
+
+ ffjtContainerConfigPIDNsPod
+
+ ffjtContainerConfigUserNsPod
+
+ ffjtContainerConfigUTSNsPod
+
+ ffjtContainerConfigCgroupNsPod
+
ffjtContainerConfigDependencies
ffjtContainerConfigCreateNetNS
@@ -564,6 +639,8 @@ const (
ffjtContainerConfigExitCommand
ffjtContainerConfigLocalVolumes
+
+ ffjtContainerConfigIsPause
)
var ffjKeyContainerConfigSpec = []byte("spec")
@@ -618,6 +695,20 @@ var ffjKeyContainerConfigUTSNsCtr = []byte("utsNsCtr")
var ffjKeyContainerConfigCgroupNsCtr = []byte("cgroupNsCtr")
+var ffjKeyContainerConfigIPCNsPod = []byte("ipcNsPod")
+
+var ffjKeyContainerConfigMountNsPod = []byte("mountNsPod")
+
+var ffjKeyContainerConfigNetNsPod = []byte("netNsPod")
+
+var ffjKeyContainerConfigPIDNsPod = []byte("pidNsPod")
+
+var ffjKeyContainerConfigUserNsPod = []byte("userNsPod")
+
+var ffjKeyContainerConfigUTSNsPod = []byte("utsNsPod")
+
+var ffjKeyContainerConfigCgroupNsPod = []byte("cgroupNsPod")
+
var ffjKeyContainerConfigDependencies = []byte("Dependencies")
var ffjKeyContainerConfigCreateNetNS = []byte("createNetNS")
@@ -662,6 +753,8 @@ var ffjKeyContainerConfigExitCommand = []byte("exitCommand")
var ffjKeyContainerConfigLocalVolumes = []byte("LocalVolumes")
+var ffjKeyContainerConfigIsPause = []byte("pause")
+
// UnmarshalJSON umarshall json - template of ffjson
func (j *ContainerConfig) UnmarshalJSON(input []byte) error {
fs := fflib.NewFFLexer(input)
@@ -770,6 +863,11 @@ mainparse:
state = fflib.FFParse_want_colon
goto mainparse
+ } else if bytes.Equal(ffjKeyContainerConfigCgroupNsPod, kn) {
+ currentKey = ffjtContainerConfigCgroupNsPod
+ state = fflib.FFParse_want_colon
+ goto mainparse
+
} else if bytes.Equal(ffjKeyContainerConfigCreateNetNS, kn) {
currentKey = ffjtContainerConfigCreateNetNS
state = fflib.FFParse_want_colon
@@ -864,6 +962,11 @@ mainparse:
currentKey = ffjtContainerConfigIPCNsCtr
state = fflib.FFParse_want_colon
goto mainparse
+
+ } else if bytes.Equal(ffjKeyContainerConfigIPCNsPod, kn) {
+ currentKey = ffjtContainerConfigIPCNsPod
+ state = fflib.FFParse_want_colon
+ goto mainparse
}
case 'l':
@@ -890,6 +993,11 @@ mainparse:
currentKey = ffjtContainerConfigMountNsCtr
state = fflib.FFParse_want_colon
goto mainparse
+
+ } else if bytes.Equal(ffjKeyContainerConfigMountNsPod, kn) {
+ currentKey = ffjtContainerConfigMountNsPod
+ state = fflib.FFParse_want_colon
+ goto mainparse
}
case 'n':
@@ -909,6 +1017,11 @@ mainparse:
state = fflib.FFParse_want_colon
goto mainparse
+ } else if bytes.Equal(ffjKeyContainerConfigNetNsPod, kn) {
+ currentKey = ffjtContainerConfigNetNsPod
+ state = fflib.FFParse_want_colon
+ goto mainparse
+
} else if bytes.Equal(ffjKeyContainerConfigNetworks, kn) {
currentKey = ffjtContainerConfigNetworks
state = fflib.FFParse_want_colon
@@ -932,6 +1045,11 @@ mainparse:
state = fflib.FFParse_want_colon
goto mainparse
+ } else if bytes.Equal(ffjKeyContainerConfigPIDNsPod, kn) {
+ currentKey = ffjtContainerConfigPIDNsPod
+ state = fflib.FFParse_want_colon
+ goto mainparse
+
} else if bytes.Equal(ffjKeyContainerConfigPortMappings, kn) {
currentKey = ffjtContainerConfigPortMappings
state = fflib.FFParse_want_colon
@@ -941,6 +1059,11 @@ mainparse:
currentKey = ffjtContainerConfigPostConfigureNetNS
state = fflib.FFParse_want_colon
goto mainparse
+
+ } else if bytes.Equal(ffjKeyContainerConfigIsPause, kn) {
+ currentKey = ffjtContainerConfigIsPause
+ state = fflib.FFParse_want_colon
+ goto mainparse
}
case 'r':
@@ -1011,6 +1134,16 @@ mainparse:
state = fflib.FFParse_want_colon
goto mainparse
+ } else if bytes.Equal(ffjKeyContainerConfigUserNsPod, kn) {
+ currentKey = ffjtContainerConfigUserNsPod
+ state = fflib.FFParse_want_colon
+ goto mainparse
+
+ } else if bytes.Equal(ffjKeyContainerConfigUTSNsPod, kn) {
+ currentKey = ffjtContainerConfigUTSNsPod
+ state = fflib.FFParse_want_colon
+ goto mainparse
+
} else if bytes.Equal(ffjKeyContainerConfigUserVolumes, kn) {
currentKey = ffjtContainerConfigUserVolumes
state = fflib.FFParse_want_colon
@@ -1019,6 +1152,12 @@ mainparse:
}
+ if fflib.EqualFoldRight(ffjKeyContainerConfigIsPause, kn) {
+ currentKey = ffjtContainerConfigIsPause
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
if fflib.EqualFoldRight(ffjKeyContainerConfigLocalVolumes, kn) {
currentKey = ffjtContainerConfigLocalVolumes
state = fflib.FFParse_want_colon
@@ -1151,6 +1290,48 @@ mainparse:
goto mainparse
}
+ if fflib.EqualFoldRight(ffjKeyContainerConfigCgroupNsPod, kn) {
+ currentKey = ffjtContainerConfigCgroupNsPod
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ if fflib.EqualFoldRight(ffjKeyContainerConfigUTSNsPod, kn) {
+ currentKey = ffjtContainerConfigUTSNsPod
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ if fflib.EqualFoldRight(ffjKeyContainerConfigUserNsPod, kn) {
+ currentKey = ffjtContainerConfigUserNsPod
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ if fflib.EqualFoldRight(ffjKeyContainerConfigPIDNsPod, kn) {
+ currentKey = ffjtContainerConfigPIDNsPod
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ if fflib.EqualFoldRight(ffjKeyContainerConfigNetNsPod, kn) {
+ currentKey = ffjtContainerConfigNetNsPod
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ if fflib.EqualFoldRight(ffjKeyContainerConfigMountNsPod, kn) {
+ currentKey = ffjtContainerConfigMountNsPod
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ if fflib.EqualFoldRight(ffjKeyContainerConfigIPCNsPod, kn) {
+ currentKey = ffjtContainerConfigIPCNsPod
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
if fflib.EqualFoldRight(ffjKeyContainerConfigCgroupNsCtr, kn) {
currentKey = ffjtContainerConfigCgroupNsCtr
state = fflib.FFParse_want_colon
@@ -1402,6 +1583,27 @@ mainparse:
case ffjtContainerConfigCgroupNsCtr:
goto handle_CgroupNsCtr
+ case ffjtContainerConfigIPCNsPod:
+ goto handle_IPCNsPod
+
+ case ffjtContainerConfigMountNsPod:
+ goto handle_MountNsPod
+
+ case ffjtContainerConfigNetNsPod:
+ goto handle_NetNsPod
+
+ case ffjtContainerConfigPIDNsPod:
+ goto handle_PIDNsPod
+
+ case ffjtContainerConfigUserNsPod:
+ goto handle_UserNsPod
+
+ case ffjtContainerConfigUTSNsPod:
+ goto handle_UTSNsPod
+
+ case ffjtContainerConfigCgroupNsPod:
+ goto handle_CgroupNsPod
+
case ffjtContainerConfigDependencies:
goto handle_Dependencies
@@ -1468,6 +1670,9 @@ mainparse:
case ffjtContainerConfigLocalVolumes:
goto handle_LocalVolumes
+ case ffjtContainerConfigIsPause:
+ goto handle_IsPause
+
case ffjtContainerConfignosuchkey:
err = fs.SkipField(tok)
if err != nil {
@@ -2264,6 +2469,251 @@ handle_CgroupNsCtr:
state = fflib.FFParse_after_value
goto mainparse
+handle_IPCNsPod:
+
+ /* handler: j.IPCNsPod type=bool kind=bool quoted=false*/
+
+ {
+ if tok != fflib.FFTok_bool && tok != fflib.FFTok_null {
+ return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for bool", tok))
+ }
+ }
+
+ {
+ if tok == fflib.FFTok_null {
+
+ } else {
+ tmpb := fs.Output.Bytes()
+
+ if bytes.Compare([]byte{'t', 'r', 'u', 'e'}, tmpb) == 0 {
+
+ j.IPCNsPod = true
+
+ } else if bytes.Compare([]byte{'f', 'a', 'l', 's', 'e'}, tmpb) == 0 {
+
+ j.IPCNsPod = false
+
+ } else {
+ err = errors.New("unexpected bytes for true/false value")
+ return fs.WrapErr(err)
+ }
+
+ }
+ }
+
+ state = fflib.FFParse_after_value
+ goto mainparse
+
+handle_MountNsPod:
+
+ /* handler: j.MountNsPod type=bool kind=bool quoted=false*/
+
+ {
+ if tok != fflib.FFTok_bool && tok != fflib.FFTok_null {
+ return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for bool", tok))
+ }
+ }
+
+ {
+ if tok == fflib.FFTok_null {
+
+ } else {
+ tmpb := fs.Output.Bytes()
+
+ if bytes.Compare([]byte{'t', 'r', 'u', 'e'}, tmpb) == 0 {
+
+ j.MountNsPod = true
+
+ } else if bytes.Compare([]byte{'f', 'a', 'l', 's', 'e'}, tmpb) == 0 {
+
+ j.MountNsPod = false
+
+ } else {
+ err = errors.New("unexpected bytes for true/false value")
+ return fs.WrapErr(err)
+ }
+
+ }
+ }
+
+ state = fflib.FFParse_after_value
+ goto mainparse
+
+handle_NetNsPod:
+
+ /* handler: j.NetNsPod type=bool kind=bool quoted=false*/
+
+ {
+ if tok != fflib.FFTok_bool && tok != fflib.FFTok_null {
+ return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for bool", tok))
+ }
+ }
+
+ {
+ if tok == fflib.FFTok_null {
+
+ } else {
+ tmpb := fs.Output.Bytes()
+
+ if bytes.Compare([]byte{'t', 'r', 'u', 'e'}, tmpb) == 0 {
+
+ j.NetNsPod = true
+
+ } else if bytes.Compare([]byte{'f', 'a', 'l', 's', 'e'}, tmpb) == 0 {
+
+ j.NetNsPod = false
+
+ } else {
+ err = errors.New("unexpected bytes for true/false value")
+ return fs.WrapErr(err)
+ }
+
+ }
+ }
+
+ state = fflib.FFParse_after_value
+ goto mainparse
+
+handle_PIDNsPod:
+
+ /* handler: j.PIDNsPod type=bool kind=bool quoted=false*/
+
+ {
+ if tok != fflib.FFTok_bool && tok != fflib.FFTok_null {
+ return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for bool", tok))
+ }
+ }
+
+ {
+ if tok == fflib.FFTok_null {
+
+ } else {
+ tmpb := fs.Output.Bytes()
+
+ if bytes.Compare([]byte{'t', 'r', 'u', 'e'}, tmpb) == 0 {
+
+ j.PIDNsPod = true
+
+ } else if bytes.Compare([]byte{'f', 'a', 'l', 's', 'e'}, tmpb) == 0 {
+
+ j.PIDNsPod = false
+
+ } else {
+ err = errors.New("unexpected bytes for true/false value")
+ return fs.WrapErr(err)
+ }
+
+ }
+ }
+
+ state = fflib.FFParse_after_value
+ goto mainparse
+
+handle_UserNsPod:
+
+ /* handler: j.UserNsPod type=bool kind=bool quoted=false*/
+
+ {
+ if tok != fflib.FFTok_bool && tok != fflib.FFTok_null {
+ return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for bool", tok))
+ }
+ }
+
+ {
+ if tok == fflib.FFTok_null {
+
+ } else {
+ tmpb := fs.Output.Bytes()
+
+ if bytes.Compare([]byte{'t', 'r', 'u', 'e'}, tmpb) == 0 {
+
+ j.UserNsPod = true
+
+ } else if bytes.Compare([]byte{'f', 'a', 'l', 's', 'e'}, tmpb) == 0 {
+
+ j.UserNsPod = false
+
+ } else {
+ err = errors.New("unexpected bytes for true/false value")
+ return fs.WrapErr(err)
+ }
+
+ }
+ }
+
+ state = fflib.FFParse_after_value
+ goto mainparse
+
+handle_UTSNsPod:
+
+ /* handler: j.UTSNsPod type=bool kind=bool quoted=false*/
+
+ {
+ if tok != fflib.FFTok_bool && tok != fflib.FFTok_null {
+ return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for bool", tok))
+ }
+ }
+
+ {
+ if tok == fflib.FFTok_null {
+
+ } else {
+ tmpb := fs.Output.Bytes()
+
+ if bytes.Compare([]byte{'t', 'r', 'u', 'e'}, tmpb) == 0 {
+
+ j.UTSNsPod = true
+
+ } else if bytes.Compare([]byte{'f', 'a', 'l', 's', 'e'}, tmpb) == 0 {
+
+ j.UTSNsPod = false
+
+ } else {
+ err = errors.New("unexpected bytes for true/false value")
+ return fs.WrapErr(err)
+ }
+
+ }
+ }
+
+ state = fflib.FFParse_after_value
+ goto mainparse
+
+handle_CgroupNsPod:
+
+ /* handler: j.CgroupNsPod type=bool kind=bool quoted=false*/
+
+ {
+ if tok != fflib.FFTok_bool && tok != fflib.FFTok_null {
+ return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for bool", tok))
+ }
+ }
+
+ {
+ if tok == fflib.FFTok_null {
+
+ } else {
+ tmpb := fs.Output.Bytes()
+
+ if bytes.Compare([]byte{'t', 'r', 'u', 'e'}, tmpb) == 0 {
+
+ j.CgroupNsPod = true
+
+ } else if bytes.Compare([]byte{'f', 'a', 'l', 's', 'e'}, tmpb) == 0 {
+
+ j.CgroupNsPod = false
+
+ } else {
+ err = errors.New("unexpected bytes for true/false value")
+ return fs.WrapErr(err)
+ }
+
+ }
+ }
+
+ state = fflib.FFParse_after_value
+ goto mainparse
+
handle_Dependencies:
/* handler: j.Dependencies type=[]string kind=slice quoted=false*/
@@ -3523,6 +3973,41 @@ handle_LocalVolumes:
state = fflib.FFParse_after_value
goto mainparse
+handle_IsPause:
+
+ /* handler: j.IsPause type=bool kind=bool quoted=false*/
+
+ {
+ if tok != fflib.FFTok_bool && tok != fflib.FFTok_null {
+ return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for bool", tok))
+ }
+ }
+
+ {
+ if tok == fflib.FFTok_null {
+
+ } else {
+ tmpb := fs.Output.Bytes()
+
+ if bytes.Compare([]byte{'t', 'r', 'u', 'e'}, tmpb) == 0 {
+
+ j.IsPause = true
+
+ } else if bytes.Compare([]byte{'f', 'a', 'l', 's', 'e'}, tmpb) == 0 {
+
+ j.IsPause = false
+
+ } else {
+ err = errors.New("unexpected bytes for true/false value")
+ return fs.WrapErr(err)
+ }
+
+ }
+ }
+
+ state = fflib.FFParse_after_value
+ goto mainparse
+
wantedvalue:
return fs.WrapErr(fmt.Errorf("wanted value token, but got token: %v", tok))
wrongtokenerror:
diff --git a/libpod/container_inspect.go b/libpod/container_inspect.go
index a7ee911a6..18a8b9b83 100644
--- a/libpod/container_inspect.go
+++ b/libpod/container_inspect.go
@@ -104,6 +104,7 @@ func (c *Container) getContainerInspectData(size bool, driverData *inspect.Data)
IPv6Gateway: "",
MacAddress: "", // TODO
},
+ IsPause: c.IsPause(),
}
// Copy port mappings into network settings
diff --git a/libpod/container_internal.go b/libpod/container_internal.go
index 32036ca7a..e276e0194 100644
--- a/libpod/container_internal.go
+++ b/libpod/container_internal.go
@@ -11,7 +11,6 @@ import (
"path/filepath"
"strings"
"syscall"
- "time"
"github.com/containers/libpod/pkg/chrootuser"
"github.com/containers/libpod/pkg/hooks"
@@ -23,13 +22,11 @@ import (
"github.com/containers/storage/pkg/archive"
"github.com/containers/storage/pkg/chrootarchive"
"github.com/containers/storage/pkg/mount"
- "github.com/containers/storage/pkg/stringid"
spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/opencontainers/runtime-tools/generate"
"github.com/opencontainers/selinux/go-selinux/label"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
- "github.com/ulule/deepcopier"
"golang.org/x/text/language"
)
@@ -174,38 +171,6 @@ func (c *Container) syncContainer() error {
return nil
}
-// Make a new container
-func newContainer(rspec *spec.Spec, lockDir string) (*Container, error) {
- if rspec == nil {
- return nil, errors.Wrapf(ErrInvalidArg, "must provide a valid runtime spec to create container")
- }
-
- ctr := new(Container)
- ctr.config = new(ContainerConfig)
- ctr.state = new(containerState)
-
- ctr.config.ID = stringid.GenerateNonCryptoID()
-
- ctr.config.Spec = new(spec.Spec)
- deepcopier.Copy(rspec).To(ctr.config.Spec)
- ctr.config.CreatedTime = time.Now()
-
- ctr.config.ShmSize = DefaultShmSize
-
- ctr.state.BindMounts = make(map[string]string)
-
- // Path our lock file will reside at
- lockPath := filepath.Join(lockDir, ctr.config.ID)
- // Grab a lockfile at the given path
- lock, err := storage.GetLockfile(lockPath)
- if err != nil {
- return nil, errors.Wrapf(err, "error creating lockfile for new container")
- }
- ctr.lock = lock
-
- return ctr, nil
-}
-
// Create container root filesystem for use
func (c *Container) setupStorage(ctx context.Context) error {
if !c.valid {
diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go
index ba02c9f5a..efd808b57 100644
--- a/libpod/container_internal_linux.go
+++ b/libpod/container_internal_linux.go
@@ -168,42 +168,91 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
}
}
+ var podInfraContainer string
+ if c.config.Pod != "" {
+ pod, err := c.runtime.state.LookupPod(c.config.Pod)
+ if err != nil {
+ return nil, err
+ }
+ if pod.SharesNamespaces() {
+ if err := pod.updatePod(); err != nil {
+ return nil, err
+ }
+ podInfraContainer = pod.state.PauseContainerID
+ }
+ }
+
// Add shared namespaces from other containers
if c.config.IPCNsCtr != "" {
if err := c.addNamespaceContainer(&g, IPCNS, c.config.IPCNsCtr, spec.IPCNamespace); err != nil {
return nil, err
}
}
+ if c.config.IPCNsPod && podInfraContainer != "" {
+ if err := c.addNamespaceContainer(&g, IPCNS, podInfraContainer, spec.IPCNamespace); err != nil {
+ return nil, err
+ }
+ }
if c.config.MountNsCtr != "" {
if err := c.addNamespaceContainer(&g, MountNS, c.config.MountNsCtr, spec.MountNamespace); err != nil {
return nil, err
}
}
+ if c.config.MountNsPod && podInfraContainer != "" {
+ if err := c.addNamespaceContainer(&g, MountNS, podInfraContainer, spec.MountNamespace); err != nil {
+ return nil, err
+ }
+ }
if c.config.NetNsCtr != "" {
if err := c.addNamespaceContainer(&g, NetNS, c.config.NetNsCtr, spec.NetworkNamespace); err != nil {
return nil, err
}
}
+ if c.config.NetNsPod && podInfraContainer != "" {
+ if err := c.addNamespaceContainer(&g, NetNS, podInfraContainer, spec.NetworkNamespace); err != nil {
+ return nil, err
+ }
+ }
if c.config.PIDNsCtr != "" {
if err := c.addNamespaceContainer(&g, PIDNS, c.config.PIDNsCtr, string(spec.PIDNamespace)); err != nil {
return nil, err
}
}
+ if c.config.PIDNsPod && podInfraContainer != "" {
+ if err := c.addNamespaceContainer(&g, PIDNS, podInfraContainer, string(spec.PIDNamespace)); err != nil {
+ return nil, err
+ }
+ }
if c.config.UserNsCtr != "" {
if err := c.addNamespaceContainer(&g, UserNS, c.config.UserNsCtr, spec.UserNamespace); err != nil {
return nil, err
}
}
+ if c.config.UserNsPod && podInfraContainer != "" {
+ if err := c.addNamespaceContainer(&g, UserNS, podInfraContainer, spec.UserNamespace); err != nil {
+ return nil, err
+ }
+ }
if c.config.UTSNsCtr != "" {
if err := c.addNamespaceContainer(&g, UTSNS, c.config.UTSNsCtr, spec.UTSNamespace); err != nil {
return nil, err
}
}
+ if c.config.UTSNsPod && podInfraContainer != "" {
+ if err := c.addNamespaceContainer(&g, UTSNS, podInfraContainer, spec.UTSNamespace); err != nil {
+ return nil, err
+ }
+ }
if c.config.CgroupNsCtr != "" {
if err := c.addNamespaceContainer(&g, CgroupNS, c.config.CgroupNsCtr, spec.CgroupNamespace); err != nil {
return nil, err
}
}
+ if c.config.CgroupNsPod && podInfraContainer != "" {
+ if err := c.addNamespaceContainer(&g, CgroupNS, podInfraContainer, spec.CgroupNamespace); err != nil {
+ return nil, err
+ }
+ }
if c.config.Rootfs == "" {
if err := idtools.MkdirAllAs(c.state.RealMountpoint, 0700, c.RootUID(), c.RootGID()); err != nil {
diff --git a/libpod/options.go b/libpod/options.go
index 7bb4a3632..c5e32d20e 100644
--- a/libpod/options.go
+++ b/libpod/options.go
@@ -304,6 +304,37 @@ func WithNamespace(ns string) RuntimeOption {
}
}
+// WithDefaultPauseImage sets the pause image for libpod.
+// A pause image is used for inter-container kernel
+// namespace sharing within a pod. Typically, a pause
+// container is lightweight and is there to reap
+// zombie processes within its pid namespace.
+func WithDefaultPauseImage(img string) RuntimeOption {
+ return func(rt *Runtime) error {
+ if rt.valid {
+ return ErrRuntimeFinalized
+ }
+
+ rt.config.PauseImage = img
+
+ return nil
+ }
+}
+
+// WithDefaultPauseCommand sets the command to
+// run on pause container start up.
+func WithDefaultPauseCommand(cmd string) RuntimeOption {
+ return func(rt *Runtime) error {
+ if rt.valid {
+ return ErrRuntimeFinalized
+ }
+
+ rt.config.PauseCommand = cmd
+
+ return nil
+ }
+}
+
// Container Creation Options
// WithShmDir sets the directory that should be mounted on /dev/shm.
@@ -518,6 +549,132 @@ func WithExitCommand(exitCommand []string) CtrCreateOption {
}
}
+// WithIPCNSFromPod indicates the the container should join the IPC namespace of
+// its pod
+func WithIPCNSFromPod() CtrCreateOption {
+ return func(ctr *Container) error {
+ if ctr.valid {
+ return ErrCtrFinalized
+ }
+
+ if ctr.config.Pod == "" {
+ return errors.Wrapf(ErrInvalidArg, "container is not a member of any pod")
+ }
+
+ ctr.config.IPCNsPod = true
+
+ return nil
+ }
+}
+
+// WithMountNSFromPod indicates the the container should join the Mount namespace of
+// its pod
+func WithMountNSFromPod() CtrCreateOption {
+ return func(ctr *Container) error {
+ if ctr.valid {
+ return ErrCtrFinalized
+ }
+
+ if ctr.config.Pod == "" {
+ return errors.Wrapf(ErrInvalidArg, "container is not a member of any pod")
+ }
+
+ ctr.config.MountNsPod = true
+
+ return nil
+ }
+}
+
+// WithNetNSFromPod indicates the the container should join the network namespace of
+// its pod
+func WithNetNSFromPod() CtrCreateOption {
+ return func(ctr *Container) error {
+ if ctr.valid {
+ return ErrCtrFinalized
+ }
+
+ if ctr.config.Pod == "" {
+ return errors.Wrapf(ErrInvalidArg, "container is not a member of any pod")
+ }
+
+ ctr.config.NetNsPod = true
+
+ return nil
+ }
+}
+
+// WithPIDNSFromPod indicates the the container should join the PID namespace of
+// its pod
+func WithPIDNSFromPod() CtrCreateOption {
+ return func(ctr *Container) error {
+ if ctr.valid {
+ return ErrCtrFinalized
+ }
+
+ if ctr.config.Pod == "" {
+ return errors.Wrapf(ErrInvalidArg, "container is not a member of any pod")
+ }
+
+ ctr.config.PIDNsPod = true
+
+ return nil
+ }
+}
+
+// WithUTSNSFromPod indicates the the container should join the UTS namespace of
+// its pod
+func WithUTSNSFromPod() CtrCreateOption {
+ return func(ctr *Container) error {
+ if ctr.valid {
+ return ErrCtrFinalized
+ }
+
+ if ctr.config.Pod == "" {
+ return errors.Wrapf(ErrInvalidArg, "container is not a member of any pod")
+ }
+
+ ctr.config.UTSNsPod = true
+
+ return nil
+ }
+}
+
+// WithUserNSFromPod indicates the the container should join the User namespace of
+// its pod
+func WithUserNSFromPod() CtrCreateOption {
+ return func(ctr *Container) error {
+ if ctr.valid {
+ return ErrCtrFinalized
+ }
+
+ if ctr.config.Pod == "" {
+ return errors.Wrapf(ErrInvalidArg, "container is not a member of any pod")
+ }
+
+ ctr.config.UserNsPod = true
+
+ return nil
+ }
+}
+
+// WithCgroupNSFromPod indicates the the container should join the Cgroup namespace of
+// its pod
+func WithCgroupNSFromPod() CtrCreateOption {
+ return func(ctr *Container) error {
+ if ctr.valid {
+ return ErrCtrFinalized
+ }
+
+ if ctr.config.Pod == "" {
+ return errors.Wrapf(ErrInvalidArg, "container is not a member of any pod")
+ }
+
+ ctr.config.CgroupNsPod = true
+
+ return nil
+ }
+}
+
// WithIPCNSFrom indicates the the container should join the IPC namespace of
// the given container.
// If the container has joined a pod, it can only join the namespaces of
@@ -999,6 +1156,20 @@ func WithCtrNamespace(ns string) CtrCreateOption {
}
}
+// withIsPause sets the container to be a pause container. This means the container will be sometimes hidden
+// and expected to be the first container in the pod.
+func withIsPause() CtrCreateOption {
+ return func(ctr *Container) error {
+ if ctr.valid {
+ return ErrCtrFinalized
+ }
+
+ ctr.config.IsPause = true
+
+ return nil
+ }
+}
+
// Pod Creation Options
// WithPodName sets the name of the pod.
@@ -1080,3 +1251,112 @@ func WithPodNamespace(ns string) PodCreateOption {
return nil
}
}
+
+// WithPodIPC tells containers in this pod to use the ipc namespace
+// created for this pod.
+// Containers in a pod will inherit the kernel namespaces from the
+// first container added.
+func WithPodIPC() PodCreateOption {
+ return func(pod *Pod) error {
+ if pod.valid {
+ return ErrPodFinalized
+ }
+
+ pod.config.UsePodIPC = true
+
+ return nil
+ }
+}
+
+// WithPodNet tells containers in this pod to use the network namespace
+// created for this pod.
+// Containers in a pod will inherit the kernel namespaces from the
+// first container added.
+func WithPodNet() PodCreateOption {
+ return func(pod *Pod) error {
+ if pod.valid {
+ return ErrPodFinalized
+ }
+
+ pod.config.UsePodNet = true
+
+ return nil
+ }
+}
+
+// WithPodMNT tells containers in this pod to use the mount namespace
+// created for this pod.
+// Containers in a pod will inherit the kernel namespaces from the
+// first container added.
+func WithPodMNT() PodCreateOption {
+ return func(pod *Pod) error {
+ if pod.valid {
+ return ErrPodFinalized
+ }
+
+ pod.config.UsePodMNT = true
+
+ return nil
+ }
+}
+
+// WithPodUser tells containers in this pod to use the user namespace
+// created for this pod.
+// Containers in a pod will inherit the kernel namespaces from the
+// first container added.
+func WithPodUser() PodCreateOption {
+ return func(pod *Pod) error {
+ if pod.valid {
+ return ErrPodFinalized
+ }
+
+ pod.config.UsePodUser = true
+
+ return nil
+ }
+}
+
+// WithPodPID tells containers in this pod to use the pid namespace
+// created for this pod.
+// Containers in a pod will inherit the kernel namespaces from the
+// first container added.
+func WithPodPID() PodCreateOption {
+ return func(pod *Pod) error {
+ if pod.valid {
+ return ErrPodFinalized
+ }
+
+ pod.config.UsePodPID = true
+
+ return nil
+ }
+}
+
+// WithPodUTS tells containers in this pod to use the uts namespace
+// created for this pod.
+// Containers in a pod will inherit the kernel namespaces from the
+// first container added.
+func WithPodUTS() PodCreateOption {
+ return func(pod *Pod) error {
+ if pod.valid {
+ return ErrPodFinalized
+ }
+
+ pod.config.UsePodUTS = true
+
+ return nil
+ }
+}
+
+// WithPauseContainer tells the pod to create a pause container
+func WithPauseContainer() PodCreateOption {
+ return func(pod *Pod) error {
+ if pod.valid {
+ return ErrPodFinalized
+ }
+
+ pod.config.PauseContainer.HasPauseContainer = true
+
+ return nil
+ }
+}
diff --git a/libpod/pod.go b/libpod/pod.go
index 666480aa8..e70cd9138 100644
--- a/libpod/pod.go
+++ b/libpod/pod.go
@@ -7,6 +7,11 @@ import (
"github.com/pkg/errors"
)
+var (
+ // KernelNamespaces is a list of the kernel namespaces a pod can share
+ KernelNamespaces = []string{"ipc", "net", "pid", "user", "mnt", "uts", "cgroup"}
+)
+
// Pod represents a group of containers that are managed together.
// Any operations on a Pod that access state must begin with a call to
// updatePod().
@@ -18,6 +23,7 @@ import (
// function takes the pod lock and accesses any part of state, it should
// updatePod() immediately after locking.
// ffjson: skip
+// Pod represents a group of containers that may share namespaces
type Pod struct {
config *PodConfig
state *podState
@@ -38,11 +44,23 @@ type PodConfig struct {
Labels map[string]string `json:"labels"`
// CgroupParent contains the pod's CGroup parent
CgroupParent string `json:"cgroupParent"`
+
// UsePodCgroup indicates whether the pod will create its own CGroup and
// join containers to it.
// If true, all containers joined to the pod will use the pod cgroup as
// their cgroup parent, and cannot set a different cgroup parent
- UsePodCgroup bool `json:"usePodCgroup"`
+ UsePodCgroup bool `json:"sharesCgroup,omitempty"`
+
+ // The following UsePod{kernelNamespace} indicate whether the containers
+ // in the pod will inherit the namespace from the first container in the pod.
+ UsePodPID bool `json:"sharesPid,omitempty"`
+ UsePodIPC bool `json:"sharesIpc,omitempty"`
+ UsePodNet bool `json:"sharesNet,omitempty"`
+ UsePodMNT bool `json:"sharesMnt,omitempty"`
+ UsePodUser bool `json:"sharesUser,omitempty"`
+ UsePodUTS bool `json:"sharesUts,omitempty"`
+
+ PauseContainer *PauseContainerConfig `json:"pauseConfig"`
// Time pod was created
CreatedTime time.Time `json:"created"`
@@ -52,6 +70,9 @@ type PodConfig struct {
type podState struct {
// CgroupPath is the path to the pod's CGroup
CgroupPath string `json:"cgroupPath"`
+ // PauseContainerID is the container that holds pod namespace information
+ // Most often a pause container
+ PauseContainerID string
}
// PodInspect represents the data we want to display for
@@ -64,7 +85,8 @@ type PodInspect struct {
// PodInspectState contains inspect data on the pod's state
type PodInspectState struct {
- CgroupPath string `json:"cgroupPath"`
+ CgroupPath string `json:"cgroupPath"`
+ PauseContainerID string `json:"pauseContainerID"`
}
// PodContainerInfo keeps information on a container in a pod
@@ -73,6 +95,11 @@ type PodContainerInfo struct {
State string `json:"state"`
}
+// PauseContainerConfig is the configuration for the pod's pause container
+type PauseContainerConfig struct {
+ HasPauseContainer bool `json:"makePauseContainer"`
+}
+
// ID retrieves the pod's ID
func (p *Pod) ID() string {
return p.config.ID
@@ -109,9 +136,45 @@ func (p *Pod) CgroupParent() string {
return p.config.CgroupParent
}
-// UsePodCgroup returns whether containers in the pod will default to this pod's
+// SharesPID returns whether containers in pod
+// default to use PID namespace of first container in pod
+func (p *Pod) SharesPID() bool {
+ return p.config.UsePodPID
+}
+
+// SharesIPC returns whether containers in pod
+// default to use IPC namespace of first container in pod
+func (p *Pod) SharesIPC() bool {
+ return p.config.UsePodIPC
+}
+
+// SharesNet returns whether containers in pod
+// default to use network namespace of first container in pod
+func (p *Pod) SharesNet() bool {
+ return p.config.UsePodNet
+}
+
+// SharesMNT returns whether containers in pod
+// default to use PID namespace of first container in pod
+func (p *Pod) SharesMNT() bool {
+ return p.config.UsePodMNT
+}
+
+// SharesUser returns whether containers in pod
+// default to use user namespace of first container in pod
+func (p *Pod) SharesUser() bool {
+ return p.config.UsePodUser
+}
+
+// SharesUTS returns whether containers in pod
+// default to use UTS namespace of first container in pod
+func (p *Pod) SharesUTS() bool {
+ return p.config.UsePodUTS
+}
+
+// SharesCgroup returns whether containers in the pod will default to this pod's
// cgroup instead of the default libpod parent
-func (p *Pod) UsePodCgroup() bool {
+func (p *Pod) SharesCgroup() bool {
return p.config.UsePodCgroup
}
@@ -161,6 +224,30 @@ func (p *Pod) allContainers() ([]*Container, error) {
return p.runtime.state.PodContainers(p)
}
+// HasPauseContainer returns whether the pod will create a pause container
+func (p *Pod) HasPauseContainer() bool {
+ return p.config.PauseContainer.HasPauseContainer
+}
+
+// SharesNamespaces checks if the pod has any kernel namespaces set as shared. A pause container will not be
+// created if no kernel namespaces are shared.
+func (p *Pod) SharesNamespaces() bool {
+ return p.SharesPID() || p.SharesIPC() || p.SharesNet() || p.SharesMNT() || p.SharesUser() || p.SharesUTS()
+}
+
+// PauseContainerID returns a the pause container ID for a pod.
+// If the container returned is "", the pod has no pause container.
+func (p *Pod) PauseContainerID() (string, error) {
+ p.lock.Lock()
+ defer p.lock.Unlock()
+
+ if err := p.updatePod(); err != nil {
+ return "", err
+ }
+
+ return p.state.PauseContainerID, nil
+}
+
// TODO add pod batching
// Lock pod to avoid lock contention
// Store and lock all containers (no RemoveContainer in batch guarantees cache will not become stale)
diff --git a/libpod/pod_api.go b/libpod/pod_api.go
index d1e19063c..096c9b513 100644
--- a/libpod/pod_api.go
+++ b/libpod/pod_api.go
@@ -426,13 +426,18 @@ func (p *Pod) Inspect() (*PodInspect, error) {
}
podContainers = append(podContainers, pc)
}
+ pauseContainerID := p.state.PauseContainerID
+ if err != nil {
+ return &PodInspect{}, err
+ }
config := new(PodConfig)
deepcopier.Copy(p.config).To(config)
inspectData := PodInspect{
Config: config,
State: &PodInspectState{
- CgroupPath: p.state.CgroupPath,
+ CgroupPath: p.state.CgroupPath,
+ PauseContainerID: pauseContainerID,
},
Containers: podContainers,
}
diff --git a/libpod/pod_ffjson.go b/libpod/pod_ffjson.go
index 36b1cf08f..a2030bb4c 100644
--- a/libpod/pod_ffjson.go
+++ b/libpod/pod_ffjson.go
@@ -12,6 +12,212 @@ import (
)
// MarshalJSON marshal bytes to json - template
+func (j *PauseContainerConfig) MarshalJSON() ([]byte, error) {
+ var buf fflib.Buffer
+ if j == nil {
+ buf.WriteString("null")
+ return buf.Bytes(), nil
+ }
+ err := j.MarshalJSONBuf(&buf)
+ if err != nil {
+ return nil, err
+ }
+ return buf.Bytes(), nil
+}
+
+// MarshalJSONBuf marshal buff to json - template
+func (j *PauseContainerConfig) MarshalJSONBuf(buf fflib.EncodingBuffer) error {
+ if j == nil {
+ buf.WriteString("null")
+ return nil
+ }
+ var err error
+ var obj []byte
+ _ = obj
+ _ = err
+ if j.HasPauseContainer {
+ buf.WriteString(`{"makePauseContainer":true`)
+ } else {
+ buf.WriteString(`{"makePauseContainer":false`)
+ }
+ buf.WriteByte('}')
+ return nil
+}
+
+const (
+ ffjtPauseContainerConfigbase = iota
+ ffjtPauseContainerConfignosuchkey
+
+ ffjtPauseContainerConfigHasPauseContainer
+)
+
+var ffjKeyPauseContainerConfigHasPauseContainer = []byte("makePauseContainer")
+
+// UnmarshalJSON umarshall json - template of ffjson
+func (j *PauseContainerConfig) UnmarshalJSON(input []byte) error {
+ fs := fflib.NewFFLexer(input)
+ return j.UnmarshalJSONFFLexer(fs, fflib.FFParse_map_start)
+}
+
+// UnmarshalJSONFFLexer fast json unmarshall - template ffjson
+func (j *PauseContainerConfig) UnmarshalJSONFFLexer(fs *fflib.FFLexer, state fflib.FFParseState) error {
+ var err error
+ currentKey := ffjtPauseContainerConfigbase
+ _ = currentKey
+ tok := fflib.FFTok_init
+ wantedTok := fflib.FFTok_init
+
+mainparse:
+ for {
+ tok = fs.Scan()
+ // println(fmt.Sprintf("debug: tok: %v state: %v", tok, state))
+ if tok == fflib.FFTok_error {
+ goto tokerror
+ }
+
+ switch state {
+
+ case fflib.FFParse_map_start:
+ if tok != fflib.FFTok_left_bracket {
+ wantedTok = fflib.FFTok_left_bracket
+ goto wrongtokenerror
+ }
+ state = fflib.FFParse_want_key
+ continue
+
+ case fflib.FFParse_after_value:
+ if tok == fflib.FFTok_comma {
+ state = fflib.FFParse_want_key
+ } else if tok == fflib.FFTok_right_bracket {
+ goto done
+ } else {
+ wantedTok = fflib.FFTok_comma
+ goto wrongtokenerror
+ }
+
+ case fflib.FFParse_want_key:
+ // json {} ended. goto exit. woo.
+ if tok == fflib.FFTok_right_bracket {
+ goto done
+ }
+ if tok != fflib.FFTok_string {
+ wantedTok = fflib.FFTok_string
+ goto wrongtokenerror
+ }
+
+ kn := fs.Output.Bytes()
+ if len(kn) <= 0 {
+ // "" case. hrm.
+ currentKey = ffjtPauseContainerConfignosuchkey
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ } else {
+ switch kn[0] {
+
+ case 'm':
+
+ if bytes.Equal(ffjKeyPauseContainerConfigHasPauseContainer, kn) {
+ currentKey = ffjtPauseContainerConfigHasPauseContainer
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ }
+
+ if fflib.EqualFoldRight(ffjKeyPauseContainerConfigHasPauseContainer, kn) {
+ currentKey = ffjtPauseContainerConfigHasPauseContainer
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ currentKey = ffjtPauseContainerConfignosuchkey
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ case fflib.FFParse_want_colon:
+ if tok != fflib.FFTok_colon {
+ wantedTok = fflib.FFTok_colon
+ goto wrongtokenerror
+ }
+ state = fflib.FFParse_want_value
+ continue
+ case fflib.FFParse_want_value:
+
+ if tok == fflib.FFTok_left_brace || tok == fflib.FFTok_left_bracket || tok == fflib.FFTok_integer || tok == fflib.FFTok_double || tok == fflib.FFTok_string || tok == fflib.FFTok_bool || tok == fflib.FFTok_null {
+ switch currentKey {
+
+ case ffjtPauseContainerConfigHasPauseContainer:
+ goto handle_HasPauseContainer
+
+ case ffjtPauseContainerConfignosuchkey:
+ err = fs.SkipField(tok)
+ if err != nil {
+ return fs.WrapErr(err)
+ }
+ state = fflib.FFParse_after_value
+ goto mainparse
+ }
+ } else {
+ goto wantedvalue
+ }
+ }
+ }
+
+handle_HasPauseContainer:
+
+ /* handler: j.HasPauseContainer type=bool kind=bool quoted=false*/
+
+ {
+ if tok != fflib.FFTok_bool && tok != fflib.FFTok_null {
+ return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for bool", tok))
+ }
+ }
+
+ {
+ if tok == fflib.FFTok_null {
+
+ } else {
+ tmpb := fs.Output.Bytes()
+
+ if bytes.Compare([]byte{'t', 'r', 'u', 'e'}, tmpb) == 0 {
+
+ j.HasPauseContainer = true
+
+ } else if bytes.Compare([]byte{'f', 'a', 'l', 's', 'e'}, tmpb) == 0 {
+
+ j.HasPauseContainer = false
+
+ } else {
+ err = errors.New("unexpected bytes for true/false value")
+ return fs.WrapErr(err)
+ }
+
+ }
+ }
+
+ state = fflib.FFParse_after_value
+ goto mainparse
+
+wantedvalue:
+ return fs.WrapErr(fmt.Errorf("wanted value token, but got token: %v", tok))
+wrongtokenerror:
+ return fs.WrapErr(fmt.Errorf("ffjson: wanted token: %v, but got token: %v output=%s", wantedTok, tok, fs.Output.String()))
+tokerror:
+ if fs.BigError != nil {
+ return fs.WrapErr(fs.BigError)
+ }
+ err = fs.Error.ToError()
+ if err != nil {
+ return fs.WrapErr(err)
+ }
+ panic("ffjson-generated: unreachable, please report bug.")
+done:
+
+ return nil
+}
+
+// MarshalJSON marshal bytes to json - template
func (j *PodConfig) MarshalJSON() ([]byte, error) {
var buf fflib.Buffer
if j == nil {
@@ -60,10 +266,76 @@ func (j *PodConfig) MarshalJSONBuf(buf fflib.EncodingBuffer) error {
}
buf.WriteString(`,"cgroupParent":`)
fflib.WriteJsonString(buf, string(j.CgroupParent))
- if j.UsePodCgroup {
- buf.WriteString(`,"usePodCgroup":true`)
+ buf.WriteByte(',')
+ if j.UsePodCgroup != false {
+ if j.UsePodCgroup {
+ buf.WriteString(`"sharesCgroup":true`)
+ } else {
+ buf.WriteString(`"sharesCgroup":false`)
+ }
+ buf.WriteByte(',')
+ }
+ if j.UsePodPID != false {
+ if j.UsePodPID {
+ buf.WriteString(`"sharesPid":true`)
+ } else {
+ buf.WriteString(`"sharesPid":false`)
+ }
+ buf.WriteByte(',')
+ }
+ if j.UsePodIPC != false {
+ if j.UsePodIPC {
+ buf.WriteString(`"sharesIpc":true`)
+ } else {
+ buf.WriteString(`"sharesIpc":false`)
+ }
+ buf.WriteByte(',')
+ }
+ if j.UsePodNet != false {
+ if j.UsePodNet {
+ buf.WriteString(`"sharesNet":true`)
+ } else {
+ buf.WriteString(`"sharesNet":false`)
+ }
+ buf.WriteByte(',')
+ }
+ if j.UsePodMNT != false {
+ if j.UsePodMNT {
+ buf.WriteString(`"sharesMnt":true`)
+ } else {
+ buf.WriteString(`"sharesMnt":false`)
+ }
+ buf.WriteByte(',')
+ }
+ if j.UsePodUser != false {
+ if j.UsePodUser {
+ buf.WriteString(`"sharesUser":true`)
+ } else {
+ buf.WriteString(`"sharesUser":false`)
+ }
+ buf.WriteByte(',')
+ }
+ if j.UsePodUTS != false {
+ if j.UsePodUTS {
+ buf.WriteString(`"sharesUts":true`)
+ } else {
+ buf.WriteString(`"sharesUts":false`)
+ }
+ buf.WriteByte(',')
+ }
+ if j.PauseContainer != nil {
+ buf.WriteString(`"pauseConfig":`)
+
+ {
+
+ err = j.PauseContainer.MarshalJSONBuf(buf)
+ if err != nil {
+ return err
+ }
+
+ }
} else {
- buf.WriteString(`,"usePodCgroup":false`)
+ buf.WriteString(`"pauseConfig":null`)
}
buf.WriteString(`,"created":`)
@@ -96,6 +368,20 @@ const (
ffjtPodConfigUsePodCgroup
+ ffjtPodConfigUsePodPID
+
+ ffjtPodConfigUsePodIPC
+
+ ffjtPodConfigUsePodNet
+
+ ffjtPodConfigUsePodMNT
+
+ ffjtPodConfigUsePodUser
+
+ ffjtPodConfigUsePodUTS
+
+ ffjtPodConfigPauseContainer
+
ffjtPodConfigCreatedTime
)
@@ -109,7 +395,21 @@ var ffjKeyPodConfigLabels = []byte("labels")
var ffjKeyPodConfigCgroupParent = []byte("cgroupParent")
-var ffjKeyPodConfigUsePodCgroup = []byte("usePodCgroup")
+var ffjKeyPodConfigUsePodCgroup = []byte("sharesCgroup")
+
+var ffjKeyPodConfigUsePodPID = []byte("sharesPid")
+
+var ffjKeyPodConfigUsePodIPC = []byte("sharesIpc")
+
+var ffjKeyPodConfigUsePodNet = []byte("sharesNet")
+
+var ffjKeyPodConfigUsePodMNT = []byte("sharesMnt")
+
+var ffjKeyPodConfigUsePodUser = []byte("sharesUser")
+
+var ffjKeyPodConfigUsePodUTS = []byte("sharesUts")
+
+var ffjKeyPodConfigPauseContainer = []byte("pauseConfig")
var ffjKeyPodConfigCreatedTime = []byte("created")
@@ -216,12 +516,50 @@ mainparse:
goto mainparse
}
- case 'u':
+ case 'p':
+
+ if bytes.Equal(ffjKeyPodConfigPauseContainer, kn) {
+ currentKey = ffjtPodConfigPauseContainer
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ case 's':
if bytes.Equal(ffjKeyPodConfigUsePodCgroup, kn) {
currentKey = ffjtPodConfigUsePodCgroup
state = fflib.FFParse_want_colon
goto mainparse
+
+ } else if bytes.Equal(ffjKeyPodConfigUsePodPID, kn) {
+ currentKey = ffjtPodConfigUsePodPID
+ state = fflib.FFParse_want_colon
+ goto mainparse
+
+ } else if bytes.Equal(ffjKeyPodConfigUsePodIPC, kn) {
+ currentKey = ffjtPodConfigUsePodIPC
+ state = fflib.FFParse_want_colon
+ goto mainparse
+
+ } else if bytes.Equal(ffjKeyPodConfigUsePodNet, kn) {
+ currentKey = ffjtPodConfigUsePodNet
+ state = fflib.FFParse_want_colon
+ goto mainparse
+
+ } else if bytes.Equal(ffjKeyPodConfigUsePodMNT, kn) {
+ currentKey = ffjtPodConfigUsePodMNT
+ state = fflib.FFParse_want_colon
+ goto mainparse
+
+ } else if bytes.Equal(ffjKeyPodConfigUsePodUser, kn) {
+ currentKey = ffjtPodConfigUsePodUser
+ state = fflib.FFParse_want_colon
+ goto mainparse
+
+ } else if bytes.Equal(ffjKeyPodConfigUsePodUTS, kn) {
+ currentKey = ffjtPodConfigUsePodUTS
+ state = fflib.FFParse_want_colon
+ goto mainparse
}
}
@@ -232,6 +570,48 @@ mainparse:
goto mainparse
}
+ if fflib.EqualFoldRight(ffjKeyPodConfigPauseContainer, kn) {
+ currentKey = ffjtPodConfigPauseContainer
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ if fflib.EqualFoldRight(ffjKeyPodConfigUsePodUTS, kn) {
+ currentKey = ffjtPodConfigUsePodUTS
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ if fflib.EqualFoldRight(ffjKeyPodConfigUsePodUser, kn) {
+ currentKey = ffjtPodConfigUsePodUser
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ if fflib.EqualFoldRight(ffjKeyPodConfigUsePodMNT, kn) {
+ currentKey = ffjtPodConfigUsePodMNT
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ if fflib.EqualFoldRight(ffjKeyPodConfigUsePodNet, kn) {
+ currentKey = ffjtPodConfigUsePodNet
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ if fflib.EqualFoldRight(ffjKeyPodConfigUsePodIPC, kn) {
+ currentKey = ffjtPodConfigUsePodIPC
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ if fflib.EqualFoldRight(ffjKeyPodConfigUsePodPID, kn) {
+ currentKey = ffjtPodConfigUsePodPID
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
if fflib.EqualFoldRight(ffjKeyPodConfigUsePodCgroup, kn) {
currentKey = ffjtPodConfigUsePodCgroup
state = fflib.FFParse_want_colon
@@ -303,6 +683,27 @@ mainparse:
case ffjtPodConfigUsePodCgroup:
goto handle_UsePodCgroup
+ case ffjtPodConfigUsePodPID:
+ goto handle_UsePodPID
+
+ case ffjtPodConfigUsePodIPC:
+ goto handle_UsePodIPC
+
+ case ffjtPodConfigUsePodNet:
+ goto handle_UsePodNet
+
+ case ffjtPodConfigUsePodMNT:
+ goto handle_UsePodMNT
+
+ case ffjtPodConfigUsePodUser:
+ goto handle_UsePodUser
+
+ case ffjtPodConfigUsePodUTS:
+ goto handle_UsePodUTS
+
+ case ffjtPodConfigPauseContainer:
+ goto handle_PauseContainer
+
case ffjtPodConfigCreatedTime:
goto handle_CreatedTime
@@ -564,6 +965,242 @@ handle_UsePodCgroup:
state = fflib.FFParse_after_value
goto mainparse
+handle_UsePodPID:
+
+ /* handler: j.UsePodPID type=bool kind=bool quoted=false*/
+
+ {
+ if tok != fflib.FFTok_bool && tok != fflib.FFTok_null {
+ return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for bool", tok))
+ }
+ }
+
+ {
+ if tok == fflib.FFTok_null {
+
+ } else {
+ tmpb := fs.Output.Bytes()
+
+ if bytes.Compare([]byte{'t', 'r', 'u', 'e'}, tmpb) == 0 {
+
+ j.UsePodPID = true
+
+ } else if bytes.Compare([]byte{'f', 'a', 'l', 's', 'e'}, tmpb) == 0 {
+
+ j.UsePodPID = false
+
+ } else {
+ err = errors.New("unexpected bytes for true/false value")
+ return fs.WrapErr(err)
+ }
+
+ }
+ }
+
+ state = fflib.FFParse_after_value
+ goto mainparse
+
+handle_UsePodIPC:
+
+ /* handler: j.UsePodIPC type=bool kind=bool quoted=false*/
+
+ {
+ if tok != fflib.FFTok_bool && tok != fflib.FFTok_null {
+ return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for bool", tok))
+ }
+ }
+
+ {
+ if tok == fflib.FFTok_null {
+
+ } else {
+ tmpb := fs.Output.Bytes()
+
+ if bytes.Compare([]byte{'t', 'r', 'u', 'e'}, tmpb) == 0 {
+
+ j.UsePodIPC = true
+
+ } else if bytes.Compare([]byte{'f', 'a', 'l', 's', 'e'}, tmpb) == 0 {
+
+ j.UsePodIPC = false
+
+ } else {
+ err = errors.New("unexpected bytes for true/false value")
+ return fs.WrapErr(err)
+ }
+
+ }
+ }
+
+ state = fflib.FFParse_after_value
+ goto mainparse
+
+handle_UsePodNet:
+
+ /* handler: j.UsePodNet type=bool kind=bool quoted=false*/
+
+ {
+ if tok != fflib.FFTok_bool && tok != fflib.FFTok_null {
+ return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for bool", tok))
+ }
+ }
+
+ {
+ if tok == fflib.FFTok_null {
+
+ } else {
+ tmpb := fs.Output.Bytes()
+
+ if bytes.Compare([]byte{'t', 'r', 'u', 'e'}, tmpb) == 0 {
+
+ j.UsePodNet = true
+
+ } else if bytes.Compare([]byte{'f', 'a', 'l', 's', 'e'}, tmpb) == 0 {
+
+ j.UsePodNet = false
+
+ } else {
+ err = errors.New("unexpected bytes for true/false value")
+ return fs.WrapErr(err)
+ }
+
+ }
+ }
+
+ state = fflib.FFParse_after_value
+ goto mainparse
+
+handle_UsePodMNT:
+
+ /* handler: j.UsePodMNT type=bool kind=bool quoted=false*/
+
+ {
+ if tok != fflib.FFTok_bool && tok != fflib.FFTok_null {
+ return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for bool", tok))
+ }
+ }
+
+ {
+ if tok == fflib.FFTok_null {
+
+ } else {
+ tmpb := fs.Output.Bytes()
+
+ if bytes.Compare([]byte{'t', 'r', 'u', 'e'}, tmpb) == 0 {
+
+ j.UsePodMNT = true
+
+ } else if bytes.Compare([]byte{'f', 'a', 'l', 's', 'e'}, tmpb) == 0 {
+
+ j.UsePodMNT = false
+
+ } else {
+ err = errors.New("unexpected bytes for true/false value")
+ return fs.WrapErr(err)
+ }
+
+ }
+ }
+
+ state = fflib.FFParse_after_value
+ goto mainparse
+
+handle_UsePodUser:
+
+ /* handler: j.UsePodUser type=bool kind=bool quoted=false*/
+
+ {
+ if tok != fflib.FFTok_bool && tok != fflib.FFTok_null {
+ return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for bool", tok))
+ }
+ }
+
+ {
+ if tok == fflib.FFTok_null {
+
+ } else {
+ tmpb := fs.Output.Bytes()
+
+ if bytes.Compare([]byte{'t', 'r', 'u', 'e'}, tmpb) == 0 {
+
+ j.UsePodUser = true
+
+ } else if bytes.Compare([]byte{'f', 'a', 'l', 's', 'e'}, tmpb) == 0 {
+
+ j.UsePodUser = false
+
+ } else {
+ err = errors.New("unexpected bytes for true/false value")
+ return fs.WrapErr(err)
+ }
+
+ }
+ }
+
+ state = fflib.FFParse_after_value
+ goto mainparse
+
+handle_UsePodUTS:
+
+ /* handler: j.UsePodUTS type=bool kind=bool quoted=false*/
+
+ {
+ if tok != fflib.FFTok_bool && tok != fflib.FFTok_null {
+ return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for bool", tok))
+ }
+ }
+
+ {
+ if tok == fflib.FFTok_null {
+
+ } else {
+ tmpb := fs.Output.Bytes()
+
+ if bytes.Compare([]byte{'t', 'r', 'u', 'e'}, tmpb) == 0 {
+
+ j.UsePodUTS = true
+
+ } else if bytes.Compare([]byte{'f', 'a', 'l', 's', 'e'}, tmpb) == 0 {
+
+ j.UsePodUTS = false
+
+ } else {
+ err = errors.New("unexpected bytes for true/false value")
+ return fs.WrapErr(err)
+ }
+
+ }
+ }
+
+ state = fflib.FFParse_after_value
+ goto mainparse
+
+handle_PauseContainer:
+
+ /* handler: j.PauseContainer type=libpod.PauseContainerConfig kind=struct quoted=false*/
+
+ {
+ if tok == fflib.FFTok_null {
+
+ j.PauseContainer = nil
+
+ } else {
+
+ if j.PauseContainer == nil {
+ j.PauseContainer = new(PauseContainerConfig)
+ }
+
+ err = j.PauseContainer.UnmarshalJSONFFLexer(fs, fflib.FFParse_want_key)
+ if err != nil {
+ return err
+ }
+ }
+ state = fflib.FFParse_after_value
+ }
+
+ state = fflib.FFParse_after_value
+ goto mainparse
+
handle_CreatedTime:
/* handler: j.CreatedTime type=time.Time kind=struct quoted=false*/
@@ -1586,6 +2223,8 @@ func (j *PodInspectState) MarshalJSONBuf(buf fflib.EncodingBuffer) error {
_ = err
buf.WriteString(`{"cgroupPath":`)
fflib.WriteJsonString(buf, string(j.CgroupPath))
+ buf.WriteString(`,"pauseContainerID":`)
+ fflib.WriteJsonString(buf, string(j.PauseContainerID))
buf.WriteByte('}')
return nil
}
@@ -1595,10 +2234,14 @@ const (
ffjtPodInspectStatenosuchkey
ffjtPodInspectStateCgroupPath
+
+ ffjtPodInspectStatePauseContainerID
)
var ffjKeyPodInspectStateCgroupPath = []byte("cgroupPath")
+var ffjKeyPodInspectStatePauseContainerID = []byte("pauseContainerID")
+
// UnmarshalJSON umarshall json - template of ffjson
func (j *PodInspectState) UnmarshalJSON(input []byte) error {
fs := fflib.NewFFLexer(input)
@@ -1668,6 +2311,20 @@ mainparse:
goto mainparse
}
+ case 'p':
+
+ if bytes.Equal(ffjKeyPodInspectStatePauseContainerID, kn) {
+ currentKey = ffjtPodInspectStatePauseContainerID
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
+ }
+
+ if fflib.EqualFoldRight(ffjKeyPodInspectStatePauseContainerID, kn) {
+ currentKey = ffjtPodInspectStatePauseContainerID
+ state = fflib.FFParse_want_colon
+ goto mainparse
}
if fflib.SimpleLetterEqualFold(ffjKeyPodInspectStateCgroupPath, kn) {
@@ -1696,6 +2353,9 @@ mainparse:
case ffjtPodInspectStateCgroupPath:
goto handle_CgroupPath
+ case ffjtPodInspectStatePauseContainerID:
+ goto handle_PauseContainerID
+
case ffjtPodInspectStatenosuchkey:
err = fs.SkipField(tok)
if err != nil {
@@ -1736,6 +2396,32 @@ handle_CgroupPath:
state = fflib.FFParse_after_value
goto mainparse
+handle_PauseContainerID:
+
+ /* handler: j.PauseContainerID type=string kind=string quoted=false*/
+
+ {
+
+ {
+ if tok != fflib.FFTok_string && tok != fflib.FFTok_null {
+ return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for string", tok))
+ }
+ }
+
+ if tok == fflib.FFTok_null {
+
+ } else {
+
+ outBuf := fs.Output.Bytes()
+
+ j.PauseContainerID = string(string(outBuf))
+
+ }
+ }
+
+ state = fflib.FFParse_after_value
+ goto mainparse
+
wantedvalue:
return fs.WrapErr(fmt.Errorf("wanted value token, but got token: %v", tok))
wrongtokenerror:
@@ -1780,6 +2466,8 @@ func (j *podState) MarshalJSONBuf(buf fflib.EncodingBuffer) error {
_ = err
buf.WriteString(`{"cgroupPath":`)
fflib.WriteJsonString(buf, string(j.CgroupPath))
+ buf.WriteString(`,"PauseContainerID":`)
+ fflib.WriteJsonString(buf, string(j.PauseContainerID))
buf.WriteByte('}')
return nil
}
@@ -1789,10 +2477,14 @@ const (
ffjtpodStatenosuchkey
ffjtpodStateCgroupPath
+
+ ffjtpodStatePauseContainerID
)
var ffjKeypodStateCgroupPath = []byte("cgroupPath")
+var ffjKeypodStatePauseContainerID = []byte("PauseContainerID")
+
// UnmarshalJSON umarshall json - template of ffjson
func (j *podState) UnmarshalJSON(input []byte) error {
fs := fflib.NewFFLexer(input)
@@ -1854,6 +2546,14 @@ mainparse:
} else {
switch kn[0] {
+ case 'P':
+
+ if bytes.Equal(ffjKeypodStatePauseContainerID, kn) {
+ currentKey = ffjtpodStatePauseContainerID
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
case 'c':
if bytes.Equal(ffjKeypodStateCgroupPath, kn) {
@@ -1864,6 +2564,12 @@ mainparse:
}
+ if fflib.EqualFoldRight(ffjKeypodStatePauseContainerID, kn) {
+ currentKey = ffjtpodStatePauseContainerID
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
if fflib.SimpleLetterEqualFold(ffjKeypodStateCgroupPath, kn) {
currentKey = ffjtpodStateCgroupPath
state = fflib.FFParse_want_colon
@@ -1890,6 +2596,9 @@ mainparse:
case ffjtpodStateCgroupPath:
goto handle_CgroupPath
+ case ffjtpodStatePauseContainerID:
+ goto handle_PauseContainerID
+
case ffjtpodStatenosuchkey:
err = fs.SkipField(tok)
if err != nil {
@@ -1930,6 +2639,32 @@ handle_CgroupPath:
state = fflib.FFParse_after_value
goto mainparse
+handle_PauseContainerID:
+
+ /* handler: j.PauseContainerID type=string kind=string quoted=false*/
+
+ {
+
+ {
+ if tok != fflib.FFTok_string && tok != fflib.FFTok_null {
+ return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for string", tok))
+ }
+ }
+
+ if tok == fflib.FFTok_null {
+
+ } else {
+
+ outBuf := fs.Output.Bytes()
+
+ j.PauseContainerID = string(string(outBuf))
+
+ }
+ }
+
+ state = fflib.FFParse_after_value
+ goto mainparse
+
wantedvalue:
return fs.WrapErr(fmt.Errorf("wanted value token, but got token: %v", tok))
wrongtokenerror:
diff --git a/libpod/pod_internal.go b/libpod/pod_internal.go
index 1ba4487ab..fb0b68906 100644
--- a/libpod/pod_internal.go
+++ b/libpod/pod_internal.go
@@ -20,6 +20,7 @@ func newPod(lockDir string, runtime *Runtime) (*Pod, error) {
pod.config.ID = stringid.GenerateNonCryptoID()
pod.config.Labels = make(map[string]string)
pod.config.CreatedTime = time.Now()
+ pod.config.PauseContainer = new(PauseContainerConfig)
pod.state = new(podState)
pod.runtime = runtime
diff --git a/libpod/runtime.go b/libpod/runtime.go
index 73f516cd5..7e006b1fc 100644
--- a/libpod/runtime.go
+++ b/libpod/runtime.go
@@ -56,6 +56,11 @@ const (
// configuration file. If OverrideConfigPath exists, it will be used in
// place of the configuration file pointed to by ConfigPath.
OverrideConfigPath = "/etc/containers/libpod.conf"
+
+ // DefaultPauseImage to use for pause container
+ DefaultPauseImage = "k8s.gcr.io/pause:3.1"
+ // DefaultPauseCommand to be run in a pause container
+ DefaultPauseCommand = "/pause"
)
// A RuntimeOption is a functional option which alters the Runtime created by
@@ -152,6 +157,10 @@ type RuntimeConfig struct {
// and all containers and pods will be visible.
// The default namespace is "".
Namespace string `toml:"namespace,omitempty"`
+ // PauseImage is the image a pod pause container will use to manage namespaces
+ PauseImage string `toml:"pause_image"`
+ // PauseCommand is the command run to start up a pod pause container
+ PauseCommand string `toml:"pause_command"`
}
var (
@@ -186,6 +195,8 @@ var (
NoPivotRoot: false,
CNIConfigDir: "/etc/cni/net.d/",
CNIPluginDir: []string{"/usr/libexec/cni", "/usr/lib/cni", "/opt/cni/bin"},
+ PauseCommand: DefaultPauseCommand,
+ PauseImage: DefaultPauseImage,
}
)
diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go
index 051b3e85e..1aca559de 100644
--- a/libpod/runtime_ctr.go
+++ b/libpod/runtime_ctr.go
@@ -8,9 +8,12 @@ import (
"strings"
"time"
+ "github.com/containers/storage"
+ "github.com/containers/storage/pkg/stringid"
spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
+ "github.com/ulule/deepcopier"
)
// CtrRemoveTimeout is the default number of seconds to wait after stopping a container
@@ -35,11 +38,37 @@ func (r *Runtime) NewContainer(ctx context.Context, rSpec *spec.Spec, options ..
if !r.valid {
return nil, ErrRuntimeStopped
}
+ return r.newContainer(ctx, rSpec, options...)
+}
+
+func (r *Runtime) newContainer(ctx context.Context, rSpec *spec.Spec, options ...CtrCreateOption) (c *Container, err error) {
+ if rSpec == nil {
+ return nil, errors.Wrapf(ErrInvalidArg, "must provide a valid runtime spec to create container")
+ }
+
+ ctr := new(Container)
+ ctr.config = new(ContainerConfig)
+ ctr.state = new(containerState)
+
+ ctr.config.ID = stringid.GenerateNonCryptoID()
+
+ ctr.config.Spec = new(spec.Spec)
+ deepcopier.Copy(rSpec).To(ctr.config.Spec)
+ ctr.config.CreatedTime = time.Now()
+
+ ctr.config.ShmSize = DefaultShmSize
+
+ ctr.state.BindMounts = make(map[string]string)
- ctr, err := newContainer(rSpec, r.lockDir)
+ // Path our lock file will reside at
+ lockPath := filepath.Join(r.lockDir, ctr.config.ID)
+ // Grab a lockfile at the given path
+ lock, err := storage.GetLockfile(lockPath)
if err != nil {
- return nil, err
+ return nil, errors.Wrapf(err, "error creating lockfile for new container")
}
+ ctr.lock = lock
+
ctr.config.StopTimeout = CtrRemoveTimeout
// Set namespace based on current runtime namespace
@@ -59,6 +88,7 @@ func (r *Runtime) NewContainer(ctx context.Context, rSpec *spec.Spec, options ..
ctr.runtime = r
var pod *Pod
+
if ctr.config.Pod != "" {
// Get the pod from state
pod, err = r.state.Pod(ctr.config.Pod)
@@ -194,6 +224,14 @@ func (r *Runtime) removeContainer(ctx context.Context, c *Container, force bool)
// Lock the pod while we're removing container
pod.lock.Lock()
defer pod.lock.Unlock()
+ if err := pod.updatePod(); err != nil {
+ return err
+ }
+
+ pauseID := pod.state.PauseContainerID
+ if c.ID() == pauseID {
+ return errors.Errorf("a pause container cannot be removed without removing pod %s", pod.ID())
+ }
}
c.lock.Lock()
diff --git a/libpod/runtime_pod.go b/libpod/runtime_pod.go
index 280699b79..19e32d1b0 100644
--- a/libpod/runtime_pod.go
+++ b/libpod/runtime_pod.go
@@ -26,6 +26,16 @@ type PodFilter func(*Pod) bool
// being removed
// Otherwise, the pod will not be removed if any containers are running
func (r *Runtime) RemovePod(ctx context.Context, p *Pod, removeCtrs, force bool) error {
+ r.lock.Lock()
+ defer r.lock.Unlock()
+
+ if !r.valid {
+ return ErrRuntimeStopped
+ }
+
+ p.lock.Lock()
+ defer p.lock.Unlock()
+
return r.removePod(ctx, p, removeCtrs, force)
}
diff --git a/libpod/runtime_pod_linux.go b/libpod/runtime_pod_linux.go
index 3592c2fee..eff15be76 100644
--- a/libpod/runtime_pod_linux.go
+++ b/libpod/runtime_pod_linux.go
@@ -15,7 +15,7 @@ import (
)
// NewPod makes a new, empty pod
-func (r *Runtime) NewPod(options ...PodCreateOption) (*Pod, error) {
+func (r *Runtime) NewPod(ctx context.Context, options ...PodCreateOption) (*Pod, error) {
r.lock.Lock()
defer r.lock.Unlock()
@@ -87,38 +87,42 @@ func (r *Runtime) NewPod(options ...PodCreateOption) (*Pod, error) {
if pod.config.UsePodCgroup {
logrus.Debugf("Got pod cgroup as %s", pod.state.CgroupPath)
}
+ if pod.HasPauseContainer() != pod.SharesNamespaces() {
+ return nil, errors.Errorf("Pods must have a pause container to share namespaces")
+ }
if err := r.state.AddPod(pod); err != nil {
return nil, errors.Wrapf(err, "error adding pod to state")
}
+ if pod.HasPauseContainer() {
+ ctr, err := r.createPauseContainer(ctx, pod)
+ if err != nil {
+ // Tear down pod, as it is assumed a the pod will contain
+ // a pause container, and it does not.
+ if err2 := r.removePod(ctx, pod, true, true); err2 != nil {
+ logrus.Errorf("Error removing pod after pause container creation failure: %v", err2)
+ }
+ return nil, errors.Wrapf(err, "error adding Pause Container")
+ }
+ pod.state.PauseContainerID = ctr.ID()
+ if err := pod.save(); err != nil {
+ return nil, err
+ }
+ }
+
return pod, nil
}
func (r *Runtime) removePod(ctx context.Context, p *Pod, removeCtrs, force bool) error {
- r.lock.Lock()
- defer r.lock.Unlock()
-
- if !r.valid {
- return ErrRuntimeStopped
- }
-
if !p.valid {
if ok, _ := r.state.HasPod(p.ID()); !ok {
- // Pod was either already removed, or never existed to
- // begin with
+ // Pod probably already removed
+ // Or was never in the runtime to begin with
return nil
}
}
- p.lock.Lock()
- defer p.lock.Unlock()
-
- // Force a pod update
- if err := p.updatePod(); err != nil {
- return err
- }
-
ctrs, err := r.state.PodContainers(p)
if err != nil {
return err
@@ -126,6 +130,15 @@ func (r *Runtime) removePod(ctx context.Context, p *Pod, removeCtrs, force bool)
numCtrs := len(ctrs)
+ // If the only container in the pod is the pause container, remove the pod and container unconditionally.
+ if err := p.updatePod(); err != nil {
+ return err
+ }
+ pauseCtrID := p.state.PauseContainerID
+ if numCtrs == 1 && ctrs[0].ID() == pauseCtrID {
+ removeCtrs = true
+ force = true
+ }
if !removeCtrs && numCtrs > 0 {
return errors.Wrapf(ErrCtrExists, "pod %s contains containers and cannot be removed", p.ID())
}
diff --git a/libpod/runtime_pod_pause_linux.go b/libpod/runtime_pod_pause_linux.go
new file mode 100644
index 000000000..41bf8b041
--- /dev/null
+++ b/libpod/runtime_pod_pause_linux.go
@@ -0,0 +1,60 @@
+// +build linux
+
+package libpod
+
+import (
+ "context"
+
+ "github.com/containers/libpod/libpod/image"
+ "github.com/opencontainers/runtime-tools/generate"
+)
+
+const (
+ // IDTruncLength is the length of the pod's id that will be used to make the
+ // pause container name
+ IDTruncLength = 12
+)
+
+func (r *Runtime) makePauseContainer(ctx context.Context, p *Pod, imgName, imgID string) (*Container, error) {
+
+ // Set up generator for pause container defaults
+ g, err := generate.New("linux")
+ if err != nil {
+ return nil, err
+ }
+
+ g.SetRootReadonly(true)
+ g.SetProcessArgs([]string{r.config.PauseCommand})
+
+ containerName := p.ID()[:IDTruncLength] + "-infra"
+ var options []CtrCreateOption
+ options = append(options, r.WithPod(p))
+ options = append(options, WithRootFSFromImage(imgID, imgName, false))
+ options = append(options, WithName(containerName))
+ options = append(options, withIsPause())
+
+ return r.newContainer(ctx, g.Config, options...)
+}
+
+// createPauseContainer wrap creates a pause container for a pod.
+// A pause container becomes the basis for kernel namespace sharing between
+// containers in the pod.
+func (r *Runtime) createPauseContainer(ctx context.Context, p *Pod) (*Container, error) {
+ if !r.valid {
+ return nil, ErrRuntimeStopped
+ }
+
+ newImage, err := r.ImageRuntime().New(ctx, r.config.PauseImage, "", "", nil, nil, image.SigningOptions{}, false, false)
+ if err != nil {
+ return nil, err
+ }
+
+ data, err := newImage.Inspect(ctx)
+ if err != nil {
+ return nil, err
+ }
+ imageName := newImage.Names()[0]
+ imageID := data.ID
+
+ return r.makePauseContainer(ctx, p, imageName, imageID)
+}
diff --git a/libpod/runtime_pod_unsupported.go b/libpod/runtime_pod_unsupported.go
index 7cecb7c56..d2629d5ab 100644
--- a/libpod/runtime_pod_unsupported.go
+++ b/libpod/runtime_pod_unsupported.go
@@ -7,7 +7,7 @@ import (
)
// NewPod makes a new, empty pod
-func (r *Runtime) NewPod(options ...PodCreateOption) (*Pod, error) {
+func (r *Runtime) NewPod(ctx context.Context, options ...PodCreateOption) (*Pod, error) {
return nil, ErrOSNotSupported
}