func main() { go worker() state, err := term.SetRawTerminal(os.Stdin.Fd()) if err != nil { panic(err) } defer term.RestoreTerminal(os.Stdin.Fd(), state) winsize, _ = term.GetWinsize(os.Stdin.Fd()) client, err := beam.NewClient(&beam.NetTransport{"tcp", ":6379"}) if err != nil { panic(err) } defer client.Close() job := createJob(client) if err := job.Start(); err != nil { panic(err) } if err := job.Wait(); err != nil { panic(err) } }
func createJob(client *beam.Client) *beam.Job { job, err := client.NewJob("tty") if err != nil { panic(err) } master, slave, err := pty.Open() if err != nil { panic(err) } _, err = term.SetRawTerminal(master.Fd()) if err != nil { panic(err) } go job.WriteTo(slave, "stdout") go job.WriteTo(slave, "stderr") go job.ReadFrom(slave, "stdin") go io.Copy(os.Stdout, master) go io.Copy(os.Stderr, master) go io.Copy(master, os.Stdin) return job }
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 }
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 }
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() }
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 }
// 'docker login': login / register a user to registry service. func (cli *DockerCli) CmdLogin(args ...string) error { var readStringOnRawTerminal = func(stdin io.Reader, stdout io.Writer, echo bool) string { char := make([]byte, 1) buffer := make([]byte, 64) var i = 0 for i < len(buffer) { n, err := stdin.Read(char) if n > 0 { if char[0] == '\r' || char[0] == '\n' { stdout.Write([]byte{'\r', '\n'}) break } else if char[0] == 127 || char[0] == '\b' { if i > 0 { if echo { stdout.Write([]byte{'\b', ' ', '\b'}) } i-- } } else if !unicode.IsSpace(rune(char[0])) && !unicode.IsControl(rune(char[0])) { if echo { stdout.Write(char) } buffer[i] = char[0] i++ } } if err != nil { if err != io.EOF { fmt.Fprintf(stdout, "Read error: %v\r\n", err) } break } } return string(buffer[:i]) } var readAndEchoString = func(stdin io.Reader, stdout io.Writer) string { return readStringOnRawTerminal(stdin, stdout, true) } var readString = func(stdin io.Reader, stdout io.Writer) string { return readStringOnRawTerminal(stdin, stdout, false) } oldState, err := term.SetRawTerminal() if err != nil { return err } else { defer term.RestoreTerminal(oldState) } cmd := Subcmd("login", "", "Register or Login to the docker registry server") if err := cmd.Parse(args); err != nil { return nil } body, _, err := cli.call("GET", "/auth", nil) if err != nil { return err } var out auth.AuthConfig err = json.Unmarshal(body, &out) if err != nil { return err } var username string var password string var email string fmt.Print("Username (", out.Username, "): ") username = readAndEchoString(os.Stdin, os.Stdout) if username == "" { username = out.Username } if username != out.Username { fmt.Print("Password: "******"" { return fmt.Errorf("Error : Password Required") } fmt.Print("Email (", out.Email, "): ") email = readAndEchoString(os.Stdin, os.Stdout) if email == "" { email = out.Email } } else { email = out.Email } out.Username = username out.Password = password out.Email = email body, _, err = cli.call("POST", "/auth", out) if err != nil { return err } var out2 ApiAuth err = json.Unmarshal(body, &out2) if err != nil { return err } if out2.Status != "" { term.RestoreTerminal(oldState) fmt.Print(out2.Status) } return nil }
// 'docker login': login / register a user to registry service. func (cli *DockerCli) CmdLogin(args ...string) error { var readStringOnRawTerminal = func(stdin io.Reader, stdout io.Writer, echo bool) string { char := make([]byte, 1) buffer := make([]byte, 64) var i = 0 for i < len(buffer) { n, err := stdin.Read(char) if n > 0 { if char[0] == '\r' || char[0] == '\n' { stdout.Write([]byte{'\r', '\n'}) break } else if char[0] == 127 || char[0] == '\b' { if i > 0 { if echo { stdout.Write([]byte{'\b', ' ', '\b'}) } i-- } } else if !unicode.IsSpace(rune(char[0])) && !unicode.IsControl(rune(char[0])) { if echo { stdout.Write(char) } buffer[i] = char[0] i++ } } if err != nil { if err != io.EOF { fmt.Fprintf(stdout, "Read error: %v\r\n", err) } break } } return string(buffer[:i]) } var readAndEchoString = func(stdin io.Reader, stdout io.Writer) string { return readStringOnRawTerminal(stdin, stdout, true) } var readString = func(stdin io.Reader, stdout io.Writer) string { return readStringOnRawTerminal(stdin, stdout, false) } cmd := Subcmd("login", "[OPTIONS]", "Register or Login to the docker registry server") flUsername := cmd.String("u", "", "username") flPassword := cmd.String("p", "", "password") flEmail := cmd.String("e", "", "email") err := cmd.Parse(args) if err != nil { return nil } var oldState *term.State if *flUsername == "" || *flPassword == "" || *flEmail == "" { oldState, err = term.SetRawTerminal(cli.terminalFd) if err != nil { return err } defer term.RestoreTerminal(cli.terminalFd, oldState) } var ( username string password string email string ) if *flUsername == "" { fmt.Fprintf(cli.out, "Username (%s): ", cli.authConfig.Username) username = readAndEchoString(cli.in, cli.out) if username == "" { username = cli.authConfig.Username } } else { username = *flUsername } if username != cli.authConfig.Username { if *flPassword == "" { fmt.Fprintf(cli.out, "Password: "******"" { return fmt.Errorf("Error : Password Required") } } else { password = *flPassword } if *flEmail == "" { fmt.Fprintf(cli.out, "Email (%s): ", cli.authConfig.Email) email = readAndEchoString(cli.in, cli.out) if email == "" { email = cli.authConfig.Email } } else { email = *flEmail } } else { password = cli.authConfig.Password email = cli.authConfig.Email } if oldState != nil { term.RestoreTerminal(cli.terminalFd, oldState) } cli.authConfig.Username = username cli.authConfig.Password = password cli.authConfig.Email = email body, statusCode, err := cli.call("POST", "/auth", cli.authConfig) if statusCode == 401 { cli.authConfig.Username = "" cli.authConfig.Password = "" cli.authConfig.Email = "" auth.SaveConfig(cli.authConfig) return err } if err != nil { return err } var out2 APIAuth err = json.Unmarshal(body, &out2) if err != nil { auth.LoadConfig(os.Getenv("HOME")) return err } auth.SaveConfig(cli.authConfig) if out2.Status != "" { fmt.Fprintf(cli.out, "%s\n", out2.Status) } return nil }
func (cli *DockerCli) hijack(method, path string, setRawTerminal bool, in io.ReadCloser, 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") req.Host = cli.addr dial, err := net.Dial(cli.proto, cli.addr) if err != nil { if strings.Contains(err.Error(), "connection refused") { return fmt.Errorf("Can't connect to docker daemon. Is 'docker -d' running on this host?") } 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() var receiveStdout (chan error) if out != nil { receiveStdout = utils.Go(func() error { _, err := io.Copy(out, br) utils.Debugf("[hijack] End of stdout") return err }) } if in != nil && setRawTerminal && cli.isTerminal && os.Getenv("NORAW") == "" { oldState, err := term.SetRawTerminal(cli.terminalFd) if err != nil { return err } defer term.RestoreTerminal(cli.terminalFd, oldState) } sendStdin := utils.Go(func() error { if in != nil { io.Copy(rwc, in) utils.Debugf("[hijack] End of stdin") } if tcpc, ok := rwc.(*net.TCPConn); ok { if err := tcpc.CloseWrite(); err != nil { utils.Debugf("Couldn't send EOF: %s\n", err) } } else if unixc, ok := rwc.(*net.UnixConn); ok { if err := unixc.CloseWrite(); err != nil { utils.Debugf("Couldn't send EOF: %s\n", err) } } // Discard errors due to pipe interruption return nil }) if out != nil { if err := <-receiveStdout; err != nil { utils.Debugf("Error receiveStdout: %s", err) return err } } if !cli.isTerminal { if err := <-sendStdin; err != nil { utils.Debugf("Error sendStdin: %s", err) return err } } return nil }
func main() { disc, err := discover.NewClient() if err != nil { log.Fatal(err) } scheduler, err := client.New() if err != nil { log.Fatal(err) } state, err := scheduler.State() if err != nil { log.Fatal(err) } var firstHost string for k := range state { firstHost = k break } if firstHost == "" { log.Fatal("no hosts") } id := randomID() services, err := disc.Services("flynn-lorne-attach." + firstHost) if err != nil { log.Fatal(err) } conn, err := net.Dial("tcp", services.OnlineAddrs()[0]) if err != nil { log.Fatal(err) } ws, _ := term.GetWinsize(os.Stdin.Fd()) err = gob.NewEncoder(conn).Encode(&lorne.AttachReq{ JobID: id, Flags: lorne.AttachFlagStdout | lorne.AttachFlagStderr | lorne.AttachFlagStdin | lorne.AttachFlagStream, Height: int(ws.Height), Width: int(ws.Width), }) if err != nil { log.Fatal(err) } attachState := make([]byte, 1) if _, err := conn.Read(attachState); err != nil { log.Fatal(err) } switch attachState[0] { case lorne.AttachError: log.Fatal("attach error") } schedReq := &sampi.ScheduleReq{ Incremental: true, HostJobs: map[string][]*sampi.Job{firstHost: {{ID: id, Config: &docker.Config{ Image: "titanous/redis", Cmd: []string{"/bin/bash", "-i"}, Tty: true, AttachStdin: true, AttachStdout: true, AttachStderr: true, OpenStdin: true, StdinOnce: true, Env: []string{ "COLUMNS=" + strconv.Itoa(int(ws.Width)), "LINES=" + strconv.Itoa(int(ws.Height)), "TERM=" + os.Getenv("TERM"), }, }}}}, } if _, err := scheduler.Schedule(schedReq); err != nil { log.Fatal(err) } if _, err := conn.Read(attachState); err != nil { log.Fatal(err) } oldState, err := term.SetRawTerminal(os.Stdin.Fd()) if err != nil { log.Fatal(err) } go io.Copy(conn, os.Stdin) if _, err := io.Copy(os.Stdout, conn); err != nil { log.Fatal(err) } term.RestoreTerminal(os.Stdin.Fd(), oldState) }