mirror of
https://github.com/containers/podman.git
synced 2025-10-19 12:12:36 +08:00
Change attach to accept a struct containing streams
Comparing Go interfaces, like io.Reader, to nil does not work. As such, we need to include a bool with each stream telling whether to attach to it. Signed-off-by: Matthew Heon <matthew.heon@gmail.com> Closes: #608 Approved by: baude
This commit is contained in:
@ -73,7 +73,7 @@ func attachCtr(ctr *libpod.Container, stdout, stderr, stdin *os.File, detachKeys
|
|||||||
|
|
||||||
// Check if we are attached to a terminal. If we are, generate resize
|
// Check if we are attached to a terminal. If we are, generate resize
|
||||||
// events, and set the terminal to raw mode
|
// events, and set the terminal to raw mode
|
||||||
if haveTerminal {
|
if haveTerminal && ctr.Spec().Process.Terminal {
|
||||||
logrus.Debugf("Handling terminal attach")
|
logrus.Debugf("Handling terminal attach")
|
||||||
|
|
||||||
resizeTty(resize)
|
resizeTty(resize)
|
||||||
@ -88,11 +88,32 @@ func attachCtr(ctr *libpod.Container, stdout, stderr, stdin *os.File, detachKeys
|
|||||||
defer term.RestoreTerminal(os.Stdin.Fd(), oldTermState)
|
defer term.RestoreTerminal(os.Stdin.Fd(), oldTermState)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
streams := new(libpod.AttachStreams)
|
||||||
|
streams.OutputStream = stdout
|
||||||
|
streams.ErrorStream = stderr
|
||||||
|
streams.InputStream = stdin
|
||||||
|
streams.AttachOutput = true
|
||||||
|
streams.AttachError = true
|
||||||
|
streams.AttachInput = true
|
||||||
|
|
||||||
|
if stdout == nil {
|
||||||
|
logrus.Debugf("Not attaching to stdout")
|
||||||
|
streams.AttachOutput = false
|
||||||
|
}
|
||||||
|
if stderr == nil {
|
||||||
|
logrus.Debugf("Not attaching to stderr")
|
||||||
|
streams.AttachError = false
|
||||||
|
}
|
||||||
|
if stdin == nil {
|
||||||
|
logrus.Debugf("Not attaching to stdin")
|
||||||
|
streams.AttachInput = false
|
||||||
|
}
|
||||||
|
|
||||||
if sigProxy {
|
if sigProxy {
|
||||||
ProxySignals(ctr)
|
ProxySignals(ctr)
|
||||||
}
|
}
|
||||||
|
|
||||||
return ctr.Attach(stdout, stderr, stdin, detachKeys, resize)
|
return ctr.Attach(streams, detachKeys, resize)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start and attach to a container
|
// Start and attach to a container
|
||||||
@ -119,7 +140,28 @@ func startAttachCtr(ctr *libpod.Container, stdout, stderr, stdin *os.File, detac
|
|||||||
defer term.RestoreTerminal(os.Stdin.Fd(), oldTermState)
|
defer term.RestoreTerminal(os.Stdin.Fd(), oldTermState)
|
||||||
}
|
}
|
||||||
|
|
||||||
attachChan, err := ctr.StartAndAttach(stdout, stderr, stdin, detachKeys, resize)
|
streams := new(libpod.AttachStreams)
|
||||||
|
streams.OutputStream = stdout
|
||||||
|
streams.ErrorStream = stderr
|
||||||
|
streams.InputStream = stdin
|
||||||
|
streams.AttachOutput = true
|
||||||
|
streams.AttachError = true
|
||||||
|
streams.AttachInput = true
|
||||||
|
|
||||||
|
if stdout == nil {
|
||||||
|
logrus.Debugf("Not attaching to stdout")
|
||||||
|
streams.AttachOutput = false
|
||||||
|
}
|
||||||
|
if stderr == nil {
|
||||||
|
logrus.Debugf("Not attaching to stderr")
|
||||||
|
streams.AttachError = false
|
||||||
|
}
|
||||||
|
if stdin == nil {
|
||||||
|
logrus.Debugf("Not attaching to stdin")
|
||||||
|
streams.AttachInput = false
|
||||||
|
}
|
||||||
|
|
||||||
|
attachChan, err := ctr.StartAndAttach(streams, detachKeys, resize)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package libpod
|
package libpod
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
@ -125,7 +124,7 @@ func (c *Container) Start() (err error) {
|
|||||||
// attach call.
|
// attach call.
|
||||||
// The channel will be closed automatically after the result of attach has been
|
// The channel will be closed automatically after the result of attach has been
|
||||||
// sent
|
// sent
|
||||||
func (c *Container) StartAndAttach(outputStream, errorStream io.WriteCloser, inputStream io.Reader, keys string, resize <-chan remotecommand.TerminalSize) (attachResChan <-chan error, err error) {
|
func (c *Container) StartAndAttach(streams *AttachStreams, keys string, resize <-chan remotecommand.TerminalSize) (attachResChan <-chan error, err error) {
|
||||||
if !c.locked {
|
if !c.locked {
|
||||||
c.lock.Lock()
|
c.lock.Lock()
|
||||||
defer c.lock.Unlock()
|
defer c.lock.Unlock()
|
||||||
@ -178,7 +177,7 @@ func (c *Container) StartAndAttach(outputStream, errorStream io.WriteCloser, inp
|
|||||||
|
|
||||||
// Attach to the container before starting it
|
// Attach to the container before starting it
|
||||||
go func() {
|
go func() {
|
||||||
if err := c.attach(outputStream, errorStream, inputStream, keys, resize); err != nil {
|
if err := c.attach(streams, keys, resize); err != nil {
|
||||||
attachChan <- err
|
attachChan <- err
|
||||||
}
|
}
|
||||||
close(attachChan)
|
close(attachChan)
|
||||||
@ -406,7 +405,7 @@ func (c *Container) Exec(tty, privileged bool, env, cmd []string, user string) e
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Attach attaches to a container
|
// Attach attaches to a container
|
||||||
func (c *Container) Attach(outputStream, errorStream io.WriteCloser, inputStream io.Reader, keys string, resize <-chan remotecommand.TerminalSize) error {
|
func (c *Container) Attach(streams *AttachStreams, keys string, resize <-chan remotecommand.TerminalSize) error {
|
||||||
if !c.locked {
|
if !c.locked {
|
||||||
c.lock.Lock()
|
c.lock.Lock()
|
||||||
if err := c.syncContainer(); err != nil {
|
if err := c.syncContainer(); err != nil {
|
||||||
@ -421,7 +420,7 @@ func (c *Container) Attach(outputStream, errorStream io.WriteCloser, inputStream
|
|||||||
return errors.Wrapf(ErrCtrStateInvalid, "can only attach to created or running containers")
|
return errors.Wrapf(ErrCtrStateInvalid, "can only attach to created or running containers")
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.attach(outputStream, errorStream, inputStream, keys, resize)
|
return c.attach(streams, keys, resize)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mount mounts a container's filesystem on the host
|
// Mount mounts a container's filesystem on the host
|
||||||
|
@ -23,16 +23,35 @@ const (
|
|||||||
AttachPipeStderr = 3
|
AttachPipeStderr = 3
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// AttachStreams contains streams that will be attached to the container
|
||||||
|
type AttachStreams struct {
|
||||||
|
// OutputStream will be attached to container's STDOUT
|
||||||
|
OutputStream io.WriteCloser
|
||||||
|
// ErrorStream will be attached to container's STDERR
|
||||||
|
ErrorStream io.WriteCloser
|
||||||
|
// InputStream will be attached to container's STDIN
|
||||||
|
InputStream io.Reader
|
||||||
|
// AttachOutput is whether to attach to STDOUT
|
||||||
|
// If false, stdout will not be attached
|
||||||
|
AttachOutput bool
|
||||||
|
// AttachError is whether to attach to STDERR
|
||||||
|
// If false, stdout will not be attached
|
||||||
|
AttachError bool
|
||||||
|
// AttachInput is whether to attach to STDIN
|
||||||
|
// If false, stdout will not be attached
|
||||||
|
AttachInput bool
|
||||||
|
}
|
||||||
|
|
||||||
// Attach to the given container
|
// Attach to the given container
|
||||||
// Does not check if state is appropriate
|
// Does not check if state is appropriate
|
||||||
func (c *Container) attach(outputStream, errorStream io.WriteCloser, inputStream io.Reader, keys string, resize <-chan remotecommand.TerminalSize) error {
|
func (c *Container) attach(streams *AttachStreams, keys string, resize <-chan remotecommand.TerminalSize) error {
|
||||||
if outputStream == nil && errorStream == nil && inputStream == nil {
|
if !streams.AttachOutput && !streams.AttachError && !streams.AttachInput {
|
||||||
return errors.Wrapf(ErrInvalidArg, "must provide at least one stream to attach to")
|
return errors.Wrapf(ErrInvalidArg, "must provide at least one stream to attach to")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do not allow stdin on containers without Stdin set
|
// Do not allow stdin on containers without Stdin set
|
||||||
// Conmon was not configured properly
|
// Conmon was not configured properly
|
||||||
if inputStream != nil && !c.config.Stdin {
|
if streams.AttachInput && !c.config.Stdin {
|
||||||
return errors.Wrapf(ErrInvalidArg, "this container was not created as interactive, cannot attach stdin")
|
return errors.Wrapf(ErrInvalidArg, "this container was not created as interactive, cannot attach stdin")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,12 +67,12 @@ func (c *Container) attach(outputStream, errorStream io.WriteCloser, inputStream
|
|||||||
|
|
||||||
logrus.Debugf("Attaching to container %s", c.ID())
|
logrus.Debugf("Attaching to container %s", c.ID())
|
||||||
|
|
||||||
return c.attachContainerSocket(resize, detachKeys, outputStream, errorStream, inputStream)
|
return c.attachContainerSocket(resize, detachKeys, streams)
|
||||||
}
|
}
|
||||||
|
|
||||||
// attachContainerSocket connects to the container's attach socket and deals with the IO
|
// attachContainerSocket connects to the container's attach socket and deals with the IO
|
||||||
// TODO add a channel to allow interruptiong
|
// TODO add a channel to allow interruptiong
|
||||||
func (c *Container) attachContainerSocket(resize <-chan remotecommand.TerminalSize, detachKeys []byte, outputStream, errorStream io.WriteCloser, inputStream io.Reader) error {
|
func (c *Container) attachContainerSocket(resize <-chan remotecommand.TerminalSize, detachKeys []byte, streams *AttachStreams) error {
|
||||||
kubeutils.HandleResizing(resize, func(size remotecommand.TerminalSize) {
|
kubeutils.HandleResizing(resize, func(size remotecommand.TerminalSize) {
|
||||||
controlPath := filepath.Join(c.bundlePath(), "ctl")
|
controlPath := filepath.Join(c.bundlePath(), "ctl")
|
||||||
controlFile, err := os.OpenFile(controlPath, unix.O_WRONLY, 0)
|
controlFile, err := os.OpenFile(controlPath, unix.O_WRONLY, 0)
|
||||||
@ -77,17 +96,17 @@ func (c *Container) attachContainerSocket(resize <-chan remotecommand.TerminalSi
|
|||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
receiveStdoutError := make(chan error)
|
receiveStdoutError := make(chan error)
|
||||||
if outputStream != nil || errorStream != nil {
|
if streams.AttachOutput || streams.AttachError {
|
||||||
go func() {
|
go func() {
|
||||||
receiveStdoutError <- redirectResponseToOutputStreams(outputStream, errorStream, conn)
|
receiveStdoutError <- redirectResponseToOutputStreams(streams.OutputStream, streams.ErrorStream, conn)
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
stdinDone := make(chan error)
|
stdinDone := make(chan error)
|
||||||
go func() {
|
go func() {
|
||||||
var err error
|
var err error
|
||||||
if inputStream != nil {
|
if streams.AttachInput {
|
||||||
_, err = utils.CopyDetachable(conn, inputStream, detachKeys)
|
_, err = utils.CopyDetachable(conn, streams.InputStream, detachKeys)
|
||||||
conn.CloseWrite()
|
conn.CloseWrite()
|
||||||
}
|
}
|
||||||
stdinDone <- err
|
stdinDone <- err
|
||||||
@ -100,7 +119,7 @@ func (c *Container) attachContainerSocket(resize <-chan remotecommand.TerminalSi
|
|||||||
if _, ok := err.(utils.DetachError); ok {
|
if _, ok := err.(utils.DetachError); ok {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if outputStream != nil || errorStream != nil {
|
if streams.AttachOutput || streams.AttachError {
|
||||||
return <-receiveStdoutError
|
return <-receiveStdoutError
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user