Example #1
0
func runCommand(args []string) error {
	var oldState *term.State
	var err error
	if term.IsTerminal(int(os.Stdin.Fd())) && os.Getenv("NORAW") == "" {
		oldState, err = term.MakeRaw(int(os.Stdin.Fd()))
		if err != nil {
			return err
		}
		defer term.Restore(int(os.Stdin.Fd()), oldState)
		c := make(chan os.Signal, 1)
		signal.Notify(c, os.Interrupt)
		go func() {
			for _ = range c {
				term.Restore(int(os.Stdin.Fd()), oldState)
				log.Printf("\nSIGINT received\n")
				os.Exit(0)
			}
		}()
	}
	// FIXME: we want to use unix sockets here, but net.UnixConn doesn't expose
	// CloseWrite(), which we need to cleanly signal that stdin is closed without
	// closing the connection.
	// See http://code.google.com/p/go/issues/detail?id=3345
	if conn, err := rcli.Call("tcp", "127.0.0.1:4242", args...); err == nil {
		receiveStdout := docker.Go(func() error {
			_, err := io.Copy(os.Stdout, conn)
			return err
		})
		sendStdin := docker.Go(func() error {
			_, err := io.Copy(conn, os.Stdin)
			if err := conn.CloseWrite(); err != nil {
				log.Printf("Couldn't send EOF: " + err.Error())
			}
			return err
		})
		if err := <-receiveStdout; err != nil {
			return err
		}
		if !term.IsTerminal(int(os.Stdin.Fd())) {
			if err := <-sendStdin; err != nil {
				return err
			}
		}
	} else {
		service, err := docker.NewServer()
		if err != nil {
			return err
		}
		if err := rcli.LocalCall(service, os.Stdin, os.Stdout, args...); err != nil {
			return err
		}
	}
	if oldState != nil {
		term.Restore(int(os.Stdin.Fd()), oldState)
	}
	return nil
}
Example #2
0
func (cli *DockerCli) hijack(method, path string, setRawTerminal bool, in *os.File, out io.Writer) error {

	req, err := http.NewRequest(method, fmt.Sprintf("/v%g%s", APIVERSION, path), nil)
	if err != nil {
		return err
	}
	req.Header.Set("User-Agent", "Docker-Client/"+VERSION)
	req.Header.Set("Content-Type", "plain/text")

	dial, err := net.Dial(cli.proto, cli.addr)
	if err != nil {
		return err
	}
	clientconn := httputil.NewClientConn(dial, nil)
	defer clientconn.Close()

	// Server hijacks the connection, error 'connection closed' expected
	clientconn.Do(req)

	rwc, br := clientconn.Hijack()
	defer rwc.Close()

	receiveStdout := utils.Go(func() error {
		_, err := io.Copy(out, br)
		return err
	})

	if in != nil && setRawTerminal && term.IsTerminal(in.Fd()) && os.Getenv("NORAW") == "" {
		oldState, err := term.SetRawTerminal()
		if err != nil {
			return err
		}
		defer term.RestoreTerminal(oldState)
	}
	sendStdin := utils.Go(func() error {
		io.Copy(rwc, in)
		if err := rwc.(*net.TCPConn).CloseWrite(); err != nil {
			utils.Debugf("Couldn't send EOF: %s\n", err)
		}
		// Discard errors due to pipe interruption
		return nil
	})

	if err := <-receiveStdout; err != nil {
		utils.Debugf("Error receiveStdout: %s", err)
		return err
	}

	if !term.IsTerminal(in.Fd()) {
		if err := <-sendStdin; err != nil {
			utils.Debugf("Error sendStdin: %s", err)
			return err
		}
	}
	return nil

}
Example #3
0
func (cli *DockerCli) hijack(method, path string, setRawTerminal bool) error {
	req, err := http.NewRequest(method, path, nil)
	if err != nil {
		return err
	}
	req.Header.Set("Content-Type", "plain/text")
	dial, err := net.Dial("tcp", fmt.Sprintf("%s:%d", cli.host, cli.port))
	if err != nil {
		return err
	}
	clientconn := httputil.NewClientConn(dial, nil)
	clientconn.Do(req)
	defer clientconn.Close()

	rwc, br := clientconn.Hijack()
	defer rwc.Close()

	receiveStdout := utils.Go(func() error {
		_, err := io.Copy(os.Stdout, br)
		return err
	})

	if setRawTerminal && term.IsTerminal(int(os.Stdin.Fd())) && os.Getenv("NORAW") == "" {
		if oldState, err := term.SetRawTerminal(); err != nil {
			return err
		} else {
			defer term.RestoreTerminal(oldState)
		}
	}

	sendStdin := utils.Go(func() error {
		_, err := io.Copy(rwc, os.Stdin)
		if err := rwc.(*net.TCPConn).CloseWrite(); err != nil {
			fmt.Fprintf(os.Stderr, "Couldn't send EOF: %s\n", err)
		}
		return err
	})

	if err := <-receiveStdout; err != nil {
		return err
	}

	if !term.IsTerminal(int(os.Stdin.Fd())) {
		if err := <-sendStdin; err != nil {
			return err
		}
	}
	return nil

}
Example #4
0
func runCommand(args []string) error {
	// FIXME: we want to use unix sockets here, but net.UnixConn doesn't expose
	// CloseWrite(), which we need to cleanly signal that stdin is closed without
	// closing the connection.
	// See http://code.google.com/p/go/issues/detail?id=3345
	if conn, err := rcli.Call("tcp", "127.0.0.1:4242", args...); err == nil {
		options := conn.GetOptions()
		if options.RawTerminal &&
			term.IsTerminal(int(os.Stdin.Fd())) &&
			os.Getenv("NORAW") == "" {
			if oldState, err := rcli.SetRawTerminal(); err != nil {
				return err
			} else {
				defer rcli.RestoreTerminal(oldState)
			}
		}
		receiveStdout := docker.Go(func() error {
			_, err := io.Copy(os.Stdout, conn)
			return err
		})
		sendStdin := docker.Go(func() error {
			_, err := io.Copy(conn, os.Stdin)
			if err := conn.CloseWrite(); err != nil {
				log.Printf("Couldn't send EOF: " + err.Error())
			}
			return err
		})
		if err := <-receiveStdout; err != nil {
			return err
		}
		if !term.IsTerminal(int(os.Stdin.Fd())) {
			if err := <-sendStdin; err != nil {
				return err
			}
		}
	} else {
		service, err := docker.NewServer()
		if err != nil {
			return err
		}
		dockerConn := rcli.NewDockerLocalConn(os.Stdout)
		defer dockerConn.Close()
		if err := rcli.LocalCall(service, os.Stdin, dockerConn, args...); err != nil {
			return err
		}
	}
	return nil
}
Example #5
0
func NewDockerCli(in io.ReadCloser, out, err io.Writer, proto, addr string) *DockerCli {
	var (
		isTerminal = false
		terminalFd uintptr
	)

	if in != nil {
		if file, ok := in.(*os.File); ok {
			terminalFd = file.Fd()
			isTerminal = term.IsTerminal(terminalFd)
		}
	}

	if err == nil {
		err = out
	}

	authConfig, _ := auth.LoadConfig(os.Getenv("HOME"))
	return &DockerCli{
		proto:      proto,
		addr:       addr,
		authConfig: authConfig,
		in:         in,
		out:        out,
		err:        err,
		isTerminal: isTerminal,
		terminalFd: terminalFd,
	}
}
Example #6
0
func NewDockerCli(in io.ReadCloser, out, err io.Writer, proto, addr string) *DockerCli {
	var (
		isTerminal = false
		terminalFd uintptr
	)

	if in != nil {
		if file, ok := in.(*os.File); ok {
			terminalFd = file.Fd()
			isTerminal = term.IsTerminal(terminalFd)
		}
	}

	if err == nil {
		err = out
	}

	configFile, e := auth.LoadConfig(os.Getenv("HOME"))
	if e != nil {
		fmt.Fprintf(err, "WARNING: %s\n", e)
	}
	return &DockerCli{
		proto:      proto,
		addr:       addr,
		configFile: configFile,
		in:         in,
		out:        out,
		err:        err,
		isTerminal: isTerminal,
		terminalFd: terminalFd,
	}
}
Example #7
0
func (client *Client) Attach(in io.ReadCloser, out io.WriteCloser) {
	client.Connect()

	client.in = in
	if file, ok := client.in.(*os.File); ok {
		client.terminalFd = file.Fd()
		client.isTerminal = term.IsTerminal(client.terminalFd)
	}

	if !client.isTerminal {
		panic(fmt.Errorf("siphon: cannot attach, no tty"))
	}

	fmt.Fprintf(log.client, "attaching to tty\r\n")

	rawOldState, err := term.SetRawTerminal(client.terminalFd)
	if err != nil {
		panic(err)
	}
	defer term.RestoreTerminal(client.terminalFd, rawOldState)

	client.monitorTtySize()

	var track sync.WaitGroup

	track.Add(1)
	go func() {
		defer track.Done()
		io.Copy(out, client.stdout)
		fmt.Fprintf(log.client, "client output closed\r\n")
	}()

	// track.Add(1) // io.Copy will block indefinitely on 'in' regardless of if client.stdin has been closed, so we can't actually wait for this.
	go func() {
		io.Copy(client.stdin, in)
		fmt.Fprintf(log.client, "client input closed\r\n")
	}()

	track.Wait()
}
Example #8
0
func (c *Client) hijack(method, path string, setRawTerminal bool, in *os.File, errStream io.Writer, out io.Writer) error {
	req, err := http.NewRequest(method, c.getURL(path), nil)
	if err != nil {
		return err
	}
	req.Header.Set("Content-Type", "plain/text")
	dial, err := net.Dial("tcp", c.endpointURL.Host)
	if err != nil {
		return err
	}
	clientconn := httputil.NewClientConn(dial, nil)
	clientconn.Do(req)
	defer clientconn.Close()
	rwc, br := clientconn.Hijack()
	defer rwc.Close()
	errStdout := make(chan error, 1)
	go func() {
		_, err := io.Copy(out, br)
		errStdout <- err
	}()
	if in != nil && setRawTerminal && term.IsTerminal(in.Fd()) && os.Getenv("NORAW") == "" {
		oldState, err := term.SetRawTerminal(in.Fd())
		if err != nil {
			return err
		}
		defer term.RestoreTerminal(in.Fd(), oldState)
	}
	go func() {
		io.Copy(rwc, in)
		if err := rwc.(*net.TCPConn).CloseWrite(); err != nil {
			fmt.Fprintf(errStream, "Couldn't send EOF: %s\n", err)
		}
	}()
	if err := <-errStdout; err != nil {
		return err
	}
	return nil
}