Browse code

add check to see if the image isn't parent of another and add -f to force

Victor Vieux authored on 2013/05/21 03:31:45
Showing 7 changed files
... ...
@@ -36,6 +36,8 @@ func httpError(w http.ResponseWriter, err error) {
36 36
 		http.Error(w, err.Error(), http.StatusNotFound)
37 37
 	} else if strings.HasPrefix(err.Error(), "Bad parameter") {
38 38
 		http.Error(w, err.Error(), http.StatusBadRequest)
39
+	} else if strings.HasPrefix(err.Error(), "Conflict") {
40
+		http.Error(w, err.Error(), http.StatusConflict)
39 41
 	} else {
40 42
 		http.Error(w, err.Error(), http.StatusInternalServerError)
41 43
 	}
... ...
@@ -453,11 +455,18 @@ func deleteContainers(srv *Server, w http.ResponseWriter, r *http.Request, vars
453 453
 }
454 454
 
455 455
 func deleteImages(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
456
+	if err := parseForm(r); err != nil {
457
+		return err
458
+	}
456 459
 	if vars == nil {
457 460
 		return fmt.Errorf("Missing parameter")
458 461
 	}
459 462
 	name := vars["name"]
460
-	if err := srv.ImageDelete(name); err != nil {
463
+	force, err := getBoolParam(r.Form.Get("force"))
464
+	if err != nil {
465
+		return err
466
+	}
467
+	if err := srv.ImageDelete(name, force); err != nil {
461 468
 		return err
462 469
 	}
463 470
 	w.WriteHeader(http.StatusNoContent)
... ...
@@ -1312,8 +1312,13 @@ func TestDeleteImages(t *testing.T) {
1312 1312
 		t.Errorf("Excepted 2 images, %d found", len(images))
1313 1313
 	}
1314 1314
 
1315
+	req, err := http.NewRequest("DELETE", "/images/test:test", nil)
1316
+	if err != nil {
1317
+		t.Fatal(err)
1318
+	}
1319
+
1315 1320
 	r := httptest.NewRecorder()
1316
-	if err := deleteImages(srv, r, nil, map[string]string{"name": "test:test"}); err != nil {
1321
+	if err := deleteImages(srv, r, req, map[string]string{"name": "test:test"}); err != nil {
1317 1322
 		t.Fatal(err)
1318 1323
 	}
1319 1324
 	if r.Code != http.StatusNoContent {
... ...
@@ -459,6 +459,7 @@ func (cli *DockerCli) CmdPort(args ...string) error {
459 459
 // 'docker rmi IMAGE' removes all images with the name IMAGE
460 460
 func (cli *DockerCli) CmdRmi(args ...string) error {
461 461
 	cmd := Subcmd("rmi", "IMAGE [IMAGE...]", "Remove an image")
462
+	force := cmd.Bool("f", false, "Force")
462 463
 	if err := cmd.Parse(args); err != nil {
463 464
 		return nil
464 465
 	}
... ...
@@ -467,8 +468,13 @@ func (cli *DockerCli) CmdRmi(args ...string) error {
467 467
 		return nil
468 468
 	}
469 469
 
470
+	v := url.Values{}
471
+	if *force {
472
+		v.Set("force", "1")
473
+	}
474
+
470 475
 	for _, name := range cmd.Args() {
471
-		_, _, err := cli.call("DELETE", "/images/"+name, nil)
476
+		_, _, err := cli.call("DELETE", "/images/"+name+"?"+v.Encode(), nil)
472 477
 		if err != nil {
473 478
 			fmt.Printf("%s", err)
474 479
 		} else {
... ...
@@ -728,6 +728,7 @@ Tag an image into a repository
728 728
 	:statuscode 200: no error
729 729
 	:statuscode 400: bad parameter
730 730
 	:statuscode 404: no such image
731
+	:statuscode 409: conflict
731 732
         :statuscode 500: server error
732 733
 
733 734
 
... ...
@@ -750,8 +751,10 @@ Remove an image
750 750
 
751 751
            HTTP/1.1 204 OK
752 752
 
753
+	:query force: 1/True/true or 0/False/false, default false
753 754
 	:statuscode 204: no error
754 755
         :statuscode 404: no such image
756
+	:statuscode 409: conflict
755 757
         :statuscode 500: server error
756 758
 
757 759
 
... ...
@@ -710,7 +710,7 @@ func (srv *Server) ContainerDestroy(name string, removeVolume bool) error {
710 710
 	return nil
711 711
 }
712 712
 
713
-func (srv *Server) ImageDelete(name string) error {
713
+func (srv *Server) ImageDelete(name string, force bool) error {
714 714
 	img, err := srv.runtime.repositories.LookupImage(name)
715 715
 	if err != nil {
716 716
 		return fmt.Errorf("No such image: %s", name)
... ...
@@ -745,11 +745,13 @@ func (srv *Server) ImageDelete(name string) error {
745 745
 		}
746 746
 	}
747 747
 	// check is the image to delete isn't parent of another image
748
-	images, _ := srv.runtime.graph.All()
749
-	for _, image := range images {
750
-		if imgParent, err := image.GetParent(); err == nil && imgParent != nil {
751
-			if imgParent.Id == img.Id {
752
-				return fmt.Errorf("Can't delete %s, otherwise %s will be broken", name, image.ShortId())
748
+	if !force {
749
+		images, _ := srv.runtime.graph.All()
750
+		for _, image := range images {
751
+			if imgParent, err := image.GetParent(); err == nil && imgParent != nil {
752
+				if imgParent.Id == img.Id {
753
+					return fmt.Errorf("Conflict: Can't delete %s otherwise %s will be broken", name, image.ShortId())
754
+				}
753 755
 			}
754 756
 		}
755 757
 	}
... ...
@@ -29,7 +29,7 @@ func TestContainerTagImageDelete(t *testing.T) {
29 29
 		t.Errorf("Excepted 3 images, %d found", len(images))
30 30
 	}
31 31
 
32
-	if err := srv.ImageDelete("utest/docker:tag2"); err != nil {
32
+	if err := srv.ImageDelete("utest/docker:tag2", true); err != nil {
33 33
 		t.Fatal(err)
34 34
 	}
35 35
 
... ...
@@ -42,7 +42,7 @@ func TestContainerTagImageDelete(t *testing.T) {
42 42
 		t.Errorf("Excepted 2 images, %d found", len(images))
43 43
 	}
44 44
 
45
-	if err := srv.ImageDelete("utest:tag1"); err != nil {
45
+	if err := srv.ImageDelete("utest:tag1", true); err != nil {
46 46
 		t.Fatal(err)
47 47
 	}
48 48
 
... ...
@@ -156,7 +156,7 @@ func (store *TagStore) Set(repoName, tag, imageName string, force bool) error {
156 156
 	} else {
157 157
 		repo = make(map[string]string)
158 158
 		if old, exists := store.Repositories[repoName]; exists && !force {
159
-			return fmt.Errorf("Tag %s:%s is already set to %s", repoName, tag, old)
159
+			return fmt.Errorf("Conflict: Tag %s:%s is already set to %s", repoName, tag, old)
160 160
 		}
161 161
 		store.Repositories[repoName] = repo
162 162
 	}