summaryrefslogtreecommitdiff
path: root/pkg
diff options
context:
space:
mode:
Diffstat (limited to 'pkg')
-rw-r--r--pkg/api/handlers/compat/images_remove.go22
-rw-r--r--pkg/domain/entities/engine_image.go2
-rw-r--r--pkg/domain/entities/images.go12
-rw-r--r--pkg/domain/infra/abi/images.go78
-rw-r--r--pkg/domain/infra/tunnel/images.go30
5 files changed, 103 insertions, 41 deletions
diff --git a/pkg/api/handlers/compat/images_remove.go b/pkg/api/handlers/compat/images_remove.go
index 3d346543e..ed0153529 100644
--- a/pkg/api/handlers/compat/images_remove.go
+++ b/pkg/api/handlers/compat/images_remove.go
@@ -36,17 +36,23 @@ func RemoveImage(w http.ResponseWriter, r *http.Request) {
return
}
- _, err = runtime.RemoveImage(r.Context(), newImage, query.Force)
+ results, err := runtime.RemoveImage(r.Context(), newImage, query.Force)
if err != nil {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, err)
return
}
- // TODO
- // This will need to be fixed for proper response, like Deleted: and Untagged:
- m := make(map[string]string)
- m["Deleted"] = newImage.ID()
- foo := []map[string]string{}
- foo = append(foo, m)
- utils.WriteResponse(w, http.StatusOK, foo)
+
+ response := make([]map[string]string, 0, len(results.Untagged)+1)
+ deleted := make(map[string]string, 1)
+ deleted["Deleted"] = results.Deleted
+ response = append(response, deleted)
+
+ for _, u := range results.Untagged {
+ untagged := make(map[string]string, 1)
+ untagged["Untagged"] = u
+ response = append(response, untagged)
+ }
+
+ utils.WriteResponse(w, http.StatusOK, response)
}
diff --git a/pkg/domain/entities/engine_image.go b/pkg/domain/entities/engine_image.go
index 0294c7129..d0c860a04 100644
--- a/pkg/domain/entities/engine_image.go
+++ b/pkg/domain/entities/engine_image.go
@@ -5,7 +5,7 @@ import (
)
type ImageEngine interface {
- Delete(ctx context.Context, nameOrId string, opts ImageDeleteOptions) (*ImageDeleteReport, error)
+ Delete(ctx context.Context, nameOrId []string, opts ImageDeleteOptions) (*ImageDeleteReport, error)
Exists(ctx context.Context, nameOrId string) (*BoolReport, error)
History(ctx context.Context, nameOrId string, opts ImageHistoryOptions) (*ImageHistoryReport, error)
List(ctx context.Context, opts ImageListOptions) ([]*ImageSummary, error)
diff --git a/pkg/domain/entities/images.go b/pkg/domain/entities/images.go
index f04317e37..4a51b3de4 100644
--- a/pkg/domain/entities/images.go
+++ b/pkg/domain/entities/images.go
@@ -81,14 +81,18 @@ func (i *ImageSummary) IsDangling() bool {
}
type ImageDeleteOptions struct {
+ All bool
Force bool
}
-// ImageDeleteResponse is the response for removing an image from storage and containers
-// what was untagged vs actually removed
+// ImageDeleteResponse is the response for removing one or more image(s) from storage
+// and containers what was untagged vs actually removed
type ImageDeleteReport struct {
- Untagged []string `json:"untagged"`
- Deleted string `json:"deleted"`
+ Untagged []string `json:",omitempty"`
+ Deleted []string `json:",omitempty"`
+ Errors []error
+ ImageNotFound error
+ ImageInUse error
}
type ImageHistoryOptions struct{}
diff --git a/pkg/domain/infra/abi/images.go b/pkg/domain/infra/abi/images.go
index 39a03ef6c..203f14987 100644
--- a/pkg/domain/infra/abi/images.go
+++ b/pkg/domain/infra/abi/images.go
@@ -4,10 +4,12 @@ package abi
import (
"context"
+ "fmt"
libpodImage "github.com/containers/libpod/libpod/image"
"github.com/containers/libpod/pkg/domain/entities"
- "github.com/containers/libpod/pkg/domain/utils"
+ "github.com/containers/storage"
+ "github.com/pkg/errors"
)
func (ir *ImageEngine) Exists(_ context.Context, nameOrId string) (*entities.BoolReport, error) {
@@ -17,24 +19,76 @@ func (ir *ImageEngine) Exists(_ context.Context, nameOrId string) (*entities.Boo
return &entities.BoolReport{Value: true}, nil
}
-func (ir *ImageEngine) Delete(ctx context.Context, nameOrId string, opts entities.ImageDeleteOptions) (*entities.ImageDeleteReport, error) {
- image, err := ir.Libpod.ImageRuntime().NewFromLocal(nameOrId)
- if err != nil {
- return nil, err
- }
+func (ir *ImageEngine) Delete(ctx context.Context, nameOrId []string, opts entities.ImageDeleteOptions) (*entities.ImageDeleteReport, error) {
+ report := entities.ImageDeleteReport{}
- results, err := ir.Libpod.RemoveImage(ctx, image, opts.Force)
- if err != nil {
- return nil, err
+ if opts.All {
+ var previousTargets []*libpodImage.Image
+ repeatRun:
+ targets, err := ir.Libpod.ImageRuntime().GetRWImages()
+ if err != nil {
+ return &report, errors.Wrapf(err, "unable to query local images")
+ }
+
+ if len(targets) > 0 && len(targets) == len(previousTargets) {
+ return &report, errors.New("unable to delete all images; re-run the rmi command again.")
+ }
+ previousTargets = targets
+
+ for _, img := range targets {
+ isParent, err := img.IsParent(ctx)
+ if err != nil {
+ return &report, err
+ }
+ if isParent {
+ continue
+ }
+ err = ir.deleteImage(ctx, img, opts, report)
+ report.Errors = append(report.Errors, err)
+ }
+ if len(targets) >= 0 || len(previousTargets) != 1 {
+ goto repeatRun
+ }
+ return &report, nil
}
- report := entities.ImageDeleteReport{}
- if err := utils.DeepCopy(&report, results); err != nil {
- return nil, err
+ for _, id := range nameOrId {
+ image, err := ir.Libpod.ImageRuntime().NewFromLocal(id)
+ if err != nil {
+ return nil, err
+ }
+
+ err = ir.deleteImage(ctx, image, opts, report)
+ if err != nil {
+ return &report, err
+ }
}
return &report, nil
}
+func (ir *ImageEngine) deleteImage(ctx context.Context, img *libpodImage.Image, opts entities.ImageDeleteOptions, report entities.ImageDeleteReport) error {
+ results, err := ir.Libpod.RemoveImage(ctx, img, opts.Force)
+ switch errors.Cause(err) {
+ case nil:
+ break
+ case storage.ErrImageUsedByContainer:
+ report.ImageInUse = errors.New(
+ fmt.Sprintf("A container associated with containers/storage, i.e. via Buildah, CRI-O, etc., may be associated with this image: %-12.12s\n", img.ID()))
+ return nil
+ case libpodImage.ErrNoSuchImage:
+ report.ImageNotFound = err
+ return nil
+ default:
+ return err
+ }
+
+ report.Deleted = append(report.Deleted, results.Deleted)
+ for _, e := range results.Untagged {
+ report.Untagged = append(report.Untagged, e)
+ }
+ return nil
+}
+
func (ir *ImageEngine) Prune(ctx context.Context, opts entities.ImagePruneOptions) (*entities.ImagePruneReport, error) {
results, err := ir.Libpod.ImageRuntime().PruneImages(ctx, opts.All, []string{})
if err != nil {
diff --git a/pkg/domain/infra/tunnel/images.go b/pkg/domain/infra/tunnel/images.go
index 921e4a6e3..6a241641e 100644
--- a/pkg/domain/infra/tunnel/images.go
+++ b/pkg/domain/infra/tunnel/images.go
@@ -14,27 +14,25 @@ func (ir *ImageEngine) Exists(_ context.Context, nameOrId string) (*entities.Boo
return &entities.BoolReport{Value: found}, err
}
-func (ir *ImageEngine) Delete(ctx context.Context, nameOrId string, opts entities.ImageDeleteOptions) (*entities.ImageDeleteReport, error) {
- results, err := images.Remove(ir.ClientCxt, nameOrId, &opts.Force)
- if err != nil {
- return nil, err
- }
+func (ir *ImageEngine) Delete(ctx context.Context, nameOrId []string, opts entities.ImageDeleteOptions) (*entities.ImageDeleteReport, error) {
+ report := entities.ImageDeleteReport{}
- report := entities.ImageDeleteReport{
- Untagged: nil,
- Deleted: "",
- }
-
- for _, e := range results {
- if a, ok := e["Deleted"]; ok {
- report.Deleted = a
+ for _, id := range nameOrId {
+ results, err := images.Remove(ir.ClientCxt, id, &opts.Force)
+ if err != nil {
+ return nil, err
}
+ for _, e := range results {
+ if a, ok := e["Deleted"]; ok {
+ report.Deleted = append(report.Deleted, a)
+ }
- if a, ok := e["Untagged"]; ok {
- report.Untagged = append(report.Untagged, a)
+ if a, ok := e["Untagged"]; ok {
+ report.Untagged = append(report.Untagged, a)
+ }
}
}
- return &report, err
+ return &report, nil
}
func (ir *ImageEngine) List(ctx context.Context, opts entities.ImageListOptions) ([]*entities.ImageSummary, error) {