spiegel_podman/libpod/runtime_volume.go
Paul Holzinger 2fab7d169b
add podman volume reload to sync volume plugins
Libpod requires that all volumes are stored in the libpod db. Because
volume plugins can be created outside of podman, it will not show all
available plugins. This podman volume reload command allows users to
sync the libpod db with their external volume plugins. All new volumes
from the plugin are also created in the libpod db and when a volume from
the db no longer exists it will be removed if possible.

There are some problems:
- naming conflicts, in this case we only use the first volume we found.
  This is not deterministic.
- race conditions, we have no control over the volume plugins. It is
  possible that the volumes changed while we run this command.

Fixes #14207

Signed-off-by: Paul Holzinger <pholzing@redhat.com>
2022-06-23 18:36:30 +02:00

148 lines
3.6 KiB
Go

package libpod
import (
"context"
"github.com/containers/podman/v4/libpod/define"
"github.com/containers/podman/v4/libpod/events"
"github.com/containers/podman/v4/pkg/domain/entities/reports"
"github.com/pkg/errors"
)
// Contains the public Runtime API for volumes
// A VolumeCreateOption is a functional option which alters the Volume created by
// NewVolume
type VolumeCreateOption func(*Volume) error
// VolumeFilter is a function to determine whether a volume is included in command
// output. Volumes to be outputted are tested using the function. a true return will
// include the volume, a false return will exclude it.
type VolumeFilter func(*Volume) bool
// RemoveVolume removes a volumes
func (r *Runtime) RemoveVolume(ctx context.Context, v *Volume, force bool, timeout *uint) error {
if !r.valid {
return define.ErrRuntimeStopped
}
if !v.valid {
if ok, _ := r.state.HasVolume(v.Name()); !ok {
// Volume probably already removed
// Or was never in the runtime to begin with
return nil
}
}
return r.removeVolume(ctx, v, force, timeout, false)
}
// GetVolume retrieves a volume given its full name.
func (r *Runtime) GetVolume(name string) (*Volume, error) {
if !r.valid {
return nil, define.ErrRuntimeStopped
}
vol, err := r.state.Volume(name)
if err != nil {
return nil, err
}
return vol, nil
}
// LookupVolume retrieves a volume by unambiguous partial name.
func (r *Runtime) LookupVolume(name string) (*Volume, error) {
if !r.valid {
return nil, define.ErrRuntimeStopped
}
vol, err := r.state.LookupVolume(name)
if err != nil {
return nil, err
}
return vol, nil
}
// HasVolume checks to see if a volume with the given name exists
func (r *Runtime) HasVolume(name string) (bool, error) {
if !r.valid {
return false, define.ErrRuntimeStopped
}
return r.state.HasVolume(name)
}
// Volumes retrieves all volumes
// Filters can be provided which will determine which volumes are included in the
// output. If multiple filters are used, a volume will be returned if
// any of the filters are matched
func (r *Runtime) Volumes(filters ...VolumeFilter) ([]*Volume, error) {
if !r.valid {
return nil, define.ErrRuntimeStopped
}
vols, err := r.state.AllVolumes()
if err != nil {
return nil, err
}
if len(filters) == 0 {
return vols, nil
}
volsFiltered := make([]*Volume, 0, len(vols))
for _, vol := range vols {
include := false
for _, filter := range filters {
include = include || filter(vol)
}
if include {
volsFiltered = append(volsFiltered, vol)
}
}
return volsFiltered, nil
}
// GetAllVolumes retrieves all the volumes
func (r *Runtime) GetAllVolumes() ([]*Volume, error) {
if !r.valid {
return nil, define.ErrRuntimeStopped
}
return r.state.AllVolumes()
}
// PruneVolumes removes unused volumes from the system
func (r *Runtime) PruneVolumes(ctx context.Context, filterFuncs []VolumeFilter) ([]*reports.PruneReport, error) {
preports := make([]*reports.PruneReport, 0)
vols, err := r.Volumes(filterFuncs...)
if err != nil {
return nil, err
}
for _, vol := range vols {
report := new(reports.PruneReport)
volSize, err := vol.Size()
if err != nil {
volSize = 0
}
report.Size = volSize
report.Id = vol.Name()
var timeout *uint
if err := r.RemoveVolume(ctx, vol, false, timeout); err != nil {
if errors.Cause(err) != define.ErrVolumeBeingUsed && errors.Cause(err) != define.ErrVolumeRemoved {
report.Err = err
} else {
// We didn't remove the volume for some reason
continue
}
} else {
vol.newVolumeEvent(events.Prune)
}
preports = append(preports, report)
}
return preports, nil
}