provider/aws: Add support for api_gateway_account (#6321)

This commit is contained in:
Radek Simko 2016-04-27 14:08:59 +02:00 committed by Paul Stack
parent 0194cfda0a
commit e3ade6a784
7 changed files with 476 additions and 0 deletions

View File

@ -114,6 +114,7 @@ func Provider() terraform.ResourceProvider {
"aws_ami": resourceAwsAmi(), "aws_ami": resourceAwsAmi(),
"aws_ami_copy": resourceAwsAmiCopy(), "aws_ami_copy": resourceAwsAmiCopy(),
"aws_ami_from_instance": resourceAwsAmiFromInstance(), "aws_ami_from_instance": resourceAwsAmiFromInstance(),
"aws_api_gateway_account": resourceAwsApiGatewayAccount(),
"aws_api_gateway_api_key": resourceAwsApiGatewayApiKey(), "aws_api_gateway_api_key": resourceAwsApiGatewayApiKey(),
"aws_api_gateway_authorizer": resourceAwsApiGatewayAuthorizer(), "aws_api_gateway_authorizer": resourceAwsApiGatewayAuthorizer(),
"aws_api_gateway_deployment": resourceAwsApiGatewayDeployment(), "aws_api_gateway_deployment": resourceAwsApiGatewayDeployment(),

View File

@ -0,0 +1,124 @@
package aws
import (
"fmt"
"log"
"time"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/service/apigateway"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/helper/schema"
)
func resourceAwsApiGatewayAccount() *schema.Resource {
return &schema.Resource{
Create: resourceAwsApiGatewayAccountUpdate,
Read: resourceAwsApiGatewayAccountRead,
Update: resourceAwsApiGatewayAccountUpdate,
Delete: resourceAwsApiGatewayAccountDelete,
Schema: map[string]*schema.Schema{
"cloudwatch_role_arn": &schema.Schema{
Type: schema.TypeString,
Optional: true,
},
"throttle_settings": &schema.Schema{
Type: schema.TypeList,
Computed: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"burst_limit": &schema.Schema{
Type: schema.TypeInt,
Computed: true,
},
"rate_limit": &schema.Schema{
Type: schema.TypeFloat,
Computed: true,
},
},
},
},
},
}
}
func resourceAwsApiGatewayAccountRead(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).apigateway
log.Printf("[INFO] Reading API Gateway Account %s", d.Id())
account, err := conn.GetAccount(&apigateway.GetAccountInput{})
if err != nil {
return err
}
log.Printf("[DEBUG] Received API Gateway Account: %s", account)
if _, ok := d.GetOk("cloudwatch_role_arn"); ok {
// CloudwatchRoleArn cannot be empty nor made empty via API
// This resource can however be useful w/out defining cloudwatch_role_arn
// (e.g. for referencing throttle_settings)
d.Set("cloudwatch_role_arn", account.CloudwatchRoleArn)
}
d.Set("throttle_settings", flattenApiGatewayThrottleSettings(account.ThrottleSettings))
return nil
}
func resourceAwsApiGatewayAccountUpdate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).apigateway
input := apigateway.UpdateAccountInput{}
operations := make([]*apigateway.PatchOperation, 0)
if d.HasChange("cloudwatch_role_arn") {
arn := d.Get("cloudwatch_role_arn").(string)
if len(arn) > 0 {
// Unfortunately AWS API doesn't allow empty ARNs,
// even though that's default settings for new AWS accounts
// BadRequestException: The role ARN is not well formed
operations = append(operations, &apigateway.PatchOperation{
Op: aws.String("replace"),
Path: aws.String("/cloudwatchRoleArn"),
Value: aws.String(arn),
})
}
}
input.PatchOperations = operations
log.Printf("[INFO] Updating API Gateway Account: %s", input)
// Retry due to eventual consistency of IAM
expectedErrMsg := "The role ARN does not have required permissions set to API Gateway"
var out *apigateway.Account
var err error
err = resource.Retry(2*time.Minute, func() *resource.RetryError {
out, err = conn.UpdateAccount(&input)
if err != nil {
if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == "BadRequestException" &&
awsErr.Message() == expectedErrMsg {
log.Printf("[DEBUG] Retrying API Gateway Account update: %s", awsErr)
return resource.RetryableError(err)
}
return resource.NonRetryableError(err)
}
return nil
})
if err != nil {
return fmt.Errorf("Updating API Gateway Account failed: %s", err)
}
log.Printf("[DEBUG] API Gateway Account updated: %s", out)
d.SetId("api-gateway-account")
return resourceAwsApiGatewayAccountRead(d, meta)
}
func resourceAwsApiGatewayAccountDelete(d *schema.ResourceData, meta interface{}) error {
// There is no API for "deleting" account or resetting it to "default" settings
d.SetId("")
return nil
}

View File

