mirror of
https://github.com/containers/podman.git
synced 2025-05-20 16:47:39 +08:00
Add constraint that dependencies must be in the same ns
Dependency containers must be in the same namespace, to ensure there are never problems resolving a dependency. Signed-off-by: Matthew Heon <matthew.heon@gmail.com>
This commit is contained in:
@ -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
|
||||
}
|
||||
|
@ -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())
|
||||
}
|
||||
|
@ -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))
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 (
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
Reference in New Issue
Block a user