Browse code

Use bitmask for conflict checking

Rather than using 2 different functions for different
types of conflicts use a bitmask to specify what
conflicts need to be checked. This allows a better way
to make exceptions.

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>

Tonis Tiigi authored on 2016/01/13 08:03:08
Showing 1 changed files
... ...
@@ -12,6 +12,17 @@ import (
12 12
 	"github.com/docker/engine-api/types"
13 13
 )
14 14
 
15
+type conflictType int
16
+
17
+const (
18
+	conflictDependentChild conflictType = (1 << iota)
19
+	conflictRunningContainer
20
+	conflictActiveReference
21
+	conflictStoppedContainer
22
+	conflictHard = conflictDependentChild | conflictRunningContainer
23
+	conflictSoft = conflictActiveReference | conflictStoppedContainer
24
+)
25
+
15 26
 // ImageDelete deletes the image referenced by the given imageRef from this
16 27
 // daemon. The given imageRef can be an image ID, ID prefix, or a repository
17 28
 // reference (with an optional tag or digest, defaulting to the tag name
... ...
@@ -128,7 +139,11 @@ func (daemon *Daemon) ImageDelete(imageRef string, force, prune bool) ([]types.I
128 128
 		// remove that reference.
129 129
 		// FIXME: Is this the behavior we want?
130 130
 		if len(repoRefs) == 1 {
131
-			if conflict := daemon.checkImageDeleteConflict(imgID, force, true); conflict != nil {
131
+			c := conflictHard
132
+			if !force {
133
+				c |= conflictSoft &^ conflictActiveReference
134
+			}
135
+			if conflict := daemon.checkImageDeleteConflict(imgID, c); conflict != nil {
132 136
 				return nil, conflict
133 137
 			}
134 138
 
... ...
@@ -245,7 +260,11 @@ func (idc *imageDeleteConflict) Error() string {
245 245
 func (daemon *Daemon) imageDeleteHelper(imgID image.ID, records *[]types.ImageDelete, force, prune, quiet bool) error {
246 246
 	// First, determine if this image has any conflicts. Ignore soft conflicts
247 247
 	// if force is true.
248
-	if conflict := daemon.checkImageDeleteConflict(imgID, force, false); conflict != nil {
248
+	c := conflictHard
249
+	if !force {
250
+		c |= conflictSoft
251
+	}
252
+	if conflict := daemon.checkImageDeleteConflict(imgID, c); conflict != nil {
249 253
 		if quiet && (!daemon.imageIsDangling(imgID) || conflict.used) {
250 254
 			// Ignore conflicts UNLESS the image is "dangling" or not being used in
251 255
 			// which case we want the user to know.
... ...
@@ -297,24 +316,9 @@ func (daemon *Daemon) imageDeleteHelper(imgID image.ID, records *[]types.ImageDe
297 297
 // using the image. A soft conflict is any tags/digest referencing the given
298 298
 // image or any stopped container using the image. If ignoreSoftConflicts is
299 299
 // true, this function will not check for soft conflict conditions.
300
-func (daemon *Daemon) checkImageDeleteConflict(imgID image.ID, ignoreSoftConflicts bool, ignoreRefConflict bool) *imageDeleteConflict {
301
-	// Check for hard conflicts first.
302
-	if conflict := daemon.checkImageDeleteHardConflict(imgID); conflict != nil {
303
-		return conflict
304
-	}
305
-
306
-	// Then check for soft conflicts.
307
-	if ignoreSoftConflicts {
308
-		// Don't bother checking for soft conflicts.
309
-		return nil
310
-	}
311
-
312
-	return daemon.checkImageDeleteSoftConflict(imgID, ignoreRefConflict)
313
-}
314
-
315
-func (daemon *Daemon) checkImageDeleteHardConflict(imgID image.ID) *imageDeleteConflict {
300
+func (daemon *Daemon) checkImageDeleteConflict(imgID image.ID, mask conflictType) *imageDeleteConflict {
316 301
 	// Check if the image has any descendent images.
317
-	if len(daemon.imageStore.Children(imgID)) > 0 {
302
+	if mask&conflictDependentChild != 0 && len(daemon.imageStore.Children(imgID)) > 0 {
318 303
 		return &imageDeleteConflict{
319 304
 			hard:    true,
320 305
 			imgID:   imgID,
... ...
@@ -322,47 +326,47 @@ func (daemon *Daemon) checkImageDeleteHardConflict(imgID image.ID) *imageDeleteC
322 322
 		}
323 323
 	}
324 324
 
325
-	// Check if any running container is using the image.
326
-	for _, container := range daemon.List() {
327
-		if !container.IsRunning() {
328
-			// Skip this until we check for soft conflicts later.
329
-			continue
330
-		}
325
+	if mask&conflictRunningContainer != 0 {
326
+		// Check if any running container is using the image.
327
+		for _, container := range daemon.List() {
328
+			if !container.IsRunning() {
329
+				// Skip this until we check for soft conflicts later.
330
+				continue
331
+			}
331 332
 
332
-		if container.ImageID == imgID {
333
-			return &imageDeleteConflict{
334
-				imgID:   imgID,
335
-				hard:    true,
336
-				used:    true,
337
-				message: fmt.Sprintf("image is being used by running container %s", stringid.TruncateID(container.ID)),
333
+			if container.ImageID == imgID {
334
+				return &imageDeleteConflict{
335
+					imgID:   imgID,
336
+					hard:    true,
337
+					used:    true,
338
+					message: fmt.Sprintf("image is being used by running container %s", stringid.TruncateID(container.ID)),
339
+				}
338 340
 			}
339 341
 		}
340 342
 	}
341 343
 
342
-	return nil
343
-}
344
-
345
-func (daemon *Daemon) checkImageDeleteSoftConflict(imgID image.ID, ignoreRefConflict bool) *imageDeleteConflict {
346 344
 	// Check if any repository tags/digest reference this image.
347
-	if !ignoreRefConflict && len(daemon.referenceStore.References(imgID)) > 0 {
345
+	if mask&conflictActiveReference != 0 && len(daemon.referenceStore.References(imgID)) > 0 {
348 346
 		return &imageDeleteConflict{
349 347
 			imgID:   imgID,
350 348
 			message: "image is referenced in one or more repositories",
351 349
 		}
352 350
 	}
353 351
 
354
-	// Check if any stopped containers reference this image.
355
-	for _, container := range daemon.List() {
356
-		if container.IsRunning() {
357
-			// Skip this as it was checked above in hard conflict conditions.
358
-			continue
359
-		}
352
+	if mask&conflictStoppedContainer != 0 {
353
+		// Check if any stopped containers reference this image.
354
+		for _, container := range daemon.List() {
355
+			if container.IsRunning() {
356
+				// Skip this as it was checked above in hard conflict conditions.
357
+				continue
358
+			}
360 359
 
361
-		if container.ImageID == imgID {
362
-			return &imageDeleteConflict{
363
-				imgID:   imgID,
364
-				used:    true,
365
-				message: fmt.Sprintf("image is being used by stopped container %s", stringid.TruncateID(container.ID)),
360
+			if container.ImageID == imgID {
361
+				return &imageDeleteConflict{
362
+					imgID:   imgID,
363
+					used:    true,
364
+					message: fmt.Sprintf("image is being used by stopped container %s", stringid.TruncateID(container.ID)),
365
+				}
366 366
 			}
367 367
 		}
368 368
 	}