diff --git a/api/client/exec.go b/api/client/exec.go index 23545ae9bf..4bf53eaec2 100644 --- a/api/client/exec.go +++ b/api/client/exec.go @@ -32,9 +32,6 @@ func (cli *DockerCli) CmdExec(args ...string) error { if err := json.NewDecoder(stream).Decode(&response); err != nil { return err } - for _, warning := range response.Warnings { - fmt.Fprintf(cli.err, "WARNING: %s\n", warning) - } execID := response.ID @@ -43,12 +40,18 @@ func (cli *DockerCli) CmdExec(args ...string) error { return nil } + //Temp struct for execStart so that we don't need to transfer all the execConfig + execStartCheck := &types.ExecStartCheck{ + Detach: execConfig.Detach, + Tty: execConfig.Tty, + } + if !execConfig.Detach { if err := cli.CheckTtyInput(execConfig.AttachStdin, execConfig.Tty); err != nil { return err } } else { - if _, _, err := readBody(cli.call("POST", "/exec/"+execID+"/start", execConfig, nil)); err != nil { + if _, _, err := readBody(cli.call("POST", "/exec/"+execID+"/start", execStartCheck, nil)); err != nil { return err } // For now don't print this - wait for when we support exec wait() diff --git a/api/server/server.go b/api/server/server.go index 6e1f35a4bf..6deb88f827 100644 --- a/api/server/server.go +++ b/api/server/server.go @@ -1,8 +1,6 @@ package server import ( - "bufio" - "bytes" "runtime" "time" @@ -1393,35 +1391,27 @@ func (s *Server) postContainerExecCreate(eng *engine.Engine, version version.Ver if err := parseForm(r); err != nil { return nil } - var ( - name = vars["name"] - job = eng.Job("execCreate", name) - stdoutBuffer = bytes.NewBuffer(nil) - outWarnings []string - warnings = bytes.NewBuffer(nil) - ) + name := vars["name"] - if err := job.DecodeEnv(r.Body); err != nil { + execConfig := &runconfig.ExecConfig{} + if err := json.NewDecoder(r.Body).Decode(execConfig); err != nil { return err } + execConfig.Container = name + + if len(execConfig.Cmd) == 0 { + return fmt.Errorf("No exec command specified") + } - job.Stdout.Add(stdoutBuffer) - // Read warnings from stderr - job.Stderr.Add(warnings) // Register an instance of Exec in container. - if err := job.Run(); err != nil { - fmt.Fprintf(os.Stderr, "Error setting up exec command in container %s: %s\n", name, err) + id, err := s.daemon.ContainerExecCreate(execConfig) + if err != nil { + logrus.Errorf("Error setting up exec command in container %s: %s", name, err) return err } - // Parse warnings from stderr - scanner := bufio.NewScanner(warnings) - for scanner.Scan() { - outWarnings = append(outWarnings, scanner.Text()) - } return writeJSON(w, http.StatusCreated, &types.ContainerExecCreateResponse{ - ID: engine.Tail(stdoutBuffer, 1), - Warnings: outWarnings, + ID: id, }) } @@ -1431,15 +1421,18 @@ func (s *Server) postContainerExecStart(eng *engine.Engine, version version.Vers return nil } var ( - name = vars["name"] - job = eng.Job("execStart", name) - errOut io.Writer = os.Stderr + execName = vars["name"] + stdin io.ReadCloser + stdout io.Writer + stderr io.Writer ) - if err := job.DecodeEnv(r.Body); err != nil { + execStartCheck := &types.ExecStartCheck{} + if err := json.NewDecoder(r.Body).Decode(execStartCheck); err != nil { return err } - if !job.GetenvBool("Detach") { + + if !execStartCheck.Detach { // Setting up the streaming http interface. inStream, outStream, err := hijackServer(w) if err != nil { @@ -1455,21 +1448,20 @@ func (s *Server) postContainerExecStart(eng *engine.Engine, version version.Vers fmt.Fprintf(outStream, "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n\r\n") } - if !job.GetenvBool("Tty") && version.GreaterThanOrEqualTo("1.6") { + if !execStartCheck.Tty && version.GreaterThanOrEqualTo("1.6") { errStream = stdcopy.NewStdWriter(outStream, stdcopy.Stderr) outStream = stdcopy.NewStdWriter(outStream, stdcopy.Stdout) } else { errStream = outStream } - job.Stdin.Add(inStream) - job.Stdout.Add(outStream) - job.Stderr.Set(errStream) - errOut = outStream + stdin = inStream + stdout = outStream + stderr = errStream } // Now run the user process in container. - job.SetCloseIO(false) - if err := job.Run(); err != nil { - fmt.Fprintf(errOut, "Error starting exec command in container %s: %s\n", name, err) + + if err := s.daemon.ContainerExecStart(execName, stdin, stdout, stderr); err != nil { + logrus.Errorf("Error starting exec command in container %s: %s", execName, err) return err } w.WriteHeader(http.StatusNoContent) diff --git a/api/types/types.go b/api/types/types.go index 01b5d38f1f..1e8b56bcef 100644 --- a/api/types/types.go +++ b/api/types/types.go @@ -16,9 +16,6 @@ type ContainerCreateResponse struct { type ContainerExecCreateResponse struct { // ID is the exec ID. ID string `json:"Id"` - - // Warnings are any warnings encountered during the execution of the command. - Warnings []string `json:"Warnings"` } // POST /auth @@ -156,3 +153,12 @@ type Info struct { Name string Labels []string } + +// This struct is a temp struct used by execStart +// Config fields is part of ExecConfig in runconfig package +type ExecStartCheck struct { + // ExecStart will first check if it's detached + Detach bool + // Check if there's a tty + Tty bool +} diff --git a/daemon/daemon.go b/daemon/daemon.go index c643ed65c6..ca3aff3e28 100644 --- a/daemon/daemon.go +++ b/daemon/daemon.go @@ -118,8 +118,6 @@ type Daemon struct { func (daemon *Daemon) Install(eng *engine.Engine) error { for name, method := range map[string]engine.Handler{ "container_inspect": daemon.ContainerInspect, - "execCreate": daemon.ContainerExecCreate, - "execStart": daemon.ContainerExecStart, } { if err := eng.Register(name, method); err != nil { return err diff --git a/daemon/exec.go b/daemon/exec.go index 4787189a77..22872adc44 100644 --- a/daemon/exec.go +++ b/daemon/exec.go @@ -10,7 +10,6 @@ import ( "github.com/Sirupsen/logrus" "github.com/docker/docker/daemon/execdriver" "github.com/docker/docker/daemon/execdriver/lxc" - "github.com/docker/docker/engine" "github.com/docker/docker/pkg/broadcastwriter" "github.com/docker/docker/pkg/ioutils" "github.com/docker/docker/pkg/promise" @@ -111,25 +110,15 @@ func (d *Daemon) getActiveContainer(name string) (*Container, error) { return container, nil } -func (d *Daemon) ContainerExecCreate(job *engine.Job) error { - if len(job.Args) != 1 { - return fmt.Errorf("Usage: %s [options] container command [args]", job.Name) - } +func (d *Daemon) ContainerExecCreate(config *runconfig.ExecConfig) (string, error) { if strings.HasPrefix(d.execDriver.Name(), lxc.DriverName) { - return lxc.ErrExec + return "", lxc.ErrExec } - var name = job.Args[0] - - container, err := d.getActiveContainer(name) + container, err := d.getActiveContainer(config.Container) if err != nil { - return err - } - - config, err := runconfig.ExecConfigFromJob(job) - if err != nil { - return err + return "", err } cmd := runconfig.NewCommand(config.Cmd...) @@ -158,20 +147,15 @@ func (d *Daemon) ContainerExecCreate(job *engine.Job) error { d.registerExecCommand(execConfig) - job.Printf("%s\n", execConfig.ID) + return execConfig.ID, nil - return nil } -func (d *Daemon) ContainerExecStart(job *engine.Job) error { - if len(job.Args) != 1 { - return fmt.Errorf("Usage: %s [options] exec", job.Name) - } +func (d *Daemon) ContainerExecStart(execName string, stdin io.ReadCloser, stdout io.Writer, stderr io.Writer) error { var ( cStdin io.ReadCloser cStdout, cStderr io.Writer - execName = job.Args[0] ) execConfig, err := d.getExecConfig(execName) @@ -201,15 +185,15 @@ func (d *Daemon) ContainerExecStart(job *engine.Job) error { go func() { defer w.Close() defer logrus.Debugf("Closing buffered stdin pipe") - io.Copy(w, job.Stdin) + io.Copy(w, stdin) }() cStdin = r } if execConfig.OpenStdout { - cStdout = job.Stdout + cStdout = stdout } if execConfig.OpenStderr { - cStderr = job.Stderr + cStderr = stderr } execConfig.StreamConfig.stderr = broadcastwriter.New() diff --git a/runconfig/exec.go b/runconfig/exec.go index e634d30813..8fe05be1bb 100644 --- a/runconfig/exec.go +++ b/runconfig/exec.go @@ -1,9 +1,6 @@ package runconfig import ( - "fmt" - - "github.com/docker/docker/engine" flag "github.com/docker/docker/pkg/mflag" ) @@ -19,25 +16,6 @@ type ExecConfig struct { Cmd []string } -func ExecConfigFromJob(job *engine.Job) (*ExecConfig, error) { - execConfig := &ExecConfig{ - User: job.Getenv("User"), - Privileged: job.GetenvBool("Privileged"), - Tty: job.GetenvBool("Tty"), - AttachStdin: job.GetenvBool("AttachStdin"), - AttachStderr: job.GetenvBool("AttachStderr"), - AttachStdout: job.GetenvBool("AttachStdout"), - } - cmd := job.GetenvList("Cmd") - if len(cmd) == 0 { - return nil, fmt.Errorf("No exec command specified") - } - - execConfig.Cmd = cmd - - return execConfig, nil -} - func ParseExec(cmd *flag.FlagSet, args []string) (*ExecConfig, error) { var ( flStdin = cmd.Bool([]string{"i", "-interactive"}, false, "Keep STDIN open even if not attached")