Browse code

Move "image_delete" to daemon/image_delete.go

Note: this cannot yet be moved to graph/ because of a lingering
dependency on daemon. This has been noted in a FIXME.

Signed-off-by: Solomon Hykes <solomon@docker.com>

Solomon Hykes authored on 2014/08/05 15:41:30
Showing 4 changed files
... ...
@@ -107,6 +107,7 @@ type Daemon struct {
107 107
 func (daemon *Daemon) Install(eng *engine.Engine) error {
108 108
 	// FIXME: rename "delete" to "rm" for consistency with the CLI command
109 109
 	// FIXME: rename ContainerDestroy to ContainerRm for consistency with the CLI command
110
+	// FIXME: remove ImageDelete's dependency on Daemon, then move to graph/
110 111
 	for name, method := range map[string]engine.Handler{
111 112
 		"attach":            daemon.ContainerAttach,
112 113
 		"commit":            daemon.ContainerCommit,
... ...
@@ -127,6 +128,7 @@ func (daemon *Daemon) Install(eng *engine.Engine) error {
127 127
 		"top":               daemon.ContainerTop,
128 128
 		"unpause":           daemon.ContainerUnpause,
129 129
 		"wait":              daemon.ContainerWait,
130
+		"image_delete":      daemon.ImageDelete, // FIXME: see above
130 131
 	} {
131 132
 		if err := eng.Register(name, method); err != nil {
132 133
 			return err
133 134
new file mode 100644
... ...
@@ -0,0 +1,156 @@
0
+package daemon
1
+
2
+import (
3
+	"fmt"
4
+	"strings"
5
+
6
+	"github.com/docker/docker/engine"
7
+	"github.com/docker/docker/graph"
8
+	"github.com/docker/docker/image"
9
+	"github.com/docker/docker/pkg/parsers"
10
+	"github.com/docker/docker/utils"
11
+)
12
+
13
+func (daemon *Daemon) ImageDelete(job *engine.Job) engine.Status {
14
+	if n := len(job.Args); n != 1 {
15
+		return job.Errorf("Usage: %s IMAGE", job.Name)
16
+	}
17
+	imgs := engine.NewTable("", 0)
18
+	if err := daemon.DeleteImage(job.Eng, job.Args[0], imgs, true, job.GetenvBool("force"), job.GetenvBool("noprune")); err != nil {
19
+		return job.Error(err)
20
+	}
21
+	if len(imgs.Data) == 0 {
22
+		return job.Errorf("Conflict, %s wasn't deleted", job.Args[0])
23
+	}
24
+	if _, err := imgs.WriteListTo(job.Stdout); err != nil {
25
+		return job.Error(err)
26
+	}
27
+	return engine.StatusOK
28
+}
29
+
30
+// FIXME: make this private and use the job instead
31
+func (daemon *Daemon) DeleteImage(eng *engine.Engine, name string, imgs *engine.Table, first, force, noprune bool) error {
32
+	var (
33
+		repoName, tag string
34
+		tags          = []string{}
35
+		tagDeleted    bool
36
+	)
37
+
38
+	// FIXME: please respect DRY and centralize repo+tag parsing in a single central place! -- shykes
39
+	repoName, tag = parsers.ParseRepositoryTag(name)
40
+	if tag == "" {
41
+		tag = graph.DEFAULTTAG
42
+	}
43
+
44
+	img, err := daemon.Repositories().LookupImage(name)
45
+	if err != nil {
46
+		if r, _ := daemon.Repositories().Get(repoName); r != nil {
47
+			return fmt.Errorf("No such image: %s:%s", repoName, tag)
48
+		}
49
+		return fmt.Errorf("No such image: %s", name)
50
+	}
51
+
52
+	if strings.Contains(img.ID, name) {
53
+		repoName = ""
54
+		tag = ""
55
+	}
56
+
57
+	byParents, err := daemon.Graph().ByParent()
58
+	if err != nil {
59
+		return err
60
+	}
61
+
62
+	//If delete by id, see if the id belong only to one repository
63
+	if repoName == "" {
64
+		for _, repoAndTag := range daemon.Repositories().ByID()[img.ID] {
65
+			parsedRepo, parsedTag := parsers.ParseRepositoryTag(repoAndTag)
66
+			if repoName == "" || repoName == parsedRepo {
67
+				repoName = parsedRepo
68
+				if parsedTag != "" {
69
+					tags = append(tags, parsedTag)
70
+				}
71
+			} else if repoName != parsedRepo && !force {
72
+				// the id belongs to multiple repos, like base:latest and user:test,
73
+				// in that case return conflict
74
+				return fmt.Errorf("Conflict, cannot delete image %s because it is tagged in multiple repositories, use -f to force", name)
75
+			}
76
+		}
77
+	} else {
78
+		tags = append(tags, tag)
79
+	}
80
+
81
+	if !first && len(tags) > 0 {
82
+		return nil
83
+	}
84
+
85
+	//Untag the current image
86
+	for _, tag := range tags {
87
+		tagDeleted, err = daemon.Repositories().Delete(repoName, tag)
88
+		if err != nil {
89
+			return err
90
+		}
91
+		if tagDeleted {
92
+			out := &engine.Env{}
93
+			out.Set("Untagged", repoName+":"+tag)
94
+			imgs.Add(out)
95
+			eng.Job("log", "untag", img.ID, "").Run()
96
+		}
97
+	}
98
+	tags = daemon.Repositories().ByID()[img.ID]
99
+	if (len(tags) <= 1 && repoName == "") || len(tags) == 0 {
100
+		if len(byParents[img.ID]) == 0 {
101
+			if err := daemon.canDeleteImage(img.ID, force, tagDeleted); err != nil {
102
+				return err
103
+			}
104
+			if err := daemon.Repositories().DeleteAll(img.ID); err != nil {
105
+				return err
106
+			}
107
+			if err := daemon.Graph().Delete(img.ID); err != nil {
108
+				return err
109
+			}
110
+			out := &engine.Env{}
111
+			out.Set("Deleted", img.ID)
112
+			imgs.Add(out)
113
+			eng.Job("log", "delete", img.ID, "").Run()
114
+			if img.Parent != "" && !noprune {
115
+				err := daemon.DeleteImage(eng, img.Parent, imgs, false, force, noprune)
116
+				if first {
117
+					return err
118
+				}
119
+
120
+			}
121
+
122
+		}
123
+	}
124
+	return nil
125
+}
126
+
127
+func (daemon *Daemon) canDeleteImage(imgID string, force, untagged bool) error {
128
+	var message string
129
+	if untagged {
130
+		message = " (docker untagged the image)"
131
+	}
132
+	for _, container := range daemon.List() {
133
+		parent, err := daemon.Repositories().LookupImage(container.Image)
134
+		if err != nil {
135
+			return err
136
+		}
137
+
138
+		if err := parent.WalkHistory(func(p *image.Image) error {
139
+			if imgID == p.ID {
140
+				if container.State.IsRunning() {
141
+					if force {
142
+						return fmt.Errorf("Conflict, cannot force delete %s because the running container %s is using it%s, stop it and retry", utils.TruncateID(imgID), utils.TruncateID(container.ID), message)
143
+					}
144
+					return fmt.Errorf("Conflict, cannot delete %s because the running container %s is using it%s, stop it and use -f to force", utils.TruncateID(imgID), utils.TruncateID(container.ID), message)
145
+				} else if !force {
146
+					return fmt.Errorf("Conflict, cannot delete %s because the container %s is using it%s, use -f to force", utils.TruncateID(imgID), utils.TruncateID(container.ID), message)
147
+				}
148
+			}
149
+			return nil
150
+		}); err != nil {
151
+			return err
152
+		}
153
+	}
154
+	return nil
155
+}
... ...
@@ -19,7 +19,6 @@ import (
19 19
 	"github.com/docker/docker/archive"
20 20
 	"github.com/docker/docker/builder"
21 21
 	"github.com/docker/docker/engine"
22
-	"github.com/docker/docker/graph"
23 22
 	"github.com/docker/docker/image"
24 23
 	"github.com/docker/docker/pkg/parsers"
25 24
 	"github.com/docker/docker/registry"
... ...
@@ -640,148 +639,6 @@ func (srv *Server) ImagePush(job *engine.Job) engine.Status {
640 640
 	return engine.StatusOK
641 641
 }
642 642
 
643
-func (srv *Server) DeleteImage(name string, imgs *engine.Table, first, force, noprune bool) error {
644
-	var (
645
-		repoName, tag string
646
-		tags          = []string{}
647
-		tagDeleted    bool
648
-	)
649
-
650
-	repoName, tag = parsers.ParseRepositoryTag(name)
651
-	if tag == "" {
652
-		tag = graph.DEFAULTTAG
653
-	}
654
-
655
-	img, err := srv.daemon.Repositories().LookupImage(name)
656
-	if err != nil {
657
-		if r, _ := srv.daemon.Repositories().Get(repoName); r != nil {
658
-			return fmt.Errorf("No such image: %s:%s", repoName, tag)
659
-		}
660
-		return fmt.Errorf("No such image: %s", name)
661
-	}
662
-
663
-	if strings.Contains(img.ID, name) {
664
-		repoName = ""
665
-		tag = ""
666
-	}
667
-
668
-	byParents, err := srv.daemon.Graph().ByParent()
669
-	if err != nil {
670
-		return err
671
-	}
672
-
673
-	//If delete by id, see if the id belong only to one repository
674
-	if repoName == "" {
675
-		for _, repoAndTag := range srv.daemon.Repositories().ByID()[img.ID] {
676
-			parsedRepo, parsedTag := parsers.ParseRepositoryTag(repoAndTag)
677
-			if repoName == "" || repoName == parsedRepo {
678
-				repoName = parsedRepo
679
-				if parsedTag != "" {
680
-					tags = append(tags, parsedTag)
681
-				}
682
-			} else if repoName != parsedRepo && !force {
683
-				// the id belongs to multiple repos, like base:latest and user:test,
684
-				// in that case return conflict
685
-				return fmt.Errorf("Conflict, cannot delete image %s because it is tagged in multiple repositories, use -f to force", name)
686
-			}
687
-		}
688
-	} else {
689
-		tags = append(tags, tag)
690
-	}
691
-
692
-	if !first && len(tags) > 0 {
693
-		return nil
694
-	}
695
-
696
-	//Untag the current image
697
-	for _, tag := range tags {
698
-		tagDeleted, err = srv.daemon.Repositories().Delete(repoName, tag)
699
-		if err != nil {
700
-			return err
701
-		}
702
-		if tagDeleted {
703
-			out := &engine.Env{}
704
-			out.Set("Untagged", repoName+":"+tag)
705
-			imgs.Add(out)
706
-			srv.LogEvent("untag", img.ID, "")
707
-		}
708
-	}
709
-	tags = srv.daemon.Repositories().ByID()[img.ID]
710
-	if (len(tags) <= 1 && repoName == "") || len(tags) == 0 {
711
-		if len(byParents[img.ID]) == 0 {
712
-			if err := srv.canDeleteImage(img.ID, force, tagDeleted); err != nil {
713
-				return err
714
-			}
715
-			if err := srv.daemon.Repositories().DeleteAll(img.ID); err != nil {
716
-				return err
717
-			}
718
-			if err := srv.daemon.Graph().Delete(img.ID); err != nil {
719
-				return err
720
-			}
721
-			out := &engine.Env{}
722
-			out.Set("Deleted", img.ID)
723
-			imgs.Add(out)
724
-			srv.LogEvent("delete", img.ID, "")
725
-			if img.Parent != "" && !noprune {
726
-				err := srv.DeleteImage(img.Parent, imgs, false, force, noprune)
727
-				if first {
728
-					return err
729
-				}
730
-
731
-			}
732
-
733
-		}
734
-	}
735
-	return nil
736
-}
737
-
738
-func (srv *Server) ImageDelete(job *engine.Job) engine.Status {
739
-	if n := len(job.Args); n != 1 {
740
-		return job.Errorf("Usage: %s IMAGE", job.Name)
741
-	}
742
-	imgs := engine.NewTable("", 0)
743
-	if err := srv.DeleteImage(job.Args[0], imgs, true, job.GetenvBool("force"), job.GetenvBool("noprune")); err != nil {
744
-		return job.Error(err)
745
-	}
746
-	if len(imgs.Data) == 0 {
747
-		return job.Errorf("Conflict, %s wasn't deleted", job.Args[0])
748
-	}
749
-	if _, err := imgs.WriteListTo(job.Stdout); err != nil {
750
-		return job.Error(err)
751
-	}
752
-	return engine.StatusOK
753
-}
754
-
755
-func (srv *Server) canDeleteImage(imgID string, force, untagged bool) error {
756
-	var message string
757
-	if untagged {
758
-		message = " (docker untagged the image)"
759
-	}
760
-	for _, container := range srv.daemon.List() {
761
-		parent, err := srv.daemon.Repositories().LookupImage(container.Image)
762
-		if err != nil {
763
-			return err
764
-		}
765
-
766
-		if err := parent.WalkHistory(func(p *image.Image) error {
767
-			if imgID == p.ID {
768
-				if container.State.IsRunning() {
769
-					if force {
770
-						return fmt.Errorf("Conflict, cannot force delete %s because the running container %s is using it%s, stop it and retry", utils.TruncateID(imgID), utils.TruncateID(container.ID), message)
771
-					}
772
-					return fmt.Errorf("Conflict, cannot delete %s because the running container %s is using it%s, stop it and use -f to force", utils.TruncateID(imgID), utils.TruncateID(container.ID), message)
773
-				} else if !force {
774
-					return fmt.Errorf("Conflict, cannot delete %s because the container %s is using it%s, use -f to force", utils.TruncateID(imgID), utils.TruncateID(container.ID), message)
775
-				}
776
-			}
777
-			return nil
778
-		}); err != nil {
779
-			return err
780
-		}
781
-	}
782
-	return nil
783
-}
784
-
785 643
 func (srv *Server) poolAdd(kind, key string) (chan struct{}, error) {
786 644
 	srv.Lock()
787 645
 	defer srv.Unlock()
... ...
@@ -86,14 +86,13 @@ func InitServer(job *engine.Job) engine.Status {
86 86
 	job.Eng.Hack_SetGlobalVar("httpapi.daemon", srv.daemon)
87 87
 
88 88
 	for name, handler := range map[string]engine.Handler{
89
-		"tag":          srv.ImageTag, // FIXME merge with "image_tag"
90
-		"info":         srv.DockerInfo,
91
-		"log":          srv.Log,
92
-		"build":        srv.Build,
93
-		"pull":         srv.ImagePull,
94
-		"image_delete": srv.ImageDelete,
95
-		"events":       srv.Events,
96
-		"push":         srv.ImagePush,
89
+		"tag":    srv.ImageTag, // FIXME merge with "image_tag"
90
+		"info":   srv.DockerInfo,
91
+		"log":    srv.Log,
92
+		"build":  srv.Build,
93
+		"pull":   srv.ImagePull,
94
+		"events": srv.Events,
95
+		"push":   srv.ImagePush,
97 96
 	} {
98 97
 		if err := job.Eng.Register(name, srv.handlerWrap(handler)); err != nil {
99 98
 			return job.Error(err)