Parcourir la source

added kill and images(wip)

Victor Vieux il y a 12 ans
Parent
commit
79e9105806
4 fichiers modifiés avec 273 ajouts et 56 suppressions
  1. 97 3
      api.go
  2. 20 3
      api_params.go
  3. 0 1
      commands.go
  4. 156 49
      commands2.go

+ 97 - 3
api.go

@@ -2,9 +2,11 @@ package docker
 
 import (
 	"encoding/json"
-	"log"
+	_ "fmt"
 	"github.com/gorilla/mux"
+	"log"
 	"net/http"
+	"time"
 )
 
 func ListenAndServe(addr string, runtime *Runtime) error {
@@ -21,10 +23,102 @@ func ListenAndServe(addr string, runtime *Runtime) error {
 		}
 	})
 
+	r.Path("/kill").Methods("GET", "POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		var ids []string
+		if err := json.NewDecoder(r.Body).Decode(&ids); err != nil {
+			w.WriteHeader(500)
+			return
+		}
+
+		var ret SimpleMessage
+		for _, name := range ids {
+			container := runtime.Get(name)
+			if container == nil {
+				ret.Message = "No such container: " + name + "\n"
+				break
+			}
+			if err := container.Kill(); err != nil {
+				ret.Message = ret.Message + "Error killing container " + name + ": " + err.Error() + "\n"
+			}
+		}
+		if ret.Message == "" {
+			w.WriteHeader(200)
+		} else {
+			w.WriteHeader(500)
+		}
+
+		b, err := json.Marshal(ret)
+		if err != nil {
+			w.WriteHeader(500)
+		} else {
+			w.Write(b)
+		}
+
+	})
+
 	r.Path("/images").Methods("GET", "POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
-		//TODO use runtime
+		var in ImagesIn
+		json.NewDecoder(r.Body).Decode(&in)
+
+		var allImages map[string]*Image
+		var err error
+		if in.All {
+			allImages, err = runtime.graph.Map()
+		} else {
+			allImages, err = runtime.graph.Heads()
+		}
+		if err != nil {
+			w.WriteHeader(500)
+			return
+		}
+		var outs []ImagesOut
+		for name, repository := range runtime.repositories.Repositories {
+			if in.NameFilter != "" && name != in.NameFilter {
+				continue
+			}
+			for tag, id := range repository {
+				var out ImagesOut
+				image, err := runtime.graph.Get(id)
+				if err != nil {
+					log.Printf("Warning: couldn't load %s from %s/%s: %s", id, name, tag, err)
+					continue
+				}
+				delete(allImages, id)
+				if !in.Quiet {
+					out.Repository = name
+					out.Tag = tag
+					out.Id = TruncateId(id)
+					out.Created = HumanDuration(time.Now().Sub(image.Created)) + " ago"
+				} else {
+					out.Id = image.ShortId()
+				}
+				outs = append(outs, out)
+			}
+		}
+		// Display images which aren't part of a
+		if in.NameFilter == "" {
+			for id, image := range allImages {
+				var out ImagesOut
+				if !in.Quiet {
+					out.Repository = "<none>"
+					out.Tag = "<none>"
+					out.Id = TruncateId(id)
+					out.Created = HumanDuration(time.Now().Sub(image.Created)) + " ago"
+				} else {
+					out.Id = image.ShortId()
+				}
+				outs = append(outs, out)
+			}
+		}
+
+		b, err := json.Marshal(outs)
+		if err != nil {
+			w.WriteHeader(500)
+		} else {
+			w.Write(b)
+		}
+
 	})
 
 	return http.ListenAndServe(addr, r)
 }
-

+ 20 - 3
api_params.go

@@ -1,7 +1,24 @@
 package docker
 
+type SimpleMessage struct {
+	Message string
+}
+
+type ImagesIn struct {
+	NameFilter string
+	Quiet      bool
+	All        bool
+}
+
+type ImagesOut struct {
+	Repository string `json:",omitempty"`
+	Tag        string `json:",omitempty"`
+	Id         string
+	Created    string `json:",omitempty"`
+}
+
 type VersionOut struct {
-        Version string
-        GitCommit string
-        MemoryLimitDisabled bool
+	Version             string
+	GitCommit           string
+	MemoryLimitDisabled bool
 }

+ 0 - 1
commands.go

@@ -976,7 +976,6 @@ func (srv *Server) CmdRun(stdin io.ReadCloser, stdout rcli.DockerConn, args ...s
 	return nil
 }
 
