diff --git a/api.go b/api.go index 819926692b..da1fa9edee 100644 --- a/api.go +++ b/api.go @@ -889,12 +889,25 @@ func postBuild(srv *Server, version float64, w http.ResponseWriter, r *http.Requ if version < 1.3 { return fmt.Errorf("Multipart upload for build is no longer supported. Please upgrade your docker client.") } - remoteURL := r.FormValue("remote") - repoName := r.FormValue("t") - rawSuppressOutput := r.FormValue("q") - rawNoCache := r.FormValue("nocache") - rawRm := r.FormValue("rm") - repoName, tag := utils.ParseRepositoryTag(repoName) + var ( + remoteURL = r.FormValue("remote") + repoName = r.FormValue("t") + rawSuppressOutput = r.FormValue("q") + rawNoCache = r.FormValue("nocache") + rawRm = r.FormValue("rm") + authEncoded = r.Header.Get("X-Registry-Auth") + authConfig = &auth.AuthConfig{} + tag string + ) + repoName, tag = utils.ParseRepositoryTag(repoName) + 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 = &auth.AuthConfig{} + } + } var context io.Reader @@ -962,7 +975,7 @@ func postBuild(srv *Server, version float64, w http.ResponseWriter, r *http.Requ Writer: utils.NewWriteFlusher(w), StreamFormatter: sf, }, - !suppressOutput, !noCache, rm, utils.NewWriteFlusher(w), sf) + !suppressOutput, !noCache, rm, utils.NewWriteFlusher(w), sf, authConfig) id, err := b.Build(context) if err != nil { if sf.Used() { diff --git a/buildfile.go b/buildfile.go index adbf98d274..7d87a17d3a 100644 --- a/buildfile.go +++ b/buildfile.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" "github.com/dotcloud/docker/archive" + "github.com/dotcloud/docker/auth" "github.com/dotcloud/docker/utils" "io" "io/ioutil" @@ -33,6 +34,8 @@ type buildFile struct { utilizeCache bool rm bool + authConfig *auth.AuthConfig + tmpContainers map[string]struct{} tmpImages map[string]struct{} @@ -57,7 +60,7 @@ func (b *buildFile) CmdFrom(name string) error { if err != nil { if b.runtime.graph.IsNotExist(err) { remote, tag := utils.ParseRepositoryTag(name) - if err := b.srv.ImagePull(remote, tag, b.outOld, b.sf, nil, nil, true); err != nil { + if err := b.srv.ImagePull(remote, tag, b.outOld, b.sf, b.authConfig, nil, true); err != nil { return err } image, err = b.runtime.repositories.LookupImage(name) @@ -568,7 +571,7 @@ func (b *buildFile) Build(context io.Reader) (string, error) { return "", fmt.Errorf("An error occurred during the build\n") } -func NewBuildFile(srv *Server, outStream, errStream io.Writer, verbose, utilizeCache, rm bool, outOld io.Writer, sf *utils.StreamFormatter) BuildFile { +func NewBuildFile(srv *Server, outStream, errStream io.Writer, verbose, utilizeCache, rm bool, outOld io.Writer, sf *utils.StreamFormatter, auth *auth.AuthConfig) BuildFile { return &buildFile{ runtime: srv.runtime, srv: srv, @@ -581,6 +584,7 @@ func NewBuildFile(srv *Server, outStream, errStream io.Writer, verbose, utilizeC utilizeCache: utilizeCache, rm: rm, sf: sf, + authConfig: auth, outOld: outOld, } } diff --git a/commands.go b/commands.go index df49b54492..ef6dce6bd5 100644 --- a/commands.go +++ b/commands.go @@ -227,6 +227,12 @@ func (cli *DockerCli) CmdBuild(args ...string) error { } headers := http.Header(make(map[string][]string)) + buf, err := json.Marshal(cli.configFile) + if err != nil { + return err + } + headers.Add("X-Registry-Auth", base64.URLEncoding.EncodeToString(buf)) + if context != nil { headers.Set("Content-Type", "application/tar") } diff --git a/docs/sources/api/docker_remote_api_v1.8.rst b/docs/sources/api/docker_remote_api_v1.8.rst index 909e9a7a7f..bc51e209ef 100644 --- a/docs/sources/api/docker_remote_api_v1.8.rst +++ b/docs/sources/api/docker_remote_api_v1.8.rst @@ -1026,6 +1026,7 @@ Build an image from Dockerfile via stdin :query q: suppress verbose build output :query nocache: do not use the cache when building the image :reqheader Content-type: should be set to ``"application/tar"``. + :reqheader X-Registry-Auth: base64-encoded AuthConfig object :statuscode 200: no error :statuscode 500: server error diff --git a/integration/buildfile_test.go b/integration/buildfile_test.go index 242bf9f412..4d15031d30 100644 --- a/integration/buildfile_test.go +++ b/integration/buildfile_test.go @@ -266,7 +266,7 @@ func buildImage(context testContextTemplate, t *testing.T, eng *engine.Engine, u } dockerfile := constructDockerfile(context.dockerfile, ip, port) - buildfile := docker.NewBuildFile(srv, ioutil.Discard, ioutil.Discard, false, useCache, false, ioutil.Discard, utils.NewStreamFormatter(false)) + buildfile := docker.NewBuildFile(srv, ioutil.Discard, ioutil.Discard, false, useCache, false, ioutil.Discard, utils.NewStreamFormatter(false), nil) id, err := buildfile.Build(mkTestContext(dockerfile, context.files, t)) if err != nil { return nil, err @@ -516,7 +516,7 @@ func TestForbiddenContextPath(t *testing.T) { } dockerfile := constructDockerfile(context.dockerfile, ip, port) - buildfile := docker.NewBuildFile(srv, ioutil.Discard, ioutil.Discard, false, true, false, ioutil.Discard, utils.NewStreamFormatter(false)) + buildfile := docker.NewBuildFile(srv, ioutil.Discard, ioutil.Discard, false, true, false, ioutil.Discard, utils.NewStreamFormatter(false), nil) _, err = buildfile.Build(mkTestContext(dockerfile, context.files, t)) if err == nil { @@ -562,7 +562,7 @@ func TestBuildADDFileNotFound(t *testing.T) { } dockerfile := constructDockerfile(context.dockerfile, ip, port) - buildfile := docker.NewBuildFile(mkServerFromEngine(eng, t), ioutil.Discard, ioutil.Discard, false, true, false, ioutil.Discard, utils.NewStreamFormatter(false)) + buildfile := docker.NewBuildFile(mkServerFromEngine(eng, t), ioutil.Discard, ioutil.Discard, false, true, false, ioutil.Discard, utils.NewStreamFormatter(false), nil) _, err = buildfile.Build(mkTestContext(dockerfile, context.files, t)) if err == nil {