github.com/sijibomii/docker@v0.0.0-20231230191044-5cf6ca554647/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/engine-api/types" 14 "golang.org/x/net/context" 15 ) 16 17 func (s *containerRouter) getExecByID(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 18 eConfig, err := s.backend.ContainerExecInspect(vars["id"]) 19 if err != nil { 20 return err 21 } 22 23 return httputils.WriteJSON(w, http.StatusOK, eConfig) 24 } 25 26 func (s *containerRouter) postContainerExecCreate(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 27 if err := httputils.ParseForm(r); err != nil { 28 return err 29 } 30 if err := httputils.CheckForJSON(r); err != nil { 31 return err 32 } 33 name := vars["name"] 34 35 execConfig := &types.ExecConfig{} 36 if err := json.NewDecoder(r.Body).Decode(execConfig); err != nil { 37 return err 38 } 39 execConfig.Container = name 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(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.ContainerExecCreateResponse{ 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 version.GreaterThan("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.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") 96 } else { 97 fmt.Fprintf(outStream, "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n\r\n") 98 } 99 100 stdin = inStream 101 stdout = outStream 102 if !execStartCheck.Tty { 103 stderr = stdcopy.NewStdWriter(outStream, stdcopy.Stderr) 104 stdout = stdcopy.NewStdWriter(outStream, stdcopy.Stdout) 105 } 106 } 107 108 // Now run the user process in container. 109 if err := s.backend.ContainerExecStart(execName, stdin, stdout, stderr); err != nil { 110 if execStartCheck.Detach { 111 return err 112 } 113 stdout.Write([]byte(err.Error())) 114 logrus.Errorf("Error running exec in container: %v\n", err) 115 } 116 return nil 117 } 118 119 func (s *containerRouter) postContainerExecResize(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 120 if err := httputils.ParseForm(r); err != nil { 121 return err 122 } 123 height, err := strconv.Atoi(r.Form.Get("h")) 124 if err != nil { 125 return err 126 } 127 width, err := strconv.Atoi(r.Form.Get("w")) 128 if err != nil { 129 return err 130 } 131 132 return s.backend.ContainerExecResize(vars["name"], height, width) 133 }