diff --git a/pkg/cincinnati/cincinnati.go b/pkg/cincinnati/cincinnati.go index da6af046e..0c866c2c4 100644 --- a/pkg/cincinnati/cincinnati.go +++ b/pkg/cincinnati/cincinnati.go @@ -32,11 +32,20 @@ const ( type Client struct { id uuid.UUID transport *http.Transport + + // userAgent configures the User-Agent header for upstream + // requests. If empty, the User-Agent header will not be + // populated. + userAgent string } // NewClient creates a new Cincinnati client with the given client identifier. -func NewClient(id uuid.UUID, transport *http.Transport) Client { - return Client{id: id, transport: transport} +func NewClient(id uuid.UUID, transport *http.Transport, userAgent string) Client { + return Client{ + id: id, + transport: transport, + userAgent: userAgent, + } } // Error is returned when are unable to get updates. @@ -92,7 +101,11 @@ func (c Client) GetUpdates(ctx context.Context, uri *url.URL, desiredArch, curre if err != nil { return current, nil, nil, &Error{Reason: "InvalidRequest", Message: err.Error(), cause: err} } - req.Header.Add("Accept", GraphMediaType) + + if c.userAgent != "" { + req.Header.Set("User-Agent", c.userAgent) + } + req.Header.Set("Accept", GraphMediaType) if c.transport != nil && c.transport.TLSClientConfig != nil { if c.transport.TLSClientConfig.ClientCAs == nil { klog.V(2).Infof("Using a root CA pool with 0 root CA subjects to request updates from %s", uri) diff --git a/pkg/cincinnati/cincinnati_test.go b/pkg/cincinnati/cincinnati_test.go index 55c97b4ae..aea8e4a94 100644 --- a/pkg/cincinnati/cincinnati_test.go +++ b/pkg/cincinnati/cincinnati_test.go @@ -745,7 +745,7 @@ func TestGetUpdates(t *testing.T) { ts := httptest.NewServer(http.HandlerFunc(handler)) defer ts.Close() - c := NewClient(clientID, nil) + c := NewClient(clientID, nil, "") uri, err := url.Parse(ts.URL) if err != nil { diff --git a/pkg/cvo/availableupdates.go b/pkg/cvo/availableupdates.go index 54f50e491..9e62dd5ba 100644 --- a/pkg/cvo/availableupdates.go +++ b/pkg/cvo/availableupdates.go @@ -67,8 +67,10 @@ func (optr *Operator) syncAvailableUpdates(ctx context.Context, config *configv1 return err } + userAgent := optr.getUserAgent() + current, updates, conditionalUpdates, condition := calculateAvailableUpdatesStatus(ctx, string(config.Spec.ClusterID), - transport, upstream, desiredArch, currentArch, channel, optr.release.Version) + transport, userAgent, upstream, desiredArch, currentArch, channel, optr.release.Version) if usedDefaultUpstream { upstream = "" @@ -211,7 +213,7 @@ func (optr *Operator) getDesiredArchitecture(update *configv1.Update) string { return "" } -func calculateAvailableUpdatesStatus(ctx context.Context, clusterID string, transport *http.Transport, upstream, desiredArch, +func calculateAvailableUpdatesStatus(ctx context.Context, clusterID string, transport *http.Transport, userAgent, upstream, desiredArch, currentArch, channel, version string) (configv1.Release, []configv1.Release, []configv1.ConditionalUpdate, configv1.ClusterOperatorStatusCondition) { @@ -269,7 +271,7 @@ func calculateAvailableUpdatesStatus(ctx context.Context, clusterID string, tran } } - current, updates, conditionalUpdates, err := cincinnati.NewClient(uuid, transport).GetUpdates(ctx, upstreamURI, desiredArch, + current, updates, conditionalUpdates, err := cincinnati.NewClient(uuid, transport, userAgent).GetUpdates(ctx, upstreamURI, desiredArch, currentArch, channel, currentVersion) if err != nil { diff --git a/pkg/cvo/egress.go b/pkg/cvo/egress.go index 57809dda1..c7d484b88 100644 --- a/pkg/cvo/egress.go +++ b/pkg/cvo/egress.go @@ -10,8 +10,19 @@ import ( "golang.org/x/net/http/httpproxy" apierrors "k8s.io/apimachinery/pkg/api/errors" + + "github.com/openshift/cluster-version-operator/pkg/version" ) +// Returns a User-Agent to be used for outgoing HTTP requests. +// +// https://www.rfc-editor.org/rfc/rfc7231#section-5.5.3 +func (optr *Operator) getUserAgent() string { + token := "ClusterVersionOperator" + productVersion := version.Version + return fmt.Sprintf("%s/%s", token, productVersion) +} + // getTransport constructs an HTTP transport configuration, including // any custom proxy configuration. func (optr *Operator) getTransport() (*http.Transport, error) {