mirror of
https://github.com/containers/podman.git
synced 2025-05-21 09:05:56 +08:00

In lipod, we now log major events that occurr. These events can be displayed using the `podman events` command. Each event contains: * Type (container, image, volume, pod...) * Status (create, rm, stop, kill, ....) * Timestamp in RFC3339Nano format * Name (if applicable) * Image (if applicable) The format of the event and the varlink endpoint are to not be considered stable until cockpit has done its enablement. Signed-off-by: baude <bbaude@redhat.com>
180 lines
4.0 KiB
Go
180 lines
4.0 KiB
Go
package libpod
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
|
|
"github.com/containers/libpod/libpod/events"
|
|
"github.com/pkg/errors"
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
// 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) error {
|
|
r.lock.Lock()
|
|
defer r.lock.Unlock()
|
|
|
|
if !r.valid {
|
|
return 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)
|
|
}
|
|
|
|
// RemoveVolumes removes a slice of volumes or all with a force bool
|
|
func (r *Runtime) RemoveVolumes(ctx context.Context, volumes []string, all, force bool) ([]string, error) {
|
|
var (
|
|
vols []*Volume
|
|
err error
|
|
deletedVols []string
|
|
)
|
|
if all {
|
|
vols, err = r.Volumes()
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "unable to get all volumes")
|
|
}
|
|
} else {
|
|
for _, i := range volumes {
|
|
vol, err := r.GetVolume(i)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
vols = append(vols, vol)
|
|
}
|
|
}
|
|
|
|
for _, vol := range vols {
|
|
if err := r.RemoveVolume(ctx, vol, force); err != nil {
|
|
return deletedVols, err
|
|
}
|
|
logrus.Debugf("removed volume %s", vol.Name())
|
|
deletedVols = append(deletedVols, vol.Name())
|
|
}
|
|
return deletedVols, nil
|
|
}
|
|
|
|
// GetVolume retrieves a volume by its name
|
|
func (r *Runtime) GetVolume(name string) (*Volume, error) {
|
|
r.lock.RLock()
|
|
defer r.lock.RUnlock()
|
|
|
|
if !r.valid {
|
|
return nil, ErrRuntimeStopped
|
|
}
|
|
|
|
vol, err := r.state.Volume(name)
|
|
if err == nil {
|
|
return vol, err
|
|
}
|
|
|
|
vols, err := r.GetAllVolumes()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for _, v := range vols {
|
|
if strings.HasPrefix(v.Name(), name) {
|
|
return v, nil
|
|
}
|
|
}
|
|
return nil, errors.Errorf("unable to find volume %s", name)
|
|
}
|
|
|
|
// HasVolume checks to see if a volume with the given name exists
|
|
func (r *Runtime) HasVolume(name string) (bool, error) {
|
|
r.lock.RLock()
|
|
defer r.lock.RUnlock()
|
|
|
|
if !r.valid {
|
|
return false, ErrRuntimeStopped
|
|
}
|
|
|
|
return r.state.HasVolume(name)
|
|
}
|
|
|
|
// Volumes retrieves all volumes
|
|
// Filters can be provided which will determine which volumes are included in the
|
|
// output. Multiple filters are handled by ANDing their output, so only volumes
|
|
// matching all filters are returned
|
|
func (r *Runtime) Volumes(filters ...VolumeFilter) ([]*Volume, error) {
|
|
r.lock.RLock()
|
|
defer r.lock.RUnlock()
|
|
|
|
if !r.valid {
|
|
return nil, ErrRuntimeStopped
|
|
}
|
|
|
|
vols, err := r.state.AllVolumes()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
volsFiltered := make([]*Volume, 0, len(vols))
|
|
for _, vol := range vols {
|
|
include := true
|
|
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) {
|
|
r.lock.RLock()
|
|
defer r.lock.RUnlock()
|
|
|
|
if !r.valid {
|
|
return nil, ErrRuntimeStopped
|
|
}
|
|
|
|
return r.state.AllVolumes()
|
|
}
|
|
|
|
// PruneVolumes removes unused volumes from the system
|
|
func (r *Runtime) PruneVolumes(ctx context.Context) ([]string, []error) {
|
|
var (
|
|
prunedIDs []string
|
|
pruneErrors []error
|
|
)
|
|
vols, err := r.GetAllVolumes()
|
|
if err != nil {
|
|
pruneErrors = append(pruneErrors, err)
|
|
return nil, pruneErrors
|
|
}
|
|
|
|
for _, vol := range vols {
|
|
if err := r.RemoveVolume(ctx, vol, false); err != nil {
|
|
if errors.Cause(err) != ErrVolumeBeingUsed && errors.Cause(err) != ErrVolumeRemoved {
|
|
pruneErrors = append(pruneErrors, err)
|
|
}
|
|
continue
|
|
}
|
|
vol.newVolumeEvent(events.Prune)
|
|
prunedIDs = append(prunedIDs, vol.Name())
|
|
}
|
|
return prunedIDs, pruneErrors
|
|
}
|