2019-06-13 20:51:31 +00:00
|
|
|
package libpod
|
|
|
|
|
|
|
|
import (
|
2019-09-11 14:53:21 +00:00
|
|
|
"time"
|
|
|
|
|
2022-01-18 09:14:48 +00:00
|
|
|
"github.com/containers/podman/v4/libpod/define"
|
2019-06-13 20:51:31 +00:00
|
|
|
"github.com/containers/storage"
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
"github.com/sirupsen/logrus"
|
|
|
|
)
|
|
|
|
|
|
|
|
// StorageContainer represents a container present in c/storage but not in
|
|
|
|
// libpod.
|
|
|
|
type StorageContainer struct {
|
|
|
|
ID string
|
|
|
|
Names []string
|
2019-09-11 14:53:21 +00:00
|
|
|
Image string
|
|
|
|
CreateTime time.Time
|
2019-06-13 20:51:31 +00:00
|
|
|
PresentInLibpod bool
|
|
|
|
}
|
|
|
|
|
|
|
|
// ListStorageContainers lists all containers visible to c/storage.
|
|
|
|
func (r *Runtime) ListStorageContainers() ([]*StorageContainer, error) {
|
|
|
|
finalCtrs := []*StorageContainer{}
|
|
|
|
|
|
|
|
ctrs, err := r.store.Containers()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, ctr := range ctrs {
|
|
|
|
storageCtr := new(StorageContainer)
|
|
|
|
storageCtr.ID = ctr.ID
|
|
|
|
storageCtr.Names = ctr.Names
|
2019-09-11 14:53:21 +00:00
|
|
|
storageCtr.Image = ctr.ImageID
|
|
|
|
storageCtr.CreateTime = ctr.Created
|
2019-06-13 20:51:31 +00:00
|
|
|
|
|
|
|
// Look up if container is in state
|
|
|
|
hasCtr, err := r.state.HasContainer(ctr.ID)
|
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Wrapf(err, "error looking up container %s in state", ctr.ID)
|
|
|
|
}
|
|
|
|
|
|
|
|
storageCtr.PresentInLibpod = hasCtr
|
|
|
|
|
|
|
|
finalCtrs = append(finalCtrs, storageCtr)
|
|
|
|
}
|
|
|
|
|
|
|
|
return finalCtrs, nil
|
|
|
|
}
|
|
|
|
|
2020-10-03 10:56:42 +00:00
|
|
|
func (r *Runtime) StorageContainer(idOrName string) (*storage.Container, error) {
|
|
|
|
return r.store.Container(idOrName)
|
|
|
|
}
|
|
|
|
|
2019-06-13 20:51:31 +00:00
|
|
|
// RemoveStorageContainer removes a container from c/storage.
|
|
|
|
// The container WILL NOT be removed if it exists in libpod.
|
|
|
|
// Accepts ID or full name of container.
|
|
|
|
// If force is set, the container will be unmounted first to ensure removal.
|
|
|
|
func (r *Runtime) RemoveStorageContainer(idOrName string, force bool) error {
|
|
|
|
targetID, err := r.store.Lookup(idOrName)
|
|
|
|
if err != nil {
|
2019-10-14 17:49:06 +00:00
|
|
|
if errors.Cause(err) == storage.ErrLayerUnknown {
|
2019-06-24 20:48:34 +00:00
|
|
|
return errors.Wrapf(define.ErrNoSuchCtr, "no container with ID or name %q found", idOrName)
|
2019-06-13 20:51:31 +00:00
|
|
|
}
|
|
|
|
return errors.Wrapf(err, "error looking up container %q", idOrName)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Lookup returns an ID but it's not guaranteed to be a container ID.
|
|
|
|
// So we can still error here.
|
|
|
|
ctr, err := r.store.Container(targetID)
|
|
|
|
if err != nil {
|
2019-10-14 17:49:06 +00:00
|
|
|
if errors.Cause(err) == storage.ErrContainerUnknown {
|
2019-06-24 20:48:34 +00:00
|
|
|
return errors.Wrapf(define.ErrNoSuchCtr, "%q does not refer to a container", idOrName)
|
2019-06-13 20:51:31 +00:00
|
|
|
}
|
|
|
|
return errors.Wrapf(err, "error retrieving container %q", idOrName)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Error out if the container exists in libpod
|
|
|
|
exists, err := r.state.HasContainer(ctr.ID)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if exists {
|
2019-06-24 20:48:34 +00:00
|
|
|
return errors.Wrapf(define.ErrCtrExists, "refusing to remove %q as it exists in libpod as container %s", idOrName, ctr.ID)
|
2019-06-13 20:51:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if !force {
|
|
|
|
timesMounted, err := r.store.Mounted(ctr.ID)
|
|
|
|
if err != nil {
|
2019-10-14 17:49:06 +00:00
|
|
|
if errors.Cause(err) == storage.ErrContainerUnknown {
|
2019-06-13 20:51:31 +00:00
|
|
|
// Container was removed from under us.
|
|
|
|
// It's gone, so don't bother erroring.
|
2020-12-01 21:15:14 +00:00
|
|
|
logrus.Infof("Storage for container %s already removed", ctr.ID)
|
2019-06-13 20:51:31 +00:00
|
|
|
return nil
|
|
|
|
}
|
2021-09-16 10:13:21 +00:00
|
|
|
logrus.Warnf("Checking if container %q is mounted, attempting to delete: %v", idOrName, err)
|
2019-06-13 20:51:31 +00:00
|
|
|
}
|
|
|
|
if timesMounted > 0 {
|
2019-06-24 20:48:34 +00:00
|
|
|
return errors.Wrapf(define.ErrCtrStateInvalid, "container %q is mounted and cannot be removed without using force", idOrName)
|
2019-06-13 20:51:31 +00:00
|
|
|
}
|
2020-01-13 12:01:45 +00:00
|
|
|
} else if _, err := r.store.Unmount(ctr.ID, true); err != nil {
|
2021-09-16 10:13:21 +00:00
|
|
|
if errors.Is(err, storage.ErrContainerUnknown) {
|
2020-01-13 12:01:45 +00:00
|
|
|
// Container again gone, no error
|
2020-12-01 21:15:14 +00:00
|
|
|
logrus.Infof("Storage for container %s already removed", ctr.ID)
|
2020-01-13 12:01:45 +00:00
|
|
|
return nil
|
2019-06-13 20:51:31 +00:00
|
|
|
}
|
2021-09-16 10:13:21 +00:00
|
|
|
logrus.Warnf("Unmounting container %q while attempting to delete storage: %v", idOrName, err)
|
2019-06-13 20:51:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if err := r.store.DeleteContainer(ctr.ID); err != nil {
|
2021-09-29 14:03:46 +00:00
|
|
|
if errors.Cause(err) == storage.ErrNotAContainer || errors.Cause(err) == storage.ErrContainerUnknown {
|
2019-06-13 20:51:31 +00:00
|
|
|
// Container again gone, no error
|
2020-12-01 21:15:14 +00:00
|
|
|
logrus.Infof("Storage for container %s already removed", ctr.ID)
|
2019-06-13 20:51:31 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return errors.Wrapf(err, "error removing storage for container %q", idOrName)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|