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.go215
1 files changed, 202 insertions, 13 deletions
diff --git a/libpod/in_memory_state.go b/libpod/in_memory_state.go
index 4e4cbb664..55162e6c8 100644
--- a/libpod/in_memory_state.go
+++ b/libpod/in_memory_state.go
@@ -1,6 +1,8 @@
package libpod
import (
+ "strings"
+
"github.com/docker/docker/pkg/truncindex"
"github.com/pkg/errors"
"github.com/projectatomic/libpod/pkg/registrar"
@@ -10,6 +12,7 @@ import (
type InMemoryState struct {
pods map[string]*Pod
containers map[string]*Container
+ ctrDepends map[string][]string
podNameIndex *registrar.Registrar
podIDIndex *truncindex.TruncIndex
ctrNameIndex *registrar.Registrar
@@ -23,6 +26,8 @@ func NewInMemoryState() (State, error) {
state.pods = make(map[string]*Pod)
state.containers = make(map[string]*Container)
+ state.ctrDepends = make(map[string][]string)
+
state.podNameIndex = registrar.NewRegistrar()
state.ctrNameIndex = registrar.NewRegistrar()
@@ -101,8 +106,7 @@ func (s *InMemoryState) HasContainer(id string) (bool, error) {
}
// AddContainer adds a container to the state
-// If the container belongs to a pod, the pod must already be present when the
-// container is added, and the container must be present in the pod
+// Containers in a pod cannot be added to the state
func (s *InMemoryState) AddContainer(ctr *Container) error {
if !ctr.valid {
return errors.Wrapf(ErrCtrRemoved, "container with ID %s is not valid", ctr.ID())
@@ -113,17 +117,8 @@ func (s *InMemoryState) AddContainer(ctr *Container) error {
return errors.Wrapf(ErrCtrExists, "container with ID %s already exists in state", ctr.ID())
}
- if ctr.pod != nil {
- if _, ok := s.pods[ctr.pod.ID()]; !ok {
- return errors.Wrapf(ErrNoSuchPod, "pod %s does not exist, cannot add container %s", ctr.pod.ID(), ctr.ID())
- }
-
- hasCtr, err := ctr.pod.HasContainer(ctr.ID())
- if err != nil {
- return errors.Wrapf(err, "error checking if container %s is present in pod %s", ctr.ID(), ctr.pod.ID())
- } else if !hasCtr {
- return errors.Wrapf(ErrNoSuchCtr, "container %s is not present in pod %s", ctr.ID(), ctr.pod.ID())
- }
+ if ctr.config.Pod != "" {
+ return errors.Wrapf(ErrInvalidArg, "cannot add a container that is in a pod with AddContainer, use AddContainerToPod")
}
if err := s.ctrNameIndex.Reserve(ctr.Name(), ctr.ID()); err != nil {
@@ -137,6 +132,12 @@ func (s *InMemoryState) AddContainer(ctr *Container) error {
s.containers[ctr.ID()] = ctr
+ // Add containers this container depends on
+ depCtrs := ctr.Dependencies()
+ for _, depCtr := range depCtrs {
+ s.addCtrToDependsMap(ctr.ID(), depCtr)
+ }
+
return nil
}
@@ -146,6 +147,13 @@ func (s *InMemoryState) RemoveContainer(ctr *Container) error {
// Almost no validity checks are performed, to ensure we can kick
// misbehaving containers out of the state
+ // Ensure we don't remove a container which other containers depend on
+ deps, ok := s.ctrDepends[ctr.ID()]
+ if ok && len(deps) != 0 {
+ depsStr := strings.Join(deps, ", ")
+ return errors.Wrapf(ErrCtrExists, "the following containers depend on container %s: %s", ctr.ID(), depsStr)
+ }
+
if _, ok := s.containers[ctr.ID()]; !ok {
return errors.Wrapf(ErrNoSuchCtr, "no container exists in state with ID %s", ctr.ID())
}
@@ -156,6 +164,14 @@ func (s *InMemoryState) RemoveContainer(ctr *Container) error {
delete(s.containers, ctr.ID())
s.ctrNameIndex.Release(ctr.Name())
+ delete(s.ctrDepends, ctr.ID())
+
+ // Remove us from container dependencies
+ depCtrs := ctr.Dependencies()
+ for _, depCtr := range depCtrs {
+ s.removeCtrFromDependsMap(ctr.ID(), depCtr)
+ }
+
return nil
}
@@ -163,6 +179,17 @@ func (s *InMemoryState) RemoveContainer(ctr *Container) error {
// As all state is in-memory, no update will be required
// As such this is a no-op
func (s *InMemoryState) UpdateContainer(ctr *Container) error {
+ // If the container is invalid, return error
+ if !ctr.valid {
+ return errors.Wrapf(ErrCtrRemoved, "container with ID %s is not valid", ctr.ID())
+ }
+
+ // If the container does not exist, return error
+ if _, ok := s.containers[ctr.ID()]; !ok {
+ ctr.valid = false
+ return errors.Wrapf(ErrNoSuchCtr, "container with ID %s not found in state", ctr.ID())
+ }
+
return nil
}
@@ -171,9 +198,34 @@ func (s *InMemoryState) UpdateContainer(ctr *Container) error {
// are made
// As such this is a no-op
func (s *InMemoryState) SaveContainer(ctr *Container) error {
+ // If the container is invalid, return error
+ if !ctr.valid {
+ return errors.Wrapf(ErrCtrRemoved, "container with ID %s is not valid", ctr.ID())
+ }
+
+ // If the container does not exist, return error
+ if _, ok := s.containers[ctr.ID()]; !ok {
+ ctr.valid = false
+ return errors.Wrapf(ErrNoSuchCtr, "container with ID %s not found in state", ctr.ID())
+ }
+
return nil
}
+// ContainerInUse checks if the given container is being used by other containers
+func (s *InMemoryState) ContainerInUse(ctr *Container) ([]string, error) {
+ if !ctr.valid {
+ return nil, ErrCtrRemoved
+ }
+
+ arr, ok := s.ctrDepends[ctr.ID()]
+ if !ok {
+ return []string{}, nil
+ }
+
+ return arr, nil
+}
+
// AllContainers retrieves all containers from the state
func (s *InMemoryState) AllContainers() ([]*Container, error) {
ctrs := make([]*Container, 0, len(s.containers))
@@ -241,6 +293,20 @@ func (s *InMemoryState) HasPod(id string) (bool, error) {
return ok, nil
}
+// PodContainers retrieves the containers from a pod given the pod's full ID
+func (s *InMemoryState) PodContainers(id string) ([]*Container, error) {
+ if id == "" {
+ return nil, ErrEmptyID
+ }
+
+ pod, ok := s.pods[id]
+ if !ok {
+ return nil, errors.Wrapf(ErrNoSuchPod, "no pod with ID %s found", id)
+ }
+
+ return pod.GetContainers()
+}
+
// AddPod adds a given pod to the state
// Only empty pods can be added to the state
func (s *InMemoryState) AddPod(pod *Pod) error {
@@ -289,6 +355,89 @@ func (s *InMemoryState) RemovePod(pod *Pod) error {
return nil
}
+// UpdatePod updates a pod's state from the backing database
+// As in-memory states have no database this is a no-op
+func (s *InMemoryState) UpdatePod(pod *Pod) error {
+ return nil
+}
+
+// AddContainerToPod adds a container to the given pod, also adding it to the
+// state
+func (s *InMemoryState) AddContainerToPod(pod *Pod, ctr *Container) error {
+ if !pod.valid {
+ return errors.Wrapf(ErrPodRemoved, "pod %s is not valid and cannot be added to", pod.ID())
+ }
+ if !ctr.valid {
+ return errors.Wrapf(ErrCtrRemoved, "container %s is not valid and cannot be added to the pod", ctr.ID())
+ }
+
+ if ctr.config.Pod != pod.ID() {
+ return errors.Wrapf(ErrInvalidArg, "container %s is not in pod %s", ctr.ID(), pod.ID())
+ }
+
+ // Add container to pod
+ if err := pod.addContainer(ctr); err != nil {
+ return err
+ }
+
+ // Add container to state
+ _, ok := s.containers[ctr.ID()]
+ if ok {
+ return errors.Wrapf(ErrCtrExists, "container with ID %s already exists in state", ctr.ID())
+ }
+
+ if err := s.ctrNameIndex.Reserve(ctr.Name(), ctr.ID()); err != nil {
+ return errors.Wrapf(err, "error reserving container name %s", ctr.Name())
+ }
+
+ if err := s.ctrIDIndex.Add(ctr.ID()); err != nil {
+ s.ctrNameIndex.Release(ctr.Name())
+ return errors.Wrapf(err, "error releasing container ID %s", ctr.ID())
+ }
+
+ s.containers[ctr.ID()] = ctr
+
+ return nil
+}
+
+// RemoveContainerFromPod removes the given container from the given pod
+// The container is also removed from the state
+func (s *InMemoryState) RemoveContainerFromPod(pod *Pod, ctr *Container) error {
+ if !pod.valid {
+ return errors.Wrapf(ErrPodRemoved, "pod %s is not valid and containers cannot be removed", pod.ID())
+ }
+ if !ctr.valid {
+ return errors.Wrapf(ErrCtrRemoved, "container %s is not valid and cannot be removed from the pod", ctr.ID())
+ }
+
+ // Is the container in the pod?
+ exists, err := pod.HasContainer(ctr.ID())
+ if err != nil {
+ return errors.Wrapf(err, "error checking for container %s in pod %s", ctr.ID(), pod.ID())
+ }
+ if !exists {
+ return errors.Wrapf(ErrNoSuchCtr, "no container %s in pod %s", ctr.ID(), pod.ID())
+ }
+
+ // Remove container from pod
+ if err := pod.removeContainer(ctr); err != nil {
+ return err
+ }
+
+ // Remove container from state
+ if _, ok := s.containers[ctr.ID()]; !ok {
+ return errors.Wrapf(ErrNoSuchCtr, "no container exists in state with ID %s", ctr.ID())
+ }
+
+ if err := s.ctrIDIndex.Delete(ctr.ID()); err != nil {
+ return errors.Wrapf(err, "error removing container ID from index")
+ }
+ delete(s.containers, ctr.ID())
+ s.ctrNameIndex.Release(ctr.Name())
+
+ return nil
+}
+
// AllPods retrieves all pods currently in the state
func (s *InMemoryState) AllPods() ([]*Pod, error) {
pods := make([]*Pod, 0, len(s.pods))
@@ -298,3 +447,43 @@ func (s *InMemoryState) AllPods() ([]*Pod, error) {
return pods, nil
}
+
+// Internal Functions
+
+// Add a container to the dependency mappings
+func (s *InMemoryState) addCtrToDependsMap(ctrID, dependsID string) {
+ if dependsID != "" {
+ arr, ok := s.ctrDepends[dependsID]
+ if !ok {
+ // Do not have a mapping for that container yet
+ s.ctrDepends[dependsID] = []string{ctrID}
+ } else {
+ // Have a mapping for the container
+ arr = append(arr, ctrID)
+ s.ctrDepends[dependsID] = arr
+ }
+ }
+}
+
+// Remove a container from dependency mappings
+func (s *InMemoryState) removeCtrFromDependsMap(ctrID, dependsID string) {
+ if dependsID != "" {
+ arr, ok := s.ctrDepends[dependsID]
+ if !ok {
+ // Internal state seems inconsistent
+ // But the dependency is definitely gone
+ // So just return
+ return
+ }
+
+ newArr := make([]string, 0, len(arr))
+
+ for _, id := range arr {
+ if id != ctrID {
+ newArr = append(newArr, id)
+ }
+ }
+
+ s.ctrDepends[dependsID] = newArr
+ }
+}