-
 type Server struct {
 	runtime *Runtime
 }

+ 156 - 49
commands2.go

@@ -1,25 +1,31 @@
 package docker
 
 import (
+	"bytes"
+	"encoding/json"
+	"flag"
 	"fmt"
 	"io/ioutil"
 	"net/http"
-	"encoding/json"
+	"os"
+	"text/tabwriter"
 )
 
 func ParseCommands(args []string) error {
-	
-	cmds := map[string]func(args []string) error {
-		"version":cmdVersion,
+
+	cmds := map[string]func(args []string) error{
+		"images":  cmdImages,
+		"kill":    cmdKill,
+		"version": cmdVersion,
 	}
 
 	if len(args) > 0 {
-		cmd, exists :=  cmds[args[0]]
+		cmd, exists := cmds[args[0]]
 		if !exists {
 			//TODO display commend not found
 			return cmdHelp(args)
 		}
-		return cmd(args)
+		return cmd(args[1:])
 	}
 	return cmdHelp(args)
 }
@@ -27,31 +33,31 @@ func ParseCommands(args []string) error {
 func cmdHelp(args []string) error {
 	help := "Usage: docker COMMAND [arg...]\n\nA self-sufficient runtime for linux containers.\n\nCommands:\n"
 	for _, cmd := range [][]string{
-//		{"attach", "Attach to a running container"},
-//		{"commit", "Create a new image from a container's changes"},
-//		{"diff", "Inspect changes on a container's filesystem"},
-//		{"export", "Stream the contents of a container as a tar archive"},
-//		{"history", "Show the history of an image"},
-//		{"images", "List images"},
-//		{"import", "Create a new filesystem image from the contents of a tarball"},
-//		{"info", "Display system-wide information"},
-//		{"inspect", "Return low-level information on a container"},
-//		{"kill", "Kill a running container"},
-//		{"login", "Register or Login to the docker registry server"},
-//		{"logs", "Fetch the logs of a container"},
-//		{"port", "Lookup the public-facing port which is NAT-ed to PRIVATE_PORT"},
-//		{"ps", "List containers"},
-//		{"pull", "Pull an image or a repository from the docker registry server"},
-//		{"push", "Push an image or a repository to the docker registry server"},
-//		{"restart", "Restart a running container"},
-//		{"rm", "Remove a container"},
-//		{"rmi", "Remove an image"},
-//		{"run", "Run a command in a new container"},
-//		{"start", "Start a stopped container"},
-//		{"stop", "Stop a running container"},
-//		{"tag", "Tag an image into a repository"},
+		//		{"attach", "Attach to a running container"},
+		//		{"commit", "Create a new image from a container's changes"},
+		//		{"diff", "Inspect changes on a container's filesystem"},
+		//		{"export", "Stream the contents of a container as a tar archive"},
+		//		{"history", "Show the history of an image"},
+		{"images", "List images"},
+		//		{"import", "Create a new filesystem image from the contents of a tarball"},
+		//		{"info", "Display system-wide information"},
+		//		{"inspect", "Return low-level information on a container"},
+		{"kill", "Kill a running container"},
+		//		{"login", "Register or Login to the docker registry server"},
+		//		{"logs", "Fetch the logs of a container"},
+		//		{"port", "Lookup the public-facing port which is NAT-ed to PRIVATE_PORT"},
+		//		{"ps", "List containers"},
+		//		{"pull", "Pull an image or a repository from the docker registry server"},
+		//		{"push", "Push an image or a repository to the docker registry server"},
+		//		{"restart", "Restart a running container"},
+		//		{"rm", "Remove a container"},
+		//		{"rmi", "Remove an image"},
+		//		{"run", "Run a command in a new container"},
+		//		{"start", "Start a stopped container"},
+		//		{"stop", "Stop a running container"},
+		//		{"tag", "Tag an image into a repository"},
 		{"version", "Show the docker version information"},
-//		{"wait", "Block until a container stops, then print its exit code"},
+		//		{"wait", "Block until a container stops, then print its exit code"},
 	} {
 		help += fmt.Sprintf("    %-10.10s%s\n", cmd[0], cmd[1])
 	}
@@ -59,8 +65,80 @@ func cmdHelp(args []string) error {
 	return nil
 }
 
-func cmdVersion(args []string) error {
-	body, err := apiCall("version")
+func cmdImages(args []string) error {
+	cmd := subcmd("images", "[OPTIONS] [NAME]", "List images")
+	quiet := cmd.Bool("q", false, "only show numeric IDs")
+	flAll := cmd.Bool("a", false, "show all images")
+	if err := cmd.Parse(args); err != nil {
+		return nil
+	}
+	if cmd.NArg() > 1 {
+		cmd.Usage()
+		return nil
+	}
+	var nameFilter string
+	if cmd.NArg() == 1 {
+		nameFilter = cmd.Arg(0)
+	}
+
+	in := ImagesIn{nameFilter, *quiet, *flAll}
+
+	body, err := apiPost("images", in)
+	if err != nil {
+		return err
+	}
+
+	var outs []ImagesOut
+	err = json.Unmarshal(body, &outs)
+	if err != nil {
+		return err
+	}
+	w := tabwriter.NewWriter(os.Stdout, 20, 1, 3, ' ', 0)
+	if !*quiet {
+		fmt.Fprintln(w, "REPOSITORY\tTAG\tID\tCREATED")
+	}
+
+	for _, out := range outs {
+		if !*quiet {
+			fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", out.Repository, out.Tag, out.Id, out.Created)
+		} else {
+			fmt.Fprintln(w, out.Id)
+		}
+	}
+
+	if !*quiet {
+		w.Flush()
+	}
+	return nil
+
+}
+
+func cmdKill(args []string) error {
+	cmd := subcmd("kill", "CONTAINER [CONTAINER...]", "Kill a running container")
+	if err := cmd.Parse(args); err != nil {
+		return nil
+	}
+	if cmd.NArg() < 1 {
+		cmd.Usage()
+		return nil
+	}
+
+	body, err := apiPost("kill", args)
+	if err != nil {
+		return err
+	}
+
+	var out SimpleMessage
+	err = json.Unmarshal(body, &out)
+	if err != nil {
+		return err
+	}
+	fmt.Print(out.Message)
+	return nil
+}
+
+func cmdVersion(_ []string) error {
+	body, err := apiGet("version")
 	if err != nil {
 		return err
 	}
@@ -68,28 +146,57 @@ func cmdVersion(args []string) error {
 	var out VersionOut
 	err = json.Unmarshal(body, &out)
 	if err != nil {
-                return err
-        }
+		return err
+	}
 	fmt.Println("Version:", out.Version)
-        fmt.Println("Git Commit:", out.GitCommit)
-        if out.MemoryLimitDisabled {
-                fmt.Println("Memory limit disabled")
-        }
+	fmt.Println("Git Commit:", out.GitCommit)
+	if out.MemoryLimitDisabled {
+		fmt.Println("Memory limit disabled")
+	}
 
 	return nil
 }
 
-func apiCall(path string) ([]byte, error) {
-	resp, err := http.Get("http://0.0.0.0:4243/" + path) 
-        if err != nil {
-                return nil,err
-        }
+func apiGet(path string) ([]byte, error) {
+	resp, err := http.Get("http://0.0.0.0:4243/" + path)
+	if err != nil {
+		return nil, err
+	}
+	//TODO check status code
+	defer resp.Body.Close()
+	body, err := ioutil.ReadAll(resp.Body)
+	if err != nil {
+		return nil, err
+	}
+	return body, nil
+
+}
+
+func apiPost(path string, data interface{}) ([]byte, error) {
+	buf, err := json.Marshal(data)
+	if err != nil {
+		return nil, err
+	}
+	dataBuf := bytes.NewBuffer(buf)
+	resp, err := http.Post("http://0.0.0.0:4243/"+path, "application/json", dataBuf)
+	if err != nil {
+		return nil, err
+	}
 	//TODO check status code
-        defer resp.Body.Close()
-        body, err := ioutil.ReadAll(resp.Body)
-        if err != nil {
-                return nil, err
-        }
+	defer resp.Body.Close()
+	body, err := ioutil.ReadAll(resp.Body)
+	if err != nil {
+		return nil, err
+	}
 	return body, nil
 
-}
+}
+
+func subcmd(name, signature, description string) *flag.FlagSet {
+	flags := flag.NewFlagSet(name, flag.ContinueOnError)
+	flags.Usage = func() {
+		fmt.Printf("\nUsage: docker %s %s\n\n%s\n\n", name, signature, description)
+		flags.PrintDefaults()
+	}
+	return flags
+}