Skip to content
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

New Resource: r/aws_config_authorization #4263

Merged
merged 1 commit into from
Jun 3, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions aws/import_aws_config_authorization_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package aws

import (
"testing"

"github.com/hashicorp/terraform/helper/acctest"
"github.com/hashicorp/terraform/helper/resource"
)

func TestAccConfigAuthorization_import(t *testing.T) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor nitpick: we're going to move away from separate import test files and tests (#4705). We can simply add the final TestStep the existing _basic test 👍

resourceName := "aws_config_authorization.example"
rString := acctest.RandStringFromCharSet(12, "0123456789")

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckConfigAuthorizationDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccConfigAuthorizationConfig_basic(rString),
},

resource.TestStep{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
},
})
}
1 change: 1 addition & 0 deletions aws/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,7 @@ func Provider() terraform.ResourceProvider {
"aws_cloudwatch_log_resource_policy": resourceAwsCloudWatchLogResourcePolicy(),
"aws_cloudwatch_log_stream": resourceAwsCloudWatchLogStream(),
"aws_cloudwatch_log_subscription_filter": resourceAwsCloudwatchLogSubscriptionFilter(),
"aws_config_authorization": resourceAwsConfigAuthorization(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry this is going to be very pedantic but the Config API refers to these as "aggregate" authorization and the resource/function naming should reflect that for clarity and in case they introduce other forms/types of authorization.

"aws_config_aggregate_authorization": resourceAwsConfigAggregateAuthoriation(),

"aws_config_config_rule": resourceAwsConfigConfigRule(),
"aws_config_configuration_recorder": resourceAwsConfigConfigurationRecorder(),
"aws_config_configuration_recorder_status": resourceAwsConfigConfigurationRecorderStatus(),
Expand Down
123 changes: 123 additions & 0 deletions aws/resource_aws_config_authorization.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
package aws

import (
"fmt"
"log"
"strings"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/configservice"

"github.com/hashicorp/terraform/helper/schema"
)

func resourceAwsConfigAuthorization() *schema.Resource {
return &schema.Resource{
Create: resourceAwsConfigAuthorizationPut,
Read: resourceAwsConfigAuthorizationRead,
Delete: resourceAwsConfigAuthorizationDelete,

Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},

Schema: map[string]*schema.Schema{
"arn": {
Type: schema.TypeString,
Computed: true,
},
"account_id": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validateAwsAccountId,
},
"region": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
},
}
}

func resourceAwsConfigAuthorizationPut(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).configconn

accountId := d.Get("account_id").(string)
region := d.Get("region").(string)

req := &configservice.PutAggregationAuthorizationInput{
AuthorizedAccountId: aws.String(accountId),
AuthorizedAwsRegion: aws.String(region),
}

_, err := conn.PutAggregationAuthorization(req)
if err != nil {
return fmt.Errorf("Error creating authorization: %s", err)
}

d.SetId(fmt.Sprintf("%s:%s", accountId, region))
return resourceAwsConfigAuthorizationRead(d, meta)
}

func resourceAwsConfigAuthorizationRead(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).configconn

accountId, region, err := resourceAwsConfigAuthorizationParseID(d.Id())
if err != nil {
return err
}

d.Set("account_id", accountId)
d.Set("region", region)

res, err := conn.DescribeAggregationAuthorizations(&configservice.DescribeAggregationAuthorizationsInput{})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This call does not currently handle NextToken so it can incorrectly report errors/missing resources in large or separate API responses.

if err != nil {
return fmt.Errorf("Error retrieving list of authorizations: %s", err)
}

// Check for existing authorization
for _, auth := range res.AggregationAuthorizations {
if accountId == *auth.AuthorizedAccountId && region == *auth.AuthorizedAwsRegion {
d.Set("arn", auth.AggregationAuthorizationArn)
return nil
}
}

log.Printf("[WARN] Authorization not found, removing from state: %s", d.Id())
d.SetId("")
return nil
}

func resourceAwsConfigAuthorizationDelete(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).configconn

accountId, region, err := resourceAwsConfigAuthorizationParseID(d.Id())
if err != nil {
return err
}

req := &configservice.DeleteAggregationAuthorizationInput{
AuthorizedAccountId: aws.String(accountId),
AuthorizedAwsRegion: aws.String(region),
}

_, err = conn.DeleteAggregationAuthorization(req)
if err != nil {
return fmt.Errorf("Error deleting authorization: %s", err)
}

d.SetId("")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor nitpick: d.SetId("") is extraneous in delete functions

return nil
}

func resourceAwsConfigAuthorizationParseID(id string) (string, string, error) {
idParts := strings.Split(id, ":")
if len(idParts) != 2 {
return "", "", fmt.Errorf("Please make sure the ID is in the form account_id:region (i.e. 123456789012:us-east-1")
}
accountId := idParts[0]
region := idParts[1]
return accountId, region, nil
}
102 changes: 102 additions & 0 deletions aws/resource_aws_config_authorization_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package aws

