Browse Source

Fix support for registry auth with Dockerfile build.

Docker-DCO-1.1-Signed-off-by: Jake Moshenko <jake@devtable.com> (github: jakedt)
Jake Moshenko 11 năm trước cách đây
mục cha
commit
6e6ff85362

+ 18 - 2
api.go

@@ -925,10 +925,17 @@ func postBuild(srv *Server, version float64, w http.ResponseWriter, r *http.Requ
 		rawRm             = r.FormValue("rm")
 		authEncoded       = r.Header.Get("X-Registry-Auth")
 		authConfig        = &auth.AuthConfig{}
+		configFileEncoded = r.Header.Get("X-Registry-Config")
+		configFile        = &auth.ConfigFile{}
 		tag               string
 	)
 	repoName, tag = utils.ParseRepositoryTag(repoName)
-	if authEncoded != "" {
+
+	// This block can be removed when API versions prior to 1.9 are deprecated.
+	// Both headers will be parsed and sent along to the daemon, but if a non-empty
+	// ConfigFile is present, any value provided as an AuthConfig directly will
+	// be overridden. See BuildFile::CmdFrom for details.
+	if version < 1.9 && 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
@@ -937,6 +944,15 @@ func postBuild(srv *Server, version float64, w http.ResponseWriter, r *http.Requ
 		}
 	}
 
+	if configFileEncoded != "" {
+		configFileJson := base64.NewDecoder(base64.URLEncoding, strings.NewReader(configFileEncoded))
+		if err := json.NewDecoder(configFileJson).Decode(configFile); 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
+			configFile = &auth.ConfigFile{}
+		}
+	}
+
 	var context io.Reader
 
 	if remoteURL == "" {
@@ -1003,7 +1019,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, authConfig)
+		!suppressOutput, !noCache, rm, utils.NewWriteFlusher(w), sf, authConfig, configFile)
 	id, err := b.Build(context)
 	if err != nil {
 		if sf.Used() {

+ 15 - 2
buildfile.go

@@ -8,6 +8,7 @@ import (
 	"fmt"
 	"github.com/dotcloud/docker/archive"
 	"github.com/dotcloud/docker/auth"
+	"github.com/dotcloud/docker/registry"
 	"github.com/dotcloud/docker/utils"
 	"io"
 	"io/ioutil"
@@ -47,6 +48,7 @@ type buildFile struct {
 	rm           bool
 
 	authConfig *auth.AuthConfig
+	configFile *auth.ConfigFile
 
 	tmpContainers map[string]struct{}
 	tmpImages     map[string]struct{}
@@ -72,7 +74,17 @@ 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, b.authConfig, nil, true); err != nil {
+			pullRegistryAuth := b.authConfig
+			if len(b.configFile.Configs) > 0 {
+				// The request came with a full auth config file, we prefer to use that
+				endpoint, _, err := registry.ResolveRepositoryName(remote)
+				if err != nil {
+					return err
+				}
+				resolvedAuth := b.configFile.ResolveAuthConfig(endpoint)
+				pullRegistryAuth = &resolvedAuth
+			}
+			if err := b.srv.ImagePull(remote, tag, b.outOld, b.sf, pullRegistryAuth, nil, true); err != nil {
 				return err
 			}
 			image, err = b.runtime.repositories.LookupImage(name)
@@ -696,7 +708,7 @@ func (b *buildFile) Build(context io.Reader) (string, error) {
 	return "", fmt.Errorf("No image was generated. This may be because the Dockerfile does not, like, do anything.\n")
 }
 
-func NewBuildFile(srv *Server, outStream, errStream io.Writer, verbose, utilizeCache, rm bool, outOld io.Writer, sf *utils.StreamFormatter, auth *auth.AuthConfig) BuildFile {
+func NewBuildFile(srv *Server, outStream, errStream io.Writer, verbose, utilizeCache, rm bool, outOld io.Writer, sf *utils.StreamFormatter, auth *auth.AuthConfig, authConfigFile *auth.ConfigFile) BuildFile {
 	return &buildFile{
 		runtime:       srv.runtime,
 		srv:           srv,
@@ -710,6 +722,7 @@ func NewBuildFile(srv *Server, outStream, errStream io.Writer, verbose, utilizeC
 		rm:            rm,
 		sf:            sf,
 		authConfig:    auth,
+		configFile:    authConfigFile,
 		outOld:        outOld,
 	}
 }

+ 3 - 1
commands.go

@@ -227,12 +227,14 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
 		v.Set("rm", "1")
 	}
 
+	cli.LoadConfigFile()
+
 	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))
+	headers.Add("X-Registry-Config", base64.URLEncoding.EncodeToString(buf))
 
 	if context != nil {
 		headers.Set("Content-Type", "application/tar")

+ 7 - 0
docs/sources/reference/api/docker_remote_api.rst

@@ -54,6 +54,13 @@ What's new
 
    **New!** This endpoint now returns a list of json message, like the events endpoint
 
+.. http:post:: /build
+
+   **New!** This endpoint now takes a serialized ConfigFile which it uses to
+   resolve the proper registry auth credentials for pulling the base image.
+   Clients which previously implemented the version accepting an AuthConfig
+   object must be updated.
+
 v1.8
 ****
 

+ 1 - 1
docs/sources/reference/api/docker_remote_api_v1.9.rst

@@ -1025,7 +1025,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
+   :reqheader X-Registry-Config: base64-encoded ConfigFile object
    :statuscode 200: no error
    :statuscode 500: server error
 

+ 3 - 3
integration/buildfile_test.go

@@ -296,7 +296,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), nil)
+	buildfile := docker.NewBuildFile(srv, ioutil.Discard, ioutil.Discard, false, useCache, false, ioutil.Discard, utils.NewStreamFormatter(false), nil, nil)
 	id, err := buildfile.Build(mkTestContext(dockerfile, context.files, t))
 	if err != nil {
 		return nil, err
@@ -700,7 +700,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), nil)
+	buildfile := docker.NewBuildFile(srv, ioutil.Discard, ioutil.Discard, false, true, false, ioutil.Discard, utils.NewStreamFormatter(false), nil, nil)
 	_, err = buildfile.Build(mkTestContext(dockerfile, context.files, t))
 
 	if err == nil {
@@ -746,7 +746,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), nil)
+	buildfile := docker.NewBuildFile(mkServerFromEngine(eng, t), ioutil.Discard, ioutil.Discard, false, true, false, ioutil.Discard, utils.NewStreamFormatter(false), nil, nil)
 	_, err = buildfile.Build(mkTestContext(dockerfile, context.files, t))
 
 	if err == nil {