diff options
author | umohnani8 <umohnani@redhat.com> | 2018-08-08 09:50:15 -0400 |
---|---|---|
committer | Urvashi Mohnani <umohnani@redhat.com> | 2018-12-06 10:17:16 +0000 |
commit | 4c70b8a94b22b31e2c39ee710dcc21cc2f3fb337 (patch) | |
tree | d6d054bd40f9f0b02c4078b38d2839dc2dd77fc5 /libpod/in_memory_state.go | |
parent | 75b19ca8abe1957f3c48035767960a6b20c10519 (diff) | |
download | podman-4c70b8a94b22b31e2c39ee710dcc21cc2f3fb337.tar.gz podman-4c70b8a94b22b31e2c39ee710dcc21cc2f3fb337.tar.bz2 podman-4c70b8a94b22b31e2c39ee710dcc21cc2f3fb337.zip |
Add "podman volume" command
Add support for podman volume and its subcommands.
The commands supported are:
podman volume create
podman volume inspect
podman volume ls
podman volume rm
podman volume prune
This is a tool to manage volumes used by podman. For now it only handle
named volumes, but eventually it will handle all volumes used by podman.
Signed-off-by: umohnani8 <umohnani@redhat.com>
Diffstat (limited to 'libpod/in_memory_state.go')
-rw-r--r-- | libpod/in_memory_state.go | 168 |
1 files changed, 167 insertions, 1 deletions
diff --git a/libpod/in_memory_state.go b/libpod/in_memory_state.go index 77eba0cc6..314799309 100644 --- a/libpod/in_memory_state.go +++ b/libpod/in_memory_state.go @@ -18,8 +18,10 @@ type InMemoryState struct { pods map[string]*Pod // Maps container ID to container struct. containers map[string]*Container + volumes map[string]*Volume // Maps container ID to a list of IDs of dependencies. - ctrDepends map[string][]string + ctrDepends map[string][]string + volumeDepends map[string][]string // Maps pod ID to a map of container ID to container struct. podContainers map[string]map[string]*Container // Global name registry - ensures name uniqueness and performs lookups. @@ -46,8 +48,10 @@ func NewInMemoryState() (State, error) { state.pods = make(map[string]*Pod) state.containers = make(map[string]*Container) + state.volumes = make(map[string]*Volume) state.ctrDepends = make(map[string][]string) + state.volumeDepends = make(map[string][]string) state.podContainers = make(map[string]map[string]*Container) @@ -244,6 +248,14 @@ func (s *InMemoryState) AddContainer(ctr *Container) error { s.addCtrToDependsMap(ctr.ID(), depCtr) } + // Add container to volume dependencies + for _, vol := range ctr.config.Spec.Mounts { + if strings.Contains(vol.Source, ctr.runtime.config.VolumePath) { + volName := strings.Split(vol.Source[len(ctr.runtime.config.VolumePath)+1:], "/")[0] + s.addCtrToVolDependsMap(ctr.ID(), volName) + } + } + return nil } @@ -294,6 +306,14 @@ func (s *InMemoryState) RemoveContainer(ctr *Container) error { s.removeCtrFromDependsMap(ctr.ID(), depCtr) } + // Remove container from volume dependencies + for _, vol := range ctr.config.Spec.Mounts { + if strings.Contains(vol.Source, ctr.runtime.config.VolumePath) { + volName := strings.Split(vol.Source[len(ctr.runtime.config.VolumePath)+1:], "/")[0] + s.removeCtrFromVolDependsMap(ctr.ID(), volName) + } + } + return nil } @@ -358,6 +378,114 @@ func (s *InMemoryState) ContainerInUse(ctr *Container) ([]string, error) { return arr, nil } +// Volume retrieves a volume from its full name +func (s *InMemoryState) Volume(name string) (*Volume, error) { + if name == "" { + return nil, ErrEmptyID + } + + vol, ok := s.volumes[name] + if !ok { + return nil, errors.Wrapf(ErrNoSuchCtr, "no volume with name %s found", name) + } + + return vol, nil +} + +// HasVolume checks if a volume with the given name is present in the state +func (s *InMemoryState) HasVolume(name string) (bool, error) { + if name == "" { + return false, ErrEmptyID + } + + _, ok := s.volumes[name] + if !ok { + return false, nil + } + + return true, nil +} + +// AddVolume adds a volume to the state +func (s *InMemoryState) AddVolume(volume *Volume) error { + if !volume.valid { + return errors.Wrapf(ErrVolumeRemoved, "volume with name %s is not valid", volume.Name()) + } + + if _, ok := s.volumes[volume.Name()]; ok { + return errors.Wrapf(ErrVolumeExists, "volume with name %s already exists in state", volume.Name()) + } + + s.volumes[volume.Name()] = volume + + return nil +} + +// RemoveVolume removes a volume from the state +func (s *InMemoryState) RemoveVolume(volume *Volume) error { + // Ensure we don't remove a volume which containers depend on + deps, ok := s.volumeDepends[volume.Name()] + if ok && len(deps) != 0 { + depsStr := strings.Join(deps, ", ") + return errors.Wrapf(ErrVolumeExists, "the following containers depend on volume %s: %s", volume.Name(), depsStr) + } + + if _, ok := s.volumes[volume.Name()]; !ok { + volume.valid = false + return errors.Wrapf(ErrVolumeRemoved, "no volume exists in state with name %s", volume.Name()) + } + + delete(s.volumes, volume.Name()) + + return nil +} + +// RemoveVolCtrDep updates the container dependencies of the volume +func (s *InMemoryState) RemoveVolCtrDep(volume *Volume, ctrID string) error { + if !volume.valid { + return errors.Wrapf(ErrVolumeRemoved, "volume with name %s is not valid", volume.Name()) + } + + if _, ok := s.volumes[volume.Name()]; !ok { + return errors.Wrapf(ErrNoSuchVolume, "volume with name %s doesn't exists in state", volume.Name()) + } + + // Remove container that is using this volume + s.removeCtrFromVolDependsMap(ctrID, volume.Name()) + + return nil +} + +// VolumeInUse checks if the given volume is being used by at least one container +func (s *InMemoryState) VolumeInUse(volume *Volume) ([]string, error) { + if !volume.valid { + return nil, ErrVolumeRemoved + } + + // If the volume does not exist, return error + if _, ok := s.volumes[volume.Name()]; !ok { + volume.valid = false + return nil, errors.Wrapf(ErrNoSuchVolume, "volume with name %s not found in state", volume.Name()) + } + + arr, ok := s.volumeDepends[volume.Name()] + if !ok { + return []string{}, nil + } + + return arr, nil +} + +// AllVolumes returns all volumes that exist in the state +func (s *InMemoryState) AllVolumes() ([]*Volume, error) { + allVols := make([]*Volume, 0, len(s.volumes)) + for _, v := range s.volumes { + allVols = append(allVols, v) + } + + return allVols, nil +} + // AllContainers retrieves all containers from the state func (s *InMemoryState) AllContainers() ([]*Container, error) { ctrs := make([]*Container, 0, len(s.containers)) @@ -945,6 +1073,44 @@ func (s *InMemoryState) removeCtrFromDependsMap(ctrID, dependsID string) { } } +// Add a container to the dependency mappings for the volume +func (s *InMemoryState) addCtrToVolDependsMap(depCtrID, volName string) { + if volName != "" { + arr, ok := s.volumeDepends[volName] + if !ok { + // Do not have a mapping for that volume yet + s.volumeDepends[volName] = []string{depCtrID} + } else { + // Have a mapping for the volume + arr = append(arr, depCtrID) + s.volumeDepends[volName] = arr + } + } +} + +// Remove a container from the dependency mappings for the volume +func (s *InMemoryState) removeCtrFromVolDependsMap(depCtrID, volName string) { + if volName != "" { + arr, ok := s.volumeDepends[volName] + 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 != depCtrID { + newArr = append(newArr, id) + } + } + + s.volumeDepends[volName] = 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 { |