diff options
Diffstat (limited to 'pkg/varlinkapi/attach.go')
-rw-r--r-- | pkg/varlinkapi/attach.go | 103 |
1 files changed, 103 insertions, 0 deletions
diff --git a/pkg/varlinkapi/attach.go b/pkg/varlinkapi/attach.go new file mode 100644 index 000000000..9e2a265be --- /dev/null +++ b/pkg/varlinkapi/attach.go @@ -0,0 +1,103 @@ +// +build varlink + +package varlinkapi + +import ( + "bufio" + "io" + + "github.com/containers/libpod/cmd/podman/varlink" + "github.com/containers/libpod/libpod" + "github.com/containers/libpod/pkg/varlinkapi/virtwriter" + "github.com/sirupsen/logrus" + "k8s.io/client-go/tools/remotecommand" +) + +func setupStreams(call iopodman.VarlinkCall) (*bufio.Reader, *bufio.Writer, *io.PipeReader, *io.PipeWriter, *libpod.AttachStreams) { + + // These are the varlink sockets + reader := call.Call.Reader + writer := call.Call.Writer + + // This pipe is used to pass stdin from the client to the input stream + // once the msg has been "decoded" + pr, pw := io.Pipe() + + stdoutWriter := virtwriter.NewVirtWriteCloser(writer, virtwriter.ToStdout) + // TODO if runc ever starts passing stderr, we can too + //stderrWriter := NewVirtWriteCloser(writer, ToStderr) + + streams := libpod.AttachStreams{ + OutputStream: stdoutWriter, + InputStream: pr, + // Runc eats the error stream + ErrorStream: stdoutWriter, + AttachInput: true, + AttachOutput: true, + // Runc eats the error stream + AttachError: true, + } + return reader, writer, pr, pw, &streams +} + +// Attach connects to a containers console +func (i *LibpodAPI) Attach(call iopodman.VarlinkCall, name string, detachKeys string, start bool) error { + var finalErr error + resize := make(chan remotecommand.TerminalSize) + errChan := make(chan error) + + if !call.WantsUpgrade() { + return call.ReplyErrorOccurred("client must use upgraded connection to attach") + } + ctr, err := i.Runtime.LookupContainer(name) + if err != nil { + return call.ReplyErrorOccurred(err.Error()) + } + + reader, writer, _, pw, streams := setupStreams(call) + + go func() { + if err := virtwriter.Reader(reader, nil, nil, pw, resize); err != nil { + errChan <- err + } + }() + + if start { + finalErr = startAndAttach(ctr, streams, detachKeys, resize, errChan) + } else { + finalErr = attach(ctr, streams, detachKeys, resize, errChan) + } + + if finalErr != libpod.ErrDetach && finalErr != nil { + logrus.Error(finalErr) + } + quitWriter := virtwriter.NewVirtWriteCloser(writer, virtwriter.Quit) + _, err = quitWriter.Write([]byte("HANG-UP")) + // TODO error handling is not quite right here yet + return call.Writer.Flush() +} + +func attach(ctr *libpod.Container, streams *libpod.AttachStreams, detachKeys string, resize chan remotecommand.TerminalSize, errChan chan error) error { + go func() { + if err := ctr.Attach(streams, detachKeys, resize); err != nil { + errChan <- err + } + }() + attachError := <-errChan + return attachError +} + +func startAndAttach(ctr *libpod.Container, streams *libpod.AttachStreams, detachKeys string, resize chan remotecommand.TerminalSize, errChan chan error) error { + var finalErr error + attachChan, err := ctr.StartAndAttach(getContext(), streams, detachKeys, resize, false) + if err != nil { + return err + } + select { + case attachChanErr := <-attachChan: + finalErr = attachChanErr + case chanError := <-errChan: + finalErr = chanError + } + return finalErr +} |