summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libpod/boltdb_state.go112
-rw-r--r--libpod/boltdb_state_internal.go50
-rw-r--r--libpod/boltdb_state_linux.go8
-rw-r--r--libpod/in_memory_state.go19
-rw-r--r--libpod/options.go25
-rw-r--r--libpod/runtime.go16
-rw-r--r--libpod/state.go4
-rw-r--r--libpod/state_test.go123
8 files changed, 340 insertions, 17 deletions
diff --git a/libpod/boltdb_state.go b/libpod/boltdb_state.go
index 648c14267..73a906761 100644
--- a/libpod/boltdb_state.go
+++ b/libpod/boltdb_state.go
@@ -1,6 +1,7 @@
package libpod
import (
+ "bytes"
"encoding/json"
"os"
"strings"
@@ -11,10 +12,12 @@ import (
// BoltState is a state implementation backed by a Bolt DB
type BoltState struct {
- valid bool
- dbPath string
- lockDir string
- runtime *Runtime
+ valid bool
+ dbPath string
+ namespace string
+ namespaceBytes []byte
+ lockDir string
+ runtime *Runtime
}
// NewBoltState creates a new bolt-backed state database
@@ -23,6 +26,8 @@ func NewBoltState(path, lockDir string, runtime *Runtime) (State, error) {
state.dbPath = path
state.lockDir = lockDir
state.runtime = runtime
+ state.namespace = ""
+ state.namespaceBytes = nil
// Make the directory that will hold container lockfiles
if err := os.MkdirAll(lockDir, 0750); err != nil {
@@ -47,6 +52,9 @@ func NewBoltState(path, lockDir string, runtime *Runtime) (State, error) {
if _, err := tx.CreateBucketIfNotExists(nameRegistryBkt); err != nil {
return errors.Wrapf(err, "error creating name-registry bucket")
}
+ if _, err := tx.CreateBucketIfNotExists(nsRegistryBkt); err != nil {
+ return errors.Wrapf(err, "error creating ns-registry bucket")
+ }
if _, err := tx.CreateBucketIfNotExists(ctrBkt); err != nil {
return errors.Wrapf(err, "error creating containers bucket")
}
@@ -193,6 +201,20 @@ func (s *BoltState) Refresh() error {
return err
}
+// SetNamespace sets the namespace that will be used for container and pod
+// retrieval
+func (s *BoltState) SetNamespace(ns string) error {
+ s.namespace = ns
+
+ if ns != "" {
+ s.namespaceBytes = []byte(ns)
+ } else {
+ s.namespaceBytes = nil
+ }
+
+ return nil
+}
+
// Container retrieves a single container from the state by its full ID
func (s *BoltState) Container(id string) (*Container, error) {
if id == "" {
@@ -262,6 +284,11 @@ func (s *BoltState) LookupContainer(idOrName string) (*Container, error) {
return err
}
+ nsBucket, err := getNSBucket(tx)
+ if err != nil {
+ return err
+ }
+
// First, check if the ID given was the actual container ID
var id []byte
ctrExists := ctrBucket.Bucket([]byte(idOrName))
@@ -274,6 +301,14 @@ func (s *BoltState) LookupContainer(idOrName string) (*Container, error) {
// Use else-if in case the name is set to a partial ID
exists := false
err = idBucket.ForEach(func(checkID, checkName []byte) error {
+ // If the container isn't in our namespace, we
+ // can't match it
+ if s.namespaceBytes != nil {
+ ns := nsBucket.Get(checkID)
+ if !bytes.Equal(ns, s.namespaceBytes) {
+ return nil
+ }
+ }
if string(checkName) == idOrName {
if exists {
return errors.Wrapf(ErrCtrExists, "more than one result for ID or name %s", idOrName)
@@ -334,7 +369,14 @@ func (s *BoltState) HasContainer(id string) (bool, error) {
ctrExists := ctrBucket.Bucket(ctrID)
if ctrExists != nil {
- exists = true
+ if s.namespaceBytes != nil {
+ nsBytes := ctrBucket.Get(namespaceKey)
+ if bytes.Equal(nsBytes, nsBytes) {
+ exists = true
+ }
+ } else {
+ exists = true
+ }
}
return nil
@@ -383,7 +425,7 @@ func (s *BoltState) RemoveContainer(ctr *Container) error {
defer db.Close()
err = db.Update(func(tx *bolt.Tx) error {
- return removeContainer(ctr, nil, tx)
+ return removeContainer(ctr, nil, tx, s.namespace)
})
return err
}
@@ -398,6 +440,12 @@ func (s *BoltState) UpdateContainer(ctr *Container) error {
return ErrCtrRemoved
}
+ if s.namespace != "" {
+ if s.namespace != ctr.config.Namespace {
+ return errors.Wrapf(ErrNSMismatch, "container %s is in namespace %q, does not match our namespace %q", ctr.ID(), ctr.config.Namespace, s.namespace)
+ }
+ }
+
newState := new(containerState)
netNSPath := ""
@@ -460,6 +508,12 @@ func (s *BoltState) SaveContainer(ctr *Container) error {
return ErrCtrRemoved
}
+ if s.namespace != "" {
+ if s.namespace != ctr.config.Namespace {
+ return errors.Wrapf(ErrNSMismatch, "container %s is in namespace %q, does not match our namespace %q", ctr.ID(), ctr.config.Namespace, s.namespace)
+ }
+ }
+
stateJSON, err := json.Marshal(ctr.state)
if err != nil {
return errors.Wrapf(err, "error marshalling container %s state to JSON", ctr.ID())
@@ -519,6 +573,12 @@ func (s *BoltState) ContainerInUse(ctr *Container) ([]string, error) {
return nil, ErrCtrRemoved
}
+ if s.namespace != "" {
+ if s.namespace != ctr.config.Namespace {
+ return nil, errors.Wrapf(ErrNSMismatch, "container %s is in namespace %q, does not match our namespace %q", ctr.ID(), ctr.config.Namespace, s.namespace)
+ }
+ }
+
depCtrs := []string{}
db, err := s.getDBCon()
@@ -602,9 +662,20 @@ func (s *BoltState) AllContainers() ([]*Container, error) {
ctr.config = new(ContainerConfig)
ctr.state = new(containerState)
- ctrs = append(ctrs, ctr)
+ if err := s.getContainerFromDB(id, ctr, ctrBucket); err != nil {
+ // If the error is a namespace mismatch, we can
+ // ignore it safely.
+ // We just won't include the container in the
+ // results.
+ if errors.Cause(err) != ErrNSMismatch {
+ return err
+ }
+ } else {
+ ctrs = append(ctrs, ctr)
+ }
+
+ return nil
- return s.getContainerFromDB(id, ctr, ctrBucket)
})
})
if err != nil {
@@ -682,6 +753,11 @@ func (s *BoltState) LookupPod(idOrName string) (*Pod, error) {
return err
}
+ nsBkt, err := getNSBucket(tx)
+ if err != nil {
+ return err
+ }
+
// First, check if the ID given was the actual pod ID
var id []byte
podExists := podBkt.Bucket([]byte(idOrName))
@@ -694,6 +770,14 @@ func (s *BoltState) LookupPod(idOrName string) (*Pod, error) {
// Use else-if in case the name is set to a partial ID
exists := false
err = idBucket.ForEach(func(checkID, checkName []byte) error {
+ // If the pod isn't in our namespace, we
+ // can't match it
+ if s.namespaceBytes != nil {
+ ns := nsBkt.Get(checkID)
+ if !bytes.Equal(ns, s.namespaceBytes) {
+ return nil
+ }
+ }
if string(checkName) == idOrName {
if exists {
return errors.Wrapf(ErrPodExists, "more than one result for ID or name %s", idOrName)
@@ -719,7 +803,6 @@ func (s *BoltState) LookupPod(idOrName string) (*Pod, error) {
// We might have found a container ID, but it's OK
// We'll just fail in getPodFromDB with ErrNoSuchPod
-
return s.getPodFromDB(id, pod, podBkt)
})
if err != nil {
@@ -757,7 +840,14 @@ func (s *BoltState) HasPod(id string) (bool, error) {
podDB := podBkt.Bucket(podID)
if podDB != nil {
- exists = true
+ if s.namespaceBytes != nil {
+ podNS := podDB.Get(namespaceKey)
+ if bytes.Equal(s.namespaceBytes, podNS) {
+ exists = true
+ }
+ } else {
+ exists = true
+ }
}
return nil
@@ -1318,7 +1408,7 @@ func (s *BoltState) RemoveContainerFromPod(pod *Pod, ctr *Container) error {
defer db.Close()
err = db.Update(func(tx *bolt.Tx) error {
- return removeContainer(ctr, pod, tx)
+ return removeContainer(ctr, pod, tx, s.namespace)
})
return err
}
diff --git a/libpod/boltdb_state_internal.go b/libpod/boltdb_state_internal.go
index 5661c5b7f..718c43046 100644
--- a/libpod/boltdb_state_internal.go
+++ b/libpod/boltdb_state_internal.go
@@ -16,6 +16,7 @@ import (
const (
idRegistryName = "id-registry"
nameRegistryName = "name-registry"
+ nsRegistryName = "ns-registry"
ctrName = "ctr"
allCtrsName = "all-ctrs"
podName = "pod"
@@ -34,6 +35,7 @@ const (
var (
idRegistryBkt = []byte(idRegistryName)
nameRegistryBkt = []byte(nameRegistryName)
+ nsRegistryBkt = []byte(nsRegistryName)
ctrBkt = []byte(ctrName)
allCtrsBkt = []byte(allCtrsName)
podBkt = []byte(podName)
@@ -168,6 +170,14 @@ func getNamesBucket(tx *bolt.Tx) (*bolt.Bucket, error) {
return bkt, nil
}
+func getNSBucket(tx *bolt.Tx) (*bolt.Bucket, error) {
+ bkt := tx.Bucket(nsRegistryBkt)
+ if bkt == nil {
+ return nil, errors.Wrapf(ErrDBBadConfig, "namespace registry bucket not found in DB")
+ }
+ return bkt, nil
+}
+
func getCtrBucket(tx *bolt.Tx) (*bolt.Bucket, error) {
bkt := tx.Bucket(ctrBkt)
if bkt == nil {
@@ -214,6 +224,13 @@ func (s *BoltState) getPodFromDB(id []byte, pod *Pod, podBkt *bolt.Bucket) error
return errors.Wrapf(ErrNoSuchPod, "pod with ID %s not found", string(id))
}
+ if s.namespaceBytes != nil {
+ podNamespaceBytes := podDB.Get(namespaceKey)
+ if !bytes.Equal(s.namespaceBytes, podNamespaceBytes) {
+ return errors.Wrapf(ErrNSMismatch, "cannot retrieve pod %s as it is part of namespace %q and we are in namespace %q", string(id), string(podNamespaceBytes), s.namespace)
+ }
+ }
+
podConfigBytes := podDB.Get(configKey)
if podConfigBytes == nil {
return errors.Wrapf(ErrInternal, "pod %s is missing configuration key in DB", string(id))
@@ -287,6 +304,11 @@ func (s *BoltState) addContainer(ctr *Container, pod *Pod) error {
return err
}
+ nsBucket, err := getNSBucket(tx)
+ if err != nil {
+ return err
+ }
+
ctrBucket, err := getCtrBucket(tx)
if err != nil {
return err
@@ -343,6 +365,11 @@ func (s *BoltState) addContainer(ctr *Container, pod *Pod) error {
if err := namesBucket.Put(ctrName, ctrID); err != nil {
return errors.Wrapf(err, "error adding container %s name (%s) to DB", ctr.ID(), ctr.Name())
}
+ if ctrNamespace != nil {
+ if err := nsBucket.Put(ctrID, ctrNamespace); err != nil {
+ return errors.Wrapf(err, "error adding container %s namespace (%q) to DB", ctr.ID(), ctr.Namespace())
+ }
+ }
if err := allCtrsBucket.Put(ctrID, ctrName); err != nil {
return errors.Wrapf(err, "error adding container %s to all containers bucket in DB", ctr.ID())
}
@@ -403,6 +430,11 @@ func (s *BoltState) addContainer(ctr *Container, pod *Pod) error {
}
}
+ depNamespace := depCtrBkt.Get(namespaceKey)
+ if !bytes.Equal(ctrNamespace, depNamespace) {
+ return errors.Wrapf(ErrNSMismatch, "container %s in namespace %q depends on container %s in namespace %q - namespaces must match", ctr.ID(), ctr.config.Namespace, dependsCtr, string(depNamespace))
+ }
+
depCtrDependsBkt := depCtrBkt.Bucket(dependenciesBkt)
if depCtrDependsBkt == nil {
return errors.Wrapf(ErrInternal, "container %s does not have a dependencies bucket", dependsCtr)
@@ -427,7 +459,7 @@ func (s *BoltState) addContainer(ctr *Container, pod *Pod) error {
// Remove a container from the DB
// If pod is not nil, the container is treated as belonging to a pod, and
// will be removed from the pod as well
-func removeContainer(ctr *Container, pod *Pod, tx *bolt.Tx) error {
+func removeContainer(ctr *Container, pod *Pod, tx *bolt.Tx, namespace string) error {
ctrID := []byte(ctr.ID())
ctrName := []byte(ctr.Name())
@@ -446,6 +478,11 @@ func removeContainer(ctr *Container, pod *Pod, tx *bolt.Tx) error {
return err
}
+ nsBucket, err := getNSBucket(tx)
+ if err != nil {
+ return err
+ }
+
allCtrsBucket, err := getAllCtrsBucket(tx)
if err != nil {
return err
@@ -475,6 +512,14 @@ func removeContainer(ctr *Container, pod *Pod, tx *bolt.Tx) error {
return errors.Wrapf(ErrNoSuchCtr, "no container with ID %s found in DB", ctr.ID())
}
+ // Compare namespace
+ // We can't remove containers not in our namespace
+ if namespace != "" {
+ if namespace != ctr.config.Namespace {
+ return errors.Wrapf(ErrNSMismatch, "container %s is in namespace %q, does not match our namespace %q", ctr.ID(), ctr.config.Namespace, namespace)
+ }
+ }
+
if podDB != nil {
// Check if the container is in the pod, remove it if it is
podCtrs := podDB.Bucket(containersBkt)
@@ -521,6 +566,9 @@ func removeContainer(ctr *Container, pod *Pod, tx *bolt.Tx) error {
if err := namesBucket.Delete(ctrName); err != nil {
return errors.Wrapf(err, "error deleting container %s name in DB", ctr.ID())
}
+ if err := nsBucket.Delete(ctrID); err != nil {
+ return errors.Wrapf(err, "error deleting container %s namespace in DB", ctr.ID())
+ }
if err := allCtrsBucket.Delete(ctrID); err != nil {
return errors.Wrapf(err, "error deleting container %s from all containers bucket in DB", ctr.ID())
}
diff --git a/libpod/boltdb_state_linux.go b/libpod/boltdb_state_linux.go
index ceea955bd..7c0e08fb3 100644
--- a/libpod/boltdb_state_linux.go
+++ b/libpod/boltdb_state_linux.go
@@ -3,6 +3,7 @@
package libpod
import (
+ "bytes"
"encoding/json"
"path/filepath"
@@ -19,6 +20,13 @@ func (s *BoltState) getContainerFromDB(id []byte, ctr *Container, ctrsBkt *bolt.
return errors.Wrapf(ErrNoSuchCtr, "container %s not found in DB", string(id))
}
+ if s.namespaceBytes != nil {
+ ctrNamespaceBytes := ctrBkt.Get(namespaceKey)
+ if !bytes.Equal(s.namespaceBytes, ctrNamespaceBytes) {
+ return errors.Wrapf(ErrNSMismatch, "cannot retrieve container %s as it is part of namespace %q and we are in namespace %q", string(id), string(ctrNamespaceBytes), s.namespace)
+ }
+ }
+
configBytes := ctrBkt.Get(configKey)
if configBytes == nil {
return errors.Wrapf(ErrInternal, "container %s missing config key in DB", string(id))
diff --git a/libpod/in_memory_state.go b/libpod/in_memory_state.go
index cf2f43477..4ea8740fb 100644
--- a/libpod/in_memory_state.go
+++ b/libpod/in_memory_state.go
@@ -20,6 +20,7 @@ type InMemoryState struct {
podContainers map[string]map[string]*Container
nameIndex *registrar.Registrar
idIndex *truncindex.TruncIndex
+ namespace string
}
// NewInMemoryState initializes a new, empty in-memory state
@@ -36,6 +37,8 @@ func NewInMemoryState() (State, error) {
state.nameIndex = registrar.NewRegistrar()
state.idIndex = truncindex.NewTruncIndex([]string{})
+ state.namespace = ""
+
return state, nil
}
@@ -51,6 +54,13 @@ func (s *InMemoryState) Refresh() error {
return nil
}
+// SetNamespace sets the namespace for container and pod retrieval.
+func (s *InMemoryState) SetNamespace(ns string) error {
+ s.namespace = ns
+
+ return nil
+}
+
// Container retrieves a container from its full ID
func (s *InMemoryState) Container(id string) (*Container, error) {
if id == "" {
@@ -133,6 +143,9 @@ func (s *InMemoryState) AddContainer(ctr *Container) error {
} else if depCtr.config.Pod != "" {
return errors.Wrapf(ErrInvalidArg, "cannot depend on container in a pod if not part of same pod")
}
+ if depCtr.config.Namespace != ctr.config.Namespace {
+ return errors.Wrapf(ErrNSMismatch, "container %s is in namespace %s and cannot depend on container %s in namespace %s", ctr.ID(), ctr.config.Namespace, depID, depCtr.config.Namespace)
+ }
}
if err := s.nameIndex.Reserve(ctr.Name(), ctr.ID()); err != nil {
@@ -519,9 +532,13 @@ func (s *InMemoryState) AddContainerToPod(pod *Pod, ctr *Container) error {
if _, ok = s.containers[depCtr]; !ok {
return errors.Wrapf(ErrNoSuchCtr, "cannot depend on nonexistent container %s", depCtr)
}
- if _, ok = podCtrs[depCtr]; !ok {
+ depCtrStruct, ok := podCtrs[depCtr]
+ if !ok {
return errors.Wrapf(ErrInvalidArg, "cannot depend on container %s as it is not in pod %s", depCtr, pod.ID())
}
+ if depCtrStruct.config.Namespace != ctr.config.Namespace {
+ return errors.Wrapf(ErrNSMismatch, "container %s is in namespace %s and cannot depend on container %s in namespace %s", ctr.ID(), ctr.config.Namespace, depCtr, depCtrStruct.config.Namespace)
+ }
}
// Add container to state
diff --git a/libpod/options.go b/libpod/options.go
index fb07d1edf..155c15333 100644
--- a/libpod/options.go
+++ b/libpod/options.go
@@ -284,6 +284,27 @@ func WithCNIPluginDir(dir string) RuntimeOption {
}
}
+// WithNamespace sets the namespace for libpod.
+// Namespace is the libpod namespace to use.
+// Namespaces are used to create scopes to separate containers and pods
+// in the state.
+// When namespace is set, libpod will only view containers and pods in
+// the same namespace. All containers and pods created will default to
+// the namespace set here.
+// A namespace of "", the empty string, is equivalent to no namespace,
+// and all containers and pods will be visible.
+func WithNamespace(ns string) RuntimeOption {
+ return func(rt *Runtime) error {
+ if rt.valid {
+ return ErrRuntimeFinalized
+ }
+
+ rt.config.Namespace = ns
+
+ return nil
+ }
+}
+
// Container Creation Options
// WithShmDir sets the directory that should be mounted on /dev/shm.
@@ -963,11 +984,11 @@ func WithRootFS(rootfs string) CtrCreateOption {
}
}
-// WithNamespace sets the namespace the container will be created in.
+// WithCtrNamespace sets the namespace the container will be created in.
// Namespaces are used to create separate views of Podman's state - runtimes can
// join a specific namespace and see only containers and pods in that namespace.
// Empty string namespaces are allowed, and correspond to a lack of namespace.
-func WithNamespace(ns string) CtrCreateOption {
+func WithCtrNamespace(ns string) CtrCreateOption {
return func(ctr *Container) error {
if ctr.valid {
return ErrCtrFinalized
diff --git a/libpod/runtime.go b/libpod/runtime.go
index a551c9134..a0b673d81 100644
--- a/libpod/runtime.go
+++ b/libpod/runtime.go
@@ -136,10 +136,22 @@ type RuntimeConfig struct {
// CNIDefaultNetwork is the network name of the default CNI network
// to attach pods to
CNIDefaultNetwork string `toml:"cni_default_network,omitempty"`
- // HooksDirNotExistFatal switches between fatal errors and non-fatal warnings if the configured HooksDir does not exist.
+ // HooksDirNotExistFatal switches between fatal errors and non-fatal
+ // warnings if the configured HooksDir does not exist.
HooksDirNotExistFatal bool `toml:"hooks_dir_not_exist_fatal"`
- // DefaultMountsFile is the path to the default mounts file for testing purposes only
+ // DefaultMountsFile is the path to the default mounts file for testing
+ // purposes only
DefaultMountsFile string `toml:"-"`
+ // Namespace is the libpod namespace to use.
+ // Namespaces are used to create scopes to separate containers and pods
+ // in the state.
+ // When namespace is set, libpod will only view containers and pods in
+ // the same namespace. All containers and pods created will default to
+ // the namespace set here.
+ // A namespace of "", the empty string, is equivalent to no namespace,
+ // and all containers and pods will be visible.
+ // The default namespace is "".
+ Namespace string `toml:"namespace,omitempty"`
}
var (
diff --git a/libpod/state.go b/libpod/state.go
index b71f811ea..6239e399a 100644
--- a/libpod/state.go
+++ b/libpod/state.go
@@ -9,6 +9,10 @@ type State interface {
// Refresh clears container and pod states after a reboot
Refresh() error
+ // SetNamespace() sets the namespace for the store, and will determine
+ // what containers are retrieved with container and pod retrieval calls
+ SetNamespace(ns string) error
+
// Return a container from the database from its full ID
Container(id string) (*Container, error)
// Return a container from the database by full or partial ID or full
diff --git a/libpod/state_test.go b/libpod/state_test.go
index 7174bbf2a..e5c5a1de0 100644
--- a/libpod/state_test.go
+++ b/libpod/state_test.go
@@ -281,6 +281,56 @@ func TestAddCtrDepInPodFails(t *testing.T) {
})
}
+func TestAddCtrDepInSameNamespaceSucceeds(t *testing.T) {
+ runForAllStates(t, func(t *testing.T, state State, lockPath string) {
+ testCtr1, err := getTestCtr1(lockPath)
+ assert.NoError(t, err)
+ testCtr2, err := getTestCtr2(lockPath)
+ assert.NoError(t, err)
+
+ testCtr2.config.UserNsCtr = testCtr1.config.ID
+
+ testCtr1.config.Namespace = "test1"
+ testCtr2.config.Namespace = "test1"
+
+ err = state.AddContainer(testCtr1)
+ assert.NoError(t, err)
+
+ err = state.AddContainer(testCtr2)
+ assert.NoError(t, err)
+
+ ctrs, err := state.AllContainers()
+ assert.NoError(t, err)
+ assert.Equal(t, 2, len(ctrs))
+ })
+}
+
+func TestAddCtrDepInDifferentNamespaceFails(t *testing.T) {
+ runForAllStates(t, func(t *testing.T, state State, lockPath string) {
+ testCtr1, err := getTestCtr1(lockPath)
+ assert.NoError(t, err)
+ testCtr2, err := getTestCtr2(lockPath)
+ assert.NoError(t, err)
+
+ testCtr2.config.UserNsCtr = testCtr1.config.ID
+
+ testCtr1.config.Namespace = "test1"
+ testCtr2.config.Namespace = "test2"
+
+ err = state.AddContainer(testCtr1)
+ assert.NoError(t, err)
+
+ err = state.AddContainer(testCtr2)
+ assert.Error(t, err)
+
+ ctrs, err := state.AllContainers()
+ assert.NoError(t, err)
+ assert.Equal(t, 1, len(ctrs))
+
+ testContainersEqual(t, testCtr1, ctrs[0])
+ })
+}
+
func TestGetNonexistentContainerFails(t *testing.T) {
runForAllStates(t, func(t *testing.T, state State, lockPath string) {
_, err := state.Container("does not exist")
@@ -2224,6 +2274,79 @@ func TestAddContainerToPodDependencyOutsidePodFails(t *testing.T) {
})
}
+func TestAddContainerToPodDependencyInSameNamespaceSucceeds(t *testing.T) {
+ runForAllStates(t, func(t *testing.T, state State, lockPath string) {
+ testPod, err := getTestPod1(lockPath)
+ assert.NoError(t, err)
+ testPod.config.Namespace = "test1"
+
+ testCtr1, err := getTestCtr2(lockPath)
+ assert.NoError(t, err)
+ testCtr1.config.Pod = testPod.ID()
+ testCtr1.config.Namespace = "test1"
+
+ testCtr2, err := getTestCtrN("3", lockPath)
+ assert.NoError(t, err)
+ testCtr2.config.Pod = testPod.ID()
+ testCtr2.config.IPCNsCtr = testCtr1.ID()
+ testCtr2.config.Namespace = "test1"
+
+ err = state.AddPod(testPod)
+ assert.NoError(t, err)
+
+ err = state.AddContainerToPod(testPod, testCtr1)
+ assert.NoError(t, err)
+
+ err = state.AddContainerToPod(testPod, testCtr2)
+ assert.NoError(t, err)
+
+ deps, err := state.ContainerInUse(testCtr1)
+ assert.NoError(t, err)
+ assert.Equal(t, 1, len(deps))
+ assert.Equal(t, testCtr2.ID(), deps[0])
+ })
+}
+
+func TestAddContainerToPodDependencyInSeparateNamespaceFails(t *testing.T) {
+ runForAllStates(t, func(t *testing.T, state State, lockPath string) {
+ testPod, err := getTestPod1(lockPath)
+ assert.NoError(t, err)
+ testPod.config.Namespace = "test1"
+
+ testCtr1, err := getTestCtr2(lockPath)
+ assert.NoError(t, err)
+ testCtr1.config.Pod = testPod.ID()
+ testCtr1.config.Namespace = "test1"
+
+ testCtr2, err := getTestCtrN("3", lockPath)
+ assert.NoError(t, err)
+ testCtr2.config.Pod = testPod.ID()
+ testCtr2.config.IPCNsCtr = testCtr1.ID()
+ testCtr2.config.Namespace = "test2"
+
+ err = state.AddPod(testPod)
+ assert.NoError(t, err)
+
+ err = state.AddContainerToPod(testPod, testCtr1)
+ assert.NoError(t, err)
+
+ err = state.AddContainerToPod(testPod, testCtr2)
+ assert.Error(t, err)
+
+ ctrs, err := state.PodContainers(testPod)
+ assert.NoError(t, err)
+ assert.Equal(t, 1, len(ctrs))
+
+ allCtrs, err := state.AllContainers()
+ assert.NoError(t, err)
+ assert.Equal(t, 1, len(allCtrs))
+
+ deps, err := state.ContainerInUse(testCtr1)
+ assert.NoError(t, err)
+ assert.Equal(t, 0, len(deps))
+ })
+}
+
func TestAddContainerToPodSameNamespaceSucceeds(t *testing.T) {
runForAllStates(t, func(t *testing.T, state State, lockPath string) {
testPod, err := getTestPod1(lockPath)