func (l *LibvirtLXCBackend) ResizeTTY(id string, height, width uint16) error { container, err := l.getContainer(id) if err != nil { return err } if !container.job.Config.TTY { return errors.New("job doesn't have a TTY") } pty, err := container.GetPtyMaster() if err != nil { return err } return term.SetWinsize(pty.Fd(), &term.Winsize{Height: height, Width: width}) }
func (l *LibvirtLXCBackend) Attach(req *AttachRequest) (err error) { client, err := l.getContainer(req.Job.Job.ID) if err != nil && (req.Job.Job.Config.TTY || req.Stdin != nil) { return err } defer func() { if client != nil && (req.Job.Job.Config.TTY || req.Stream) && err == io.EOF { <-client.done job := l.state.GetJob(req.Job.Job.ID) if job.Status == host.StatusDone || job.Status == host.StatusCrashed { err = ExitError(job.ExitStatus) return } err = errors.New(*job.Error) } }() if req.Job.Job.Config.TTY { pty, err := client.GetPtyMaster() if err != nil { return err } if err := term.SetWinsize(pty.Fd(), &term.Winsize{Height: req.Height, Width: req.Width}); err != nil { return err } if req.Attached != nil { req.Attached <- struct{}{} } if req.Stdin != nil && req.Stdout != nil { go io.Copy(pty, req.Stdin) } else if req.Stdin != nil { io.Copy(pty, req.Stdin) } if req.Stdout != nil { io.Copy(req.Stdout, pty) } pty.Close() return io.EOF } if req.Stdin != nil { stdinPipe, err := client.GetStdin() if err != nil { return err } go func() { io.Copy(stdinPipe, req.Stdin) stdinPipe.Close() }() } if req.Job.Job.Config.DisableLog { stdout, stderr, initLog, err := client.GetStreams() if err != nil { return err } if req.Attached != nil { req.Attached <- struct{}{} } var wg sync.WaitGroup cp := func(w io.Writer, r io.Reader) { if w == nil { w = ioutil.Discard } wg.Add(1) go func() { io.Copy(w, r) wg.Done() }() } cp(req.InitLog, initLog) cp(req.Stdout, stdout) cp(req.Stderr, stderr) wg.Wait() return io.EOF } if req.Attached != nil { req.Attached <- struct{}{} } lines := -1 if !req.Logs { lines = 0 } log := l.openLog(req.Job.Job.ID) ch := make(chan logbuf.Data) done := make(chan struct{}) go log.Read(lines, req.Stream, ch, done) defer close(done) for data := range ch { var w io.Writer switch data.Stream { case 1: w = req.Stdout case 2: w = req.Stderr case 3: w = req.InitLog } if w == nil { continue } if _, err := w.Write([]byte(data.Message)); err != nil { return nil } } return io.EOF }
func (l *LibvirtLXCBackend) Attach(req *AttachRequest) (err error) { var client *libvirtContainer if req.Stdin != nil || req.Job.Job.Config.TTY { client, err = l.getContainer(req.Job.Job.ID) if err != nil { return err } } defer func() { if req.Job.Job.Config.TTY || req.Stream && err == io.EOF { <-client.done job := l.state.GetJob(req.Job.Job.ID) if job.Status == host.StatusDone || job.Status == host.StatusCrashed { err = ExitError(job.ExitStatus) } } }() if req.Job.Job.Config.TTY { pty, err := client.GetPtyMaster() if err != nil { return err } if err := term.SetWinsize(pty.Fd(), &term.Winsize{Height: req.Height, Width: req.Width}); err != nil { return err } if req.Attached != nil { req.Attached <- struct{}{} } if req.Stdin != nil && req.Stdout != nil { go io.Copy(pty, req.Stdin) } else if req.Stdin != nil { io.Copy(pty, req.Stdin) } if req.Stdout != nil { io.Copy(req.Stdout, pty) } pty.Close() return io.EOF } if req.Stdin != nil { stdinPipe, err := client.GetStdin() if err != nil { return err } go func() { io.Copy(stdinPipe, req.Stdin) stdinPipe.Close() }() } log := l.openLog(req.Job.Job.ID) r := log.NewReader() defer r.Close() if !req.Logs { if err := r.SeekToEnd(); err != nil { return err } } if req.Attached != nil { req.Attached <- struct{}{} } for { data, err := r.ReadData(req.Stream) if err != nil { return err } switch data.Stream { case 1: if req.Stdout == nil { continue } if _, err := req.Stdout.Write([]byte(data.Message)); err != nil { return err } case 2: if req.Stderr == nil { continue } if _, err := req.Stderr.Write([]byte(data.Message)); err != nil { return err } } } }
func (l *LibvirtLXCBackend) Attach(req *AttachRequest) (err error) { client, err := l.getContainer(req.Job.Job.ID) if err != nil { if req.Job.Job.Config.TTY || req.Stdin != nil { return host.ErrJobNotRunning } // if the container has exited and logging was disabled, return EOF if req.Job.Job.Config.DisableLog { if req.Attached != nil { req.Attached <- struct{}{} } return io.EOF } } defer func() { if client != nil && (req.Job.Job.Config.TTY || req.Stream) && err == io.EOF { <-client.done job := l.state.GetJob(req.Job.Job.ID) if job.Status == host.StatusDone || job.Status == host.StatusCrashed { err = ExitError(*job.ExitStatus) return } err = errors.New(*job.Error) } }() if req.Job.Job.Config.TTY { pty, err := client.GetPtyMaster() if err != nil { return err } if err := term.SetWinsize(pty.Fd(), &term.Winsize{Height: req.Height, Width: req.Width}); err != nil { return err } if req.Attached != nil { req.Attached <- struct{}{} } if req.Stdin != nil && req.Stdout != nil { go io.Copy(pty, req.Stdin) } else if req.Stdin != nil { io.Copy(pty, req.Stdin) } if req.Stdout != nil { io.Copy(req.Stdout, pty) } pty.Close() return io.EOF } if req.Stdin != nil { stdinPipe, err := client.GetStdin() if err != nil { return err } go func() { io.Copy(stdinPipe, req.Stdin) stdinPipe.Close() }() } if req.Job.Job.Config.DisableLog { stdout, stderr, initLog, err := client.GetStreams() if err != nil { return err } if req.Attached != nil { req.Attached <- struct{}{} } var wg sync.WaitGroup cp := func(w io.Writer, r io.Reader) { if w == nil { w = ioutil.Discard } wg.Add(1) go func() { io.Copy(w, r) wg.Done() }() } cp(req.InitLog, initLog) cp(req.Stdout, stdout) cp(req.Stderr, stderr) wg.Wait() return io.EOF } if req.Attached != nil { req.Attached <- struct{}{} } ch := make(chan *rfc5424.Message) stream, err := l.mux.StreamLog(req.Job.Job.Metadata["flynn-controller.app"], req.Job.Job.ID, req.Logs, req.Stream, ch) if err != nil { return err } defer stream.Close() for msg := range ch { var w io.Writer switch string(msg.MsgID) { case "ID1": w = req.Stdout case "ID2": w = req.Stderr case "ID3": w = req.InitLog } if w == nil { continue } if _, err := w.Write(append(msg.Msg, '\n')); err != nil { return nil } } return io.EOF }