func wsContainersAttach(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } if vars == nil { return fmt.Errorf("Missing parameter") } if err := eng.Job("container_inspect", vars["name"]).Run(); err != nil { return err } h := websocket.Handler(func(ws *websocket.Conn) { defer ws.Close() job := eng.Job("attach", vars["name"]) job.Setenv("logs", r.Form.Get("logs")) job.Setenv("stream", r.Form.Get("stream")) job.Setenv("stdin", r.Form.Get("stdin")) job.Setenv("stdout", r.Form.Get("stdout")) job.Setenv("stderr", r.Form.Get("stderr")) job.Stdin.Add(ws) job.Stdout.Add(ws) job.Stderr.Set(ws) if err := job.Run(); err != nil { log.Errorf("Error attaching websocket: %s", err) } }) h.ServeHTTP(w, r) return nil }
func postContainersCreate(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return nil } if err := checkForJson(r); err != nil { return err } var ( job = eng.Job("create", r.Form.Get("name")) outWarnings []string stdoutBuffer = bytes.NewBuffer(nil) warnings = bytes.NewBuffer(nil) ) if err := job.DecodeEnv(r.Body); err != nil { return err } // Read container ID from the first line of stdout job.Stdout.Add(stdoutBuffer) // Read warnings from stderr job.Stderr.Add(warnings) if err := job.Run(); err != nil { return err } // Parse warnings from stderr scanner := bufio.NewScanner(warnings) for scanner.Scan() { outWarnings = append(outWarnings, scanner.Text()) } return writeJSON(w, http.StatusCreated, &types.ContainerCreateResponse{ ID: engine.Tail(stdoutBuffer, 1), Warnings: outWarnings, }) }
func postContainersStart(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { return fmt.Errorf("Missing parameter") } var ( name = vars["name"] job = eng.Job("start", name) ) // If contentLength is -1, we can assumed chunked encoding // or more technically that the length is unknown // http://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 if r.Body != nil && (r.ContentLength > 0 || r.ContentLength == -1) { if err := checkForJson(r); err != nil { return err } if err := job.DecodeEnv(r.Body); err != nil { return err } } if err := job.Run(); err != nil { if err.Error() == "Container already started" { w.WriteHeader(http.StatusNotModified) return nil } return err } w.WriteHeader(http.StatusNoContent) return nil }
func postContainerExecCreate(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return nil } var ( name = vars["name"] job = eng.Job("execCreate", name) stdoutBuffer = bytes.NewBuffer(nil) outWarnings []string warnings = bytes.NewBuffer(nil) ) if err := job.DecodeEnv(r.Body); err != nil { return err } job.Stdout.Add(stdoutBuffer) // Read warnings from stderr job.Stderr.Add(warnings) // Register an instance of Exec in container. if err := job.Run(); err != nil { fmt.Fprintf(os.Stderr, "Error setting up exec command in container %s: %s\n", name, err) return err } // Parse warnings from stderr scanner := bufio.NewScanner(warnings) for scanner.Scan() { outWarnings = append(outWarnings, scanner.Text()) } return writeJSON(w, http.StatusCreated, &types.ContainerExecCreateResponse{ ID: engine.Tail(stdoutBuffer, 1), Warnings: outWarnings, }) }
func getImagesSearch(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } var ( authEncoded = r.Header.Get("X-Registry-Auth") authConfig = ®istry.AuthConfig{} metaHeaders = map[string][]string{} ) if authEncoded != "" { authJson := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authEncoded)) if err := json.NewDecoder(authJson).Decode(authConfig); err != nil { // for a search it is not an error if no auth was given // to increase compatibility with the existing api it is defaulting to be empty authConfig = ®istry.AuthConfig{} } } for k, v := range r.Header { if strings.HasPrefix(k, "X-Meta-") { metaHeaders[k] = v } } var job = eng.Job("search", r.Form.Get("term")) job.SetenvJson("metaHeaders", metaHeaders) job.SetenvJson("authConfig", authConfig) streamJSON(job, w, false) return job.Run() }
// Creates an image from Pull or from Import func postImagesCreate(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } var ( image = r.Form.Get("fromImage") repo = r.Form.Get("repo") tag = r.Form.Get("tag") job *engine.Job ) authEncoded := r.Header.Get("X-Registry-Auth") authConfig := ®istry.AuthConfig{} if authEncoded != "" { authJson := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authEncoded)) if err := json.NewDecoder(authJson).Decode(authConfig); err != nil { // for a pull it is not an error if no auth was given // to increase compatibility with the existing api it is defaulting to be empty authConfig = ®istry.AuthConfig{} } } if image != "" { //pull if tag == "" { image, tag = parsers.ParseRepositoryTag(image) } metaHeaders := map[string][]string{} for k, v := range r.Header { if strings.HasPrefix(k, "X-Meta-") { metaHeaders[k] = v } } job = eng.Job("pull", image, tag) job.SetenvBool("parallel", version.GreaterThan("1.3")) job.SetenvJson("metaHeaders", metaHeaders) job.SetenvJson("authConfig", authConfig) } else { //import if tag == "" { repo, tag = parsers.ParseRepositoryTag(repo) } job = eng.Job("import", r.Form.Get("fromSrc"), repo, tag) job.Stdin.Add(r.Body) job.SetenvList("changes", r.Form["changes"]) } if version.GreaterThan("1.0") { job.SetenvBool("json", true) streamJSON(job, w, true) } else { job.Stdout.Add(utils.NewWriteFlusher(w)) } if err := job.Run(); err != nil { if !job.Stdout.Used() { return err } sf := utils.NewStreamFormatter(version.GreaterThan("1.0")) w.Write(sf.FormatError(err)) } return nil }
// Install installs registry capabilities to eng. func (s *Service) Install(eng *engine.Engine) error { eng.Register("auth", s.Auth) eng.Register("search", s.Search) eng.Register("resolve_repository", s.ResolveRepository) eng.Register("resolve_index", s.ResolveIndex) eng.Register("registry_config", s.GetRegistryConfig) return nil }
func getExecByID(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { return fmt.Errorf("Missing parameter 'id'") } var job = eng.Job("execInspect", vars["id"]) streamJSON(job, w, false) return job.Run() }
func getImagesViz(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if version.GreaterThan("1.6") { w.WriteHeader(http.StatusNotFound) return fmt.Errorf("This is now implemented in the client.") } eng.ServeHTTP(w, r) return nil }
func getContainersChanges(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { return fmt.Errorf("Missing parameter") } var job = eng.Job("container_changes", vars["name"]) streamJSON(job, w, false) return job.Run() }
func newPortAllocationJobWithInvalidHostIP(eng *engine.Engine, port int) (job *engine.Job) { strPort := strconv.Itoa(port) job = eng.Job("allocate_port", "container_id") job.Setenv("HostIP", "localhost") job.Setenv("HostPort", strPort) job.Setenv("Proto", "tcp") job.Setenv("ContainerPort", strPort) return }
func postContainersAttach(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } if vars == nil { return fmt.Errorf("Missing parameter") } var ( job = eng.Job("container_inspect", vars["name"]) c, err = job.Stdout.AddEnv() ) if err != nil { return err } if err = job.Run(); err != nil { return err } inStream, outStream, err := hijackServer(w) if err != nil { return err } defer closeStreams(inStream, outStream) var errStream io.Writer 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") } if c.GetSubEnv("Config") != nil && !c.GetSubEnv("Config").GetBool("Tty") && version.GreaterThanOrEqualTo("1.6") { errStream = stdcopy.NewStdWriter(outStream, stdcopy.Stderr) outStream = stdcopy.NewStdWriter(outStream, stdcopy.Stdout) } else { errStream = outStream } job = eng.Job("attach", vars["name"]) job.Setenv("logs", r.Form.Get("logs")) job.Setenv("stream", r.Form.Get("stream")) job.Setenv("stdin", r.Form.Get("stdin")) job.Setenv("stdout", r.Form.Get("stdout")) job.Setenv("stderr", r.Form.Get("stderr")) job.Stdin.Add(inStream) job.Stdout.Add(outStream) job.Stderr.Set(errStream) if err := job.Run(); err != nil { fmt.Fprintf(outStream, "Error attaching: %s\n", err) } return nil }
func getContainersByName(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { return fmt.Errorf("Missing parameter") } var job = eng.Job("container_inspect", vars["name"]) if version.LessThan("1.12") { job.SetenvBool("raw", true) } streamJSON(job, w, false) return job.Run() }
func getContainersExport(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { return fmt.Errorf("Missing parameter") } job := eng.Job("export", vars["name"]) job.Stdout.Add(w) if err := job.Run(); err != nil { return err } return nil }
func (s *TagStore) recursiveLoad(eng *engine.Engine, address, tmpImageDir string) error { if err := eng.Job("image_get", address).Run(); err != nil { log.Debugf("Loading %s", address) imageJson, err := ioutil.ReadFile(path.Join(tmpImageDir, "repo", address, "json")) if err != nil { log.Debugf("Error reading json", err) return err } layer, err := os.Open(path.Join(tmpImageDir, "repo", address, "layer.tar")) if err != nil { log.Debugf("Error reading embedded tar", err) return err } img, err := image.NewImgJSON(imageJson) if err != nil { log.Debugf("Error unmarshalling json", err) return err } if err := utils.ValidateID(img.ID); err != nil { log.Debugf("Error validating ID: %s", err) return err } // ensure no two downloads of the same layer happen at the same time if c, err := s.poolAdd("pull", "layer:"+img.ID); err != nil { if c != nil { log.Debugf("Image (id: %s) load is already running, waiting: %v", img.ID, err) <-c return nil } return err } defer s.poolRemove("pull", "layer:"+img.ID) if img.Parent != "" { if !s.graph.Exists(img.Parent) { if err := s.recursiveLoad(eng, img.Parent, tmpImageDir); err != nil { return err } } } if err := s.graph.Register(img, layer); err != nil { return err } } log.Debugf("Completed processing %s", address) return nil }
func getContainersStats(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } if vars == nil { return fmt.Errorf("Missing parameter") } name := vars["name"] job := eng.Job("container_stats", name) streamJSON(job, w, true) return job.Run() }
func getEvents(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } var job = eng.Job("events") streamJSON(job, w, true) job.Setenv("since", r.Form.Get("since")) job.Setenv("until", r.Form.Get("until")) job.Setenv("filters", r.Form.Get("filters")) return job.Run() }
func (s *TagStore) verifyManifest(eng *engine.Engine, manifestBytes []byte) (*registry.ManifestData, bool, error) { sig, err := libtrust.ParsePrettySignature(manifestBytes, "signatures") if err != nil { return nil, false, fmt.Errorf("error parsing payload: %s", err) } keys, err := sig.Verify() if err != nil { return nil, false, fmt.Errorf("error verifying payload: %s", err) } payload, err := sig.Payload() if err != nil { return nil, false, fmt.Errorf("error retrieving payload: %s", err) } var manifest registry.ManifestData if err := json.Unmarshal(payload, &manifest); err != nil { return nil, false, fmt.Errorf("error unmarshalling manifest: %s", err) } if manifest.SchemaVersion != 1 { return nil, false, fmt.Errorf("unsupported schema version: %d", manifest.SchemaVersion) } var verified bool for _, key := range keys { job := eng.Job("trust_key_check") b, err := key.MarshalJSON() if err != nil { return nil, false, fmt.Errorf("error marshalling public key: %s", err) } namespace := manifest.Name if namespace[0] != '/' { namespace = "/" + namespace } stdoutBuffer := bytes.NewBuffer(nil) job.Args = append(job.Args, namespace) job.Setenv("PublicKey", string(b)) // Check key has read/write permission (0x03) job.SetenvInt("Permission", 0x03) job.Stdout.Add(stdoutBuffer) if err = job.Run(); err != nil { return nil, false, fmt.Errorf("error running key check: %s", err) } result := engine.Tail(stdoutBuffer, 1) log.Debugf("Key check result: %q", result) if result == "verified" { verified = true } } return &manifest, verified, nil }
func postContainersResize(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } if vars == nil { return fmt.Errorf("Missing parameter") } if err := eng.Job("resize", vars["name"], r.Form.Get("h"), r.Form.Get("w")).Run(); err != nil { return err } return nil }
func getImagesHistory(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { return fmt.Errorf("Missing parameter") } var job = eng.Job("history", vars["name"]) streamJSON(job, w, false) if err := job.Run(); err != nil { return err } return nil }
func postImagesPush(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { return fmt.Errorf("Missing parameter") } metaHeaders := map[string][]string{} for k, v := range r.Header { if strings.HasPrefix(k, "X-Meta-") { metaHeaders[k] = v } } if err := parseForm(r); err != nil { return err } authConfig := ®istry.AuthConfig{} authEncoded := r.Header.Get("X-Registry-Auth") if authEncoded != "" { // the new format is to handle the authConfig as a header authJson := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authEncoded)) if err := json.NewDecoder(authJson).Decode(authConfig); err != nil { // to increase compatibility to existing api it is defaulting to be empty authConfig = ®istry.AuthConfig{} } } else { // the old format is supported for compatibility if there was no authConfig header if err := json.NewDecoder(r.Body).Decode(authConfig); err != nil { return err } } job := eng.Job("push", vars["name"]) job.SetenvJson("metaHeaders", metaHeaders) job.SetenvJson("authConfig", authConfig) job.Setenv("tag", r.Form.Get("tag")) if version.GreaterThan("1.0") { job.SetenvBool("json", true) streamJSON(job, w, true) } else { job.Stdout.Add(utils.NewWriteFlusher(w)) } if err := job.Run(); err != nil { if !job.Stdout.Used() { return err } sf := utils.NewStreamFormatter(version.GreaterThan("1.0")) w.Write(sf.FormatError(err)) } return nil }
// TODO(vishh): Refactor the code to avoid having to specify stream config as part of both create and start. func postContainerExecStart(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return nil } var ( name = vars["name"] job = eng.Job("execStart", name) errOut io.Writer = os.Stderr ) if err := job.DecodeEnv(r.Body); err != nil { return err } if !job.GetenvBool("Detach") { // Setting up the streaming http interface. inStream, outStream, err := hijackServer(w) if err != nil { return err } defer closeStreams(inStream, outStream) var errStream io.Writer 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") } if !job.GetenvBool("Tty") && version.GreaterThanOrEqualTo("1.6") { errStream = stdcopy.NewStdWriter(outStream, stdcopy.Stderr) outStream = stdcopy.NewStdWriter(outStream, stdcopy.Stdout) } else { errStream = outStream } job.Stdin.Add(inStream) job.Stdout.Add(outStream) job.Stderr.Set(errStream) errOut = outStream } // Now run the user process in container. job.SetCloseIO(false) if err := job.Run(); err != nil { fmt.Fprintf(errOut, "Error starting exec command in container %s: %s\n", name, err) return err } w.WriteHeader(http.StatusNoContent) return nil }
func postContainersUnpause(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { return fmt.Errorf("Missing parameter") } if err := parseForm(r); err != nil { return err } job := eng.Job("unpause", vars["name"]) if err := job.Run(); err != nil { return err } w.WriteHeader(http.StatusNoContent) return nil }
func deleteImages(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } if vars == nil { return fmt.Errorf("Missing parameter") } var job = eng.Job("image_delete", vars["name"]) streamJSON(job, w, false) job.Setenv("force", r.Form.Get("force")) job.Setenv("noprune", r.Form.Get("noprune")) return job.Run() }
func getContainersTop(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if version.LessThan("1.4") { return fmt.Errorf("top was improved a lot since 1.3, Please upgrade your docker client.") } if vars == nil { return fmt.Errorf("Missing parameter") } if err := parseForm(r); err != nil { return err } job := eng.Job("top", vars["name"], r.Form.Get("ps_args")) streamJSON(job, w, false) return job.Run() }
func getImagesJSON(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } var ( err error outs *engine.Table job = eng.Job("images") ) job.Setenv("filters", r.Form.Get("filters")) // FIXME this parameter could just be a match filter job.Setenv("filter", r.Form.Get("filter")) job.Setenv("all", r.Form.Get("all")) if version.GreaterThanOrEqualTo("1.7") { streamJSON(job, w, false) } else if outs, err = job.Stdout.AddListTable(); err != nil { return err } if err := job.Run(); err != nil { return err } if version.LessThan("1.7") && outs != nil { // Convert to legacy format outsLegacy := engine.NewTable("Created", 0) for _, out := range outs.Data { for _, repoTag := range out.GetList("RepoTags") { repo, tag := parsers.ParseRepositoryTag(repoTag) outLegacy := &engine.Env{} outLegacy.Set("Repository", repo) outLegacy.SetJson("Tag", tag) outLegacy.Set("Id", out.Get("Id")) outLegacy.SetInt64("Created", out.GetInt64("Created")) outLegacy.SetInt64("Size", out.GetInt64("Size")) outLegacy.SetInt64("VirtualSize", out.GetInt64("VirtualSize")) outsLegacy.Add(outLegacy) } } w.Header().Set("Content-Type", "application/json") if _, err := outsLegacy.WriteListTo(w); err != nil { return err } } return nil }
func postImagesTag(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } if vars == nil { return fmt.Errorf("Missing parameter") } job := eng.Job("tag", vars["name"], r.Form.Get("repo"), r.Form.Get("tag")) job.Setenv("force", r.Form.Get("force")) if err := job.Run(); err != nil { return err } w.WriteHeader(http.StatusCreated) return nil }
func getContainersLogs(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } if vars == nil { return fmt.Errorf("Missing parameter") } var ( inspectJob = eng.Job("container_inspect", vars["name"]) logsJob = eng.Job("logs", vars["name"]) c, err = inspectJob.Stdout.AddEnv() ) if err != nil { return err } logsJob.Setenv("follow", r.Form.Get("follow")) logsJob.Setenv("tail", r.Form.Get("tail")) logsJob.Setenv("stdout", r.Form.Get("stdout")) logsJob.Setenv("stderr", r.Form.Get("stderr")) logsJob.Setenv("timestamps", r.Form.Get("timestamps")) // Validate args here, because we can't return not StatusOK after job.Run() call stdout, stderr := logsJob.GetenvBool("stdout"), logsJob.GetenvBool("stderr") if !(stdout || stderr) { return fmt.Errorf("Bad parameters: you must choose at least one stream") } if err = inspectJob.Run(); err != nil { return err } var outStream, errStream io.Writer outStream = utils.NewWriteFlusher(w) if c.GetSubEnv("Config") != nil && !c.GetSubEnv("Config").GetBool("Tty") && version.GreaterThanOrEqualTo("1.6") { errStream = stdcopy.NewStdWriter(outStream, stdcopy.Stderr) outStream = stdcopy.NewStdWriter(outStream, stdcopy.Stdout) } else { errStream = outStream } logsJob.Stdout.Add(outStream) logsJob.Stderr.Set(errStream) if err := logsJob.Run(); err != nil { fmt.Fprintf(outStream, "Error running logs job: %s\n", err) } return nil }
func postContainersWait(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { return fmt.Errorf("Missing parameter") } var ( env engine.Env stdoutBuffer = bytes.NewBuffer(nil) job = eng.Job("wait", vars["name"]) ) job.Stdout.Add(stdoutBuffer) if err := job.Run(); err != nil { return err } env.Set("StatusCode", engine.Tail(stdoutBuffer, 1)) return writeJSONEnv(w, http.StatusOK, env) }
func postContainerRename(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } if vars == nil { return fmt.Errorf("Missing parameter") } newName := r.URL.Query().Get("name") job := eng.Job("container_rename", vars["name"], newName) job.Setenv("t", r.Form.Get("t")) if err := job.Run(); err != nil { return err } w.WriteHeader(http.StatusNoContent) return nil }