Signed-off-by: Derek McGowan <derek@mcg.dev>
| ... | ... |
@@ -5,7 +5,9 @@ import ( |
| 5 | 5 |
"fmt" |
| 6 | 6 |
"sort" |
| 7 | 7 |
"strings" |
| 8 |
+ "time" |
|
| 8 | 9 |
|
| 10 |
+ cerrdefs "github.com/containerd/containerd/errdefs" |
|
| 9 | 11 |
"github.com/containerd/containerd/images" |
| 10 | 12 |
"github.com/containerd/log" |
| 11 | 13 |
"github.com/distribution/reference" |
| ... | ... |
@@ -135,7 +137,7 @@ func (i *ImageService) ImageDelete(ctx context.Context, imageRef string, force, |
| 135 | 135 |
} |
| 136 | 136 |
} |
| 137 | 137 |
return records, nil |
| 138 |
- } else if !force {
|
|
| 138 |
+ } else if len(all) > 1 && !force {
|
|
| 139 | 139 |
// Since only a single used reference, remove all active |
| 140 | 140 |
// TODO: Consider keeping the conflict and changing active |
| 141 | 141 |
// reference calculation in image checker. |
| ... | ... |
@@ -145,6 +147,7 @@ func (i *ImageService) ImageDelete(ctx context.Context, imageRef string, force, |
| 145 | 145 |
using := func(c *container.Container) bool {
|
| 146 | 146 |
return c.ImageID == imgID |
| 147 | 147 |
} |
| 148 |
+ // TODO: Should this also check parentage here? |
|
| 148 | 149 |
ctr := i.containers.First(using) |
| 149 | 150 |
if ctr != nil {
|
| 150 | 151 |
familiarRef := reference.FamiliarString(parsedRef) |
| ... | ... |
@@ -372,6 +375,24 @@ func (i *ImageService) imageDeleteHelper(ctx context.Context, img images.Image, |
| 372 | 372 |
return err |
| 373 | 373 |
} |
| 374 | 374 |
|
| 375 |
+ if !isDanglingImage(img) && len(all) == 1 && extra&conflictActiveReference != 0 {
|
|
| 376 |
+ children, err := i.Children(ctx, imgID) |
|
| 377 |
+ if err != nil {
|
|
| 378 |
+ return err |
|
| 379 |
+ } |
|
| 380 |
+ if len(children) > 0 {
|
|
| 381 |
+ img := images.Image{
|
|
| 382 |
+ Name: danglingImageName(img.Target.Digest), |
|
| 383 |
+ Target: img.Target, |
|
| 384 |
+ CreatedAt: time.Now(), |
|
| 385 |
+ Labels: img.Labels, |
|
| 386 |
+ } |
|
| 387 |
+ if _, err = i.client.ImageService().Create(ctx, img); err != nil && !cerrdefs.IsAlreadyExists(err) {
|
|
| 388 |
+ return fmt.Errorf("failed to create dangling image: %w", err)
|
|
| 389 |
+ } |
|
| 390 |
+ } |
|
| 391 |
+ } |
|
| 392 |
+ |
|
| 375 | 393 |
// TODO: Add target option |
| 376 | 394 |
err = i.images.Delete(ctx, img.Name, images.SynchronousDelete()) |
| 377 | 395 |
if err != nil {
|
| ... | ... |
@@ -295,7 +295,7 @@ RUN echo 2 #layer2 |
| 295 | 295 |
// should not be untagged without the -f flag |
| 296 | 296 |
assert.ErrorContains(c, err, "") |
| 297 | 297 |
assert.Assert(c, strings.Contains(out, cID[:12])) |
| 298 |
- assert.Assert(c, strings.Contains(out, "(must force)")) |
|
| 298 |
+ assert.Assert(c, strings.Contains(out, "(must force)") || strings.Contains(out, "(must be forced)")) |
|
| 299 | 299 |
// Add the -f flag and test again. |
| 300 | 300 |
out = cli.DockerCmd(c, "rmi", "-f", newTag).Combined() |
| 301 | 301 |
// should be allowed to untag with the -f flag |