Parcourir la source

Move docker rmi to a job

Docker-DCO-1.1-Signed-off-by: Victor Vieux <victor.vieux@docker.com> (github: vieux)
Victor Vieux il y a 11 ans
Parent
commit
564e6bc780
6 fichiers modifiés avec 99 ajouts et 69 suppressions
  1. 21 9
      api.go
  2. 6 7
      commands.go
  3. 3 3
      integration/commands_test.go
  4. 1 1
      integration/runtime_test.go
  5. 9 11
      integration/server_test.go
  6. 59 38
      server.go

+ 21 - 9
api.go

@@ -668,19 +668,31 @@ func deleteImages(srv *Server, version float64, w http.ResponseWriter, r *http.R
 	if vars == nil {
 		return fmt.Errorf("Missing parameter")
 	}
-	name := vars["name"]
-	imgs, err := srv.ImageDelete(name, version > 1.1)
-	if err != nil {
+	var (
+		buffer = bytes.NewBuffer(nil)
+		job    = srv.Eng.Job("image_delete", vars["name"])
+	)
+	job.Stdout.Add(buffer)
+	job.SetenvBool("autoPrune", version > 1.1)
+	if err := job.Run(); err != nil {
 		return err
 	}
-	if imgs != nil {
-		if len(imgs) != 0 {
-			return writeJSON(w, http.StatusOK, imgs)
+
+	outs := engine.NewTable("", 0)
+	if _, err := outs.ReadFrom(buffer); err != nil {
+		return err
+	}
+
+	if len(outs.Data) != 0 {
+		var err error
+		if version < 1.9 {
+			_, err = outs.WriteTo(w)
+		} else {
+			_, err = outs.WriteListTo(w)
 		}
-		return fmt.Errorf("Conflict, %s wasn't deleted", name)
+		return err
 	}
-	w.WriteHeader(http.StatusNoContent)
-	return nil
+	return fmt.Errorf("Conflict, %s wasn't deleted", vars["name"])
 }
 
 func postContainersStart(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {

+ 6 - 7
commands.go

@@ -828,18 +828,17 @@ func (cli *DockerCli) CmdRmi(args ...string) error {
 			fmt.Fprintf(cli.err, "%s\n", err)
 			encounteredError = fmt.Errorf("Error: failed to remove one or more images")
 		} else {
-			var outs []APIRmi
-			err = json.Unmarshal(body, &outs)
-			if err != nil {
+			outs := engine.NewTable("Created", 0)
+			if _, err := outs.ReadFrom(bytes.NewReader(body)); err != nil {
 				fmt.Fprintf(cli.err, "%s\n", err)
 				encounteredError = fmt.Errorf("Error: failed to remove one or more images")
 				continue
 			}
-			for _, out := range outs {
-				if out.Deleted != "" {
-					fmt.Fprintf(cli.out, "Deleted: %s\n", out.Deleted)
+			for _, out := range outs.Data {
+				if out.Get("Deleted") != "" {
+					fmt.Fprintf(cli.out, "Deleted: %s\n", out.Get("Deleted"))
 				} else {
-					fmt.Fprintf(cli.out, "Untagged: %s\n", out.Untagged)
+					fmt.Fprintf(cli.out, "Untagged: %s\n", out.Get("Untagged"))
 				}
 			}
 		}

+ 3 - 3
integration/commands_test.go

@@ -1030,11 +1030,11 @@ func TestContainerOrphaning(t *testing.T) {
 	buildSomething(template2, imageName)
 
 	// remove the second image by name
-	resp, err := srv.ImageDelete(imageName, true)
+	resp, err := srv.DeleteImage(imageName, true)
 
 	// see if we deleted the first image (and orphaned the container)
-	for _, i := range resp {
-		if img1 == i.Deleted {
+	for _, i := range resp.Data {
+		if img1 == i.Get("Deleted") {
 			t.Fatal("Orphaned image with container")
 		}
 	}

+ 1 - 1
integration/runtime_test.go

@@ -61,7 +61,7 @@ func cleanup(eng *engine.Engine, t *testing.T) error {
 	}
 	for _, image := range images.Data {
 		if image.Get("ID") != unitTestImageID {
-			mkServerFromEngine(eng, t).ImageDelete(image.Get("ID"), false)
+			mkServerFromEngine(eng, t).DeleteImage(image.Get("ID"), false)
 		}
 	}
 	return nil

+ 9 - 11
integration/server_test.go

@@ -35,7 +35,7 @@ func TestImageTagImageDelete(t *testing.T) {
 		t.Errorf("Expected %d images, %d found", nExpected, nActual)
 	}
 
-	if _, err := srv.ImageDelete("utest/docker:tag2", true); err != nil {
+	if _, err := srv.DeleteImage("utest/docker:tag2", true); err != nil {
 		t.Fatal(err)
 	}
 
@@ -47,7 +47,7 @@ func TestImageTagImageDelete(t *testing.T) {
 		t.Errorf("Expected %d images, %d found", nExpected, nActual)
 	}
 
-	if _, err := srv.ImageDelete("utest:5000/docker:tag3", true); err != nil {
+	if _, err := srv.DeleteImage("utest:5000/docker:tag3", true); err != nil {
 		t.Fatal(err)
 	}
 
@@ -56,7 +56,7 @@ func TestImageTagImageDelete(t *testing.T) {
 	nExpected = len(initialImages.Data[0].GetList("RepoTags")) + 1
 	nActual = len(images.Data[0].GetList("RepoTags"))
 
-	if _, err := srv.ImageDelete("utest:tag1", true); err != nil {
+	if _, err := srv.DeleteImage("utest:tag1", true); err != nil {
 		t.Fatal(err)
 	}
 
@@ -358,7 +358,7 @@ func TestRmi(t *testing.T) {
 		t.Fatalf("Expected 2 new images, found %d.", images.Len()-initialImages.Len())
 	}
 
-	_, err = srv.ImageDelete(imageID, true)
+	_, err = srv.DeleteImage(imageID, true)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -472,18 +472,16 @@ func TestDeleteTagWithExistingContainers(t *testing.T) {
 	}
 
 	// Try to remove the tag
-	imgs, err := srv.ImageDelete("utest:tag1", true)
+	imgs, err := srv.DeleteImage("utest:tag1", true)
 	if err != nil {
 		t.Fatal(err)
 	}
 
-	if len(imgs) != 1 {
-		t.Fatalf("Should only have deleted one untag %d", len(imgs))
+	if len(imgs.Data) != 1 {
+		t.Fatalf("Should only have deleted one untag %d", len(imgs.Data))
 	}
 
-	untag := imgs[0]
-
-	if untag.Untagged != unitTestImageID {
-		t.Fatalf("Expected %s got %s", unitTestImageID, untag.Untagged)
+	if untag := imgs.Data[0].Get("Untagged"); untag != unitTestImageID {
+		t.Fatalf("Expected %s got %s", unitTestImageID, untag)
 	}
 }

+ 59 - 38
server.go

@@ -336,6 +336,10 @@ func (srv *Server) ImageExport(job *engine.Job) engine.Status {
 		job.Error(err)
 		return engine.StatusErr
 	}
+	if err := job.Eng.Register("image_delete", srv.ImageDelete); err != nil {
+		job.Error(err)
+		return engine.StatusErr
+	}
 	return engine.StatusOK
 }
 
@@ -1813,7 +1817,7 @@ func (srv *Server) ContainerDestroy(job *engine.Job) engine.Status {
 
 var ErrImageReferenced = errors.New("Image referenced by a repository")
 
-func (srv *Server) deleteImageAndChildren(id string, imgs *[]APIRmi, byParents map[string][]*Image) error {
+func (srv *Server) deleteImageAndChildren(id string, imgs *engine.Table, byParents map[string][]*Image) error {
 	// If the image is referenced by a repo, do not delete
 	if len(srv.runtime.repositories.ByID()[id]) != 0 {
 		return ErrImageReferenced
@@ -1845,14 +1849,16 @@ func (srv *Server) deleteImageAndChildren(id string, imgs *[]APIRmi, byParents m
 		if err != nil {
 			return err
 		}
-		*imgs = append(*imgs, APIRmi{Deleted: id})
+		out := &engine.Env{}
+		out.Set("Deleted", id)
+		imgs.Add(out)
 		srv.LogEvent("delete", id, "")
 		return nil
 	}
 	return nil
 }
 
-func (srv *Server) deleteImageParents(img *Image, imgs *[]APIRmi) error {
+func (srv *Server) deleteImageParents(img *Image, imgs *engine.Table) error {
 	if img.Parent != "" {
 		parent, err := srv.runtime.graph.Get(img.Parent)
 		if err != nil {
@@ -1871,12 +1877,42 @@ func (srv *Server) deleteImageParents(img *Image, imgs *[]APIRmi) error {
 	return nil
 }
 
-func (srv *Server) deleteImage(img *Image, repoName, tag string) ([]APIRmi, error) {
+func (srv *Server) DeleteImage(name string, autoPrune bool) (*engine.Table, error) {
 	var (
-		imgs = []APIRmi{}
-		tags = []string{}
+		repoName, tag string
+		img, err      = srv.runtime.repositories.LookupImage(name)
+		imgs          = engine.NewTable("", 0)
+		tags          = []string{}
 	)
 
+	if err != nil {
+		return nil, fmt.Errorf("No such image: %s", name)
+	}
+
+	// FIXME: What does autoPrune mean ?
+	if !autoPrune {
+		if err := srv.runtime.graph.Delete(img.ID); err != nil {
+			return nil, fmt.Errorf("Cannot delete image %s: %s", name, err)
+		}
+		return nil, nil
+	}
+
+	if !strings.Contains(img.ID, name) {
+		repoName, tag = utils.ParseRepositoryTag(name)
+	}
+
+	// If we have a repo and the image is not referenced anywhere else
+	// then just perform an untag and do not validate.
+	//
+	// i.e. only validate if we are performing an actual delete and not
+	// an untag op
+	if repoName != "" && len(srv.runtime.repositories.ByID()[img.ID]) == 1 {
+		// Prevent deletion if image is used by a container
+		if err := srv.canDeleteImage(img.ID); err != nil {
+			return nil, err
+		}
+	}
+
 	//If delete by id, see if the id belong only to one repository
 	if repoName == "" {
 		for _, repoAndTag := range srv.runtime.repositories.ByID()[img.ID] {
@@ -1903,17 +1939,19 @@ func (srv *Server) deleteImage(img *Image, repoName, tag string) ([]APIRmi, erro
 			return nil, err
 		}
 		if tagDeleted {
-			imgs = append(imgs, APIRmi{Untagged: img.ID})
+			out := &engine.Env{}
+			out.Set("Untagged", img.ID)
+			imgs.Add(out)
 			srv.LogEvent("untag", img.ID, "")
 		}
 	}
 
 	if len(srv.runtime.repositories.ByID()[img.ID]) == 0 {
-		if err := srv.deleteImageAndChildren(img.ID, &imgs, nil); err != nil {
+		if err := srv.deleteImageAndChildren(img.ID, imgs, nil); err != nil {
 			if err != ErrImageReferenced {
 				return imgs, err
 			}
-		} else if err := srv.deleteImageParents(img, &imgs); err != nil {
+		} else if err := srv.deleteImageParents(img, imgs); err != nil {
 			if err != ErrImageReferenced {
 				return imgs, err
 			}
@@ -1922,39 +1960,22 @@ func (srv *Server) deleteImage(img *Image, repoName, tag string) ([]APIRmi, erro
 	return imgs, nil
 }
 
-func (srv *Server) ImageDelete(name string, autoPrune bool) ([]APIRmi, error) {
-	var (
-		repository, tag string
-		img, err        = srv.runtime.repositories.LookupImage(name)
-	)
-	if err != nil {
-		return nil, fmt.Errorf("No such image: %s", name)
-	}
-
-	// FIXME: What does autoPrune mean ?
-	if !autoPrune {
-		if err := srv.runtime.graph.Delete(img.ID); err != nil {
-			return nil, fmt.Errorf("Cannot delete image %s: %s", name, err)
-		}
-		return nil, nil
+func (srv *Server) ImageDelete(job *engine.Job) engine.Status {
+	if n := len(job.Args); n != 1 {
+		job.Errorf("Usage: %s IMAGE", job.Name)
+		return engine.StatusErr
 	}
 
-	if !strings.Contains(img.ID, name) {
-		repository, tag = utils.ParseRepositoryTag(name)
+	imgs, err := srv.DeleteImage(job.Args[0], job.GetenvBool("autoPrune"))
+	if err != nil {
+		job.Error(err)
+		return engine.StatusErr
 	}
-
-	// If we have a repo and the image is not referenced anywhere else
-	// then just perform an untag and do not validate.
-	//
-	// i.e. only validate if we are performing an actual delete and not
-	// an untag op
-	if repository != "" && len(srv.runtime.repositories.ByID()[img.ID]) == 1 {
-		// Prevent deletion if image is used by a container
-		if err := srv.canDeleteImage(img.ID); err != nil {
-			return nil, err
-		}
+	if _, err := imgs.WriteTo(job.Stdout); err != nil {
+		job.Error(err)
+		return engine.StatusErr
 	}
-	return srv.deleteImage(img, repository, tag)
+	return engine.StatusOK
 }
 
 func (srv *Server) canDeleteImage(imgID string) error {