@ -0,0 +1,205 @@
package aws
import (
"fmt"
"regexp"
"testing"
"github.com/aws/aws-sdk-go/service/apigateway"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
)
func TestAccAWSAPIGatewayAccount_basic(t *testing.T) {
var conf apigateway.Account
expectedRoleArn_first := regexp.MustCompile("[0-9]+")
expectedRoleArn_second := regexp.MustCompile("[0-9]+")
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSAPIGatewayAccountDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccAWSAPIGatewayAccountConfig_updated,
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSAPIGatewayAccountExists("aws_api_gateway_account.test", &conf),
testAccCheckAWSAPIGatewayAccountCloudwatchRoleArn(&conf, expectedRoleArn_first),
resource.TestMatchResourceAttr("aws_api_gateway_account.test", "cloudwatch_role_arn", expectedRoleArn_first),
),
},
resource.TestStep{
Config: testAccAWSAPIGatewayAccountConfig_updated2,
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSAPIGatewayAccountExists("aws_api_gateway_account.test", &conf),
testAccCheckAWSAPIGatewayAccountCloudwatchRoleArn(&conf, expectedRoleArn_second),
resource.TestMatchResourceAttr("aws_api_gateway_account.test", "cloudwatch_role_arn", expectedRoleArn_second),
),
},
resource.TestStep{
Config: testAccAWSAPIGatewayAccountConfig_empty,
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSAPIGatewayAccountExists("aws_api_gateway_account.test", &conf),
testAccCheckAWSAPIGatewayAccountCloudwatchRoleArn(&conf, expectedRoleArn_second),
),
},
},
})
}
func testAccCheckAWSAPIGatewayAccountCloudwatchRoleArn(conf *apigateway.Account, expectedArn *regexp.Regexp) resource.TestCheckFunc {
return func(s *terraform.State) error {
if expectedArn == nil && conf.CloudwatchRoleArn == nil {
return nil
}
if expectedArn == nil && conf.CloudwatchRoleArn != nil {
return fmt.Errorf("Expected empty CloudwatchRoleArn, given: %q", *conf.CloudwatchRoleArn)
}
if expectedArn != nil && conf.CloudwatchRoleArn == nil {
return fmt.Errorf("Empty CloudwatchRoleArn, expected: %q", expectedArn)
}
if !expectedArn.MatchString(*conf.CloudwatchRoleArn) {
return fmt.Errorf("CloudwatchRoleArn didn't match. Expected: %q, Given: %q", expectedArn, *conf.CloudwatchRoleArn)
}
return nil
}
}
func testAccCheckAWSAPIGatewayAccountExists(n string, res *apigateway.Account) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n]
if !ok {
return fmt.Errorf("Not found: %s", n)
}
if rs.Primary.ID == "" {
return fmt.Errorf("No API Gateway Account ID is set")
}
conn := testAccProvider.Meta().(*AWSClient).apigateway
req := &apigateway.GetAccountInput{}
describe, err := conn.GetAccount(req)
if err != nil {
return err
}
if describe == nil {
return fmt.Errorf("Got nil account ?!")
}
*res = *describe
return nil
}
}
func testAccCheckAWSAPIGatewayAccountDestroy(s *terraform.State) error {
// Intentionally noop
// as there is no API method for deleting or resetting account settings
return nil
}
const testAccAWSAPIGatewayAccountConfig_empty = `
resource "aws_api_gateway_account" "test" {
}
`
const testAccAWSAPIGatewayAccountConfig_updated = `
resource "aws_api_gateway_account" "test" {
cloudwatch_role_arn = "${aws_iam_role.cloudwatch.arn}"
}
resource "aws_iam_role" "cloudwatch" {
name = "api_gateway_cloudwatch_global"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Service": "apigateway.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
EOF
}
resource "aws_iam_role_policy" "cloudwatch" {
name = "default"
role = "${aws_iam_role.cloudwatch.id}"
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:DescribeLogGroups",
"logs:DescribeLogStreams",
"logs:PutLogEvents",
"logs:GetLogEvents",
"logs:FilterLogEvents"
],
"Resource": "*"
}
]
}
EOF
}
`
const testAccAWSAPIGatewayAccountConfig_updated2 = `
resource "aws_api_gateway_account" "test" {
cloudwatch_role_arn = "${aws_iam_role.second.arn}"
}
resource "aws_iam_role" "second" {
name = "api_gateway_cloudwatch_global_modified"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Service": "apigateway.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
EOF
}
resource "aws_iam_role_policy" "cloudwatch" {
name = "default"
role = "${aws_iam_role.second.id}"
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:DescribeLogGroups",
"logs:DescribeLogStreams",
"logs:PutLogEvents",
"logs:GetLogEvents",
"logs:FilterLogEvents"
],
"Resource": "*"
}
]
}
EOF
}
`

View File

@ -1097,3 +1097,22 @@ func sortInterfaceSlice(in []interface{}) []interface{} {
return b return b
} }
func flattenApiGatewayThrottleSettings(settings *apigateway.ThrottleSettings) []map[string]interface{} {
result := make([]map[string]interface{}, 0, 1)
if settings != nil {
r := make(map[string]interface{})
if settings.BurstLimit != nil {
r["burst_limit"] = *settings.BurstLimit
}
if settings.RateLimit != nil {
r["rate_limit"] = *settings.RateLimit
}
result = append(result, r)
}
return result
}

