github.com/ncdc/docker@v0.10.1-0.20160129113957-6c6729ef5b74/api/server/router/container/exec.go (about) 1 package container 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "io" 7 "net/http" 8 "strconv" 9 10 "github.com/Sirupsen/logrus" 11 "github.com/docker/docker/api/server/httputils" 12 "github.com/docker/docker/pkg/stdcopy" 13 "github.com/docker/docker/utils" 14 "github.com/docker/engine-api/types" 15 "golang.org/x/net/context" 16 ) 17 18 func (s *containerRouter) getExecByID(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 19 eConfig, err := s.backend.ContainerExecInspect(vars["id"]) 20 if err != nil { 21 return err 22 } 23 24 return httputils.WriteJSON(w, http.StatusOK, eConfig) 25 } 26 27 func (s *containerRouter) postContainerExecCreate(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 28 if err := httputils.ParseForm(r); err != nil { 29 return err 30 } 31 if err := httputils.CheckForJSON(r); err != nil { 32 return err 33 } 34 name := vars["name"] 35 36 execConfig := &types.ExecConfig{} 37 if err := json.NewDecoder(r.Body).Decode(execConfig); err != nil { 38 return err 39 } 40 execConfig.Container = name 41 42 if len(execConfig.Cmd) == 0 { 43 return fmt.Errorf("No exec command specified") 44 } 45 46 // Register an instance of Exec in container. 47 id, err := s.backend.ContainerExecCreate(execConfig) 48 if err != nil { 49 logrus.Errorf("Error setting up exec command in container %s: %s", name, utils.GetErrorMessage(err)) 50 return err 51 } 52 53 return httputils.WriteJSON(w, http.StatusCreated, &types.ContainerExecCreateResponse{ 54 ID: id, 55 }) 56 } 57 58 // TODO(vishh): Refactor the code to avoid having to specify stream config as part of both create and start. 59 func (s *containerRouter) postContainerExecStart(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 60 if err := httputils.ParseForm(r); err != nil { 61 return err 62 } 63 64 version := httputils.VersionFromContext(ctx) 65 if version.GreaterThan("1.21") { 66 if err := httputils.CheckForJSON(r); err != nil { 67 return err 68 } 69 } 70 71 var ( 72 execName = vars["name"] 73 stdin, inStream io.ReadCloser 74 stdout, stderr, outStream io.Writer 75 ) 76 77 execStartCheck := &types.ExecStartCheck{} 78 if err := json.NewDecoder(r.Body).Decode(execStartCheck); err != nil { 79 return err 80 } 81 82 if exists, err := s.backend.ExecExists(execName); !exists { 83 return err 84 } 85 86 if !execStartCheck.Detach { 87 var err error 88 // Setting up the streaming http interface. 89 inStream, outStream, err = httputils.HijackConnection(w) 90 if err != nil { 91 return err 92 } 93 defer httputils.CloseStreams(inStream, outStream) 94 95 if _, ok := r.Header["Upgrade"]; ok { 96 fmt.Fprintf(outStream, "HTTP/1.1 101 UPGRADED\r\nContent-Type: application/vnd.docker.raw-stream\r\nConnection: Upgrade\r\nUpgrade: tcp\r\n\r\n") 97 } else { 98 fmt.Fprintf(outStream, "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n\r\n") 99 } 100 101 stdin = inStream 102 stdout = outStream 103 if !execStartCheck.Tty { 104 stderr = stdcopy.NewStdWriter(outStream, stdcopy.Stderr) 105 stdout = stdcopy.NewStdWriter(outStream, stdcopy.Stdout) 106 } 107 } else { 108 outStream = w 109 } 110 111 // Now run the user process in container. 112 if err := s.backend.ContainerExecStart(execName, stdin, stdout, stderr); err != nil { 113 if execStartCheck.Detach { 114 return err 115 } 116 logrus.Errorf("Error running exec in container: %v\n", utils.GetErrorMessage(err)) 117 } 118 return nil 119 } 120 121 func (s *containerRouter) postContainerExecResize(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 122 if err := httputils.ParseForm(r); err != nil { 123 return err 124 } 125 height, err := strconv.Atoi(r.Form.Get("h")) 126 if err != nil { 127 return err 128 } 129 width, err := strconv.Atoi(r.Form.Get("w")) 130 if err != nil { 131 return err 132 } 133 134 return s.backend.ContainerExecResize(vars["name"], height, width) 135 }