123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528 |
- package docker
- import (
- "bytes"
- "encoding/json"
- "flag"
- "fmt"
- "io"
- "io/ioutil"
- "net/http"
- "os"
- "text/tabwriter"
- )
- func ParseCommands(args []string) error {
- cmds := map[string]func(args []string) error{
- "images": cmdImages,
- "info": cmdInfo,
- "history": cmdHistory,
- "kill": cmdKill,
- "logs": cmdLogs,
- "ps": cmdPs,
- "restart": cmdRestart,
- "rm": cmdRm,
- "rmi": cmdRmi,
- "run": cmdRun,
- "start": cmdStart,
- "stop": cmdStop,
- "version": cmdVersion,
- }
- if len(args) > 0 {
- cmd, exists := cmds[args[0]]
- if !exists {
- //TODO display commend not found
- return cmdHelp(args)
- }
- return cmd(args[1:])
- }
- return cmdHelp(args)
- }
- 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"},
- {"version", "Show the docker version information"},
- // {"wait", "Block until a container stops, then print its exit code"},
- } {
- help += fmt.Sprintf(" %-10.10s%s\n", cmd[0], cmd[1])
- }
- fmt.Println(help)
- return nil
- }
- func cmdImages(args []string) error {
- cmd := Subcmd("images", "[OPTIONS] [NAME]", "List images")
- var in ImagesIn
- cmd.BoolVar(&in.Quiet, "q", false, "only show numeric IDs")
- cmd.BoolVar(&in.All, "a", false, "show all images")
- if err := cmd.Parse(args); err != nil {
- return nil
- }
- if cmd.NArg() > 1 {
- cmd.Usage()
- return nil
- }
- if cmd.NArg() == 1 {
- in.NameFilter = cmd.Arg(0)
- }
- 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 !in.Quiet {
- fmt.Fprintln(w, "REPOSITORY\tTAG\tID\tCREATED")
- }
- for _, out := range outs {
- if !in.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 !in.Quiet {
- w.Flush()
- }
- return nil
- }
- func cmdInfo(args []string) error {
- cmd := Subcmd("info", "", "Display system-wide information")
- if err := cmd.Parse(args); err != nil {
- return nil
- }
- if cmd.NArg() > 0 {
- cmd.Usage()
- return nil
- }
- body, err := apiGet("info")
- if err != nil {
- return err
- }
- var out InfoOut
- err = json.Unmarshal(body, &out)
- if err != nil {
- return err
- }
- fmt.Printf("containers: %d\nversion: %s\nimages: %d\n", out.Containers, out.Version, out.Images)
- if out.Debug {
- fmt.Println("debug mode enabled")
- fmt.Printf("fds: %d\ngoroutines: %d\n", out.NFd, out.NGoroutines)
- }
- return nil
- }
- func cmdHistory(args []string) error {
- cmd := Subcmd("history", "IMAGE", "Show the history of an image")
- if err := cmd.Parse(args); err != nil {
- return nil
- }
- if cmd.NArg() != 1 {
- cmd.Usage()
- return nil
- }
- body, err := apiPost("history", HistoryIn{cmd.Arg(0)})
- if err != nil {
- return err
- }
- var outs []HistoryOut
- err = json.Unmarshal(body, &outs)
- if err != nil {
- return err
- }
- w := tabwriter.NewWriter(os.Stdout, 20, 1, 3, ' ', 0)
- fmt.Fprintln(w, "ID\tCREATED\tCREATED BY")
- for _, out := range outs {
- fmt.Fprintf(w, "%s\t%s\t%s\n", out.Id, out.Created, out.CreatedBy)
- }
- 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 cmdLogs(args []string) error {
- cmd := Subcmd("logs", "CONTAINER", "Fetch the logs of a container")
- if err := cmd.Parse(args); err != nil {
- return nil
- }
- if cmd.NArg() != 1 {
- cmd.Usage()
- return nil
- }
- body, err := apiPost("logs", LogsIn{cmd.Arg(0)})
- if err != nil {
- return err
- }
- var out LogsOut
- err = json.Unmarshal(body, &out)
- if err != nil {
- return err
- }
- fmt.Fprintln(os.Stdout, out.Stdout)
- fmt.Fprintln(os.Stderr, out.Stderr)
- return nil
- }
- func cmdPs(args []string) error {
- cmd := Subcmd("ps", "[OPTIONS]", "List containers")
- var in PsIn
- cmd.BoolVar(&in.Quiet, "q", false, "Only display numeric IDs")
- cmd.BoolVar(&in.All, "a", false, "Show all containers. Only running containers are shown by default.")
- cmd.BoolVar(&in.Full, "notrunc", false, "Don't truncate output")
- nLatest := cmd.Bool("l", false, "Show only the latest created container, include non-running ones.")
- cmd.IntVar(&in.Last, "n", -1, "Show n last created containers, include non-running ones.")
- if err := cmd.Parse(args); err != nil {
- return nil
- }
- if in.Last == -1 && *nLatest {
- in.Last = 1
- }
- body, err := apiPost("ps", in)
- if err != nil {
- return err
- }
- var outs []PsOut
- err = json.Unmarshal(body, &outs)
- if err != nil {
- return err
- }
- w := tabwriter.NewWriter(os.Stdout, 20, 1, 3, ' ', 0)
- if !in.Quiet {
- fmt.Fprintln(w, "ID\tIMAGE\tCOMMAND\tCREATED\tSTATUS")
- }
- for _, out := range outs {
- if !in.Quiet {
- fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", out.Id, out.Image, out.Command, out.Status, out.Created)
- } else {
- fmt.Fprintln(w, out.Id)
- }
- }
- if !in.Quiet {
- w.Flush()
- }
- return nil
- }
- func cmdRestart(args []string) error {
- cmd := Subcmd("restart", "CONTAINER [CONTAINER...]", "Restart a running container")
- if err := cmd.Parse(args); err != nil {
- return nil
- }
- if cmd.NArg() < 1 {
- cmd.Usage()
- return nil
- }
- body, err := apiPost("restart", cmd.Args())
- if err != nil {
- return err
- }
- var out []string
- err = json.Unmarshal(body, &out)
- if err != nil {
- return err
- }
- for _, name := range out {
- fmt.Println(name)
- }
- return nil
- }
- func cmdRm(args []string) error {
- cmd := Subcmd("rm", "CONTAINER [CONTAINER...]", "Remove a container")
- if err := cmd.Parse(args); err != nil {
- return nil
- }
- if cmd.NArg() < 1 {
- cmd.Usage()
- return nil
- }
- body, err := apiPost("rm", cmd.Args())
- if err != nil {
- return err
- }
- var out []string
- err = json.Unmarshal(body, &out)
- if err != nil {
- return err
- }
- for _, name := range out {
- fmt.Println(name)
- }
- return nil
- }
- func cmdRmi(args []string) error {
- cmd := Subcmd("rmi", "IMAGE [IMAGE...]", "Remove an image")
- if err := cmd.Parse(args); err != nil {
- return nil
- }
- if cmd.NArg() < 1 {
- cmd.Usage()
- return nil
- }
- body, err := apiPost("rmi", cmd.Args())
- if err != nil {
- return err
- }
- var out []string
- err = json.Unmarshal(body, &out)
- if err != nil {
- return err
- }
- for _, name := range out {
- fmt.Println(name)
- }
- return nil
- }
- func cmdRun(args []string) error {
- config, err := ParseRun(args)
- if err != nil {
- return err
- }
- if config.Image == "" {
- fmt.Println("Error: Image not specified")
- return fmt.Errorf("Image not specified")
- }
- if len(config.Cmd) == 0 {
- fmt.Println("Error: Command not specified")
- return fmt.Errorf("Command not specified")
- }
- body, err := apiPostHijack("run", config)
- if err != nil {
- return err
- }
- defer body.Close()
- /*str, err2 := ioutil.ReadAll(body)
- if err2 != nil {
- return err2
- }
- fmt.Println(str)*/
- return nil
- }
- func cmdStart(args []string) error {
- cmd := Subcmd("start", "CONTAINER [CONTAINER...]", "Restart a stopped container")
- if err := cmd.Parse(args); err != nil {
- return nil
- }
- if cmd.NArg() < 1 {
- cmd.Usage()
- return nil
- }
- body, err := apiPost("start", cmd.Args())
- if err != nil {
- return err
- }
- var out []string
- err = json.Unmarshal(body, &out)
- if err != nil {
- return err
- }
- for _, name := range out {
- fmt.Println(name)
- }
- return nil
- }
- func cmdStop(args []string) error {
- cmd := Subcmd("stop", "CONTAINER [CONTAINER...]", "Restart a running container")
- if err := cmd.Parse(args); err != nil {
- return nil
- }
- if cmd.NArg() < 1 {
- cmd.Usage()
- return nil
- }
- body, err := apiPost("stop", cmd.Args())
- if err != nil {
- return err
- }
- var out []string
- err = json.Unmarshal(body, &out)
- if err != nil {
- return err
- }
- for _, name := range out {
- fmt.Println(name)
- }
- return nil
- }
- func cmdVersion(args []string) error {
- cmd := Subcmd("version", "", "Show the docker version information.")
- if err := cmd.Parse(args); err != nil {
- return nil
- }
- if cmd.NArg() > 0 {
- cmd.Usage()
- return nil
- }
- body, err := apiGet("version")
- if err != nil {
- return err
- }
- var out VersionOut
- err = json.Unmarshal(body, &out)
- if err != nil {
- return err
- }
- fmt.Println("Version:", out.Version)
- fmt.Println("Git Commit:", out.GitCommit)
- if out.MemoryLimitDisabled {
- fmt.Println("Memory limit disabled")
- }
- return nil
- }
- func apiGet(path string) ([]byte, error) {
- resp, err := http.Get("http://0.0.0.0:4243/" + path)
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
- body, err := ioutil.ReadAll(resp.Body)
- if err != nil {
- return nil, err
- }
- if resp.StatusCode != 200 {
- return nil, fmt.Errorf("error: %s", body)
- }
- 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
- }
- defer resp.Body.Close()
- body, err := ioutil.ReadAll(resp.Body)
- if err != nil {
- return nil, err
- }
- if resp.StatusCode != 200 {
- return nil, fmt.Errorf("[error] %s", body)
- }
- return body, nil
- }
- func apiPostHijack(path string, data interface{}) (io.ReadCloser, 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
- return resp.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
- }
|