summaryrefslogtreecommitdiff
path: root/libpod/in_memory_state.go
diff options
context:
space:
mode:
Diffstat (limited to 'libpod/in_memory_state.go')
-rw-r--r--libpod/in_memory_state.go295
1 files changed, 277 insertions, 18 deletions
diff --git a/libpod/in_memory_state.go b/libpod/in_memory_state.go
index 36077b9d1..8bdd0881c 100644
--- a/libpod/in_memory_state.go
+++ b/libpod/in_memory_state.go
@@ -14,12 +14,30 @@ import (
// An InMemoryState is a purely in-memory state store
type InMemoryState struct {
- pods map[string]*Pod
- containers map[string]*Container
- ctrDepends map[string][]string
+ // Maps pod ID to pod struct.
+ pods map[string]*Pod
+ // Maps container ID to container struct.
+ containers map[string]*Container
+ // Maps container ID to a list of IDs of dependencies.
+ ctrDepends map[string][]string
+ // Maps pod ID to a map of container ID to container struct.
podContainers map[string]map[string]*Container
- nameIndex *registrar.Registrar
- idIndex *truncindex.TruncIndex
+ // Global name registry - ensures name uniqueness and performs lookups.
+ nameIndex *registrar.Registrar
+ // Global ID registry - ensures ID uniqueness and performs lookups.
+ idIndex *truncindex.TruncIndex
+ // Namespace the state is joined to.
+ namespace string
+ // Maps namespace name to local ID and name registries for looking up
+ // pods and containers in a specific namespace.
+ namespaceIndexes map[string]*namespaceIndex
+}
+
+// namespaceIndex contains name and ID registries for a specific namespace.
+// This is used for namespaces lookup operations.
+type namespaceIndex struct {
+ nameIndex *registrar.Registrar
+ idIndex *truncindex.TruncIndex
}
// NewInMemoryState initializes a new, empty in-memory state
@@ -36,6 +54,10 @@ func NewInMemoryState() (State, error) {
state.nameIndex = registrar.NewRegistrar()
state.idIndex = truncindex.NewTruncIndex([]string{})
+ state.namespace = ""
+
+ state.namespaceIndexes = make(map[string]*namespaceIndex)
+
return state, nil
}
@@ -51,6 +73,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 == "" {
@@ -62,20 +91,43 @@ func (s *InMemoryState) Container(id string) (*Container, error) {
return nil, errors.Wrapf(ErrNoSuchCtr, "no container with ID %s found", id)
}
+ if err := s.checkNSMatch(ctr.ID(), ctr.Namespace()); err != nil {
+ return nil, err
+ }
+
return ctr, nil
}
// LookupContainer retrieves a container by full ID, unique partial ID, or name
func (s *InMemoryState) LookupContainer(idOrName string) (*Container, error) {
+ var (
+ nameIndex *registrar.Registrar
+ idIndex *truncindex.TruncIndex
+ )
+
if idOrName == "" {
return nil, ErrEmptyID
}
- fullID, err := s.nameIndex.Get(idOrName)
+ if s.namespace != "" {
+ nsIndex, ok := s.namespaceIndexes[s.namespace]
+ if !ok {
+ // We have no containers in the namespace
+ // Return false
+ return nil, errors.Wrapf(ErrNoSuchCtr, "no container found with name or ID %s", idOrName)
+ }
+ nameIndex = nsIndex.nameIndex
+ idIndex = nsIndex.idIndex
+ } else {
+ nameIndex = s.nameIndex
+ idIndex = s.idIndex
+ }
+
+ fullID, err := nameIndex.Get(idOrName)
if err != nil {
if err == registrar.ErrNameNotReserved {
// What was passed is not a name, assume it's an ID
- fullID, err = s.idIndex.Get(idOrName)
+ fullID, err = idIndex.Get(idOrName)
if err != nil {
if err == truncindex.ErrNotExist {
return nil, errors.Wrapf(ErrNoSuchCtr, "no container found with name or ID %s", idOrName)
@@ -102,9 +154,12 @@ func (s *InMemoryState) HasContainer(id string) (bool, error) {
return false, ErrEmptyID
}
- _, ok := s.containers[id]
+ ctr, ok := s.containers[id]
+ if !ok || (s.namespace != "" && s.namespace != ctr.config.Namespace) {
+ return false, nil
+ }
- return ok, nil
+ return true, nil
}
// AddContainer adds a container to the state
@@ -122,6 +177,10 @@ func (s *InMemoryState) AddContainer(ctr *Container) error {
return errors.Wrapf(ErrInvalidArg, "cannot add a container that is in a pod with AddContainer, use AddContainerToPod")
}
+ if err := s.checkNSMatch(ctr.ID(), ctr.Namespace()); err != nil {
+ return err
+ }
+
// There are potential race conditions with this
// But in-memory state is intended purely for testing and not production
// use, so this should be fine.
@@ -133,6 +192,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 {
@@ -146,6 +208,25 @@ func (s *InMemoryState) AddContainer(ctr *Container) error {
s.containers[ctr.ID()] = ctr
+ // If we're in a namespace, add us to that namespace's indexes
+ if ctr.config.Namespace != "" {
+ var nsIndex *namespaceIndex
+ nsIndex, ok := s.namespaceIndexes[ctr.config.Namespace]
+ if !ok {
+ nsIndex = new(namespaceIndex)
+ nsIndex.nameIndex = registrar.NewRegistrar()
+ nsIndex.idIndex = truncindex.NewTruncIndex([]string{})
+ s.namespaceIndexes[ctr.config.Namespace] = nsIndex
+ }
+ // Should be no errors here, the previous index adds should have caught that
+ if err := nsIndex.nameIndex.Reserve(ctr.Name(), ctr.ID()); err != nil {
+ return errors.Wrapf(err, "error registering container name %s", ctr.Name())
+ }
+ if err := nsIndex.idIndex.Add(ctr.ID()); err != nil {
+ return errors.Wrapf(err, "error registering container ID %s", ctr.ID())
+ }
+ }
+
// Add containers this container depends on
for _, depCtr := range depCtrs {
s.addCtrToDependsMap(ctr.ID(), depCtr)
@@ -160,6 +241,10 @@ func (s *InMemoryState) RemoveContainer(ctr *Container) error {
// Almost no validity checks are performed, to ensure we can kick
// misbehaving containers out of the state
+ if err := s.checkNSMatch(ctr.ID(), ctr.Namespace()); err != nil {
+ return err
+ }
+
// Ensure we don't remove a container which other containers depend on
deps, ok := s.ctrDepends[ctr.ID()]
if ok && len(deps) != 0 {
@@ -180,6 +265,17 @@ func (s *InMemoryState) RemoveContainer(ctr *Container) error {
delete(s.ctrDepends, ctr.ID())
+ if ctr.config.Namespace != "" {
+ nsIndex, ok := s.namespaceIndexes[ctr.config.Namespace]
+ if !ok {
+ return errors.Wrapf(ErrInternal, "error retrieving index for namespace %q", ctr.config.Namespace)
+ }
+ if err := nsIndex.idIndex.Delete(ctr.ID()); err != nil {
+ return errors.Wrapf(err, "error removing container %s from namespace ID index", ctr.ID())
+ }
+ nsIndex.nameIndex.Release(ctr.Name())
+ }
+
// Remove us from container dependencies
depCtrs := ctr.Dependencies()
for _, depCtr := range depCtrs {
@@ -204,7 +300,7 @@ func (s *InMemoryState) UpdateContainer(ctr *Container) error {
return errors.Wrapf(ErrNoSuchCtr, "container with ID %s not found in state", ctr.ID())
}
- return nil
+ return s.checkNSMatch(ctr.ID(), ctr.Namespace())
}
// SaveContainer saves a container's state
@@ -223,7 +319,7 @@ func (s *InMemoryState) SaveContainer(ctr *Container) error {
return errors.Wrapf(ErrNoSuchCtr, "container with ID %s not found in state", ctr.ID())
}
- return nil
+ return s.checkNSMatch(ctr.ID(), ctr.Namespace())
}
// ContainerInUse checks if the given container is being used by other containers
@@ -232,6 +328,16 @@ func (s *InMemoryState) ContainerInUse(ctr *Container) ([]string, error) {
return nil, ErrCtrRemoved
}
+ // If the container does not exist, return error
+ if _, ok := s.containers[ctr.ID()]; !ok {
+ ctr.valid = false
+ return nil, errors.Wrapf(ErrNoSuchCtr, "container with ID %s not found in state", ctr.ID())
+ }
+
+ if err := s.checkNSMatch(ctr.ID(), ctr.Namespace()); err != nil {
+ return nil, err
+ }
+
arr, ok := s.ctrDepends[ctr.ID()]
if !ok {
return []string{}, nil
@@ -244,7 +350,9 @@ func (s *InMemoryState) ContainerInUse(ctr *Container) ([]string, error) {
func (s *InMemoryState) AllContainers() ([]*Container, error) {
ctrs := make([]*Container, 0, len(s.containers))
for _, ctr := range s.containers {
- ctrs = append(ctrs, ctr)
+ if s.namespace == "" || ctr.config.Namespace == s.namespace {
+ ctrs = append(ctrs, ctr)
+ }
}
return ctrs, nil
@@ -261,21 +369,44 @@ func (s *InMemoryState) Pod(id string) (*Pod, error) {
return nil, errors.Wrapf(ErrNoSuchPod, "no pod with id %s found", id)
}
+ if err := s.checkNSMatch(pod.ID(), pod.Namespace()); err != nil {
+ return nil, err
+ }
+
return pod, nil
}
// LookupPod retrieves a pod from the state from a full or unique partial ID or
// a full name
func (s *InMemoryState) LookupPod(idOrName string) (*Pod, error) {
+ var (
+ nameIndex *registrar.Registrar
+ idIndex *truncindex.TruncIndex
+ )
+
if idOrName == "" {
return nil, ErrEmptyID
}
- fullID, err := s.nameIndex.Get(idOrName)
+ if s.namespace != "" {
+ nsIndex, ok := s.namespaceIndexes[s.namespace]
+ if !ok {
+ // We have no containers in the namespace
+ // Return false
+ return nil, errors.Wrapf(ErrNoSuchCtr, "no container found with name or ID %s", idOrName)
+ }
+ nameIndex = nsIndex.nameIndex
+ idIndex = nsIndex.idIndex
+ } else {
+ nameIndex = s.nameIndex
+ idIndex = s.idIndex
+ }
+
+ fullID, err := nameIndex.Get(idOrName)
if err != nil {
if err == registrar.ErrNameNotReserved {
// What was passed is not a name, assume it's an ID
- fullID, err = s.idIndex.Get(idOrName)
+ fullID, err = idIndex.Get(idOrName)
if err != nil {
if err == truncindex.ErrNotExist {
return nil, errors.Wrapf(ErrNoSuchPod, "no pod found with name or ID %s", idOrName)
@@ -302,9 +433,12 @@ func (s *InMemoryState) HasPod(id string) (bool, error) {
return false, ErrEmptyID
}
- _, ok := s.pods[id]
+ pod, ok := s.pods[id]
+ if !ok || (s.namespace != "" && s.namespace != pod.config.Namespace) {
+ return false, nil
+ }
- return ok, nil
+ return true, nil
}
// PodHasContainer checks if the given pod has a container with the given ID
@@ -317,6 +451,10 @@ func (s *InMemoryState) PodHasContainer(pod *Pod, ctrID string) (bool, error) {
return false, ErrEmptyID
}
+ if err := s.checkNSMatch(pod.ID(), pod.Namespace()); err != nil {
+ return false, err
+ }
+
podCtrs, ok := s.podContainers[pod.ID()]
if !ok {
pod.valid = false
@@ -333,6 +471,10 @@ func (s *InMemoryState) PodContainersByID(pod *Pod) ([]string, error) {
return nil, errors.Wrapf(ErrPodRemoved, "pod %s is not valid", pod.ID())
}
+ if err := s.checkNSMatch(pod.ID(), pod.Namespace()); err != nil {
+ return nil, err
+ }
+
podCtrs, ok := s.podContainers[pod.ID()]
if !ok {
pod.valid = false
@@ -358,6 +500,10 @@ func (s *InMemoryState) PodContainers(pod *Pod) ([]*Container, error) {
return nil, errors.Wrapf(ErrPodRemoved, "pod %s is not valid", pod.ID())
}
+ if err := s.checkNSMatch(pod.ID(), pod.Namespace()); err != nil {
+ return nil, err
+ }
+
podCtrs, ok := s.podContainers[pod.ID()]
if !ok {
pod.valid = false
@@ -383,6 +529,10 @@ func (s *InMemoryState) AddPod(pod *Pod) error {
return errors.Wrapf(ErrPodRemoved, "pod %s is not valid and cannot be added", pod.ID())
}
+ if err := s.checkNSMatch(pod.ID(), pod.Namespace()); err != nil {
+ return err
+ }
+
if _, ok := s.pods[pod.ID()]; ok {
return errors.Wrapf(ErrPodExists, "pod with ID %s already exists in state", pod.ID())
}
@@ -404,6 +554,25 @@ func (s *InMemoryState) AddPod(pod *Pod) error {
s.podContainers[pod.ID()] = make(map[string]*Container)
+ // If we're in a namespace, add us to that namespace's indexes
+ if pod.config.Namespace != "" {
+ var nsIndex *namespaceIndex
+ nsIndex, ok := s.namespaceIndexes[pod.config.Namespace]
+ if !ok {
+ nsIndex = new(namespaceIndex)
+ nsIndex.nameIndex = registrar.NewRegistrar()
+ nsIndex.idIndex = truncindex.NewTruncIndex([]string{})
+ s.namespaceIndexes[pod.config.Namespace] = nsIndex
+ }
+ // Should be no errors here, the previous index adds should have caught that
+ if err := nsIndex.nameIndex.Reserve(pod.Name(), pod.ID()); err != nil {
+ return errors.Wrapf(err, "error registering container name %s", pod.Name())
+ }
+ if err := nsIndex.idIndex.Add(pod.ID()); err != nil {
+ return errors.Wrapf(err, "error registering container ID %s", pod.ID())
+ }
+ }
+
return nil
}
@@ -413,6 +582,10 @@ func (s *InMemoryState) RemovePod(pod *Pod) error {
// Don't make many validity checks to ensure we can kick badly formed
// pods out of the state
+ if err := s.checkNSMatch(pod.ID(), pod.Namespace()); err != nil {
+ return err
+ }
+
if _, ok := s.pods[pod.ID()]; !ok {
pod.valid = false
return errors.Wrapf(ErrNoSuchPod, "no pod exists in state with ID %s", pod.ID())
@@ -433,6 +606,17 @@ func (s *InMemoryState) RemovePod(pod *Pod) error {
delete(s.podContainers, pod.ID())
s.nameIndex.Release(pod.Name())
+ if pod.config.Namespace != "" {
+ nsIndex, ok := s.namespaceIndexes[pod.config.Namespace]
+ if !ok {
+ return errors.Wrapf(ErrInternal, "error retrieving index for namespace %q", pod.config.Namespace)
+ }
+ if err := nsIndex.idIndex.Delete(pod.ID()); err != nil {
+ return errors.Wrapf(err, "error removing container %s from namespace ID index", pod.ID())
+ }
+ nsIndex.nameIndex.Release(pod.Name())
+ }
+
return nil
}
@@ -445,6 +629,10 @@ func (s *InMemoryState) RemovePodContainers(pod *Pod) error {
return errors.Wrapf(ErrPodRemoved, "pod %s is not valid", pod.ID())
}
+ if err := s.checkNSMatch(pod.ID(), pod.Namespace()); err != nil {
+ return err
+ }
+
// Get pod containers
podCtrs, ok := s.podContainers[pod.ID()]
if !ok {
@@ -494,6 +682,15 @@ func (s *InMemoryState) AddContainerToPod(pod *Pod, ctr *Container) error {
return errors.Wrapf(ErrInvalidArg, "container %s is not in pod %s", ctr.ID(), pod.ID())
}
+ if ctr.config.Namespace != pod.config.Namespace {
+ return errors.Wrapf(ErrNSMismatch, "container %s is in namespace %s and pod %s is in namespace %s",
+ ctr.ID(), ctr.config.Namespace, pod.ID(), pod.config.Namespace)
+ }
+
+ if err := s.checkNSMatch(ctr.ID(), ctr.Namespace()); err != nil {
+ return err
+ }
+
// Retrieve pod containers list
podCtrs, ok := s.podContainers[pod.ID()]
if !ok {
@@ -514,9 +711,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
@@ -538,6 +739,25 @@ func (s *InMemoryState) AddContainerToPod(pod *Pod, ctr *Container) error {
// Add container to pod containers
podCtrs[ctr.ID()] = ctr
+ // If we're in a namespace, add us to that namespace's indexes
+ if ctr.config.Namespace != "" {
+ var nsIndex *namespaceIndex
+ nsIndex, ok := s.namespaceIndexes[ctr.config.Namespace]
+ if !ok {
+ nsIndex = new(namespaceIndex)
+ nsIndex.nameIndex = registrar.NewRegistrar()
+ nsIndex.idIndex = truncindex.NewTruncIndex([]string{})
+ s.namespaceIndexes[ctr.config.Namespace] = nsIndex
+ }
+ // Should be no errors here, the previous index adds should have caught that
+ if err := nsIndex.nameIndex.Reserve(ctr.Name(), ctr.ID()); err != nil {
+ return errors.Wrapf(err, "error registering container name %s", ctr.Name())
+ }
+ if err := nsIndex.idIndex.Add(ctr.ID()); err != nil {
+ return errors.Wrapf(err, "error registering container ID %s", ctr.ID())
+ }
+ }
+
// Add containers this container depends on
for _, depCtr := range depCtrs {
s.addCtrToDependsMap(ctr.ID(), depCtr)
@@ -556,6 +776,10 @@ func (s *InMemoryState) RemoveContainerFromPod(pod *Pod, ctr *Container) error {
return errors.Wrapf(ErrCtrRemoved, "container %s is not valid and cannot be removed from the pod", ctr.ID())
}
+ if err := s.checkNSMatch(ctr.ID(), ctr.Namespace()); err != nil {
+ return err
+ }
+
// Ensure we don't remove a container which other containers depend on
deps, ok := s.ctrDepends[ctr.ID()]
if ok && len(deps) != 0 {
@@ -595,6 +819,17 @@ func (s *InMemoryState) RemoveContainerFromPod(pod *Pod, ctr *Container) error {
// Remove the container from the pod
delete(podCtrs, ctr.ID())
+ if ctr.config.Namespace != "" {
+ nsIndex, ok := s.namespaceIndexes[ctr.config.Namespace]
+ if !ok {
+ return errors.Wrapf(ErrInternal, "error retrieving index for namespace %q", ctr.config.Namespace)
+ }
+ if err := nsIndex.idIndex.Delete(ctr.ID()); err != nil {
+ return errors.Wrapf(err, "error removing container %s from namespace ID index", ctr.ID())
+ }
+ nsIndex.nameIndex.Release(ctr.Name())
+ }
+
// Remove us from container dependencies
depCtrs := ctr.Dependencies()
for _, depCtr := range depCtrs {
@@ -611,6 +846,10 @@ func (s *InMemoryState) UpdatePod(pod *Pod) error {
return ErrPodRemoved
}
+ if err := s.checkNSMatch(pod.ID(), pod.Namespace()); err != nil {
+ return err
+ }
+
if _, ok := s.pods[pod.ID()]; !ok {
pod.valid = false
return errors.Wrapf(ErrNoSuchPod, "no pod exists in state with ID %s", pod.ID())
@@ -626,6 +865,10 @@ func (s *InMemoryState) SavePod(pod *Pod) error {
return ErrPodRemoved
}
+ if err := s.checkNSMatch(pod.ID(), pod.Namespace()); err != nil {
+ return err
+ }
+
if _, ok := s.pods[pod.ID()]; !ok {
pod.valid = false
return errors.Wrapf(ErrNoSuchPod, "no pod exists in state with ID %s", pod.ID())
@@ -638,7 +881,13 @@ func (s *InMemoryState) SavePod(pod *Pod) error {
func (s *InMemoryState) AllPods() ([]*Pod, error) {
pods := make([]*Pod, 0, len(s.pods))
for _, pod := range s.pods {
- pods = append(pods, pod)
+ if s.namespace != "" {
+ if s.namespace == pod.config.Namespace {
+ pods = append(pods, pod)
+ }
+ } else {
+ pods = append(pods, pod)
+ }
}
return pods, nil
@@ -683,3 +932,13 @@ func (s *InMemoryState) removeCtrFromDependsMap(ctrID, dependsID string) {
s.ctrDepends[dependsID] = newArr
}
}
+
+// Check if we can access a pod or container, or if that is blocked by
+// namespaces.
+func (s *InMemoryState) checkNSMatch(id, ns string) error {
+ if s.namespace != "" && s.namespace != ns {
+ return errors.Wrapf(ErrNSMismatch, "cannot access %s as it is in namespace %q and we are in namespace %q",
+ id, ns, s.namespace)
+ }
+ return nil
+}