Просмотр исходного кода

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 лет назад
Родитель
Сommit
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")
 		rawRm             = r.FormValue("rm")
 		authEncoded       = r.Header.Get("X-Registry-Auth")
 		authEncoded       = r.Header.Get("X-Registry-Auth")
 		authConfig        = &auth.AuthConfig{}
 		authConfig        = &auth.AuthConfig{}
+		configFileEncoded = r.Header.Get("X-Registry-Config")
+		configFile        = &auth.ConfigFile{}
 		tag               string
 		tag               string
 	)
 	)
 	repoName, tag = utils.ParseRepositoryTag(repoName)
 	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))
 		authJson := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authEncoded))
 		if err := json.NewDecoder(authJson).Decode(authConfig); err != nil {
 		if err := json.NewDecoder(authJson).Decode(authConfig); err != nil {
 			// for a pull it is not an error if no auth was given
 			// 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
 	var context io.Reader
 
 
 	if remoteURL == "" {
 	if remoteURL == "" {
@@ -1003,7 +1019,7 @@ func postBuild(srv *Server, version float64, w http.ResponseWriter, r *http.Requ
 			Writer:          utils.NewWriteFlusher(w),
 			Writer:          utils.NewWriteFlusher(w),
 			StreamFormatter: sf,
 			StreamFormatter: sf,
 		},
 		},
-		!suppressOutput, !noCache, rm, utils.NewWriteFlusher(w), sf, authConfig)
+		!suppressOutput, !noCache, rm, utils.NewWriteFlusher(w), sf, authConfig, configFile)
 	id, err := b.Build(context)
 	id, err := b.Build(context)
 	if err != nil {
 	if err != nil {
 		if sf.Used() {
 		if sf.Used() {

+ 15 - 2
buildfile.go

@@ -8,6 +8,7 @@ import (
 	"fmt"
 	"fmt"
 	"github.com/dotcloud/docker/archive"
 	"github.com/dotcloud/docker/archive"
 	"github.com/dotcloud/docker/auth"
 	"github.com/dotcloud/docker/auth"
+	"github.com/dotcloud/docker/registry"
 	"github.com/dotcloud/docker/utils"
 	"github.com/dotcloud/docker/utils"
 	"io"
 	"io"
 	"io/ioutil"
 	"io/ioutil"
@@ -47,6 +48,7 @@ type buildFile struct {
 	rm           bool
 	rm           bool
 
 
 	authConfig *auth.AuthConfig
 	authConfig *auth.AuthConfig
+	configFile *auth.ConfigFile
 
 
 	tmpContainers map[string]struct{}
 	tmpContainers map[string]struct{}
 	tmpImages     map[string]struct{}
 	tmpImages     map[string]struct{}
@@ -72,7 +74,17 @@ func (b *buildFile) CmdFrom(name string) error {
 	if err != nil {
 	if err != nil {
 		if b.runtime.graph.IsNotExist(err) {
 		if b.runtime.graph.IsNotExist(err) {
 			remote, tag := utils.ParseRepositoryTag(name)
 			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
 				return err
 			}
 			}
 			image, err = b.runtime.repositories.LookupImage(name)
 			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")
 	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{
 	return &buildFile{
 		runtime:       srv.runtime,
 		runtime:       srv.runtime,
 		srv:           srv,
 		srv:           srv,
@@ -710,6 +722,7 @@ func NewBuildFile(srv *Server, outStream, errStream io.Writer, verbose, utilizeC
 		rm:            rm,
 		rm:            rm,
 		sf:            sf,
 		sf:            sf,
 		authConfig:    auth,
 		authConfig:    auth,
+		configFile:    authConfigFile,
 		outOld:        outOld,
 		outOld:        outOld,
 	}
 	}
 }
 }

+ 3 - 1
commands.go

@@ -227,12 +227,14 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
 		v.Set("rm", "1")
 		v.Set("rm", "1")
 	}
 	}
 
 
+	cli.LoadConfigFile()
+
 	headers := http.Header(make(map[string][]string))
 	headers := http.Header(make(map[string][]string))
 	buf, err := json.Marshal(cli.configFile)
 	buf, err := json.Marshal(cli.configFile)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
-	headers.Add("X-Registry-Auth", base64.URLEncoding.EncodeToString(buf))
+	headers.Add("X-Registry-Config", base64.URLEncoding.EncodeToString(buf))
 
 
 	if context != nil {
 	if context != nil {
 		headers.Set("Content-Type", "application/tar")
 		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
    **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
 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 q: suppress verbose build output
    :query nocache: do not use the cache when building the image
    :query nocache: do not use the cache when building the image
    :reqheader Content-type: should be set to ``"application/tar"``.
    :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 200: no error
    :statuscode 500: server 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)
 	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))
 	id, err := buildfile.Build(mkTestContext(dockerfile, context.files, t))
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
@@ -700,7 +700,7 @@ func TestForbiddenContextPath(t *testing.T) {
 	}
 	}
 	dockerfile := constructDockerfile(context.dockerfile, ip, port)
 	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))
 	_, err = buildfile.Build(mkTestContext(dockerfile, context.files, t))
 
 
 	if err == nil {
 	if err == nil {
@@ -746,7 +746,7 @@ func TestBuildADDFileNotFound(t *testing.T) {
 	}
 	}
 	dockerfile := constructDockerfile(context.dockerfile, ip, port)
 	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))
 	_, err = buildfile.Build(mkTestContext(dockerfile, context.files, t))
 
 
 	if err == nil {
 	if err == nil {