Skip to content

Commit 843153d

Browse files
Merge pull request #6477 from thaJeztah/28.x_backport_cli_user_agent
[28.x backport] cli/command: add WithUserAgent option
2 parents a2d7989 + 985cee2 commit 843153d

File tree

4 files changed

+43
-5
lines changed

4 files changed

+43
-5
lines changed

cli/command/cli.go

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ type DockerCli struct {
7878
dockerEndpoint docker.Endpoint
7979
contextStoreConfig *store.Config
8080
initTimeout time.Duration
81+
userAgent string
8182
res telemetryResource
8283

8384
// baseCtx is the base context used for internal operations. In the future
@@ -313,10 +314,10 @@ func NewAPIClientFromFlags(opts *cliflags.ClientOptions, configFile *configfile.
313314
if err != nil {
314315
return nil, errors.Wrap(err, "unable to resolve docker endpoint")
315316
}
316-
return newAPIClientFromEndpoint(endpoint, configFile)
317+
return newAPIClientFromEndpoint(endpoint, configFile, client.WithUserAgent(UserAgent()))
317318
}
318319

319-
func newAPIClientFromEndpoint(ep docker.Endpoint, configFile *configfile.ConfigFile) (client.APIClient, error) {
320+
func newAPIClientFromEndpoint(ep docker.Endpoint, configFile *configfile.ConfigFile, extraOpts ...client.Opt) (client.APIClient, error) {
320321
opts, err := ep.ClientOpts()
321322
if err != nil {
322323
return nil, err
@@ -331,7 +332,7 @@ func newAPIClientFromEndpoint(ep docker.Endpoint, configFile *configfile.ConfigF
331332
if withCustomHeaders != nil {
332333
opts = append(opts, withCustomHeaders)
333334
}
334-
opts = append(opts, client.WithUserAgent(UserAgent()))
335+
opts = append(opts, extraOpts...)
335336
return client.NewClientWithOpts(opts...)
336337
}
337338

@@ -552,7 +553,8 @@ func (cli *DockerCli) initialize() error {
552553
return
553554
}
554555
if cli.client == nil {
555-
if cli.client, cli.initErr = newAPIClientFromEndpoint(cli.dockerEndpoint, cli.configFile); cli.initErr != nil {
556+
ops := []client.Opt{client.WithUserAgent(cli.userAgent)}
557+
if cli.client, cli.initErr = newAPIClientFromEndpoint(cli.dockerEndpoint, cli.configFile, ops...); cli.initErr != nil {
556558
return
557559
}
558560
}
@@ -599,6 +601,7 @@ func NewDockerCli(ops ...CLIOption) (*DockerCli, error) {
599601
WithContentTrustFromEnv(),
600602
WithDefaultContextStoreConfig(),
601603
WithStandardStreams(),
604+
WithUserAgent(UserAgent()),
602605
}
603606
ops = append(defaultOps, ops...)
604607

@@ -622,7 +625,7 @@ func getServerHost(hosts []string, defaultToTLS bool) (string, error) {
622625
}
623626
}
624627

625-
// UserAgent returns the user agent string used for making API requests
628+
// UserAgent returns the default user agent string used for making API requests.
626629
func UserAgent() string {
627630
return "Docker-Client/" + version.Version + " (" + runtime.GOOS + ")"
628631
}

cli/command/cli_options.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,3 +236,14 @@ func withCustomHeadersFromEnv() (client.Opt, error) {
236236
// see https://github.com/docker/cli/pull/5098#issuecomment-2147403871 (when updating, also update the WARNING in the function and env-var GoDoc)
237237
return client.WithHTTPHeaders(env), nil
238238
}
239+
240+
// WithUserAgent configures the User-Agent string for cli HTTP requests.
241+
func WithUserAgent(userAgent string) CLIOption {
242+
return func(cli *DockerCli) error {
243+
if userAgent == "" {
244+
return errors.New("user agent cannot be blank")
245+
}
246+
cli.userAgent = userAgent
247+
return nil
248+
}
249+
}

cli/command/cli_test.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,3 +374,26 @@ func TestSetGoDebug(t *testing.T) {
374374
assert.Equal(t, "val1,val2=1", os.Getenv("GODEBUG"))
375375
})
376376
}
377+
378+
func TestNewDockerCliWithCustomUserAgent(t *testing.T) {
379+
var received string
380+
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
381+
received = r.UserAgent()
382+
w.WriteHeader(http.StatusOK)
383+
}))
384+
defer ts.Close()
385+
host := strings.Replace(ts.URL, "http://", "tcp://", 1)
386+
opts := &flags.ClientOptions{Hosts: []string{host}}
387+
388+
cli, err := NewDockerCli(
389+
WithUserAgent("fake-agent/0.0.1"),
390+
)
391+
assert.NilError(t, err)
392+
cli.currentContext = DefaultContextName
393+
cli.options = opts
394+
cli.configFile = &configfile.ConfigFile{}
395+
396+
_, err = cli.Client().Ping(context.Background())
397+
assert.NilError(t, err)
398+
assert.DeepEqual(t, received, "fake-agent/0.0.1")
399+
}

cli/command/manifest/annotate.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ func newRegistryClient(dockerCLI command.Cli, allowInsecure bool) registryclient
5454
resolver := func(ctx context.Context, index *registry.IndexInfo) registry.AuthConfig {
5555
return command.ResolveAuthConfig(dockerCLI.ConfigFile(), index)
5656
}
57+
// FIXME(thaJeztah): this should use the userAgent as configured on the dockerCLI.
5758
return registryclient.NewRegistryClient(resolver, command.UserAgent(), allowInsecure)
5859
}
5960

0 commit comments

Comments
 (0)