From 2cfd696b9bacda67468a0a2ef93d61258781e8bc Mon Sep 17 00:00:00 2001 From: "Roberto G. Hashioka" Date: Tue, 21 Jan 2014 04:06:19 +0000 Subject: [PATCH 1/2] Added missing attributes to api search calls: - Added an argument to the call() method in order to control the auth sharing - Enabled it only for search. Pulls and pushes were enabled already. - Grouped a few variable declarations Docker-DCO-1.1-Signed-off-by: Roberto Hashioka (github: rogaha) --- api.go | 21 ++++++++++ commands.go | 91 ++++++++++++++++++++++++++------------------ registry/registry.go | 4 ++ server.go | 10 ++++- 4 files changed, 88 insertions(+), 38 deletions(-) diff --git a/api.go b/api.go index 61df3e7fe6..f48b3ea261 100644 --- a/api.go +++ b/api.go @@ -500,12 +500,33 @@ func getImagesSearch(srv *Server, version float64, w http.ResponseWriter, r *htt if err := parseForm(r); err != nil { return err } + var ( + authEncoded = r.Header.Get("X-Registry-Auth") + authConfig = &auth.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 = &auth.AuthConfig{} + } + } + for k, v := range r.Header { + if strings.HasPrefix(k, "X-Meta-") { + metaHeaders[k] = v + } + } var ( err error outs *engine.Table job = srv.Eng.Job("search", r.Form.Get("term")) ) + job.SetenvJson("metaHeaders", metaHeaders) + job.SetenvJson("authConfig", authConfig) if version >= 1.9 { job.Stdout.Add(w) } else if outs, err = job.Stdout.AddTable(); err != nil { diff --git a/commands.go b/commands.go index a5d7c9100a..17d3f0ede1 100644 --- a/commands.go +++ b/commands.go @@ -335,7 +335,7 @@ func (cli *DockerCli) CmdLogin(args ...string) error { authconfig.ServerAddress = serverAddress cli.configFile.Configs[serverAddress] = authconfig - body, statusCode, err := readBody(cli.call("POST", "/auth", cli.configFile.Configs[serverAddress])) + body, statusCode, err := readBody(cli.call("POST", "/auth", cli.configFile.Configs[serverAddress], false)) if statusCode == 401 { delete(cli.configFile.Configs, serverAddress) auth.SaveConfig(cli.configFile) @@ -400,7 +400,7 @@ func (cli *DockerCli) CmdVersion(args ...string) error { fmt.Fprintf(cli.out, "Git commit (client): %s\n", GITCOMMIT) } - body, _, err := readBody(cli.call("GET", "/version", nil)) + body, _, err := readBody(cli.call("GET", "/version", nil, false)) if err != nil { return err } @@ -441,7 +441,7 @@ func (cli *DockerCli) CmdInfo(args ...string) error { return nil } - body, _, err := readBody(cli.call("GET", "/info", nil)) + body, _, err := readBody(cli.call("GET", "/info", nil, false)) if err != nil { return err } @@ -521,7 +521,7 @@ func (cli *DockerCli) CmdStop(args ...string) error { var encounteredError error for _, name := range cmd.Args() { - _, _, err := readBody(cli.call("POST", "/containers/"+name+"/stop?"+v.Encode(), nil)) + _, _, err := readBody(cli.call("POST", "/containers/"+name+"/stop?"+v.Encode(), nil, false)) if err != nil { fmt.Fprintf(cli.err, "%s\n", err) encounteredError = fmt.Errorf("Error: failed to stop one or more containers") @@ -548,7 +548,7 @@ func (cli *DockerCli) CmdRestart(args ...string) error { var encounteredError error for _, name := range cmd.Args() { - _, _, err := readBody(cli.call("POST", "/containers/"+name+"/restart?"+v.Encode(), nil)) + _, _, err := readBody(cli.call("POST", "/containers/"+name+"/restart?"+v.Encode(), nil, false)) if err != nil { fmt.Fprintf(cli.err, "%s\n", err) encounteredError = fmt.Errorf("Error: failed to restart one or more containers") @@ -567,7 +567,7 @@ func (cli *DockerCli) forwardAllSignals(cid string) chan os.Signal { if s == syscall.SIGCHLD { continue } - if _, _, err := readBody(cli.call("POST", fmt.Sprintf("/containers/%s/kill?signal=%d", cid, s), nil)); err != nil { + if _, _, err := readBody(cli.call("POST", fmt.Sprintf("/containers/%s/kill?signal=%d", cid, s), nil, false)); err != nil { utils.Debugf("Error sending signal: %s", err) } } @@ -594,7 +594,7 @@ func (cli *DockerCli) CmdStart(args ...string) error { return fmt.Errorf("Impossible to start and attach multiple containers at once.") } - body, _, err := readBody(cli.call("GET", "/containers/"+cmd.Arg(0)+"/json", nil)) + body, _, err := readBody(cli.call("GET", "/containers/"+cmd.Arg(0)+"/json", nil, false)) if err != nil { return err } @@ -630,7 +630,7 @@ func (cli *DockerCli) CmdStart(args ...string) error { var encounteredError error for _, name := range cmd.Args() { - _, _, err := readBody(cli.call("POST", "/containers/"+name+"/start", nil)) + _, _, err := readBody(cli.call("POST", "/containers/"+name+"/start", nil, false)) if err != nil { if !*attach || !*openStdin { fmt.Fprintf(cli.err, "%s\n", err) @@ -687,9 +687,9 @@ func (cli *DockerCli) CmdInspect(args ...string) error { status := 0 for _, name := range cmd.Args() { - obj, _, err := readBody(cli.call("GET", "/containers/"+name+"/json", nil)) + obj, _, err := readBody(cli.call("GET", "/containers/"+name+"/json", nil, false)) if err != nil { - obj, _, err = readBody(cli.call("GET", "/images/"+name+"/json", nil)) + obj, _, err = readBody(cli.call("GET", "/images/"+name+"/json", nil, false)) if err != nil { if strings.Contains(err.Error(), "No such") { fmt.Fprintf(cli.err, "Error: No such image or container: %s\n", name) @@ -755,7 +755,7 @@ func (cli *DockerCli) CmdTop(args ...string) error { val.Set("ps_args", strings.Join(cmd.Args()[1:], " ")) } - body, _, err := readBody(cli.call("GET", "/containers/"+cmd.Arg(0)+"/top?"+val.Encode(), nil)) + body, _, err := readBody(cli.call("GET", "/containers/"+cmd.Arg(0)+"/top?"+val.Encode(), nil, false)) if err != nil { return err } @@ -790,7 +790,7 @@ func (cli *DockerCli) CmdPort(args ...string) error { port = parts[0] proto = parts[1] } - body, _, err := readBody(cli.call("GET", "/containers/"+cmd.Arg(0)+"/json", nil)) + body, _, err := readBody(cli.call("GET", "/containers/"+cmd.Arg(0)+"/json", nil, false)) if err != nil { return err } @@ -823,7 +823,7 @@ func (cli *DockerCli) CmdRmi(args ...string) error { var encounteredError error for _, name := range cmd.Args() { - body, _, err := readBody(cli.call("DELETE", "/images/"+name, nil)) + body, _, err := readBody(cli.call("DELETE", "/images/"+name, nil, false)) if err != nil { fmt.Fprintf(cli.err, "%s\n", err) encounteredError = fmt.Errorf("Error: failed to remove one or more images") @@ -860,7 +860,7 @@ func (cli *DockerCli) CmdHistory(args ...string) error { return nil } - stream, _, err := cli.call("GET", "/images/"+cmd.Arg(0)+"/history", nil) + stream, _, err := cli.call("GET", "/images/"+cmd.Arg(0)+"/history", nil, false) if stream != nil { defer stream.Close() } @@ -929,7 +929,7 @@ func (cli *DockerCli) CmdRm(args ...string) error { var encounteredError error for _, name := range cmd.Args() { - _, _, err := readBody(cli.call("DELETE", "/containers/"+name+"?"+val.Encode(), nil)) + _, _, err := readBody(cli.call("DELETE", "/containers/"+name+"?"+val.Encode(), nil, false)) if err != nil { fmt.Fprintf(cli.err, "%s\n", err) encounteredError = fmt.Errorf("Error: failed to remove one or more containers") @@ -953,7 +953,7 @@ func (cli *DockerCli) CmdKill(args ...string) error { var encounteredError error for _, name := range args { - if _, _, err := readBody(cli.call("POST", "/containers/"+name+"/kill", nil)); err != nil { + if _, _, err := readBody(cli.call("POST", "/containers/"+name+"/kill", nil, false)); err != nil { fmt.Fprintf(cli.err, "%s\n", err) encounteredError = fmt.Errorf("Error: failed to kill one or more containers") } else { @@ -1138,7 +1138,7 @@ func (cli *DockerCli) CmdImages(args ...string) error { filter := cmd.Arg(0) if *flViz || *flTree { - stream, _, err := cli.call("GET", "/images/json?all=1", nil) + stream, _, err := cli.call("GET", "/images/json?all=1", nil, false) if stream != nil { defer stream.Close() } @@ -1210,7 +1210,7 @@ func (cli *DockerCli) CmdImages(args ...string) error { v.Set("all", "1") } - stream, _, err := cli.call("GET", "/images/json?"+v.Encode(), nil) + stream, _, err := cli.call("GET", "/images/json?"+v.Encode(), nil, false) if stream != nil { defer stream.Close() } @@ -1364,7 +1364,7 @@ func (cli *DockerCli) CmdPs(args ...string) error { v.Set("size", "1") } - body, _, err := readBody(cli.call("GET", "/containers/json?"+v.Encode(), nil)) + body, _, err := readBody(cli.call("GET", "/containers/json?"+v.Encode(), nil, false)) if err != nil { return err } @@ -1456,7 +1456,7 @@ func (cli *DockerCli) CmdCommit(args ...string) error { return err } } - body, _, err := readBody(cli.call("POST", "/commit?"+v.Encode(), config)) + body, _, err := readBody(cli.call("POST", "/commit?"+v.Encode(), config, false)) if err != nil { return err } @@ -1531,7 +1531,7 @@ func (cli *DockerCli) CmdDiff(args ...string) error { return nil } - stream, _, err := cli.call("GET", "/containers/"+cmd.Arg(0)+"/changes", nil) + stream, _, err := cli.call("GET", "/containers/"+cmd.Arg(0)+"/changes", nil, false) if stream != nil { defer stream.Close() } @@ -1569,7 +1569,7 @@ func (cli *DockerCli) CmdLogs(args ...string) error { return nil } name := cmd.Arg(0) - body, _, err := readBody(cli.call("GET", "/containers/"+name+"/json", nil)) + body, _, err := readBody(cli.call("GET", "/containers/"+name+"/json", nil, false)) if err != nil { return err } @@ -1606,7 +1606,7 @@ func (cli *DockerCli) CmdAttach(args ...string) error { return nil } name := cmd.Arg(0) - body, _, err := readBody(cli.call("GET", "/containers/"+name+"/json", nil)) + body, _, err := readBody(cli.call("GET", "/containers/"+name+"/json", nil, false)) if err != nil { return err } @@ -1673,7 +1673,7 @@ func (cli *DockerCli) CmdSearch(args ...string) error { v := url.Values{} v.Set("term", cmd.Arg(0)) - stream, _, err := cli.call("GET", "/images/search?"+v.Encode(), nil) + stream, _, err := cli.call("GET", "/images/search?"+v.Encode(), nil, true) if stream != nil { defer stream.Close() } @@ -1741,7 +1741,7 @@ func (cli *DockerCli) CmdTag(args ...string) error { v.Set("force", "1") } - if _, _, err := readBody(cli.call("POST", "/images/"+cmd.Arg(0)+"/tag?"+v.Encode(), nil)); err != nil { + if _, _, err := readBody(cli.call("POST", "/images/"+cmd.Arg(0)+"/tag?"+v.Encode(), nil, false)); err != nil { return err } return nil @@ -1990,7 +1990,7 @@ func (cli *DockerCli) CmdRun(args ...string) error { } //create the container - body, statusCode, err := readBody(cli.call("POST", "/containers/create?"+containerValues.Encode(), config)) + body, statusCode, err := readBody(cli.call("POST", "/containers/create?"+containerValues.Encode(), config, false)) //if image not found try to pull it if statusCode == 404 { _, tag := utils.ParseRepositoryTag(config.Image) @@ -2027,7 +2027,7 @@ func (cli *DockerCli) CmdRun(args ...string) error { if err = cli.stream("POST", "/images/create?"+v.Encode(), nil, cli.err, map[string][]string{"X-Registry-Auth": registryAuthHeader}); err != nil { return err } - if body, _, err = readBody(cli.call("POST", "/containers/create?"+containerValues.Encode(), config)); err != nil { + if body, _, err = readBody(cli.call("POST", "/containers/create?"+containerValues.Encode(), config, false)); err != nil { return err } } else if err != nil { @@ -2128,7 +2128,7 @@ func (cli *DockerCli) CmdRun(args ...string) error { } //start the container - if _, _, err = readBody(cli.call("POST", "/containers/"+runResult.ID+"/start", hostConfig)); err != nil { + if _, _, err = readBody(cli.call("POST", "/containers/"+runResult.ID+"/start", hostConfig, false)); err != nil { return err } @@ -2158,13 +2158,13 @@ func (cli *DockerCli) CmdRun(args ...string) error { if autoRemove { // Autoremove: wait for the container to finish, retrieve // the exit code and remove the container - if _, _, err := readBody(cli.call("POST", "/containers/"+runResult.ID+"/wait", nil)); err != nil { + if _, _, err := readBody(cli.call("POST", "/containers/"+runResult.ID+"/wait", nil, false)); err != nil { return err } if _, status, err = getExitCode(cli, runResult.ID); err != nil { return err } - if _, _, err := readBody(cli.call("DELETE", "/containers/"+runResult.ID+"?v=1", nil)); err != nil { + if _, _, err := readBody(cli.call("DELETE", "/containers/"+runResult.ID+"?v=1", nil, false)); err != nil { return err } } else { @@ -2200,7 +2200,7 @@ func (cli *DockerCli) CmdCp(args ...string) error { copyData.Resource = info[1] copyData.HostPath = cmd.Arg(1) - stream, statusCode, err := cli.call("POST", "/containers/"+info[0]+"/copy", copyData) + stream, statusCode, err := cli.call("POST", "/containers/"+info[0]+"/copy", copyData, false) if stream != nil { defer stream.Close() } @@ -2251,7 +2251,7 @@ func (cli *DockerCli) CmdLoad(args ...string) error { return nil } -func (cli *DockerCli) call(method, path string, data interface{}) (io.ReadCloser, int, error) { +func (cli *DockerCli) call(method, path string, data interface{}, passAuthInfo bool) (io.ReadCloser, int, error) { var params io.Reader if data != nil { buf, err := json.Marshal(data) @@ -2260,7 +2260,6 @@ func (cli *DockerCli) call(method, path string, data interface{}) (io.ReadCloser } params = bytes.NewBuffer(buf) } - // fixme: refactor client to support redirect re := regexp.MustCompile("/+") path = re.ReplaceAllString(path, "/") @@ -2269,6 +2268,26 @@ func (cli *DockerCli) call(method, path string, data interface{}) (io.ReadCloser if err != nil { return nil, -1, err } + if passAuthInfo { + cli.LoadConfigFile() + // Resolve the Auth config relevant for this server + authConfig := cli.configFile.ResolveAuthConfig(auth.IndexServerAddress()) + getHeaders := func(authConfig auth.AuthConfig) (map[string][]string, error) { + buf, err := json.Marshal(authConfig) + if err != nil { + return nil, err + } + registryAuthHeader := []string{ + base64.URLEncoding.EncodeToString(buf), + } + return map[string][]string{"X-Registry-Auth": registryAuthHeader}, nil + } + if headers, err := getHeaders(authConfig); err == nil && headers != nil { + for k, v := range headers { + req.Header[k] = v + } + } + } req.Header.Set("User-Agent", "Docker-Client/"+VERSION) req.Host = cli.addr if data != nil { @@ -2493,7 +2512,7 @@ func (cli *DockerCli) resizeTty(id string) { v := url.Values{} v.Set("h", strconv.Itoa(height)) v.Set("w", strconv.Itoa(width)) - if _, _, err := readBody(cli.call("POST", "/containers/"+id+"/resize?"+v.Encode(), nil)); err != nil { + if _, _, err := readBody(cli.call("POST", "/containers/"+id+"/resize?"+v.Encode(), nil, false)); err != nil { utils.Errorf("Error resize: %s", err) } } @@ -2530,7 +2549,7 @@ func (cli *DockerCli) LoadConfigFile() (err error) { } func waitForExit(cli *DockerCli, containerId string) (int, error) { - body, _, err := readBody(cli.call("POST", "/containers/"+containerId+"/wait", nil)) + body, _, err := readBody(cli.call("POST", "/containers/"+containerId+"/wait", nil, false)) if err != nil { return -1, err } @@ -2545,7 +2564,7 @@ func waitForExit(cli *DockerCli, containerId string) (int, error) { // getExitCode perform an inspect on the container. It returns // the running state and the exit code. func getExitCode(cli *DockerCli, containerId string) (bool, int, error) { - body, _, err := readBody(cli.call("GET", "/containers/"+containerId+"/json", nil)) + body, _, err := readBody(cli.call("GET", "/containers/"+containerId+"/json", nil, false)) if err != nil { // If we can't connect, then the daemon probably died. if err != ErrConnectionRefused { diff --git a/registry/registry.go b/registry/registry.go index b2d26a2dba..c0d8414de0 100644 --- a/registry/registry.go +++ b/registry/registry.go @@ -617,6 +617,10 @@ func (r *Registry) SearchRepositories(term string) (*SearchResults, error) { if err != nil { return nil, err } + if r.authConfig != nil && len(r.authConfig.Username) > 0 { + req.SetBasicAuth(r.authConfig.Username, r.authConfig.Password) + } + req.Header.Set("X-Docker-Token", "true") res, err := r.client.Do(req) if err != nil { return nil, err diff --git a/server.go b/server.go index c99b689069..6617bab7e4 100644 --- a/server.go +++ b/server.go @@ -462,9 +462,15 @@ func (srv *Server) ImagesSearch(job *engine.Job) engine.Status { job.Errorf("Usage: %s TERM", job.Name) return engine.StatusErr } - term := job.Args[0] + var ( + term = job.Args[0] + metaHeaders = map[string][]string{} + authConfig = &auth.AuthConfig{} + ) + job.GetenvJson("authConfig", authConfig) + job.GetenvJson("metaHeaders", metaHeaders) - r, err := registry.NewRegistry(nil, srv.HTTPRequestFactory(nil), auth.IndexServerAddress()) + r, err := registry.NewRegistry(authConfig, srv.HTTPRequestFactory(metaHeaders), auth.IndexServerAddress()) if err != nil { job.Error(err) return engine.StatusErr From d16691e3ad520675752ff319be054e688c50c475 Mon Sep 17 00:00:00 2001 From: "Roberto G. Hashioka" Date: Tue, 21 Jan 2014 04:11:40 +0000 Subject: [PATCH 2/2] - Ajusted server.go with gofmt Docker-DCO-1.1-Signed-off-by: Roberto Hashioka (github: rogaha) --- server.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/server.go b/server.go index 6617bab7e4..a3e15307be 100644 --- a/server.go +++ b/server.go @@ -462,13 +462,13 @@ func (srv *Server) ImagesSearch(job *engine.Job) engine.Status { job.Errorf("Usage: %s TERM", job.Name) return engine.StatusErr } - var ( - term = job.Args[0] - metaHeaders = map[string][]string{} - authConfig = &auth.AuthConfig{} - ) - job.GetenvJson("authConfig", authConfig) - job.GetenvJson("metaHeaders", metaHeaders) + var ( + term = job.Args[0] + metaHeaders = map[string][]string{} + authConfig = &auth.AuthConfig{} + ) + job.GetenvJson("authConfig", authConfig) + job.GetenvJson("metaHeaders", metaHeaders) r, err := registry.NewRegistry(authConfig, srv.HTTPRequestFactory(metaHeaders), auth.IndexServerAddress()) if err != nil {