2017-06-16 17:24:00 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
|
|
|
|
"github.com/containers/storage"
|
2017-08-31 15:17:21 +00:00
|
|
|
"github.com/kubernetes-incubator/cri-o/libpod/images"
|
2017-06-16 17:24:00 +00:00
|
|
|
"github.com/pkg/errors"
|
|
|
|
"github.com/urfave/cli"
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
rmiDescription = "removes one or more locally stored images."
|
|
|
|
rmiFlags = []cli.Flag{
|
|
|
|
cli.BoolFlag{
|
|
|
|
Name: "force, f",
|
|
|
|
Usage: "force removal of the image",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
rmiCommand = cli.Command{
|
|
|
|
Name: "rmi",
|
|
|
|
Usage: "removes one or more images from local storage",
|
|
|
|
Description: rmiDescription,
|
|
|
|
Action: rmiCmd,
|
|
|
|
ArgsUsage: "IMAGE-NAME-OR-ID [...]",
|
|
|
|
Flags: rmiFlags,
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
func rmiCmd(c *cli.Context) error {
|
|
|
|
|
|
|
|
force := false
|
|
|
|
if c.IsSet("force") {
|
|
|
|
force = c.Bool("force")
|
|
|
|
}
|
|
|
|
|
|
|
|
args := c.Args()
|
|
|
|
if len(args) == 0 {
|
|
|
|
return errors.Errorf("image name or ID must be specified")
|
|
|
|
}
|
|
|
|
|
2017-07-27 17:18:07 +00:00
|
|
|
config, err := getConfig(c)
|
|
|
|
if err != nil {
|
|
|
|
return errors.Wrapf(err, "Could not get config")
|
|
|
|
}
|
|
|
|
store, err := getStore(config)
|
2017-06-16 17:24:00 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, id := range args {
|
2017-08-31 15:17:21 +00:00
|
|
|
image, err := images.FindImage(store, id)
|
2017-06-16 17:24:00 +00:00
|
|
|
if err != nil {
|
|
|
|
return errors.Wrapf(err, "could not get image %q", id)
|
|
|
|
}
|
|
|
|
if image != nil {
|
|
|
|
ctrIDs, err := runningContainers(image, store)
|
|
|
|
if err != nil {
|
|
|
|
return errors.Wrapf(err, "error getting running containers for image %q", id)
|
|
|
|
}
|
|
|
|
if len(ctrIDs) > 0 && len(image.Names) <= 1 {
|
|
|
|
if force {
|
|
|
|
removeContainers(ctrIDs, store)
|
|
|
|
} else {
|
|
|
|
for ctrID := range ctrIDs {
|
|
|
|
return fmt.Errorf("Could not remove image %q (must force) - container %q is using its reference image", id, ctrID)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// If the user supplied an ID, we cannot delete the image if it is referred to by multiple tags
|
2017-08-31 15:17:21 +00:00
|
|
|
if images.MatchesID(image.ID, id) {
|
2017-06-16 17:24:00 +00:00
|
|
|
if len(image.Names) > 1 && !force {
|
|
|
|
return fmt.Errorf("unable to delete %s (must force) - image is referred to in multiple tags", image.ID)
|
|
|
|
}
|
|
|
|
// If it is forced, we have to untag the image so that it can be deleted
|
|
|
|
image.Names = image.Names[:0]
|
|
|
|
} else {
|
2017-08-31 15:17:21 +00:00
|
|
|
name, err2 := images.UntagImage(store, image, id)
|
2017-06-16 17:24:00 +00:00
|
|
|
if err2 != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
fmt.Printf("untagged: %s", name)
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(image.Names) > 0 {
|
|
|
|
continue
|
|
|
|
}
|
2017-08-31 15:17:21 +00:00
|
|
|
id, err := images.RemoveImage(image, store)
|
2017-06-16 17:24:00 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
fmt.Printf("%s\n", id)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns a list of running containers associated with the given ImageReference
|
2017-07-24 13:21:50 +00:00
|
|
|
// TODO: replace this with something in libkpod
|
2017-06-16 17:24:00 +00:00
|
|
|
func runningContainers(image *storage.Image, store storage.Store) ([]string, error) {
|
|
|
|
ctrIDs := []string{}
|
2017-07-24 15:14:18 +00:00
|
|
|
containers, err := store.Containers()
|
2017-06-16 17:24:00 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
for _, ctr := range containers {
|
|
|
|
if ctr.ImageID == image.ID {
|
|
|
|
ctrIDs = append(ctrIDs, ctr.ID)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ctrIDs, nil
|
|
|
|
}
|
|
|
|
|
2017-07-24 13:21:50 +00:00
|
|
|
// TODO: replace this with something in libkpod
|
2017-06-16 17:24:00 +00:00
|
|
|
func removeContainers(ctrIDs []string, store storage.Store) error {
|
|
|
|
for _, ctrID := range ctrIDs {
|
2017-07-24 15:14:18 +00:00
|
|
|
if err := store.DeleteContainer(ctrID); err != nil {
|
2017-06-16 17:24:00 +00:00
|
|
|
return errors.Wrapf(err, "could not remove container %q", ctrID)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|