import (
"fmt"
"log"
"regexp"
"testing"

"github.com/aws/aws-sdk-go/service/configservice"
"github.com/hashicorp/terraform/helper/acctest"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
)

func init() {
resource.AddTestSweepers("aws_config_authorization", &resource.Sweeper{
Name: "aws_config_authorization",
F: testSweepConfigAuthorizations,
})
}

func testSweepConfigAuthorizations(region string) error {
client, err := sharedClientForRegion(region)
if err != nil {
return fmt.Errorf("Error getting client: %s", err)
}
conn := client.(*AWSClient).configconn

resp, err := conn.DescribeAggregationAuthorizations(&configservice.DescribeAggregationAuthorizationsInput{})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This call does not currently handle NextToken so it can potentially miss authorizations in large or separate API responses.

if err != nil {
return fmt.Errorf("Error retrieving config authorizations: %s", err)
}

if len(resp.AggregationAuthorizations) == 0 {
log.Print("[DEBUG] No config authorizations to sweep")
return nil
}

log.Printf("[INFO] Found %d config authorizations", len(resp.AggregationAuthorizations))

for _, auth := range resp.AggregationAuthorizations {
log.Printf("[INFO] Deleting config authorization %s", *auth.AggregationAuthorizationArn)
_, err := conn.DeleteAggregationAuthorization(&configservice.DeleteAggregationAuthorizationInput{
AuthorizedAccountId: auth.AuthorizedAccountId,
AuthorizedAwsRegion: auth.AuthorizedAwsRegion,
})
if err != nil {
return fmt.Errorf("Error deleting config authorization %s: %s", *auth.AggregationAuthorizationArn, err)
}
}

return nil
}

func TestAccConfigAuthorization_basic(t *testing.T) {
rString := acctest.RandStringFromCharSet(12, "0123456789")

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckConfigAuthorizationDestroy,
Steps: []resource.TestStep{
{
Config: testAccConfigAuthorizationConfig_basic(rString),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("aws_config_authorization.example", "account_id", rString),
resource.TestCheckResourceAttr("aws_config_authorization.example", "region", "eu-west-1"),
resource.TestMatchResourceAttr("aws_config_authorization.example", "arn", regexp.MustCompile("^arn:aws:config:[\\w-]+:\\d{12}:aggregation-authorization/\\d{12}/[\\w-]+$")),
),
},
},
})
}

func testAccCheckConfigAuthorizationDestroy(s *terraform.State) error {
conn := testAccProvider.Meta().(*AWSClient).configconn

for _, rs := range s.RootModule().Resources {
if rs.Type != "aws_config_authorization" {
continue
}

resp, err := conn.DescribeAggregationAuthorizations(&configservice.DescribeAggregationAuthorizationsInput{})

if err == nil {
if len(resp.AggregationAuthorizations) != 0 &&
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There may be additional other authorizations present, especially with testing concurrency or in non-testing accounts. This needs to be updated to specifically handle NextToken and loop through all authorizations, only returning an error if the account ID and region is found.

*resp.AggregationAuthorizations[0].AuthorizedAccountId == rs.Primary.Attributes["account_id"] {
return fmt.Errorf("Config authorization still exists: %s", rs.Primary.Attributes["account_id"])
}
}
}

return nil
}

func testAccConfigAuthorizationConfig_basic(rString string) string {
return fmt.Sprintf(`
resource "aws_config_authorization" "example" {
account_id = "%s" # Required
region = "eu-west-1" # Required
}`, rString)
}
3 changes: 3 additions & 0 deletions website/aws.erb
Original file line number Diff line number Diff line change
Expand Up @@ -583,6 +583,9 @@
<li<%= sidebar_current("docs-aws-resource-config") %>>
<a href="#">Config Resources</a>
<ul class="nav nav-visible">
<li<%= sidebar_current("docs-aws-resource-config-authorization") %>>
<a href="/docs/providers/aws/r/config_authorization.html">aws_config_authorization</a>
</li>

<li<%= sidebar_current("docs-aws-resource-config-config-rule") %>>
<a href="/docs/providers/aws/r/config_config_rule.html">aws_config_config_rule</a>
Expand Down
41 changes: 41 additions & 0 deletions website/docs/r/config_authorization.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
---
layout: "aws"
page_title: "AWS: aws_config_authorization"
sidebar_current: "docs-aws-resource-config-authorization"
description: |-
Provides an AWS Config Authorization.
---

# aws_config_authorization

Provides an AWS Config Authorization

## Example Usage

```hcl
resource "aws_config_authorization" "example" {
account_id = "123456789012" # Required
region = "eu-west-2" # Required
}
```

## Argument Reference

The following arguments are supported:

* `account_id` - (Required) Account ID
* `region` - (Required) Region

## Attributes Reference

The following attributes are exported:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're in the process of updating all these for clarity (#4685): In addition to all arguments above, the following attributes are exported:


* `arn` - The ARN of the authorization

## Import

Config authorizations can be imported using `account_id:region`, e.g.

```
$ terraform import aws_config_authorization.example 123456789012:us-east-1
```