diff --git a/commands.go b/commands.go index 168c04bc2f..3103f52766 100644 --- a/commands.go +++ b/commands.go @@ -890,24 +890,6 @@ func CmdAttach(args ...string) error { return nil } -/* -// Ports type - Used to parse multiple -p flags -type ports []int - -func (p *ports) String() string { - return fmt.Sprint(*p) -} - -func (p *ports) Set(value string) error { - port, err := strconv.Atoi(value) - if err != nil { - return fmt.Errorf("Invalid port: %v", value) - } - *p = append(*p, port) - return nil -} -*/ - // ListOpts type type ListOpts []string @@ -1053,11 +1035,6 @@ func CmdRun(args ...string) error { v.Set("stderr", "1") } - /* - attach := Go(func() error { - err := hijack("POST", "/containers/"+out.Id+"/attach?"+v.Encode(), config.Tty) - return err - })*/ //start the container _, _, err = call("POST", "/containers/"+out.Id+"/start", nil) diff --git a/rcli/tcp.go b/rcli/tcp.go deleted file mode 100644 index cf111cdf71..0000000000 --- a/rcli/tcp.go +++ /dev/null @@ -1,169 +0,0 @@ -package rcli - -import ( - "bufio" - "bytes" - "encoding/json" - "fmt" - "io" - "io/ioutil" - "log" - "net" -) - -// Note: the globals are here to avoid import cycle -// FIXME: Handle debug levels mode? -var DEBUG_FLAG bool = false -var CLIENT_SOCKET io.Writer = nil - -type DockerTCPConn struct { - conn *net.TCPConn - options *DockerConnOptions - optionsBuf *[]byte - handshaked bool - client bool -} - -func NewDockerTCPConn(conn *net.TCPConn, client bool) *DockerTCPConn { - return &DockerTCPConn{ - conn: conn, - options: &DockerConnOptions{}, - client: client, - } -} - -func (c *DockerTCPConn) SetOptionRawTerminal() { - c.options.RawTerminal = true -} - -func (c *DockerTCPConn) GetOptions() *DockerConnOptions { - if c.client && !c.handshaked { - // Attempt to parse options encoded as a JSON dict and store - // the reminder of what we read from the socket in a buffer. - // - // bufio (and its ReadBytes method) would have been nice here, - // but if json.Unmarshal() fails (which will happen if we speak - // to a version of docker that doesn't send any option), then - // we can't put the data back in it for the next Read(). - c.handshaked = true - buf := make([]byte, 4096) - if n, _ := c.conn.Read(buf); n > 0 { - buf = buf[:n] - if nl := bytes.IndexByte(buf, '\n'); nl != -1 { - if err := json.Unmarshal(buf[:nl], c.options); err == nil { - buf = buf[nl+1:] - } - } - c.optionsBuf = &buf - } - } - - return c.options -} - -func (c *DockerTCPConn) Read(b []byte) (int, error) { - if c.optionsBuf != nil { - // Consume what we buffered in GetOptions() first: - optionsBuf := *c.optionsBuf - optionsBuflen := len(optionsBuf) - copied := copy(b, optionsBuf) - if copied < optionsBuflen { - optionsBuf = optionsBuf[copied:] - c.optionsBuf = &optionsBuf - return copied, nil - } - c.optionsBuf = nil - return copied, nil - } - return c.conn.Read(b) -} - -func (c *DockerTCPConn) Write(b []byte) (int, error) { - optionsLen := 0 - if !c.client && !c.handshaked { - c.handshaked = true - options, _ := json.Marshal(c.options) - options = append(options, '\n') - if optionsLen, err := c.conn.Write(options); err != nil { - return optionsLen, err - } - } - n, err := c.conn.Write(b) - return n + optionsLen, err -} - -func (c *DockerTCPConn) Flush() error { - _, err := c.Write([]byte{}) - return err -} - -func (c *DockerTCPConn) Close() error { return c.conn.Close() } - -func (c *DockerTCPConn) CloseWrite() error { return c.conn.CloseWrite() } - -func (c *DockerTCPConn) CloseRead() error { return c.conn.CloseRead() } - -// Connect to a remote endpoint using protocol `proto` and address `addr`, -// issue a single call, and return the result. -// `proto` may be "tcp", "unix", etc. See the `net` package for available protocols. -func Call(proto, addr string, args ...string) (DockerConn, error) { - cmd, err := json.Marshal(args) - if err != nil { - return nil, err - } - conn, err := dialDocker(proto, addr) - if err != nil { - return nil, err - } - if _, err := fmt.Fprintln(conn, string(cmd)); err != nil { - return nil, err - } - return conn, nil -} - -// Listen on `addr`, using protocol `proto`, for incoming rcli calls, -// and pass them to `service`. -func ListenAndServe(proto, addr string, service Service) error { - listener, err := net.Listen(proto, addr) - if err != nil { - return err - } - log.Printf("Listening for RCLI/%s on %s\n", proto, addr) - defer listener.Close() - for { - if conn, err := listener.Accept(); err != nil { - return err - } else { - conn, err := newDockerServerConn(conn) - if err != nil { - return err - } - go func(conn DockerConn) { - defer conn.Close() - if DEBUG_FLAG { - CLIENT_SOCKET = conn - } - if err := Serve(conn, service); err != nil { - log.Println("Error:", err.Error()) - fmt.Fprintln(conn, "Error:", err.Error()) - } - }(conn) - } - } - return nil -} - -// Parse an rcli call on a new connection, and pass it to `service` if it -// is valid. -func Serve(conn DockerConn, service Service) error { - r := bufio.NewReader(conn) - var args []string - if line, err := r.ReadString('\n'); err != nil { - return err - } else if err := json.Unmarshal([]byte(line), &args); err != nil { - return err - } else { - return call(service, ioutil.NopCloser(r), conn, args...) - } - return nil -} diff --git a/rcli/types.go b/rcli/types.go deleted file mode 100644 index 38f4a8c008..0000000000 --- a/rcli/types.go +++ /dev/null @@ -1,181 +0,0 @@ -package rcli - -// rcli (Remote Command-Line Interface) is a simple protocol for... -// serving command-line interfaces remotely. -// -// rcli can be used over any transport capable of a) sending binary streams in -// both directions, and b) capable of half-closing a connection. TCP and Unix sockets -// are the usual suspects. - -import ( - "flag" - "fmt" - "github.com/dotcloud/docker/term" - "io" - "log" - "net" - "os" - "reflect" - "strings" -) - -type DockerConnOptions struct { - RawTerminal bool -} - -type DockerConn interface { - io.ReadWriteCloser - CloseWrite() error - CloseRead() error - GetOptions() *DockerConnOptions - SetOptionRawTerminal() - Flush() error -} - -type DockerLocalConn struct { - writer io.WriteCloser - savedState *term.State -} - -func NewDockerLocalConn(w io.WriteCloser) *DockerLocalConn { - return &DockerLocalConn{ - writer: w, - } -} - -func (c *DockerLocalConn) Read(b []byte) (int, error) { - return 0, fmt.Errorf("DockerLocalConn does not implement Read()") -} - -func (c *DockerLocalConn) Write(b []byte) (int, error) { return c.writer.Write(b) } - -func (c *DockerLocalConn) Close() error { - if c.savedState != nil { - RestoreTerminal(c.savedState) - c.savedState = nil - } - return c.writer.Close() -} - -func (c *DockerLocalConn) Flush() error { return nil } - -func (c *DockerLocalConn) CloseWrite() error { return nil } - -func (c *DockerLocalConn) CloseRead() error { return nil } - -func (c *DockerLocalConn) GetOptions() *DockerConnOptions { return nil } - -func (c *DockerLocalConn) SetOptionRawTerminal() { - if state, err := SetRawTerminal(); err != nil { - if os.Getenv("DEBUG") != "" { - log.Printf("Can't set the terminal in raw mode: %s", err) - } - } else { - c.savedState = state - } -} - -var UnknownDockerProto = fmt.Errorf("Only TCP is actually supported by Docker at the moment") - -func dialDocker(proto string, addr string) (DockerConn, error) { - conn, err := net.Dial(proto, addr) - if err != nil { - return nil, err - } - switch i := conn.(type) { - case *net.TCPConn: - return NewDockerTCPConn(i, true), nil - } - return nil, UnknownDockerProto -} - -func newDockerFromConn(conn net.Conn, client bool) (DockerConn, error) { - switch i := conn.(type) { - case *net.TCPConn: - return NewDockerTCPConn(i, client), nil - } - return nil, UnknownDockerProto -} - -func newDockerServerConn(conn net.Conn) (DockerConn, error) { - return newDockerFromConn(conn, false) -} - -type Service interface { - Name() string - Help() string -} - -type Cmd func(io.ReadCloser, io.Writer, ...string) error -type CmdMethod func(Service, io.ReadCloser, io.Writer, ...string) error - -// FIXME: For reverse compatibility -func call(service Service, stdin io.ReadCloser, stdout DockerConn, args ...string) error { - return LocalCall(service, stdin, stdout, args...) -} - -func LocalCall(service Service, stdin io.ReadCloser, stdout DockerConn, args ...string) error { - if len(args) == 0 { - args = []string{"help"} - } - flags := flag.NewFlagSet("main", flag.ContinueOnError) - flags.SetOutput(stdout) - flags.Usage = func() { stdout.Write([]byte(service.Help())) } - if err := flags.Parse(args); err != nil { - return err - } - cmd := flags.Arg(0) - log.Printf("%s\n", strings.Join(append(append([]string{service.Name()}, cmd), flags.Args()[1:]...), " ")) - if cmd == "" { - cmd = "help" - } - method := getMethod(service, cmd) - if method != nil { - return method(stdin, stdout, flags.Args()[1:]...) - } - return fmt.Errorf("No such command: %s", cmd) -} - -func getMethod(service Service, name string) Cmd { - if name == "help" { - return func(stdin io.ReadCloser, stdout io.Writer, args ...string) error { - if len(args) == 0 { - stdout.Write([]byte(service.Help())) - } else { - if method := getMethod(service, args[0]); method == nil { - return fmt.Errorf("No such command: %s", args[0]) - } else { - method(stdin, stdout, "--help") - } - } - return nil - } - } - methodName := "Cmd" + strings.ToUpper(name[:1]) + strings.ToLower(name[1:]) - method, exists := reflect.TypeOf(service).MethodByName(methodName) - if !exists { - return nil - } - return func(stdin io.ReadCloser, stdout io.Writer, args ...string) error { - ret := method.Func.CallSlice([]reflect.Value{ - reflect.ValueOf(service), - reflect.ValueOf(stdin), - reflect.ValueOf(stdout), - reflect.ValueOf(args), - })[0].Interface() - if ret == nil { - return nil - } - return ret.(error) - } -} - -func Subcmd(output io.Writer, name, signature, description string) *flag.FlagSet { - flags := flag.NewFlagSet(name, flag.ContinueOnError) - flags.SetOutput(output) - flags.Usage = func() { - fmt.Fprintf(output, "\nUsage: docker %s %s\n\n%s\n\n", name, signature, description) - flags.PrintDefaults() - } - return flags -} diff --git a/rcli/utils.go b/rcli/utils.go deleted file mode 100644 index dbd579ffcd..0000000000 --- a/rcli/utils.go +++ /dev/null @@ -1,27 +0,0 @@ -package rcli - -import ( - "github.com/dotcloud/docker/term" - "os" - "os/signal" -) - -//FIXME: move these function to utils.go (in rcli to avoid import loop) -func SetRawTerminal() (*term.State, error) { - oldState, err := term.MakeRaw(int(os.Stdin.Fd())) - if err != nil { - return nil, err - } - c := make(chan os.Signal, 1) - signal.Notify(c, os.Interrupt) - go func() { - _ = <-c - term.Restore(int(os.Stdin.Fd()), oldState) - os.Exit(0) - }() - return oldState, err -} - -func RestoreTerminal(state *term.State) { - term.Restore(int(os.Stdin.Fd()), state) -} diff --git a/server_test.go b/server_test.go new file mode 100644 index 0000000000..fe10cfd356 --- /dev/null +++ b/server_test.go @@ -0,0 +1,96 @@ +package docker + +import ( + "testing" +) + +func TestCreateRm(t *testing.T) { + runtime, err := newTestRuntime() + if err != nil { + t.Fatal(err) + } + defer nuke(runtime) + + srv := &Server{runtime: runtime} + + config, _, err := ParseRun([]string{GetTestImage(runtime).Id, "echo test"}) + if err != nil { + t.Fatal(err) + } + + id, _, _, err := srv.ContainerCreate(*config) + if err != nil { + t.Fatal(err) + } + + if len(runtime.List()) != 1 { + t.Errorf("Expected 1 container, %v found", len(runtime.List())) + } + + if err = srv.ContainerDestroy(id, true); err != nil { + t.Fatal(err) + } + + if len(runtime.List()) != 0 { + t.Errorf("Expected 0 container, %v found", len(runtime.List())) + } + +} + +func TestCreateStartRestartStopStartKillRm(t *testing.T) { + runtime, err := newTestRuntime() + if err != nil { + t.Fatal(err) + } + defer nuke(runtime) + + srv := &Server{runtime: runtime} + + config, _, err := ParseRun([]string{GetTestImage(runtime).Id, "/bin/cat"}) + if err != nil { + t.Fatal(err) + } + + id, _, _, err := srv.ContainerCreate(*config) + if err != nil { + t.Fatal(err) + } + + if len(runtime.List()) != 1 { + t.Errorf("Expected 1 container, %v found", len(runtime.List())) + } + + err = srv.ContainerStart(id) + if err != nil { + t.Fatal(err) + } + + err = srv.ContainerRestart(id, 1) + if err != nil { + t.Fatal(err) + } + + err = srv.ContainerStop(id, 1) + if err != nil { + t.Fatal(err) + } + + err = srv.ContainerStart(id) + if err != nil { + t.Fatal(err) + } + + err = srv.ContainerKill(id) + if err != nil { + t.Fatal(err) + } + + if err = srv.ContainerDestroy(id, true); err != nil { + t.Fatal(err) + } + + if len(runtime.List()) != 0 { + t.Errorf("Expected 0 container, %v found", len(runtime.List())) + } + +} diff --git a/utils.go b/utils.go index 8f269df40c..b5258fd494 100644 --- a/utils.go +++ b/utils.go @@ -4,7 +4,6 @@ import ( "bytes" "errors" "fmt" - "github.com/dotcloud/docker/rcli" "github.com/dotcloud/docker/term" "index/suffixarray" "io" @@ -58,9 +57,6 @@ func Debugf(format string, a ...interface{}) { } fmt.Fprintf(os.Stderr, fmt.Sprintf("[debug] %s:%d %s\n", file, line, format), a...) - if rcli.CLIENT_SOCKET != nil { - fmt.Fprintf(rcli.CLIENT_SOCKET, fmt.Sprintf("[debug] %s:%d %s\n", file, line, format), a...) - } } }