From 414b1ecd1633cb37ce90b692f2d67ab38613ea8f Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Tue, 2 Nov 2021 16:57:45 -0700 Subject: [PATCH] Adds Config parameter to append user-agent products --- aws_config.go | 5 +++ aws_config_test.go | 57 +++++++++++++++++++++++++++++++++-- config.go | 4 +-- internal/config/apn_info.go | 13 -------- internal/config/config.go | 7 +++-- internal/config/user_agent.go | 26 ++++++++++++++++ v2/awsv1shim/session.go | 4 +++ v2/awsv1shim/session_test.go | 57 +++++++++++++++++++++++++++++++++-- 8 files changed, 152 insertions(+), 21 deletions(-) create mode 100644 internal/config/user_agent.go diff --git a/aws_config.go b/aws_config.go index 7a1c6502..682a56ce 100644 --- a/aws_config.go +++ b/aws_config.go @@ -135,6 +135,11 @@ func commonLoadOptions(c *Config) ([]func(*config.LoadOptions) error, error) { return stack.Build.Add(apnUserAgentMiddleware(*c.APNInfo), middleware.After) }) } + + if len(c.UserAgent) > 0 { + apiOptions = append(apiOptions, awsmiddleware.AddUserAgentKey(c.UserAgent.BuildUserAgentString())) + } + if v := os.Getenv(constants.AppendUserAgentEnvVar); v != "" { log.Printf("[DEBUG] Using additional User-Agent Info: %s", v) apiOptions = append(apiOptions, awsmiddleware.AddUserAgentKey(v)) diff --git a/aws_config_test.go b/aws_config_test.go index e0af89bb..fab097df 100644 --- a/aws_config_test.go +++ b/aws_config_test.go @@ -999,7 +999,7 @@ func TestUserAgentProducts(t *testing.T) { SecretKey: servicemocks.MockStaticSecretKey, APNInfo: &APNInfo{ PartnerName: "partner", - Products: []APNProduct{ + Products: []UserAgentProduct{ { Name: "first", Version: "1.2.3", @@ -1022,7 +1022,7 @@ func TestUserAgentProducts(t *testing.T) { SecretKey: servicemocks.MockStaticSecretKey, APNInfo: &APNInfo{ PartnerName: "partner", - Products: []APNProduct{ + Products: []UserAgentProduct{ { Name: "first", Version: "1.2.3", @@ -1040,6 +1040,59 @@ func TestUserAgentProducts(t *testing.T) { }, ExpectedUserAgent: "APN/1.0 partner/1.0 first/1.2.3 second/1.0.2 " + awsSdkGoUserAgent() + " Last", }, + { + Config: &Config{ + AccessKey: servicemocks.MockStaticAccessKey, + Region: "us-east-1", + SecretKey: servicemocks.MockStaticSecretKey, + UserAgent: []UserAgentProduct{ + { + Name: "first", + Version: "1.2.3", + }, + { + Name: "second", + Version: "1.0.2", + Comment: "a comment", + }, + }, + }, + Description: "User-Agent Products", + ExpectedUserAgent: awsSdkGoUserAgent() + " first/1.2.3 second/1.0.2 (a comment)", + }, + { + Config: &Config{ + AccessKey: servicemocks.MockStaticAccessKey, + Region: "us-east-1", + SecretKey: servicemocks.MockStaticSecretKey, + APNInfo: &APNInfo{ + PartnerName: "partner", + Products: []UserAgentProduct{ + { + Name: "first", + Version: "1.2.3", + }, + { + Name: "second", + Version: "1.0.2", + Comment: "a comment", + }, + }, + }, + UserAgent: []UserAgentProduct{ + { + Name: "third", + Version: "4.5.6", + }, + { + Name: "fourth", + Version: "2.1", + }, + }, + }, + Description: "APN and User-Agent Products", + ExpectedUserAgent: "APN/1.0 partner/1.0 first/1.2.3 second/1.0.2 (a comment) " + awsSdkGoUserAgent() + " third/4.5.6 fourth/2.1", + }, } var ( diff --git a/config.go b/config.go index bf997e84..e63893ad 100644 --- a/config.go +++ b/config.go @@ -11,6 +11,6 @@ type Config = config.Config type APNInfo = config.APNInfo -type APNProduct = config.APNProduct - type AssumeRole = config.AssumeRole + +type UserAgentProduct = config.UserAgentProduct diff --git a/internal/config/apn_info.go b/internal/config/apn_info.go index ae5c5fd6..9079fe98 100644 --- a/internal/config/apn_info.go +++ b/internal/config/apn_info.go @@ -14,16 +14,3 @@ func (apn APNInfo) BuildUserAgentString() string { } return builder.Build() } - -func (p APNProduct) buildUserAgentPart(b *smithyhttp.UserAgentBuilder) { - if p.Name != "" { - if p.Version != "" { - b.AddKeyValue(p.Name, p.Version) - } else { - b.AddKey(p.Name) - } - } - if p.Comment != "" { - b.AddKey("(" + p.Comment + ")") - } -} diff --git a/internal/config/config.go b/internal/config/config.go index ab4c398c..0cd5f774 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -20,19 +20,22 @@ type Config struct { SkipMetadataApiCheck bool StsEndpoint string Token string + UserAgent UserAgentProducts } type APNInfo struct { PartnerName string - Products []APNProduct + Products []UserAgentProduct } -type APNProduct struct { +type UserAgentProduct struct { Name string Version string Comment string } +type UserAgentProducts []UserAgentProduct + type AssumeRole struct { RoleARN string DurationSeconds int diff --git a/internal/config/user_agent.go b/internal/config/user_agent.go new file mode 100644 index 00000000..31f8ba9a --- /dev/null +++ b/internal/config/user_agent.go @@ -0,0 +1,26 @@ +package config + +import ( + smithyhttp "github.com/aws/smithy-go/transport/http" +) + +func (ua UserAgentProducts) BuildUserAgentString() string { + builder := smithyhttp.NewUserAgentBuilder() + for _, p := range ua { + p.buildUserAgentPart(builder) + } + return builder.Build() +} + +func (p UserAgentProduct) buildUserAgentPart(b *smithyhttp.UserAgentBuilder) { + if p.Name != "" { + if p.Version != "" { + b.AddKeyValue(p.Name, p.Version) + } else { + b.AddKey(p.Name) + } + } + if p.Comment != "" { + b.AddKey("(" + p.Comment + ")") + } +} diff --git a/v2/awsv1shim/session.go b/v2/awsv1shim/session.go index aa43aabd..7d56281e 100644 --- a/v2/awsv1shim/session.go +++ b/v2/awsv1shim/session.go @@ -88,6 +88,10 @@ func GetSession(awsC *awsv2.Config, c *awsbase.Config) (*session.Session, error) ) } + if len(c.UserAgent) > 0 { + sess.Handlers.Build.PushBack(request.MakeAddToUserAgentFreeFormHandler(c.UserAgent.BuildUserAgentString())) + } + // Add custom input from ENV to the User-Agent request header // Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/9149 if v := os.Getenv(constants.AppendUserAgentEnvVar); v != "" { diff --git a/v2/awsv1shim/session_test.go b/v2/awsv1shim/session_test.go index 7e498345..58f0e2c2 100644 --- a/v2/awsv1shim/session_test.go +++ b/v2/awsv1shim/session_test.go @@ -1047,7 +1047,7 @@ func TestUserAgentProducts(t *testing.T) { SecretKey: servicemocks.MockStaticSecretKey, APNInfo: &awsbase.APNInfo{ PartnerName: "partner", - Products: []awsbase.APNProduct{ + Products: []awsbase.UserAgentProduct{ { Name: "first", Version: "1.2.3", @@ -1073,7 +1073,7 @@ func TestUserAgentProducts(t *testing.T) { SecretKey: servicemocks.MockStaticSecretKey, APNInfo: &awsbase.APNInfo{ PartnerName: "partner", - Products: []awsbase.APNProduct{ + Products: []awsbase.UserAgentProduct{ { Name: "first", Version: "1.2.3", @@ -1094,6 +1094,59 @@ func TestUserAgentProducts(t *testing.T) { servicemocks.MockStsGetCallerIdentityValidEndpoint, }, }, + // { + // Config: &awsbase.Config{ + // AccessKey: servicemocks.MockStaticAccessKey, + // Region: "us-east-1", + // SecretKey: servicemocks.MockStaticSecretKey, + // UserAgent: []awsbase.UserAgentProduct{ + // { + // Name: "first", + // Version: "1.2.3", + // }, + // { + // Name: "second", + // Version: "1.0.2", + // Comment: "a comment", + // }, + // }, + // }, + // Description: "User-Agent Products", + // ExpectedUserAgent: awsSdkGoUserAgent() + " first/1.2.3 second/1.0.2 (a comment)", + // }, + { + Config: &awsbase.Config{ + AccessKey: servicemocks.MockStaticAccessKey, + Region: "us-east-1", + SecretKey: servicemocks.MockStaticSecretKey, + APNInfo: &awsbase.APNInfo{ + PartnerName: "partner", + Products: []awsbase.UserAgentProduct{ + { + Name: "first", + Version: "1.2.3", + }, + { + Name: "second", + Version: "1.0.2", + Comment: "a comment", + }, + }, + }, + UserAgent: []awsbase.UserAgentProduct{ + { + Name: "third", + Version: "4.5.6", + }, + { + Name: "fourth", + Version: "2.1", + }, + }, + }, + Description: "APN and User-Agent Products", + ExpectedUserAgent: "APN/1.0 partner/1.0 first/1.2.3 second/1.0.2 (a comment) " + awsSdkGoUserAgent() + " third/4.5.6 fourth/2.1", + }, } for _, testCase := range testCases {