-
Notifications
You must be signed in to change notification settings - Fork 9.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
provider: Prevent panic when setting endpoints configuration #8226
Changes from all commits
d9351bd
67dbc79
d3eb7ff
3af4c38
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -968,6 +968,7 @@ func providerConfigure(d *schema.ResourceData) (interface{}, error) { | |
Profile: d.Get("profile").(string), | ||
Token: d.Get("token").(string), | ||
Region: d.Get("region").(string), | ||
Endpoints: make(map[string]string), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ✔️ |
||
MaxRetries: d.Get("max_retries").(int), | ||
Insecure: d.Get("insecure").(bool), | ||
SkipCredsValidation: d.Get("skip_credentials_validation").(bool), | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,7 +4,9 @@ import ( | |
"fmt" | ||
"log" | ||
"os" | ||
"reflect" | ||
"regexp" | ||
"strings" | ||
"testing" | ||
|
||
"github.com/aws/aws-sdk-go/aws/arn" | ||
|
@@ -355,3 +357,212 @@ func testSweepSkipSweepError(err error) bool { | |
} | ||
return false | ||
} | ||
|
||
func TestAccAWSProvider_Endpoints(t *testing.T) { | ||
var providers []*schema.Provider | ||
var endpoints strings.Builder | ||
|
||
// Initialize each endpoint configuration with matching name and value | ||
for _, endpointServiceName := range endpointServiceNames { | ||
// Skip deprecated endpoint configurations as they will override expected values | ||
if endpointServiceName == "kinesis_analytics" || endpointServiceName == "r53" { | ||
continue | ||
} | ||
|
||
endpoints.WriteString(fmt.Sprintf("%s = \"http://%s\"\n", endpointServiceName, endpointServiceName)) | ||
} | ||
|
||
resource.ParallelTest(t, resource.TestCase{ | ||
PreCheck: func() { testAccPreCheck(t) }, | ||
ProviderFactories: testAccProviderFactories(&providers), | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: testAccAWSProviderConfigEndpoints(endpoints.String()), | ||
Check: resource.ComposeTestCheckFunc( | ||
testAccCheckAWSProviderEndpoints(&providers), | ||
), | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func TestAccAWSProvider_Endpoints_Deprecated(t *testing.T) { | ||
var providers []*schema.Provider | ||
var endpointsDeprecated strings.Builder | ||
|
||
// Initialize each deprecated endpoint configuration with matching name and value | ||
for _, endpointServiceName := range endpointServiceNames { | ||
// Only configure deprecated endpoint configurations | ||
if endpointServiceName != "kinesis_analytics" && endpointServiceName != "r53" { | ||
continue | ||
} | ||
|
||
endpointsDeprecated.WriteString(fmt.Sprintf("%s = \"http://%s\"\n", endpointServiceName, endpointServiceName)) | ||
} | ||
|
||
resource.ParallelTest(t, resource.TestCase{ | ||
PreCheck: func() { testAccPreCheck(t) }, | ||
ProviderFactories: testAccProviderFactories(&providers), | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: testAccAWSProviderConfigEndpoints(endpointsDeprecated.String()), | ||
Check: resource.ComposeTestCheckFunc( | ||
testAccCheckAWSProviderEndpointsDeprecated(&providers), | ||
), | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func testAccCheckAWSProviderEndpoints(providers *[]*schema.Provider) resource.TestCheckFunc { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This function signature threw me for a bit. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Indeed it is a little bizarre! Dealing with pointers here so we can instantiate the slice during runtime. See also: |
||
return func(s *terraform.State) error { | ||
if providers == nil { | ||
return fmt.Errorf("no providers initialized") | ||
} | ||
|
||
// Match AWSClient struct field names to endpoint configuration names | ||
endpointFieldNameF := func(endpoint string) func(string) bool { | ||
return func(name string) bool { | ||
switch endpoint { | ||
case "applicationautoscaling": | ||
endpoint = "appautoscaling" | ||
case "budgets": | ||
endpoint = "budget" | ||
case "cloudformation": | ||
endpoint = "cf" | ||
case "cloudhsm": | ||
endpoint = "cloudhsmv2" | ||
case "cognitoidentity": | ||
endpoint = "cognito" | ||
case "configservice": | ||
endpoint = "config" | ||
case "cur": | ||
endpoint = "costandusagereport" | ||
case "directconnect": | ||
endpoint = "dx" | ||
case "lexmodels": | ||
endpoint = "lexmodel" | ||
case "route53": | ||
endpoint = "r53" | ||
case "sdb": | ||
endpoint = "simpledb" | ||
case "serverlessrepo": | ||
endpoint = "serverlessapplicationrepository" | ||
case "servicecatalog": | ||
endpoint = "sc" | ||
case "servicediscovery": | ||
endpoint = "sd" | ||
case "stepfunctions": | ||
endpoint = "sfn" | ||
} | ||
|
||
switch name { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thought about recommending an if statement here, but the multiple |
||
case endpoint, fmt.Sprintf("%sconn", endpoint), fmt.Sprintf("%sConn", endpoint): | ||
return true | ||
} | ||
|
||
return false | ||
} | ||
} | ||
|
||
for _, provider := range *providers { | ||
if provider == nil || provider.Meta() == nil || provider.Meta().(*AWSClient) == nil { | ||
continue | ||
} | ||
|
||
providerClient := provider.Meta().(*AWSClient) | ||
|
||
for _, endpointServiceName := range endpointServiceNames { | ||
// Skip deprecated endpoint configurations as they will override expected values | ||
if endpointServiceName == "kinesis_analytics" || endpointServiceName == "r53" { | ||
continue | ||
} | ||
|
||
providerClientField := reflect.Indirect(reflect.ValueOf(providerClient)).FieldByNameFunc(endpointFieldNameF(endpointServiceName)) | ||
|
||
if !providerClientField.IsValid() { | ||
return fmt.Errorf("unable to match AWSClient struct field name for endpoint name: %s", endpointServiceName) | ||
} | ||
|
||
actualEndpoint := reflect.Indirect(reflect.Indirect(providerClientField).FieldByName("Config").FieldByName("Endpoint")).String() | ||
expectedEndpoint := fmt.Sprintf("http://%s", endpointServiceName) | ||
|
||
if actualEndpoint != expectedEndpoint { | ||
return fmt.Errorf("expected endpoint (%s) value (%s), got: %s", endpointServiceName, expectedEndpoint, actualEndpoint) | ||
} | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
} | ||
|
||
func testAccCheckAWSProviderEndpointsDeprecated(providers *[]*schema.Provider) resource.TestCheckFunc { | ||
return func(s *terraform.State) error { | ||
if providers == nil { | ||
return fmt.Errorf("no providers initialized") | ||
} | ||
|
||
// Match AWSClient struct field names to endpoint configuration names | ||
endpointFieldNameF := func(endpoint string) func(string) bool { | ||
return func(name string) bool { | ||
switch endpoint { | ||
case "kinesis_analytics": | ||
endpoint = "kinesisanalytics" | ||
} | ||
|
||
return name == fmt.Sprintf("%sconn", endpoint) | ||
} | ||
} | ||
|
||
for _, provider := range *providers { | ||
if provider == nil || provider.Meta() == nil || provider.Meta().(*AWSClient) == nil { | ||
continue | ||
} | ||
|
||
providerClient := provider.Meta().(*AWSClient) | ||
|
||
for _, endpointServiceName := range endpointServiceNames { | ||
// Only check deprecated endpoint configurations | ||
if endpointServiceName != "kinesis_analytics" && endpointServiceName != "r53" { | ||
continue | ||
} | ||
|
||
providerClientField := reflect.Indirect(reflect.ValueOf(providerClient)).FieldByNameFunc(endpointFieldNameF(endpointServiceName)) | ||
|
||
if !providerClientField.IsValid() { | ||
return fmt.Errorf("unable to match AWSClient struct field name for endpoint name: %s", endpointServiceName) | ||
} | ||
|
||
actualEndpoint := reflect.Indirect(reflect.Indirect(providerClientField).FieldByName("Config").FieldByName("Endpoint")).String() | ||
expectedEndpoint := fmt.Sprintf("http://%s", endpointServiceName) | ||
|
||
if actualEndpoint != expectedEndpoint { | ||
return fmt.Errorf("expected endpoint (%s) value (%s), got: %s", endpointServiceName, expectedEndpoint, actualEndpoint) | ||
} | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
} | ||
|
||
func testAccAWSProviderConfigEndpoints(endpoints string) string { | ||
return fmt.Sprintf(` | ||
provider "aws" { | ||
skip_credentials_validation = true | ||
skip_get_ec2_platforms = true | ||
skip_metadata_api_check = true | ||
skip_requesting_account_id = true | ||
|
||
endpoints { | ||
%[1]s | ||
} | ||
} | ||
|
||
# Required to initialize the provider | ||
data "aws_arn" "test" { | ||
arn = "arn:aws:s3:::test" | ||
} | ||
`, endpoints) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was a bug discovered by the new acceptance testing. 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