1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

docker run [-a [stdin|stdout|stderr] [...]]: choose which streams to attach to when running a command. Fixes #234.

This commit is contained in:
Solomon Hykes 2013-04-02 18:07:16 -07:00
parent c77063afcd
commit c04af2a330
2 changed files with 87 additions and 40 deletions

View file

@ -827,6 +827,33 @@ func (opts *ListOpts) Set(value string) error {
return nil return nil
} }
// AttachOpts stores arguments to 'docker run -a', eg. which streams to attach to
type AttachOpts map[string]bool
func NewAttachOpts() *AttachOpts {
opts := make(map[string]bool)
return (*AttachOpts)(&opts)
}
func (opts *AttachOpts) String() string {
return fmt.Sprint(*opts)
}
func (opts *AttachOpts) Set(val string) error {
if val != "stdin" && val != "stdout" && val != "stderr" {
return fmt.Errorf("Unsupported stream name: %s", val)
}
(*opts)[val] = true
return nil
}
func (opts *AttachOpts) Get(val string) bool {
if res, exists := (*opts)[val]; exists {
return res
}
return false
}
func (srv *Server) CmdTag(stdin io.ReadCloser, stdout io.Writer, args ...string) error { func (srv *Server) CmdTag(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
cmd := rcli.Subcmd(stdout, "tag", "[OPTIONS] IMAGE REPOSITORY [TAG]", "Tag an image into a repository") cmd := rcli.Subcmd(stdout, "tag", "[OPTIONS] IMAGE REPOSITORY [TAG]", "Tag an image into a repository")
force := cmd.Bool("f", false, "Force") force := cmd.Bool("f", false, "Force")
@ -870,28 +897,29 @@ func (srv *Server) CmdRun(stdin io.ReadCloser, stdout io.Writer, args ...string)
return err return err
} }
} }
// Run the container var (
if !config.Detach { cStdin io.Reader
var attachErr chan error cStdout, cStderr io.Writer
if config.OpenStdin { )
Debugf("Attaching with stdin\n") if config.AttachStdin {
attachErr = container.Attach(stdin, stdout, stdout) cStdin = stdin
} else {
Debugf("Attaching without stdin\n")
attachErr = container.Attach(nil, stdout, nil)
}
Debugf("Starting\n")
if err := container.Start(); err != nil {
return err
}
Debugf("Waiting for attach to return\n")
return <-attachErr
} }
if config.AttachStdout {
cStdout = stdout
}
if config.AttachStderr {
cStderr = stdout // FIXME: rcli can't differentiate stdout from stderr
}
attachErr := container.Attach(cStdin, cStdout, cStderr)
Debugf("Starting\n")
if err := container.Start(); err != nil { if err := container.Start(); err != nil {
return err return err
} }
fmt.Fprintln(stdout, container.ShortId()) if cStdout == nil && cStderr == nil {
return nil fmt.Fprintln(stdout, container.ShortId())
}
Debugf("Waiting for attach to return\n")
return <-attachErr
} }
func NewServer() (*Server, error) { func NewServer() (*Server, error) {

View file

@ -48,18 +48,20 @@ type Container struct {
} }
type Config struct { type Config struct {
Hostname string Hostname string
User string User string
Memory int64 // Memory limit (in bytes) Memory int64 // Memory limit (in bytes)
MemorySwap int64 // Total memory usage (memory + swap); set `-1' to disable swap MemorySwap int64 // Total memory usage (memory + swap); set `-1' to disable swap
Detach bool AttachStdin bool
Ports []int AttachStdout bool
Tty bool // Attach standard streams to a tty, including stdin if it is not closed. AttachStderr bool
OpenStdin bool // Open stdin Ports []int
StdinOnce bool // If true, close stdin after the 1 attached client disconnects. Tty bool // Attach standard streams to a tty, including stdin if it is not closed.
Env []string OpenStdin bool // Open stdin
Cmd []string StdinOnce bool // If true, close stdin after the 1 attached client disconnects.
Image string // Name of the image as it was passed by the operator (eg. could be symbolic) Env []string
Cmd []string
Image string // Name of the image as it was passed by the operator (eg. could be symbolic)
} }
func ParseRun(args []string, stdout io.Writer) (*Config, error) { func ParseRun(args []string, stdout io.Writer) (*Config, error) {
@ -70,6 +72,8 @@ func ParseRun(args []string, stdout io.Writer) (*Config, error) {
flUser := cmd.String("u", "", "Username or UID") flUser := cmd.String("u", "", "Username or UID")
flDetach := cmd.Bool("d", false, "Detached mode: leave the container running in the background") flDetach := cmd.Bool("d", false, "Detached mode: leave the container running in the background")
flAttach := NewAttachOpts()
cmd.Var(flAttach, "a", "Attach to stdin, stdout or stderr.")
flStdin := cmd.Bool("i", false, "Keep stdin open even if not attached") flStdin := cmd.Bool("i", false, "Keep stdin open even if not attached")
flTty := cmd.Bool("t", false, "Allocate a pseudo-tty") flTty := cmd.Bool("t", false, "Allocate a pseudo-tty")
flMemory := cmd.Int64("m", 0, "Memory limit (in bytes)") flMemory := cmd.Int64("m", 0, "Memory limit (in bytes)")
@ -81,6 +85,19 @@ func ParseRun(args []string, stdout io.Writer) (*Config, error) {
if err := cmd.Parse(args); err != nil { if err := cmd.Parse(args); err != nil {
return nil, err return nil, err
} }
if *flDetach && len(*flAttach) > 0 {
return nil, fmt.Errorf("Conflicting options: -a and -d")
}
// If neither -d or -a are set, attach to everything by default
if len(*flAttach) == 0 && !*flDetach {
if !*flDetach {
flAttach.Set("stdout")
flAttach.Set("stderr")
if *flStdin {
flAttach.Set("stdin")
}
}
}
parsedArgs := cmd.Args() parsedArgs := cmd.Args()
runCmd := []string{} runCmd := []string{}
image := "" image := ""
@ -91,18 +108,20 @@ func ParseRun(args []string, stdout io.Writer) (*Config, error) {
runCmd = parsedArgs[1:] runCmd = parsedArgs[1:]
} }
config := &Config{ config := &Config{
Ports: flPorts, Ports: flPorts,
User: *flUser, User: *flUser,
Tty: *flTty, Tty: *flTty,
OpenStdin: *flStdin, OpenStdin: *flStdin,
Memory: *flMemory, Memory: *flMemory,
Detach: *flDetach, AttachStdin: flAttach.Get("stdin"),
Env: flEnv, AttachStdout: flAttach.Get("stdout"),
Cmd: runCmd, AttachStderr: flAttach.Get("stderr"),
Image: image, Env: flEnv,
Cmd: runCmd,
Image: image,
} }
// When allocating stdin in attached mode, close stdin at client disconnect // When allocating stdin in attached mode, close stdin at client disconnect
if config.OpenStdin && !config.Detach { if config.OpenStdin && config.AttachStdin {
config.StdinOnce = true config.StdinOnce = true
} }
return config, nil return config, nil