Skip to content

deconstruct the dockerversion package and move internal #50715

@thaJeztah

Description

@thaJeztah

Description

related;

deconstruct the dockerversion package and move internal

The dockerversion package is for internal use by the daemon. It has a couple of responsibilities / functionalities;

Handling of user-agent

It defines the UAtringKey{} type, which is used to attach the "upstream" (API client's) user-agent (if any) to the context and to include in OTel;

// UAStringKey is used as key type for user-agent string in net/context struct
type UAStringKey struct{}

func (s *Server) makeHTTPHandler(handler httputils.APIFunc, operation string) http.HandlerFunc {
return otelhttp.NewHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Define the context that we'll pass around to share info
// like the docker-request-id.
//
// The 'context' will be used for global data that should
// apply to all requests. Data that is specific to the
// immediate function being called should still be passed
// as 'args' on the function call.
// use intermediate variable to prevent "should not use basic type
// string as key in context.WithValue" golint errors
ua := r.Header.Get("User-Agent")
ctx := baggage.ContextWithBaggage(context.WithValue(r.Context(), dockerversion.UAStringKey{}, ua), otelutil.MustNewBaggage(
otelutil.MustNewMemberRaw(otelutil.TriggerKey, "api"),
))

It has a getUpstreamUserAgent utility to get that user-agent from the context;

// getUpstreamUserAgent returns the previously saved user-agent context stored
// in ctx, if one exists, and formats it as:
//
// UpstreamClient(<upstream user agent string>)
//
// It returns an empty string if no user-agent is present in the context.
func getUpstreamUserAgent(ctx context.Context) string {

It has a DockerUserAgent utility, which is used to construct the User-Agent that's used by the daemon itself for network requests (to registries); this user-agent is contructed of;

  • The "upstream" user-agent (if any); see above
  • The daemon's useer-agent (which includes the daemon's binary version, go version, git-commit, the host's kernel version, os, and architecture)

// 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(ctx context.Context, extraVersions ...useragent.VersionInfo) string {

To construct the user-agent, it makes use of;

  • pkg/useragent, which is a "generic" package to handle user-agents (and to handle escaping to make it well-formed)
  • pkg/parsers/kernel, which is a "somewhat" generic package to get the kernel version; it's a bit too broad for our own use (as it also handles macOS)

Version Metadata (set at compile time)

In addition to handling user-agents, it contains a number of variables that are set at compile-time;

// Default build-time variable for library-import.
// These variables are overridden on build with build-time information.
var (
GitCommit = "library-import"
Version = "library-import"
BuildTime = "library-import"
PlatformName = ""
ProductName = ""
DefaultProductLicense = ""
)

Suggested changes

User-Agent utilities

These utilities are really for internal use by the daemon and API server;

  • We should move them internal to the daemon, which can be either daemon/internal.
  • TBD: constructing the user-agent of the daemon is rather involved; do we want a WithUserAgent (e.g.) option when constructing the daemon?
  • TBD: the daemonUserAgent has docker hard-coded; should this be taken from the meta package (see below) and configurable at compile-time?

Version metadata

The compile-time variables are currently consumed directly in many places, but likely make most sense in the cmd/ or cmd/dockerd package, as they are directly related to the binary being compiled.

  • We can move the vars to a meta (e.g.) package under cmd/ or cmd/dockerd
  • Perhaps it's cleanest to pass such metadata as argument when constructing the daemon, instead of depending directly on the meta package. The daemon can hold this information?
  • ☝️ but there's some places in (e.g.) integration tests that use it, so to be looked at more closely.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions