github.com/hms58/moby@v1.13.1/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/api/types" 13 "github.com/docker/docker/api/types/versions" 14 "github.com/docker/docker/pkg/stdcopy" 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 41 if len(execConfig.Cmd) == 0 { 42 return fmt.Errorf("No exec command specified") 43 } 44 45 // Register an instance of Exec in container. 46 id, err := s.backend.ContainerExecCreate(name, execConfig) 47 if err != nil { 48 logrus.Errorf("Error setting up exec command in container %s: %v", name, err) 49 return err 50 } 51 52 return httputils.WriteJSON(w, http.StatusCreated, &types.IDResponse{ 53 ID: id, 54 }) 55 } 56 57 // TODO(vishh): Refactor the code to avoid having to specify stream config as part of both create and start. 58 func (s *containerRouter) postContainerExecStart(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 59 if err := httputils.ParseForm(r); err != nil { 60 return err 61 } 62 63 version := httputils.VersionFromContext(ctx) 64 if versions.GreaterThan(version, "1.21") { 65 if err := httputils.CheckForJSON(r); err != nil { 66 return err 67 } 68 } 69 70 var ( 71 execName = vars["name"] 72 stdin, inStream io.ReadCloser 73 stdout, stderr, outStream io.Writer 74 ) 75 76 execStartCheck := &types.ExecStartCheck{} 77 if err := json.NewDecoder(r.Body).Decode(execStartCheck); err != nil { 78 return err 79 } 80 81 if exists, err := s.backend.ExecExists(execName); !exists { 82 return err 83 } 84 85 if !execStartCheck.Detach { 86 var err error 87 // Setting up the streaming http interface. 88 inStream, outStream, err = httputils.HijackConnection(w) 89 if err != nil { 90 return err 91 } 92 defer httputils.CloseStreams(inStream, outStream) 93 94 if _, ok := r.Header["Upgrade"]; ok { 95 fmt.Fprint(outStream, "HTTP/1.1 101 UPGRADED\r\nContent-Type: application/vnd.docker.raw-stream\r\nConnection: Upgrade\r\nUpgrade: tcp\r\n") 96 } else { 97 fmt.Fprint(outStream, "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n") 98 } 99 100 // copy headers that were removed as part of hijack 101 if err := w.Header().WriteSubset(outStream, nil); err != nil { 102 return err 103 } 104 fmt.Fprint(outStream, "\r\n") 105 106 stdin = inStream 107 stdout = outStream 108 if !execStartCheck.Tty { 109 stderr = stdcopy.NewStdWriter(outStream, stdcopy.Stderr) 110 stdout = stdcopy.NewStdWriter(outStream, stdcopy.Stdout) 111 } 112 } 113 114 // Now run the user process in container. 115 // Maybe we should we pass ctx here if we're not detaching? 116 if err := s.backend.ContainerExecStart(context.Background(), execName, stdin, stdout, stderr); err != nil { 117 if execStartCheck.Detach { 118 return err 119 } 120 stdout.Write([]byte(err.Error() + "\r\n")) 121 logrus.Errorf("Error running exec in container: %v", err) 122 } 123 return nil 124 } 125 126 func (s *containerRouter) postContainerExecResize(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 127 if err := httputils.ParseForm(r); err != nil { 128 return err 129 } 130 height, err := strconv.Atoi(r.Form.Get("h")) 131 if err != nil { 132 return err 133 } 134 width, err := strconv.Atoi(r.Form.Get("w")) 135 if err != nil { 136 return err 137 } 138 139 return s.backend.ContainerExecResize(vars["name"], height, width) 140 }