diff --git a/builtin/providers/aws/config.go b/builtin/providers/aws/config.go index 7f2ee0d96..b703a6780 100644 --- a/builtin/providers/aws/config.go +++ b/builtin/providers/aws/config.go @@ -136,6 +136,7 @@ type AWSClient struct { r53conn *route53.Route53 partition string accountid string + supportedplatforms []string region string rdsconn *rds.RDS iamconn *iam.IAM @@ -272,6 +273,17 @@ func (c *Config) Client() (interface{}, error) { return nil, authErr } + client.ec2conn = ec2.New(awsEc2Sess) + + supportedPlatforms, err := GetSupportedEC2Platforms(client.ec2conn) + if err != nil { + // We intentionally fail *silently* because there's a chance + // user just doesn't have ec2:DescribeAccountAttributes permissions + log.Printf("[WARN] Unable to get supported EC2 platforms: %s", err) + } else { + client.supportedplatforms = supportedPlatforms + } + client.acmconn = acm.New(sess) client.apigateway = apigateway.New(sess) client.appautoscalingconn = applicationautoscaling.New(sess) @@ -290,7 +302,6 @@ func (c *Config) Client() (interface{}, error) { client.codepipelineconn = codepipeline.New(sess) client.dsconn = directoryservice.New(sess) client.dynamodbconn = dynamodb.New(dynamoSess) - client.ec2conn = ec2.New(awsEc2Sess) client.ecrconn = ecr.New(sess) client.ecsconn = ecs.New(sess) client.efsconn = efs.New(sess) @@ -389,6 +400,34 @@ func (c *Config) ValidateAccountId(accountId string) error { return nil } +func GetSupportedEC2Platforms(conn *ec2.EC2) ([]string, error) { + attrName := "supported-platforms" + + input := ec2.DescribeAccountAttributesInput{ + AttributeNames: []*string{aws.String(attrName)}, + } + attributes, err := conn.DescribeAccountAttributes(&input) + if err != nil { + return nil, err + } + + var platforms []string + for _, attr := range attributes.AccountAttributes { + if *attr.AttributeName == attrName { + for _, v := range attr.AttributeValues { + platforms = append(platforms, *v.AttributeValue) + } + break + } + } + + if len(platforms) == 0 { + return nil, fmt.Errorf("No EC2 platforms detected") + } + + return platforms, nil +} + // addTerraformVersionToUserAgent is a named handler that will add Terraform's // version information to requests made by the AWS SDK. var addTerraformVersionToUserAgent = request.NamedHandler{ diff --git a/builtin/providers/aws/config_test.go b/builtin/providers/aws/config_test.go index dc93688df..50b175c1e 100644 --- a/builtin/providers/aws/config_test.go +++ b/builtin/providers/aws/config_test.go @@ -6,13 +6,41 @@ import ( "log" "net/http" "net/http/httptest" + "reflect" + "testing" "time" "github.com/aws/aws-sdk-go/aws" awsCredentials "github.com/aws/aws-sdk-go/aws/credentials" "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go/service/ec2" ) +func TestGetSupportedEC2Platforms(t *testing.T) { + ec2Endpoints := []*awsMockEndpoint{ + &awsMockEndpoint{ + Request: &awsMockRequest{"POST", "/", "Action=DescribeAccountAttributes&" + + "AttributeName.1=supported-platforms&Version=2016-11-15"}, + Response: &awsMockResponse{200, test_ec2_describeAccountAttributes_response, "text/xml"}, + }, + } + closeFunc, sess, err := getMockedAwsApiSession("EC2", ec2Endpoints) + if err != nil { + t.Fatal(err) + } + defer closeFunc() + conn := ec2.New(sess) + + platforms, err := GetSupportedEC2Platforms(conn) + if err != nil { + t.Fatalf("Expected no error, received: %s", err) + } + expectedPlatforms := []string{"VPC", "EC2"} + if !reflect.DeepEqual(platforms, expectedPlatforms) { + t.Fatalf("Received platforms: %q\nExpected: %q\n", platforms, expectedPlatforms) + } +} + // getMockedAwsApiSession establishes a httptest server to simulate behaviour // of a real AWS API server func getMockedAwsApiSession(svcName string, endpoints []*awsMockEndpoint) (func(), *session.Session, error) { @@ -71,3 +99,20 @@ type awsMockResponse struct { Body string ContentType string } + +var test_ec2_describeAccountAttributes_response = ` + 7a62c49f-347e-4fc4-9331-6e8eEXAMPLE + + + supported-platforms + + + VPC + + + EC2 + + + + +`