func (n *networkRouter) postNetworkDisconnect(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { var disconnect types.NetworkDisconnect if err := httputils.ParseForm(r); err != nil { return err } if err := httputils.CheckForJSON(r); err != nil { return err } if err := json.NewDecoder(r.Body).Decode(&disconnect); err != nil { return err } nw, err := n.daemon.FindNetwork(vars["id"]) if err != nil { return err } container, err := n.daemon.Get(disconnect.Container) if err != nil { return fmt.Errorf("invalid container %s : %v", container, err) } return container.DisconnectFromNetwork(nw) }
// debugRequestMiddleware dumps the request to logger func debugRequestMiddleware(handler httputils.APIFunc) httputils.APIFunc { return func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { logrus.Debugf("%s %s", r.Method, r.RequestURI) if r.Method == "POST" { if err := httputils.CheckForJSON(r); err == nil { var buf bytes.Buffer if _, err := buf.ReadFrom(r.Body); err == nil { r.Body.Close() r.Body = ioutil.NopCloser(&buf) var postForm map[string]interface{} if err := json.Unmarshal(buf.Bytes(), &postForm); err == nil { if _, exists := postForm["password"]; exists { postForm["password"] = "******" } formStr, errMarshal := json.Marshal(postForm) if errMarshal == nil { logrus.Debugf("form data: %s", string(formStr)) } else { logrus.Debugf("form data: %q", postForm) } } } } } return handler(ctx, w, r, vars) } }
func (s *containerRouter) postContainersStart(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { // If contentLength is -1, we can assumed chunked encoding // or more technically that the length is unknown // https://golang.org/src/pkg/net/http/request.go#L139 // net/http otherwise seems to swallow any headers related to chunked encoding // including r.TransferEncoding // allow a nil body for backwards compatibility version := httputils.VersionFromContext(ctx) var hostConfig *container.HostConfig // A non-nil json object is at least 7 characters. if r.ContentLength > 7 || r.ContentLength == -1 { if versions.GreaterThanOrEqualTo(version, "1.24") { return validationError{fmt.Errorf("starting container with non-empty request body was deprecated since v1.10 and removed in v1.12")} } if err := httputils.CheckForJSON(r); err != nil { return err } c, err := s.decoder.DecodeHostConfig(r.Body) if err != nil { return err } hostConfig = c } validateHostname := versions.GreaterThanOrEqualTo(version, "1.24") if err := s.backend.ContainerStart(vars["name"], hostConfig, validateHostname); err != nil { return err } w.WriteHeader(http.StatusNoContent) return nil }
func (s *containerRouter) postContainerUpdate(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := httputils.ParseForm(r); err != nil { return err } if err := httputils.CheckForJSON(r); err != nil { return err } version := httputils.VersionFromContext(ctx) var updateConfig container.UpdateConfig decoder := json.NewDecoder(r.Body) if err := decoder.Decode(&updateConfig); err != nil { return err } hostConfig := &container.HostConfig{ Resources: updateConfig.Resources, RestartPolicy: updateConfig.RestartPolicy, } name := vars["name"] validateHostname := versions.GreaterThanOrEqualTo(version, "1.24") warnings, err := s.backend.ContainerUpdate(name, hostConfig, validateHostname) if err != nil { return err } return httputils.WriteJSON(w, http.StatusOK, &types.ContainerUpdateResponse{ Warnings: warnings, }) }
func (s *containerRouter) postContainerExecCreate(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := httputils.ParseForm(r); err != nil { return err } if err := httputils.CheckForJSON(r); err != nil { return err } name := vars["name"] execConfig := &types.ExecConfig{} if err := json.NewDecoder(r.Body).Decode(execConfig); err != nil { return err } if len(execConfig.Cmd) == 0 { return fmt.Errorf("No exec command specified") } // Register an instance of Exec in container. id, err := s.backend.ContainerExecCreate(name, execConfig) if err != nil { logrus.Errorf("Error setting up exec command in container %s: %v", name, err) return err } return httputils.WriteJSON(w, http.StatusCreated, &types.ContainerExecCreateResponse{ ID: id, }) }
func (s *router) postContainersStart(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { // If contentLength is -1, we can assumed chunked encoding // or more technically that the length is unknown // https://golang.org/src/pkg/net/http/request.go#L139 // net/http otherwise seems to swallow any headers related to chunked encoding // including r.TransferEncoding // allow a nil body for backwards compatibility var hostConfig *runconfig.HostConfig if r.Body != nil && (r.ContentLength > 0 || r.ContentLength == -1) { if err := httputils.CheckForJSON(r); err != nil { return err } c, err := runconfig.DecodeHostConfig(r.Body) if err != nil { return err } hostConfig = c } if err := s.daemon.ContainerStart(vars["name"], hostConfig); err != nil { return err } w.WriteHeader(http.StatusNoContent) return nil }
func (n *networkRouter) postNetworkDisconnect(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { var disconnect types.NetworkDisconnect if err := httputils.ParseForm(r); err != nil { return err } if err := httputils.CheckForJSON(r); err != nil { return err } if err := json.NewDecoder(r.Body).Decode(&disconnect); err != nil { return err } nw, err := n.backend.FindNetwork(vars["id"]) if err != nil { return err } if nw.Info().Dynamic() { err := fmt.Errorf("operation not supported for swarm scoped networks") return errors.NewRequestForbiddenError(err) } return n.backend.DisconnectContainerFromNetwork(disconnect.Container, nw, disconnect.Force) }
func (n *networkRouter) postNetworkCreate(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { var create types.NetworkCreateRequest if err := httputils.ParseForm(r); err != nil { return err } if err := httputils.CheckForJSON(r); err != nil { return err } if err := json.NewDecoder(r.Body).Decode(&create); err != nil { return err } if _, err := n.clusterProvider.GetNetwork(create.Name); err == nil { return libnetwork.NetworkNameError(create.Name) } nw, err := n.backend.CreateNetwork(create) if err != nil { if _, ok := err.(libnetwork.ManagerRedirectError); !ok { return err } id, err := n.clusterProvider.CreateNetwork(create) if err != nil { return err } nw = &types.NetworkCreateResponse{ID: id} } return httputils.WriteJSON(w, http.StatusCreated, nw) }
func (s *containerRouter) postContainerUpdate(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := httputils.ParseForm(r); err != nil { return err } if err := httputils.CheckForJSON(r); err != nil { return err } var updateConfig container.UpdateConfig decoder := json.NewDecoder(r.Body) if err := decoder.Decode(&updateConfig); err != nil { return err } hostConfig := &container.HostConfig{ Resources: updateConfig.Resources, RestartPolicy: updateConfig.RestartPolicy, } name := vars["name"] resp, err := s.backend.ContainerUpdate(name, hostConfig) if err != nil { return err } return httputils.WriteJSON(w, http.StatusOK, resp) }
// postContainersCopy is deprecated in favor of getContainersArchive. func (s *router) postContainersCopy(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := httputils.CheckForJSON(r); err != nil { return err } cfg := types.CopyConfig{} if err := json.NewDecoder(r.Body).Decode(&cfg); err != nil { return err } if cfg.Resource == "" { return fmt.Errorf("Path cannot be empty") } data, err := s.daemon.ContainerCopy(vars["name"], cfg.Resource) if err != nil { if strings.Contains(strings.ToLower(err.Error()), "no such id") { w.WriteHeader(http.StatusNotFound) return nil } if os.IsNotExist(err) { return fmt.Errorf("Could not find the file %s in container %s", cfg.Resource, vars["name"]) } return err } defer data.Close() w.Header().Set("Content-Type", "application/x-tar") if _, err := io.Copy(w, data); err != nil { return err } return nil }
func (s *containerRouter) postContainersCreate(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := httputils.ParseForm(r); err != nil { return err } if err := httputils.CheckForJSON(r); err != nil { return err } name := r.Form.Get("name") config, hostConfig, networkingConfig, err := s.decoder.DecodeConfig(r.Body) if err != nil { return err } version := httputils.VersionFromContext(ctx) adjustCPUShares := versions.LessThan(version, "1.19") ccr, err := s.backend.ContainerCreate(types.ContainerCreateConfig{ Name: name, Config: config, HostConfig: hostConfig, NetworkingConfig: networkingConfig, AdjustCPUShares: adjustCPUShares, }) if err != nil { return err } return httputils.WriteJSON(w, http.StatusCreated, ccr) }
// TODO(vishh): Refactor the code to avoid having to specify stream config as part of both create and start. func (s *containerRouter) postContainerExecStart(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := httputils.ParseForm(r); err != nil { return err } version := httputils.VersionFromContext(ctx) if versions.GreaterThan(version, "1.21") { if err := httputils.CheckForJSON(r); err != nil { return err } } var ( execName = vars["name"] stdin, inStream io.ReadCloser stdout, stderr, outStream io.Writer ) execStartCheck := &types.ExecStartCheck{} if err := json.NewDecoder(r.Body).Decode(execStartCheck); err != nil { return err } if exists, err := s.backend.ExecExists(execName); !exists { return err } if !execStartCheck.Detach { var err error // Setting up the streaming http interface. inStream, outStream, err = httputils.HijackConnection(w) if err != nil { return err } defer httputils.CloseStreams(inStream, outStream) if _, ok := r.Header["Upgrade"]; ok { 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") } else { fmt.Fprintf(outStream, "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n\r\n") } stdin = inStream stdout = outStream if !execStartCheck.Tty { stderr = stdcopy.NewStdWriter(outStream, stdcopy.Stderr) stdout = stdcopy.NewStdWriter(outStream, stdcopy.Stdout) } } // Now run the user process in container. if err := s.backend.ContainerExecStart(execName, stdin, stdout, stderr); err != nil { if execStartCheck.Detach { return err } stdout.Write([]byte(err.Error() + "\r\n")) logrus.Errorf("Error running exec in container: %v", err) } return nil }
func (s *router) postCommit(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := httputils.ParseForm(r); err != nil { return err } if err := httputils.CheckForJSON(r); err != nil { return err } cname := r.Form.Get("container") pause := httputils.BoolValue(r, "pause") version := httputils.VersionFromContext(ctx) if r.FormValue("pause") == "" && version.GreaterThanOrEqualTo("1.13") { pause = true } c, _, _, err := runconfig.DecodeContainerConfig(r.Body) if err != nil && err != io.EOF { //Do not fail if body is empty. return err } if c == nil { c = &container.Config{} } if !s.daemon.Exists(cname) { return derr.ErrorCodeNoSuchContainer.WithArgs(cname) } newConfig, err := dockerfile.BuildFromConfig(c, r.Form["changes"]) if err != nil { return err } commitCfg := &types.ContainerCommitConfig{ Pause: pause, Repo: r.Form.Get("repo"), Tag: r.Form.Get("tag"), Author: r.Form.Get("author"), Comment: r.Form.Get("comment"), Config: newConfig, MergeConfigs: true, } imgID, err := s.daemon.Commit(cname, commitCfg) if err != nil { return err } return httputils.WriteJSON(w, http.StatusCreated, &types.ContainerCommitResponse{ ID: string(imgID), }) }
func (n *networkRouter) postNetworkDisconnect(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { var disconnect types.NetworkDisconnect if err := httputils.ParseForm(r); err != nil { return err } if err := httputils.CheckForJSON(r); err != nil { return err } if err := json.NewDecoder(r.Body).Decode(&disconnect); err != nil { return err } return n.backend.DisconnectContainerFromNetwork(disconnect.Container, vars["id"], disconnect.Force) }
func (n *networkRouter) postNetworkConnect(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { var connect types.NetworkConnect if err := httputils.ParseForm(r); err != nil { return err } if err := httputils.CheckForJSON(r); err != nil { return err } if err := json.NewDecoder(r.Body).Decode(&connect); err != nil { return err } return n.backend.ConnectContainerToNetwork(connect.Container, vars["id"], connect.EndpointConfig) }
func (s *imageRouter) postCommit(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := httputils.ParseForm(r); err != nil { return err } if err := httputils.CheckForJSON(r); err != nil { return err } cname := r.Form.Get("container") pause := httputils.BoolValue(r, "pause") version := httputils.VersionFromContext(ctx) if r.FormValue("pause") == "" && versions.GreaterThanOrEqualTo(version, "1.13") { pause = true } c, _, _, err := s.decoder.DecodeConfig(r.Body) if err != nil && err != io.EOF { //Do not fail if body is empty. return err } if c == nil { c = &container.Config{} } commitCfg := &backend.ContainerCommitConfig{ ContainerCommitConfig: types.ContainerCommitConfig{ Pause: pause, Repo: r.Form.Get("repo"), Tag: r.Form.Get("tag"), Author: r.Form.Get("author"), Comment: r.Form.Get("comment"), Config: c, MergeConfigs: true, }, Changes: r.Form["changes"], } imgID, err := s.backend.Commit(cname, commitCfg) if err != nil { return err } return httputils.WriteJSON(w, http.StatusCreated, &types.ContainerCommitResponse{ ID: string(imgID), }) }
func (n *networkRouter) postNetworkCreate(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { var create types.NetworkCreate var warning string if err := httputils.ParseForm(r); err != nil { return err } if err := httputils.CheckForJSON(r); err != nil { return err } if err := json.NewDecoder(r.Body).Decode(&create); err != nil { return err } if runconfig.IsPreDefinedNetwork(create.Name) { return httputils.WriteJSON(w, http.StatusForbidden, fmt.Sprintf("%s is a pre-defined network and cannot be created", create.Name)) } nw, err := n.backend.GetNetworkByName(create.Name) if _, ok := err.(libnetwork.ErrNoSuchNetwork); err != nil && !ok { return err } if nw != nil { if create.CheckDuplicate { return libnetwork.NetworkNameError(create.Name) } warning = fmt.Sprintf("Network with name %s (id : %s) already exists", nw.Name(), nw.ID()) } nw, err = n.backend.CreateNetwork(create.Name, create.Driver, create.IPAM, create.Options, create.Internal, create.EnableIPv6) if err != nil { return err } return httputils.WriteJSON(w, http.StatusCreated, &types.NetworkCreateResponse{ ID: nw.ID(), Warning: warning, }) }
func (v *volumeRouter) postVolumesCreate(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := httputils.ParseForm(r); err != nil { return err } if err := httputils.CheckForJSON(r); err != nil { return err } var req types.VolumeCreateRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { return err } volume, err := v.backend.VolumeCreate(req.Name, req.Driver, req.DriverOpts, req.Labels) if err != nil { return err } return httputils.WriteJSON(w, http.StatusCreated, volume) }
func (n *networkRouter) postNetworksPrune(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := httputils.ParseForm(r); err != nil { return err } if err := httputils.CheckForJSON(r); err != nil { return err } var cfg types.NetworksPruneConfig if err := json.NewDecoder(r.Body).Decode(&cfg); err != nil { return err } pruneReport, err := n.backend.NetworksPrune(&cfg) if err != nil { return err } return httputils.WriteJSON(w, http.StatusOK, pruneReport) }
// debugRequestMiddleware dumps the request to logger func debugRequestMiddleware(handler httputils.APIFunc) httputils.APIFunc { return func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { logrus.Debugf("%s %s", r.Method, r.RequestURI) if r.Method != "POST" { return handler(ctx, w, r, vars) } if err := httputils.CheckForJSON(r); err != nil { return handler(ctx, w, r, vars) } maxBodySize := 4096 // 4KB if r.ContentLength > int64(maxBodySize) { return handler(ctx, w, r, vars) } body := r.Body bufReader := bufio.NewReaderSize(body, maxBodySize) r.Body = ioutils.NewReadCloserWrapper(bufReader, func() error { return body.Close() }) b, err := bufReader.Peek(maxBodySize) if err != io.EOF { // either there was an error reading, or the buffer is full (in which case the request is too large) return handler(ctx, w, r, vars) } var postForm map[string]interface{} if err := json.Unmarshal(b, &postForm); err == nil { if _, exists := postForm["password"]; exists { postForm["password"] = "******" } formStr, errMarshal := json.Marshal(postForm) if errMarshal == nil { logrus.Debugf("form data: %s", string(formStr)) } else { logrus.Debugf("form data: %q", postForm) } } return handler(ctx, w, r, vars) } }
func (n *networkRouter) postNetworkConnect(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { var connect types.NetworkConnect if err := httputils.ParseForm(r); err != nil { return err } if err := httputils.CheckForJSON(r); err != nil { return err } if err := json.NewDecoder(r.Body).Decode(&connect); err != nil { return err } nw, err := n.daemon.FindNetwork(vars["id"]) if err != nil { return err } return n.daemon.ConnectContainerToNetwork(connect.Container, nw.Name()) }
func (n *networkRouter) postNetworkCreate(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { var create types.NetworkCreate if err := httputils.ParseForm(r); err != nil { return err } if err := httputils.CheckForJSON(r); err != nil { return err } if err := json.NewDecoder(r.Body).Decode(&create); err != nil { return err } nw, err := n.backend.CreateNetwork(create) if err != nil { return err } return httputils.WriteJSON(w, http.StatusCreated, nw) }
func (s *containerRouter) postContainerUpdate(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := httputils.ParseForm(r); err != nil { return err } if err := httputils.CheckForJSON(r); err != nil { return err } _, hostConfig, _, err := runconfig.DecodeContainerConfig(r.Body) if err != nil { return err } name := vars["name"] warnings, err := s.backend.ContainerUpdate(name, hostConfig) if err != nil { return err } return httputils.WriteJSON(w, http.StatusOK, &types.ContainerUpdateResponse{ Warnings: warnings, }) }
func (n *networkRouter) postNetworkCreate(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { var create types.NetworkCreate var warning string if err := httputils.ParseForm(r); err != nil { return err } if err := httputils.CheckForJSON(r); err != nil { return err } if err := json.NewDecoder(r.Body).Decode(&create); err != nil { return err } nw, err := n.daemon.GetNetwork(create.Name, daemon.NetworkByName) if _, ok := err.(libnetwork.ErrNoSuchNetwork); err != nil && !ok { return err } if nw != nil { if create.CheckDuplicate { return libnetwork.NetworkNameError(create.Name) } warning = fmt.Sprintf("Network with name %s (id : %s) already exists", nw.Name(), nw.ID()) } nw, err = n.daemon.CreateNetwork(create.Name, create.Driver, create.IPAM, create.Options) if err != nil { return err } return httputils.WriteJSON(w, http.StatusCreated, &types.NetworkCreateResponse{ ID: nw.ID(), Warning: warning, }) }
func (s *router) postContainersCreate(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := httputils.ParseForm(r); err != nil { return err } if err := httputils.CheckForJSON(r); err != nil { return err } name := r.Form.Get("name") config, hostConfig, err := runconfig.DecodeContainerConfig(r.Body) if err != nil { return err } version := httputils.VersionFromContext(ctx) adjustCPUShares := version.LessThan("1.19") ccr, err := s.daemon.ContainerCreate(name, config, hostConfig, adjustCPUShares) if err != nil { return err } return httputils.WriteJSON(w, http.StatusCreated, ccr) }