summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/podman/rm.go23
-rw-r--r--completions/bash/podman1
-rw-r--r--docs/podman-rm.1.md7
-rw-r--r--libpod/runtime_cstorage.go118
4 files changed, 149 insertions, 0 deletions
diff --git a/cmd/podman/rm.go b/cmd/podman/rm.go
index 7c0569b78..d6978a460 100644
--- a/cmd/podman/rm.go
+++ b/cmd/podman/rm.go
@@ -21,6 +21,10 @@ var (
},
LatestFlag,
cli.BoolFlag{
+ Name: "storage",
+ Usage: "Remove container from storage library",
+ },
+ cli.BoolFlag{
Name: "volumes, v",
Usage: "Remove the volumes associated with the container (Not implemented yet)",
},
@@ -62,6 +66,25 @@ func rmCmd(c *cli.Context) error {
return err
}
+ // Storage conflicts with --all/--latest/--volumes
+ if c.Bool("storage") {
+ if c.Bool("all") || c.Bool("latest") || c.Bool("volumes") {
+ return errors.Errorf("--storage conflicts with --volumes, --all, and --latest")
+ }
+
+ var lastErr error
+ for _, ctr := range c.Args() {
+ if err := runtime.RemoveStorageContainer(ctr, c.Bool("force")); err != nil {
+ if lastErr != nil {
+ logrus.Errorf("Error removing container %s from storage: %v", ctr, lastErr)
+ }
+ lastErr = err
+ }
+ fmt.Printf("%s\n", ctr)
+ }
+ return lastErr
+ }
+
delContainers, err := getAllOrLatestContainers(c, runtime, -1, "all")
if err != nil {
if len(delContainers) == 0 {
diff --git a/completions/bash/podman b/completions/bash/podman
index 410180638..49fc0c7b7 100644
--- a/completions/bash/podman
+++ b/completions/bash/podman
@@ -1911,6 +1911,7 @@ _podman_rm() {
-h
--latest
-l
+ --storage
--volumes
-v
"
diff --git a/docs/podman-rm.1.md b/docs/podman-rm.1.md
index 56664a8c1..944e74d81 100644
--- a/docs/podman-rm.1.md
+++ b/docs/podman-rm.1.md
@@ -24,6 +24,13 @@ Remove all containers. Can be used in conjunction with -f as well.
Instead of providing the container name or ID, use the last created container. If you use methods other than Podman
to run containers such as CRI-O, the last started container could be from either of those methods.
+**--storage**
+
+Remove the container from the storage library only.
+This is only possible with containers that are not present in libpod (cannot be seen by `podman ps`).
+It is used to remove containers from `podman build` and `buildah`, and orphan containers which were only partially removed by `podman rm`.
+The storage option conflicts with the **--all**, **--latest**, and **--volumes** options.
+
**--volumes, -v**
Remove the volumes associated with the container. (Not yet implemented)
diff --git a/libpod/runtime_cstorage.go b/libpod/runtime_cstorage.go
new file mode 100644
index 000000000..569f63322
--- /dev/null
+++ b/libpod/runtime_cstorage.go
@@ -0,0 +1,118 @@
+package libpod
+
+import (
+ "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
+ PresentInLibpod bool
+}
+
+// ListStorageContainers lists all containers visible to c/storage.
+func (r *Runtime) ListStorageContainers() ([]*StorageContainer, error) {
+ r.lock.RLock()
+ defer r.lock.RUnlock()
+
+ 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
+
+ // 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
+}
+
+// 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 {
+ r.lock.Lock()
+ defer r.lock.Unlock()
+
+ targetID, err := r.store.Lookup(idOrName)
+ if err != nil {
+ if err == storage.ErrLayerUnknown {
+ return errors.Wrapf(ErrNoSuchCtr, "no container with ID or name %q found", idOrName)
+ }
+ 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 {
+ if err == storage.ErrContainerUnknown {
+ return errors.Wrapf(ErrNoSuchCtr, "%q does not refer to a container", idOrName)
+ }
+ 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 {
+ return errors.Wrapf(ErrCtrExists, "refusing to remove %q as it exists in libpod as container %s", idOrName, ctr.ID)
+ }
+
+ if !force {
+ timesMounted, err := r.store.Mounted(ctr.ID)
+ if err != nil {
+ if err == storage.ErrContainerUnknown {
+ // Container was removed from under us.
+ // It's gone, so don't bother erroring.
+ logrus.Warnf("Storage for container %s already removed", ctr.ID)
+ return nil
+ }
+ return errors.Wrapf(err, "error looking up container %q mounts", idOrName)
+ }
+ if timesMounted > 0 {
+ return errors.Wrapf(ErrCtrStateInvalid, "container %q is mounted and cannot be removed without using force", idOrName)
+ }
+ } else {
+ if _, err := r.store.Unmount(ctr.ID, true); err != nil {
+ if err == storage.ErrContainerUnknown {
+ // Container again gone, no error
+ logrus.Warnf("Storage for container %s already removed", ctr.ID)
+ return nil
+ }
+ return errors.Wrapf(err, "error unmounting container %q", idOrName)
+ }
+ }
+
+ if err := r.store.DeleteContainer(ctr.ID); err != nil {
+ if err == storage.ErrContainerUnknown {
+ // Container again gone, no error
+ logrus.Warnf("Storage for container %s already removed", ctr.ID)
+ return nil
+ }
+ return errors.Wrapf(err, "error removing storage for container %q", idOrName)
+ }
+
+ return nil
+}