View File

@ -6,6 +6,7 @@ import (
"testing" "testing"
"github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/apigateway"
"github.com/aws/aws-sdk-go/service/autoscaling" "github.com/aws/aws-sdk-go/service/autoscaling"
"github.com/aws/aws-sdk-go/service/ec2" "github.com/aws/aws-sdk-go/service/ec2"
"github.com/aws/aws-sdk-go/service/elasticache" "github.com/aws/aws-sdk-go/service/elasticache"
@ -902,3 +903,42 @@ func TestFlattenSecurityGroups(t *testing.T) {
} }
} }
} }
func TestFlattenApiGatewayThrottleSettings(t *testing.T) {
expectedBurstLimit := int64(140)
expectedRateLimit := 120.0
ts := &apigateway.ThrottleSettings{
BurstLimit: aws.Int64(expectedBurstLimit),
RateLimit: aws.Float64(expectedRateLimit),
}
result := flattenApiGatewayThrottleSettings(ts)
if len(result) != 1 {
t.Fatalf("Expected map to have exactly 1 element, got %d", len(result))
}
burstLimit, ok := result[0]["burst_limit"]
if !ok {
t.Fatal("Expected 'burst_limit' key in the map")
}
burstLimitInt, ok := burstLimit.(int64)
if !ok {
t.Fatal("Expected 'burst_limit' to be int")
}
if burstLimitInt != expectedBurstLimit {
t.Fatalf("Expected 'burst_limit' to equal %d, got %d", expectedBurstLimit, burstLimitInt)
}
rateLimit, ok := result[0]["rate_limit"]
if !ok {
t.Fatal("Expected 'rate_limit' key in the map")
}
rateLimitFloat, ok := rateLimit.(float64)
if !ok {
t.Fatal("Expected 'rate_limit' to be float64")
}
if rateLimitFloat != expectedRateLimit {
t.Fatalf("Expected 'rate_limit' to equal %f, got %f", expectedRateLimit, rateLimitFloat)
}
}

View File

@ -0,0 +1,84 @@
---
layout: "aws"
page_title: "AWS: aws_api_gateway_account"
sidebar_current: "docs-aws-resource-api-gateway-account"
description: |-
Provides a settings of an API Gateway Account.
---
# aws\_api\_gateway\_account
Provides a settings of an API Gateway Account. Settings is applied region-wide per `provider` block.
-> **Note:** As there is no API method for deleting account settings or resetting it to defaults, destroying this resource will keep your account settings intact
## Example Usage
```
resource "aws_api_gateway_account" "demo" {
cloudwatch_role_arn = "${aws_iam_role.cloudwatch.arn}"
}
resource "aws_iam_role" "cloudwatch" {
name = "api_gateway_cloudwatch_global"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Service": "apigateway.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
EOF
}
resource "aws_iam_role_policy" "cloudwatch" {
name = "default"
role = "${aws_iam_role.cloudwatch.id}"
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:DescribeLogGroups",
"logs:DescribeLogStreams",
"logs:PutLogEvents",
"logs:GetLogEvents",
"logs:FilterLogEvents"
],
"Resource": "*"
}
]
}
EOF
}
```
## Argument Reference
The following argument is supported:
* `cloudwatch_role_arn` - (Optional) The ARN of an IAM role for CloudWatch (to allow logging & monitoring).
See more [in AWS Docs](https://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-stage-settings.html#how-to-stage-settings-console).
Logging & monitoring can be enabled/disabled and otherwise tuned on the API Gateway Stage level.
## Attribute Reference
The following attribute is exported:
* `throttle_settings` - Account-Level throttle settings. See exported fields below.
`throttle_settings` block exports the following:
* `burst_limit` - The absolute maximum number of times API Gateway allows the API to be called per second (RPS).
* `rate_limit` - The number of times API Gateway allows the API to be called per second on average (RPS).

View File

@ -13,6 +13,9 @@
<li<%= sidebar_current(/^docs-aws-resource-api-gateway/) %>> <li<%= sidebar_current(/^docs-aws-resource-api-gateway/) %>>
<a href="#">API Gateway Resources</a> <a href="#">API Gateway Resources</a>
<ul class="nav nav-visible"> <ul class="nav nav-visible">
<li<%= sidebar_current("docs-aws-resource-api-gateway-account") %>>
<a href="/docs/providers/aws/r/api_gateway_account.html">aws_api_gateway_account</a>
</li>
<li<%= sidebar_current("docs-aws-resource-api-gateway-api-key") %>> <li<%= sidebar_current("docs-aws-resource-api-gateway-api-key") %>>
<a href="/docs/providers/aws/r/api_gateway_api_key.html">aws_api_gateway_api_key</a> <a href="/docs/providers/aws/r/api_gateway_api_key.html">aws_api_gateway_api_key</a>
</li> </li>