mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
removed rcli completly
This commit is contained in:
parent
f37399d22b
commit
5a2a5ccdaf
6 changed files with 96 additions and 404 deletions
23
commands.go
23
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)
|
||||
|
|
169
rcli/tcp.go
169
rcli/tcp.go
|
@ -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
|
||||
}
|
181
rcli/types.go
181
rcli/types.go
|
@ -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
|
||||
}
|
|
@ -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)
|
||||
}
|
96
server_test.go
Normal file
96
server_test.go
Normal file
|
@ -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()))
|
||||
}
|
||||
|
||||
}
|
4
utils.go
4
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...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue