diff --git a/api/client/cli.go b/api/client/cli.go index e49c5351d5..6c673da42f 100644 --- a/api/client/cli.go +++ b/api/client/cli.go @@ -140,7 +140,7 @@ func NewDockerCli(in io.ReadCloser, out, err io.Writer, clientFlags *cli.ClientF if customHeaders == nil { customHeaders = map[string]string{} } - customHeaders["User-Agent"] = "Docker-Client/" + dockerversion.Version + " (" + runtime.GOOS + ")" + customHeaders["User-Agent"] = clientUserAgent() verStr := api.DefaultVersion.String() if tmpStr := os.Getenv("DOCKER_API_VERSION"); tmpStr != "" { @@ -209,3 +209,7 @@ func newHTTPClient(host string, tlsOptions *tlsconfig.Options) (*http.Client, er Transport: tr, }, nil } + +func clientUserAgent() string { + return "Docker-Client/" + dockerversion.Version + " (" + runtime.GOOS + ")" +} diff --git a/api/client/trust.go b/api/client/trust.go index d897872ca3..fe23c2f9d3 100644 --- a/api/client/trust.go +++ b/api/client/trust.go @@ -23,7 +23,6 @@ import ( "github.com/docker/distribution/registry/client/transport" "github.com/docker/docker/cliconfig" "github.com/docker/docker/distribution" - "github.com/docker/docker/dockerversion" "github.com/docker/docker/pkg/jsonmessage" flag "github.com/docker/docker/pkg/mflag" "github.com/docker/docker/reference" @@ -152,7 +151,7 @@ func (cli *DockerCli) getNotaryRepository(repoInfo *registry.RepositoryInfo, aut } // Skip configuration headers since request is not going to Docker daemon - modifiers := registry.DockerHeaders(dockerversion.DockerUserAgent(""), http.Header{}) + modifiers := registry.DockerHeaders(clientUserAgent(), http.Header{}) authTransport := transport.NewTransport(base, modifiers...) pingClient := &http.Client{ Transport: authTransport, diff --git a/api/server/router/build/backend.go b/api/server/router/build/backend.go index 6d8fca3c62..839f316088 100644 --- a/api/server/router/build/backend.go +++ b/api/server/router/build/backend.go @@ -1,9 +1,11 @@ package build import ( + "io" + "github.com/docker/docker/builder" "github.com/docker/engine-api/types" - "io" + "golang.org/x/net/context" ) // Backend abstracts an image builder whose only purpose is to build an image referenced by an imageID. @@ -14,5 +16,5 @@ type Backend interface { // by the caller. // // TODO: make this return a reference instead of string - Build(config *types.ImageBuildOptions, context builder.Context, stdout io.Writer, stderr io.Writer, out io.Writer, clientGone <-chan bool) (string, error) + Build(clientCtx context.Context, config *types.ImageBuildOptions, context builder.Context, stdout io.Writer, stderr io.Writer, out io.Writer, clientGone <-chan bool) (string, error) } diff --git a/api/server/router/build/build_routes.go b/api/server/router/build/build_routes.go index 0025c85a93..a6ab71f57d 100644 --- a/api/server/router/build/build_routes.go +++ b/api/server/router/build/build_routes.go @@ -171,7 +171,7 @@ func (br *buildRouter) postBuild(ctx context.Context, w http.ResponseWriter, r * closeNotifier = notifier.CloseNotify() } - imgID, err := br.backend.Build(buildOptions, + imgID, err := br.backend.Build(ctx, buildOptions, builder.DockerIgnoreContext{ModifiableContext: context}, stdout, stderr, out, closeNotifier) diff --git a/api/server/router/image/backend.go b/api/server/router/image/backend.go index c0bf3aeba5..dfb02a4df3 100644 --- a/api/server/router/image/backend.go +++ b/api/server/router/image/backend.go @@ -39,6 +39,6 @@ type importExportBackend interface { type registryBackend interface { PullImage(ctx context.Context, ref reference.Named, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error - PushImage(ref reference.Named, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error - SearchRegistryForImages(term string, authConfig *types.AuthConfig, metaHeaders map[string][]string) (*registry.SearchResults, error) + PushImage(ctx context.Context, ref reference.Named, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error + SearchRegistryForImages(ctx context.Context, term string, authConfig *types.AuthConfig, metaHeaders map[string][]string) (*registry.SearchResults, error) } diff --git a/api/server/router/image/image_routes.go b/api/server/router/image/image_routes.go index aa68e115da..bd51abf3ba 100644 --- a/api/server/router/image/image_routes.go +++ b/api/server/router/image/image_routes.go @@ -228,7 +228,7 @@ func (s *imageRouter) postImagesPush(ctx context.Context, w http.ResponseWriter, w.Header().Set("Content-Type", "application/json") - if err := s.backend.PushImage(ref, metaHeaders, authConfig, output); err != nil { + if err := s.backend.PushImage(ctx, ref, metaHeaders, authConfig, output); err != nil { if !output.Flushed() { return err } @@ -373,7 +373,7 @@ func (s *imageRouter) getImagesSearch(ctx context.Context, w http.ResponseWriter headers[k] = v } } - query, err := s.backend.SearchRegistryForImages(r.Form.Get("term"), config, headers) + query, err := s.backend.SearchRegistryForImages(ctx, r.Form.Get("term"), config, headers) if err != nil { return err } diff --git a/api/server/router/system/backend.go b/api/server/router/system/backend.go index c842ce68cc..e6284cd4ab 100644 --- a/api/server/router/system/backend.go +++ b/api/server/router/system/backend.go @@ -4,6 +4,7 @@ import ( "github.com/docker/engine-api/types" "github.com/docker/engine-api/types/events" "github.com/docker/engine-api/types/filters" + "golang.org/x/net/context" ) // Backend is the methods that need to be implemented to provide @@ -13,5 +14,5 @@ type Backend interface { SystemVersion() types.Version SubscribeToEvents(since, sinceNano int64, ef filters.Args) ([]events.Message, chan interface{}) UnsubscribeFromEvents(chan interface{}) - AuthenticateToRegistry(authConfig *types.AuthConfig) (string, string, error) + AuthenticateToRegistry(ctx context.Context, authConfig *types.AuthConfig) (string, string, error) } diff --git a/api/server/router/system/system_routes.go b/api/server/router/system/system_routes.go index 1819747f7d..a994a46eb7 100644 --- a/api/server/router/system/system_routes.go +++ b/api/server/router/system/system_routes.go @@ -115,7 +115,7 @@ func (s *systemRouter) postAuth(ctx context.Context, w http.ResponseWriter, r *h if err != nil { return err } - status, token, err := s.backend.AuthenticateToRegistry(config) + status, token, err := s.backend.AuthenticateToRegistry(ctx, config) if err != nil { return err } diff --git a/builder/builder.go b/builder/builder.go index 43586a1e4f..6f8fdb8dc5 100644 --- a/builder/builder.go +++ b/builder/builder.go @@ -12,6 +12,7 @@ import ( "github.com/docker/docker/reference" "github.com/docker/engine-api/types" "github.com/docker/engine-api/types/container" + "golang.org/x/net/context" ) const ( @@ -109,7 +110,7 @@ type Backend interface { // Tag an image with newTag TagImage(newTag reference.Named, imageName string) error // Pull tells Docker to pull image referenced by `name`. - PullOnBuild(name string, authConfigs map[string]types.AuthConfig, output io.Writer) (Image, error) + PullOnBuild(ctx context.Context, name string, authConfigs map[string]types.AuthConfig, output io.Writer) (Image, error) // ContainerAttach attaches to container. ContainerAttachRaw(cID string, stdin io.ReadCloser, stdout, stderr io.Writer, stream bool) error // ContainerCreate creates a new Docker container and returns potential warnings diff --git a/builder/dockerfile/builder.go b/builder/dockerfile/builder.go index 24b31a0f9b..0d42971beb 100644 --- a/builder/dockerfile/builder.go +++ b/builder/dockerfile/builder.go @@ -17,6 +17,7 @@ import ( "github.com/docker/docker/reference" "github.com/docker/engine-api/types" "github.com/docker/engine-api/types/container" + "golang.org/x/net/context" ) var validCommitCommands = map[string]bool{ @@ -52,8 +53,9 @@ type Builder struct { Stderr io.Writer Output io.Writer - docker builder.Backend - context builder.Context + docker builder.Backend + context builder.Context + clientCtx context.Context dockerfile *parser.Node runConfig *container.Config // runconfig for cmd, run, entrypoint etc. @@ -86,7 +88,7 @@ func NewBuildManager(b builder.Backend) (bm *BuildManager) { // NewBuilder creates a new Dockerfile builder from an optional dockerfile and a Config. // If dockerfile is nil, the Dockerfile specified by Config.DockerfileName, // will be read from the Context passed to Build(). -func NewBuilder(config *types.ImageBuildOptions, backend builder.Backend, context builder.Context, dockerfile io.ReadCloser) (b *Builder, err error) { +func NewBuilder(clientCtx context.Context, config *types.ImageBuildOptions, backend builder.Backend, context builder.Context, dockerfile io.ReadCloser) (b *Builder, err error) { if config == nil { config = new(types.ImageBuildOptions) } @@ -94,6 +96,7 @@ func NewBuilder(config *types.ImageBuildOptions, backend builder.Backend, contex config.BuildArgs = make(map[string]string) } b = &Builder{ + clientCtx: clientCtx, options: config, Stdout: os.Stdout, Stderr: os.Stderr, @@ -158,8 +161,8 @@ func sanitizeRepoAndTags(names []string) ([]reference.Named, error) { } // Build creates a NewBuilder, which builds the image. -func (bm *BuildManager) Build(config *types.ImageBuildOptions, context builder.Context, stdout io.Writer, stderr io.Writer, out io.Writer, clientGone <-chan bool) (string, error) { - b, err := NewBuilder(config, bm.backend, context, nil) +func (bm *BuildManager) Build(clientCtx context.Context, config *types.ImageBuildOptions, context builder.Context, stdout io.Writer, stderr io.Writer, out io.Writer, clientGone <-chan bool) (string, error) { + b, err := NewBuilder(clientCtx, config, bm.backend, context, nil) if err != nil { return "", err } @@ -291,7 +294,7 @@ func BuildFromConfig(config *container.Config, changes []string) (*container.Con } } - b, err := NewBuilder(nil, nil, nil, nil) + b, err := NewBuilder(context.Background(), nil, nil, nil, nil) if err != nil { return nil, err } diff --git a/builder/dockerfile/dispatchers.go b/builder/dockerfile/dispatchers.go index 6323b75621..ac7c2b07e9 100644 --- a/builder/dockerfile/dispatchers.go +++ b/builder/dockerfile/dispatchers.go @@ -206,7 +206,7 @@ func from(b *Builder, args []string, attributes map[string]bool, original string // TODO: shouldn't we error out if error is different from "not found" ? } if image == nil { - image, err = b.docker.PullOnBuild(name, b.options.AuthConfigs, b.Output) + image, err = b.docker.PullOnBuild(b.clientCtx, name, b.options.AuthConfigs, b.Output) if err != nil { return err } diff --git a/daemon/daemon.go b/daemon/daemon.go index 974bf6e9d9..f04a417750 100644 --- a/daemon/daemon.go +++ b/daemon/daemon.go @@ -1030,7 +1030,7 @@ func (daemon *Daemon) PullImage(ctx context.Context, ref reference.Named, metaHe } // PullOnBuild tells Docker to pull image referenced by `name`. -func (daemon *Daemon) PullOnBuild(name string, authConfigs map[string]types.AuthConfig, output io.Writer) (builder.Image, error) { +func (daemon *Daemon) PullOnBuild(ctx context.Context, name string, authConfigs map[string]types.AuthConfig, output io.Writer) (builder.Image, error) { ref, err := reference.ParseNamed(name) if err != nil { return nil, err @@ -1052,7 +1052,7 @@ func (daemon *Daemon) PullOnBuild(name string, authConfigs map[string]types.Auth pullRegistryAuth = &resolvedConfig } - if err := daemon.PullImage(context.Background(), ref, nil, pullRegistryAuth, output); err != nil { + if err := daemon.PullImage(ctx, ref, nil, pullRegistryAuth, output); err != nil { return nil, err } return daemon.GetImage(name) @@ -1069,14 +1069,14 @@ func (daemon *Daemon) ExportImage(names []string, outStream io.Writer) error { } // PushImage initiates a push operation on the repository named localName. -func (daemon *Daemon) PushImage(ref reference.Named, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error { +func (daemon *Daemon) PushImage(ctx context.Context, ref reference.Named, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error { // Include a buffer so that slow client connections don't affect // transfer performance. progressChan := make(chan progress.Progress, 100) writesDone := make(chan struct{}) - ctx, cancelFunc := context.WithCancel(context.Background()) + ctx, cancelFunc := context.WithCancel(ctx) go func() { writeDistributionProgress(cancelFunc, outStream, progressChan) @@ -1502,16 +1502,16 @@ func configureVolumes(config *Config, rootUID, rootGID int) (*store.VolumeStore, } // AuthenticateToRegistry checks the validity of credentials in authConfig -func (daemon *Daemon) AuthenticateToRegistry(authConfig *types.AuthConfig) (string, string, error) { - return daemon.RegistryService.Auth(authConfig, dockerversion.DockerUserAgent("")) +func (daemon *Daemon) AuthenticateToRegistry(ctx context.Context, authConfig *types.AuthConfig) (string, string, error) { + return daemon.RegistryService.Auth(authConfig, dockerversion.DockerUserAgent(ctx)) } // SearchRegistryForImages queries the registry for images matching // term. authConfig is used to login. -func (daemon *Daemon) SearchRegistryForImages(term string, +func (daemon *Daemon) SearchRegistryForImages(ctx context.Context, term string, authConfig *types.AuthConfig, headers map[string][]string) (*registrytypes.SearchResults, error) { - return daemon.RegistryService.Search(term, authConfig, dockerversion.DockerUserAgent(""), headers) + return daemon.RegistryService.Search(term, authConfig, dockerversion.DockerUserAgent(ctx), headers) } // IsShuttingDown tells whether the daemon is shutting down or not diff --git a/distribution/pull_v1.go b/distribution/pull_v1.go index 9c23a676b8..a8ae624915 100644 --- a/distribution/pull_v1.go +++ b/distribution/pull_v1.go @@ -49,10 +49,10 @@ func (p *v1Puller) Pull(ctx context.Context, ref reference.Named) error { tr := transport.NewTransport( // TODO(tiborvass): was ReceiveTimeout registry.NewTransport(tlsConfig), - registry.DockerHeaders(dockerversion.DockerUserAgent(""), p.config.MetaHeaders)..., + registry.DockerHeaders(dockerversion.DockerUserAgent(ctx), p.config.MetaHeaders)..., ) client := registry.HTTPClient(tr) - v1Endpoint, err := p.endpoint.ToV1Endpoint(dockerversion.DockerUserAgent(""), p.config.MetaHeaders) + v1Endpoint, err := p.endpoint.ToV1Endpoint(dockerversion.DockerUserAgent(ctx), p.config.MetaHeaders) if err != nil { logrus.Debugf("Could not get v1 endpoint: %v", err) return fallbackError{err: err} diff --git a/distribution/push_v1.go b/distribution/push_v1.go index d82d120718..b6e4a13046 100644 --- a/distribution/push_v1.go +++ b/distribution/push_v1.go @@ -38,10 +38,10 @@ func (p *v1Pusher) Push(ctx context.Context) error { tr := transport.NewTransport( // TODO(tiborvass): was NoTimeout registry.NewTransport(tlsConfig), - registry.DockerHeaders(dockerversion.DockerUserAgent(""), p.config.MetaHeaders)..., + registry.DockerHeaders(dockerversion.DockerUserAgent(ctx), p.config.MetaHeaders)..., ) client := registry.HTTPClient(tr) - v1Endpoint, err := p.endpoint.ToV1Endpoint(dockerversion.DockerUserAgent(""), p.config.MetaHeaders) + v1Endpoint, err := p.endpoint.ToV1Endpoint(dockerversion.DockerUserAgent(ctx), p.config.MetaHeaders) if err != nil { logrus.Debugf("Could not get v1 endpoint: %v", err) return fallbackError{err: err} diff --git a/distribution/registry.go b/distribution/registry.go index 54e314bbd6..f768a14d86 100644 --- a/distribution/registry.go +++ b/distribution/registry.go @@ -37,8 +37,6 @@ func (dcs dumbCredentialStore) SetRefreshToken(*url.URL, string, string) { // providing timeout settings and authentication support, and also verifies the // remote API version. func NewV2Repository(ctx context.Context, repoInfo *registry.RepositoryInfo, endpoint registry.APIEndpoint, metaHeaders http.Header, authConfig *types.AuthConfig, actions ...string) (repo distribution.Repository, foundVersion bool, err error) { - upstreamUA := dockerversion.GetUserAgentFromContext(ctx) - repoName := repoInfo.FullName() // If endpoint does not support CanonicalName, use the RemoteName instead if endpoint.TrimHostname { @@ -59,7 +57,7 @@ func NewV2Repository(ctx context.Context, repoInfo *registry.RepositoryInfo, end DisableKeepAlives: true, } - modifiers := registry.DockerHeaders(dockerversion.DockerUserAgent(upstreamUA), metaHeaders) + modifiers := registry.DockerHeaders(dockerversion.DockerUserAgent(ctx), metaHeaders) authTransport := transport.NewTransport(base, modifiers...) challengeManager, foundVersion, err := registry.PingV2Registry(endpoint, authTransport) diff --git a/dockerversion/useragent.go b/dockerversion/useragent.go index abc0ed7f46..d2a891c4d6 100644 --- a/dockerversion/useragent.go +++ b/dockerversion/useragent.go @@ -13,7 +13,7 @@ import ( // DockerUserAgent is the User-Agent the Docker client uses to identify itself. // In accordance with RFC 7231 (5.5.3) is of the form: // [docker client's UA] UpstreamClient([upstream client's UA]) -func DockerUserAgent(upstreamUA string) string { +func DockerUserAgent(ctx context.Context) string { httpVersion := make([]useragent.VersionInfo, 0, 6) httpVersion = append(httpVersion, useragent.VersionInfo{Name: "docker", Version: Version}) httpVersion = append(httpVersion, useragent.VersionInfo{Name: "go", Version: runtime.Version()}) @@ -25,6 +25,7 @@ func DockerUserAgent(upstreamUA string) string { httpVersion = append(httpVersion, useragent.VersionInfo{Name: "arch", Version: runtime.GOARCH}) dockerUA := useragent.AppendVersions("", httpVersion...) + upstreamUA := getUserAgentFromContext(ctx) if len(upstreamUA) > 0 { ret := insertUpstreamUserAgent(upstreamUA, dockerUA) return ret @@ -32,8 +33,8 @@ func DockerUserAgent(upstreamUA string) string { return dockerUA } -// GetUserAgentFromContext returns the previously saved user-agent context stored in ctx, if one exists -func GetUserAgentFromContext(ctx context.Context) string { +// getUserAgentFromContext returns the previously saved user-agent context stored in ctx, if one exists +func getUserAgentFromContext(ctx context.Context) string { var upstreamUA string if ctx != nil { var ki interface{} = ctx.Value(httputils.UAStringKey) @@ -51,7 +52,7 @@ func escapeStr(s string, charsToEscape string) string { appended := false for _, escapeableRune := range charsToEscape { if currRune == escapeableRune { - ret += "\\" + string(currRune) + ret += `\` + string(currRune) appended = true break } @@ -67,7 +68,7 @@ func escapeStr(s string, charsToEscape string) string { // string of the form: // $dockerUA UpstreamClient($upstreamUA) func insertUpstreamUserAgent(upstreamUA string, dockerUA string) string { - charsToEscape := "();\\" //["\\", ";", "(", ")"]string + charsToEscape := `();\` upstreamUAEscaped := escapeStr(upstreamUA, charsToEscape) return fmt.Sprintf("%s UpstreamClient(%s)", dockerUA, upstreamUAEscaped) } diff --git a/integration-cli/docker_cli_registry_user_agent_test.go b/integration-cli/docker_cli_registry_user_agent_test.go index ebb2093bcb..67a950cabd 100644 --- a/integration-cli/docker_cli_registry_user_agent_test.go +++ b/integration-cli/docker_cli_registry_user_agent_test.go @@ -10,17 +10,17 @@ import ( // unescapeBackslashSemicolonParens unescapes \;() func unescapeBackslashSemicolonParens(s string) string { - re := regexp.MustCompile("\\\\;") + re := regexp.MustCompile(`\\;`) ret := re.ReplaceAll([]byte(s), []byte(";")) - re = regexp.MustCompile("\\\\\\(") + re = regexp.MustCompile(`\\\(`) ret = re.ReplaceAll([]byte(ret), []byte("(")) - re = regexp.MustCompile("\\\\\\)") + re = regexp.MustCompile(`\\\)`) ret = re.ReplaceAll([]byte(ret), []byte(")")) - re = regexp.MustCompile("\\\\\\\\") - ret = re.ReplaceAll([]byte(ret), []byte("\\")) + re = regexp.MustCompile(`\\\\`) + ret = re.ReplaceAll([]byte(ret), []byte(`\`)) return string(ret) } @@ -46,14 +46,7 @@ func regexpCheckUA(c *check.C, ua string) { c.Assert(bMatchUpstreamUA, check.Equals, true, check.Commentf("(Upstream) Docker Client User-Agent malformed")) } -// TestUserAgentPassThroughOnPull verifies that when an image is pulled from -// a registry, the registry should see a User-Agent string of the form -// [docker engine UA] UptreamClientSTREAM-CLIENT([client UA]) -func (s *DockerRegistrySuite) TestUserAgentPassThroughOnPull(c *check.C) { - reg, err := newTestRegistry(c) - c.Assert(err, check.IsNil) - expectUpstreamUA := false - +func registerUserAgentHandler(reg *testRegistry, result *string) { reg.registerHandler("/v2/", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(404) var ua string @@ -62,29 +55,66 @@ func (s *DockerRegistrySuite) TestUserAgentPassThroughOnPull(c *check.C) { ua = v[0] } } - c.Assert(ua, check.Not(check.Equals), "", check.Commentf("No User-Agent found in request")) - if r.URL.Path == "/v2/busybox/manifests/latest" { - if expectUpstreamUA { - regexpCheckUA(c, ua) - } - } + *result = ua }) +} - repoName := fmt.Sprintf("%s/busybox", reg.hostport) - err = s.d.Start("--insecure-registry", reg.hostport, "--disable-legacy-registry=true") +// TestUserAgentPassThroughOnPull verifies that when an image is pulled from +// a registry, the registry should see a User-Agent string of the form +// [docker engine UA] UptreamClientSTREAM-CLIENT([client UA]) +func (s *DockerRegistrySuite) TestUserAgentPassThrough(c *check.C) { + var ( + buildUA string + pullUA string + pushUA string + loginUA string + ) + + buildReg, err := newTestRegistry(c) + c.Assert(err, check.IsNil) + registerUserAgentHandler(buildReg, &buildUA) + buildRepoName := fmt.Sprintf("%s/busybox", buildReg.hostport) + + pullReg, err := newTestRegistry(c) + c.Assert(err, check.IsNil) + registerUserAgentHandler(pullReg, &pullUA) + pullRepoName := fmt.Sprintf("%s/busybox", pullReg.hostport) + + pushReg, err := newTestRegistry(c) + c.Assert(err, check.IsNil) + registerUserAgentHandler(pushReg, &pushUA) + pushRepoName := fmt.Sprintf("%s/busybox", pushReg.hostport) + + loginReg, err := newTestRegistry(c) + c.Assert(err, check.IsNil) + registerUserAgentHandler(loginReg, &loginUA) + + err = s.d.Start( + "--insecure-registry", buildReg.hostport, + "--insecure-registry", pullReg.hostport, + "--insecure-registry", pushReg.hostport, + "--insecure-registry", loginReg.hostport, + "--disable-legacy-registry=true") c.Assert(err, check.IsNil) - dockerfileName, cleanup, err := makefile(fmt.Sprintf("FROM %s/busybox", reg.hostport)) + dockerfileName, cleanup1, err := makefile(fmt.Sprintf("FROM %s", buildRepoName)) c.Assert(err, check.IsNil, check.Commentf("Unable to create test dockerfile")) - defer cleanup() - + defer cleanup1() s.d.Cmd("build", "--file", dockerfileName, ".") + regexpCheckUA(c, buildUA) - s.d.Cmd("run", repoName) - s.d.Cmd("login", "-u", "richard", "-p", "testtest", "-e", "testuser@testdomain.com", reg.hostport) - s.d.Cmd("tag", "busybox", repoName) - s.d.Cmd("push", repoName) + s.d.Cmd("login", "-u", "richard", "-p", "testtest", "-e", "testuser@testdomain.com", loginReg.hostport) + regexpCheckUA(c, loginUA) - expectUpstreamUA = true - s.d.Cmd("pull", repoName) + s.d.Cmd("pull", pullRepoName) + regexpCheckUA(c, pullUA) + + dockerfileName, cleanup2, err := makefile(`FROM scratch + ENV foo bar`) + c.Assert(err, check.IsNil, check.Commentf("Unable to create test dockerfile")) + defer cleanup2() + s.d.Cmd("build", "-t", pushRepoName, "--file", dockerfileName, ".") + + s.d.Cmd("push", pushRepoName) + regexpCheckUA(c, pushUA) }