diff options
Diffstat (limited to 'libpod/in_memory_state.go')
-rw-r--r-- | libpod/in_memory_state.go | 215 |
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 + } +} |