remove execCreate & execStart from job
| ... | ... |
@@ -32,9 +32,6 @@ func (cli *DockerCli) CmdExec(args ...string) error {
|
| 32 | 32 |
if err := json.NewDecoder(stream).Decode(&response); err != nil {
|
| 33 | 33 |
return err |
| 34 | 34 |
} |
| 35 |
- for _, warning := range response.Warnings {
|
|
| 36 |
- fmt.Fprintf(cli.err, "WARNING: %s\n", warning) |
|
| 37 |
- } |
|
| 38 | 35 |
|
| 39 | 36 |
execID := response.ID |
| 40 | 37 |
|
| ... | ... |
@@ -43,12 +40,18 @@ func (cli *DockerCli) CmdExec(args ...string) error {
|
| 43 | 43 |
return nil |
| 44 | 44 |
} |
| 45 | 45 |
|
| 46 |
+ //Temp struct for execStart so that we don't need to transfer all the execConfig |
|
| 47 |
+ execStartCheck := &types.ExecStartCheck{
|
|
| 48 |
+ Detach: execConfig.Detach, |
|
| 49 |
+ Tty: execConfig.Tty, |
|
| 50 |
+ } |
|
| 51 |
+ |
|
| 46 | 52 |
if !execConfig.Detach {
|
| 47 | 53 |
if err := cli.CheckTtyInput(execConfig.AttachStdin, execConfig.Tty); err != nil {
|
| 48 | 54 |
return err |
| 49 | 55 |
} |
| 50 | 56 |
} else {
|
| 51 |
- if _, _, err := readBody(cli.call("POST", "/exec/"+execID+"/start", execConfig, nil)); err != nil {
|
|
| 57 |
+ if _, _, err := readBody(cli.call("POST", "/exec/"+execID+"/start", execStartCheck, nil)); err != nil {
|
|
| 52 | 58 |
return err |
| 53 | 59 |
} |
| 54 | 60 |
// For now don't print this - wait for when we support exec wait() |
| ... | ... |
@@ -1,8 +1,6 @@ |
| 1 | 1 |
package server |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
- "bufio" |
|
| 5 |
- "bytes" |
|
| 6 | 4 |
"runtime" |
| 7 | 5 |
"time" |
| 8 | 6 |
|
| ... | ... |
@@ -1393,35 +1391,27 @@ func (s *Server) postContainerExecCreate(eng *engine.Engine, version version.Ver |
| 1393 | 1393 |
if err := parseForm(r); err != nil {
|
| 1394 | 1394 |
return nil |
| 1395 | 1395 |
} |
| 1396 |
- var ( |
|
| 1397 |
- name = vars["name"] |
|
| 1398 |
- job = eng.Job("execCreate", name)
|
|
| 1399 |
- stdoutBuffer = bytes.NewBuffer(nil) |
|
| 1400 |
- outWarnings []string |
|
| 1401 |
- warnings = bytes.NewBuffer(nil) |
|
| 1402 |
- ) |
|
| 1396 |
+ name := vars["name"] |
|
| 1403 | 1397 |
|
| 1404 |
- if err := job.DecodeEnv(r.Body); err != nil {
|
|
| 1398 |
+ execConfig := &runconfig.ExecConfig{}
|
|
| 1399 |
+ if err := json.NewDecoder(r.Body).Decode(execConfig); err != nil {
|
|
| 1405 | 1400 |
return err |
| 1406 | 1401 |
} |
| 1402 |
+ execConfig.Container = name |
|
| 1403 |
+ |
|
| 1404 |
+ if len(execConfig.Cmd) == 0 {
|
|
| 1405 |
+ return fmt.Errorf("No exec command specified")
|
|
| 1406 |
+ } |
|
| 1407 | 1407 |
|
| 1408 |
- job.Stdout.Add(stdoutBuffer) |
|
| 1409 |
- // Read warnings from stderr |
|
| 1410 |
- job.Stderr.Add(warnings) |
|
| 1411 | 1408 |
// Register an instance of Exec in container. |
| 1412 |
- if err := job.Run(); err != nil {
|
|
| 1413 |
- fmt.Fprintf(os.Stderr, "Error setting up exec command in container %s: %s\n", name, err) |
|
| 1409 |
+ id, err := s.daemon.ContainerExecCreate(execConfig) |
|
| 1410 |
+ if err != nil {
|
|
| 1411 |
+ logrus.Errorf("Error setting up exec command in container %s: %s", name, err)
|
|
| 1414 | 1412 |
return err |
| 1415 | 1413 |
} |
| 1416 |
- // Parse warnings from stderr |
|
| 1417 |
- scanner := bufio.NewScanner(warnings) |
|
| 1418 |
- for scanner.Scan() {
|
|
| 1419 |
- outWarnings = append(outWarnings, scanner.Text()) |
|
| 1420 |
- } |
|
| 1421 | 1414 |
|
| 1422 | 1415 |
return writeJSON(w, http.StatusCreated, &types.ContainerExecCreateResponse{
|
| 1423 |
- ID: engine.Tail(stdoutBuffer, 1), |
|
| 1424 |
- Warnings: outWarnings, |
|
| 1416 |
+ ID: id, |
|
| 1425 | 1417 |
}) |
| 1426 | 1418 |
} |
| 1427 | 1419 |
|
| ... | ... |
@@ -1431,15 +1421,18 @@ func (s *Server) postContainerExecStart(eng *engine.Engine, version version.Vers |
| 1431 | 1431 |
return nil |
| 1432 | 1432 |
} |
| 1433 | 1433 |
var ( |
| 1434 |
- name = vars["name"] |
|
| 1435 |
- job = eng.Job("execStart", name)
|
|
| 1436 |
- errOut io.Writer = os.Stderr |
|
| 1434 |
+ execName = vars["name"] |
|
| 1435 |
+ stdin io.ReadCloser |
|
| 1436 |
+ stdout io.Writer |
|
| 1437 |
+ stderr io.Writer |
|
| 1437 | 1438 |
) |
| 1438 | 1439 |
|
| 1439 |
- if err := job.DecodeEnv(r.Body); err != nil {
|
|
| 1440 |
+ execStartCheck := &types.ExecStartCheck{}
|
|
| 1441 |
+ if err := json.NewDecoder(r.Body).Decode(execStartCheck); err != nil {
|
|
| 1440 | 1442 |
return err |
| 1441 | 1443 |
} |
| 1442 |
- if !job.GetenvBool("Detach") {
|
|
| 1444 |
+ |
|
| 1445 |
+ if !execStartCheck.Detach {
|
|
| 1443 | 1446 |
// Setting up the streaming http interface. |
| 1444 | 1447 |
inStream, outStream, err := hijackServer(w) |
| 1445 | 1448 |
if err != nil {
|
| ... | ... |
@@ -1455,21 +1448,20 @@ func (s *Server) postContainerExecStart(eng *engine.Engine, version version.Vers |
| 1455 | 1455 |
fmt.Fprintf(outStream, "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n\r\n") |
| 1456 | 1456 |
} |
| 1457 | 1457 |
|
| 1458 |
- if !job.GetenvBool("Tty") && version.GreaterThanOrEqualTo("1.6") {
|
|
| 1458 |
+ if !execStartCheck.Tty && version.GreaterThanOrEqualTo("1.6") {
|
|
| 1459 | 1459 |
errStream = stdcopy.NewStdWriter(outStream, stdcopy.Stderr) |
| 1460 | 1460 |
outStream = stdcopy.NewStdWriter(outStream, stdcopy.Stdout) |
| 1461 | 1461 |
} else {
|
| 1462 | 1462 |
errStream = outStream |
| 1463 | 1463 |
} |
| 1464 |
- job.Stdin.Add(inStream) |
|
| 1465 |
- job.Stdout.Add(outStream) |
|
| 1466 |
- job.Stderr.Set(errStream) |
|
| 1467 |
- errOut = outStream |
|
| 1464 |
+ stdin = inStream |
|
| 1465 |
+ stdout = outStream |
|
| 1466 |
+ stderr = errStream |
|
| 1468 | 1467 |
} |
| 1469 | 1468 |
// Now run the user process in container. |
| 1470 |
- job.SetCloseIO(false) |
|
| 1471 |
- if err := job.Run(); err != nil {
|
|
| 1472 |
- fmt.Fprintf(errOut, "Error starting exec command in container %s: %s\n", name, err) |
|
| 1469 |
+ |
|
| 1470 |
+ if err := s.daemon.ContainerExecStart(execName, stdin, stdout, stderr); err != nil {
|
|
| 1471 |
+ logrus.Errorf("Error starting exec command in container %s: %s", execName, err)
|
|
| 1473 | 1472 |
return err |
| 1474 | 1473 |
} |
| 1475 | 1474 |
w.WriteHeader(http.StatusNoContent) |
| ... | ... |
@@ -16,9 +16,6 @@ type ContainerCreateResponse struct {
|
| 16 | 16 |
type ContainerExecCreateResponse struct {
|
| 17 | 17 |
// ID is the exec ID. |
| 18 | 18 |
ID string `json:"Id"` |
| 19 |
- |
|
| 20 |
- // Warnings are any warnings encountered during the execution of the command. |
|
| 21 |
- Warnings []string `json:"Warnings"` |
|
| 22 | 19 |
} |
| 23 | 20 |
|
| 24 | 21 |
// POST /auth |
| ... | ... |
@@ -156,3 +153,12 @@ type Info struct {
|
| 156 | 156 |
Name string |
| 157 | 157 |
Labels []string |
| 158 | 158 |
} |
| 159 |
+ |
|
| 160 |
+// This struct is a temp struct used by execStart |
|
| 161 |
+// Config fields is part of ExecConfig in runconfig package |
|
| 162 |
+type ExecStartCheck struct {
|
|
| 163 |
+ // ExecStart will first check if it's detached |
|
| 164 |
+ Detach bool |
|
| 165 |
+ // Check if there's a tty |
|
| 166 |
+ Tty bool |
|
| 167 |
+} |
| ... | ... |
@@ -118,8 +118,6 @@ type Daemon struct {
|
| 118 | 118 |
func (daemon *Daemon) Install(eng *engine.Engine) error {
|
| 119 | 119 |
for name, method := range map[string]engine.Handler{
|
| 120 | 120 |
"container_inspect": daemon.ContainerInspect, |
| 121 |
- "execCreate": daemon.ContainerExecCreate, |
|
| 122 |
- "execStart": daemon.ContainerExecStart, |
|
| 123 | 121 |
} {
|
| 124 | 122 |
if err := eng.Register(name, method); err != nil {
|
| 125 | 123 |
return err |
| ... | ... |
@@ -10,7 +10,6 @@ import ( |
| 10 | 10 |
"github.com/Sirupsen/logrus" |
| 11 | 11 |
"github.com/docker/docker/daemon/execdriver" |
| 12 | 12 |
"github.com/docker/docker/daemon/execdriver/lxc" |
| 13 |
- "github.com/docker/docker/engine" |
|
| 14 | 13 |
"github.com/docker/docker/pkg/broadcastwriter" |
| 15 | 14 |
"github.com/docker/docker/pkg/ioutils" |
| 16 | 15 |
"github.com/docker/docker/pkg/promise" |
| ... | ... |
@@ -111,25 +110,15 @@ func (d *Daemon) getActiveContainer(name string) (*Container, error) {
|
| 111 | 111 |
return container, nil |
| 112 | 112 |
} |
| 113 | 113 |
|
| 114 |
-func (d *Daemon) ContainerExecCreate(job *engine.Job) error {
|
|
| 115 |
- if len(job.Args) != 1 {
|
|
| 116 |
- return fmt.Errorf("Usage: %s [options] container command [args]", job.Name)
|
|
| 117 |
- } |
|
| 114 |
+func (d *Daemon) ContainerExecCreate(config *runconfig.ExecConfig) (string, error) {
|
|
| 118 | 115 |
|
| 119 | 116 |
if strings.HasPrefix(d.execDriver.Name(), lxc.DriverName) {
|
| 120 |
- return lxc.ErrExec |
|
| 117 |
+ return "", lxc.ErrExec |
|
| 121 | 118 |
} |
| 122 | 119 |
|
| 123 |
- var name = job.Args[0] |
|
| 124 |
- |
|
| 125 |
- container, err := d.getActiveContainer(name) |
|
| 120 |
+ container, err := d.getActiveContainer(config.Container) |
|
| 126 | 121 |
if err != nil {
|
| 127 |
- return err |
|
| 128 |
- } |
|
| 129 |
- |
|
| 130 |
- config, err := runconfig.ExecConfigFromJob(job) |
|
| 131 |
- if err != nil {
|
|
| 132 |
- return err |
|
| 122 |
+ return "", err |
|
| 133 | 123 |
} |
| 134 | 124 |
|
| 135 | 125 |
cmd := runconfig.NewCommand(config.Cmd...) |
| ... | ... |
@@ -158,20 +147,15 @@ func (d *Daemon) ContainerExecCreate(job *engine.Job) error {
|
| 158 | 158 |
|
| 159 | 159 |
d.registerExecCommand(execConfig) |
| 160 | 160 |
|
| 161 |
- job.Printf("%s\n", execConfig.ID)
|
|
| 161 |
+ return execConfig.ID, nil |
|
| 162 | 162 |
|
| 163 |
- return nil |
|
| 164 | 163 |
} |
| 165 | 164 |
|
| 166 |
-func (d *Daemon) ContainerExecStart(job *engine.Job) error {
|
|
| 167 |
- if len(job.Args) != 1 {
|
|
| 168 |
- return fmt.Errorf("Usage: %s [options] exec", job.Name)
|
|
| 169 |
- } |
|
| 165 |
+func (d *Daemon) ContainerExecStart(execName string, stdin io.ReadCloser, stdout io.Writer, stderr io.Writer) error {
|
|
| 170 | 166 |
|
| 171 | 167 |
var ( |
| 172 | 168 |
cStdin io.ReadCloser |
| 173 | 169 |
cStdout, cStderr io.Writer |
| 174 |
- execName = job.Args[0] |
|
| 175 | 170 |
) |
| 176 | 171 |
|
| 177 | 172 |
execConfig, err := d.getExecConfig(execName) |
| ... | ... |
@@ -201,15 +185,15 @@ func (d *Daemon) ContainerExecStart(job *engine.Job) error {
|
| 201 | 201 |
go func() {
|
| 202 | 202 |
defer w.Close() |
| 203 | 203 |
defer logrus.Debugf("Closing buffered stdin pipe")
|
| 204 |
- io.Copy(w, job.Stdin) |
|
| 204 |
+ io.Copy(w, stdin) |
|
| 205 | 205 |
}() |
| 206 | 206 |
cStdin = r |
| 207 | 207 |
} |
| 208 | 208 |
if execConfig.OpenStdout {
|
| 209 |
- cStdout = job.Stdout |
|
| 209 |
+ cStdout = stdout |
|
| 210 | 210 |
} |
| 211 | 211 |
if execConfig.OpenStderr {
|
| 212 |
- cStderr = job.Stderr |
|
| 212 |
+ cStderr = stderr |
|
| 213 | 213 |
} |
| 214 | 214 |
|
| 215 | 215 |
execConfig.StreamConfig.stderr = broadcastwriter.New() |
| ... | ... |
@@ -1,9 +1,6 @@ |
| 1 | 1 |
package runconfig |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
- "fmt" |
|
| 5 |
- |
|
| 6 |
- "github.com/docker/docker/engine" |
|
| 7 | 4 |
flag "github.com/docker/docker/pkg/mflag" |
| 8 | 5 |
) |
| 9 | 6 |
|
| ... | ... |
@@ -19,25 +16,6 @@ type ExecConfig struct {
|
| 19 | 19 |
Cmd []string |
| 20 | 20 |
} |
| 21 | 21 |
|
| 22 |
-func ExecConfigFromJob(job *engine.Job) (*ExecConfig, error) {
|
|
| 23 |
- execConfig := &ExecConfig{
|
|
| 24 |
- User: job.Getenv("User"),
|
|
| 25 |
- Privileged: job.GetenvBool("Privileged"),
|
|
| 26 |
- Tty: job.GetenvBool("Tty"),
|
|
| 27 |
- AttachStdin: job.GetenvBool("AttachStdin"),
|
|
| 28 |
- AttachStderr: job.GetenvBool("AttachStderr"),
|
|
| 29 |
- AttachStdout: job.GetenvBool("AttachStdout"),
|
|
| 30 |
- } |
|
| 31 |
- cmd := job.GetenvList("Cmd")
|
|
| 32 |
- if len(cmd) == 0 {
|
|
| 33 |
- return nil, fmt.Errorf("No exec command specified")
|
|
| 34 |
- } |
|
| 35 |
- |
|
| 36 |
- execConfig.Cmd = cmd |
|
| 37 |
- |
|
| 38 |
- return execConfig, nil |
|
| 39 |
-} |
|
| 40 |
- |
|
| 41 | 22 |
func ParseExec(cmd *flag.FlagSet, args []string) (*ExecConfig, error) {
|
| 42 | 23 |
var ( |
| 43 | 24 |
flStdin = cmd.Bool([]string{"i", "-interactive"}, false, "Keep STDIN open even if not attached")
|