Skip to content

Commit

Permalink
New Resources: aws_config_organization_custom_rule and aws_config_org…
Browse files Browse the repository at this point in the history
…anization_managed_rule

Reference: #9299

Output from acceptance testing:

```
    --- PASS: TestAccAWSConfig/OrganizationCustomRule (3029.15s)
        --- PASS: TestAccAWSConfig/OrganizationCustomRule/InputParameters (305.03s)
        --- PASS: TestAccAWSConfig/OrganizationCustomRule/MaximumExecutionFrequency (232.54s)
        --- PASS: TestAccAWSConfig/OrganizationCustomRule/ResourceIdScope (226.23s)
        --- PASS: TestAccAWSConfig/OrganizationCustomRule/ResourceTypesScope (282.06s)
        --- PASS: TestAccAWSConfig/OrganizationCustomRule/basic (130.37s)
        --- PASS: TestAccAWSConfig/OrganizationCustomRule/disappears (141.50s)
        --- PASS: TestAccAWSConfig/OrganizationCustomRule/errorHandling (155.78s)
        --- PASS: TestAccAWSConfig/OrganizationCustomRule/ExcludedAccounts (246.06s)
        --- PASS: TestAccAWSConfig/OrganizationCustomRule/TagValueScope (255.75s)
        --- PASS: TestAccAWSConfig/OrganizationCustomRule/TriggerTypes (258.28s)
        --- PASS: TestAccAWSConfig/OrganizationCustomRule/Description (271.57s)
        --- PASS: TestAccAWSConfig/OrganizationCustomRule/LambdaFunctionArn (231.53s)
        --- PASS: TestAccAWSConfig/OrganizationCustomRule/TagKeyScope (292.43s)
    --- PASS: TestAccAWSConfig/OrganizationManagedRule (2809.33s)
        --- PASS: TestAccAWSConfig/OrganizationManagedRule/RuleIdentifier (254.75s)
        --- PASS: TestAccAWSConfig/OrganizationManagedRule/TagKeyScope (301.58s)
        --- PASS: TestAccAWSConfig/OrganizationManagedRule/Description (238.37s)
        --- PASS: TestAccAWSConfig/OrganizationManagedRule/ExcludedAccounts (300.45s)
        --- PASS: TestAccAWSConfig/OrganizationManagedRule/MaximumExecutionFrequency (234.66s)
        --- PASS: TestAccAWSConfig/OrganizationManagedRule/ResourceTypesScope (261.44s)
        --- PASS: TestAccAWSConfig/OrganizationManagedRule/ResourceIdScope (285.29s)
        --- PASS: TestAccAWSConfig/OrganizationManagedRule/TagValueScope (263.19s)
        --- PASS: TestAccAWSConfig/OrganizationManagedRule/basic (115.53s)
        --- PASS: TestAccAWSConfig/OrganizationManagedRule/disappears (176.75s)
        --- PASS: TestAccAWSConfig/OrganizationManagedRule/errorHandling (150.24s)
        --- PASS: TestAccAWSConfig/OrganizationManagedRule/InputParameters (227.08s)
```
  • Loading branch information
bflad committed Aug 10, 2019
1 parent cc3dba0 commit a82f045
Show file tree
Hide file tree
Showing 11 changed files with 2,465 additions and 0 deletions.
23 changes: 23 additions & 0 deletions aws/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -550,6 +550,29 @@ func (c *Config) Client() (interface{}, error) {
}
})

client.configconn.Handlers.Retry.PushBack(func(r *request.Request) {
// When calling Config Organization Rules API actions immediately
// after Organization creation, the API can randomly return the
// OrganizationAccessDeniedException error for a few minutes, even
// after succeeding a few requests.
switch r.Operation.Name {
case "DeleteOrganizationConfigRule", "DescribeOrganizationConfigRules", "DescribeOrganizationConfigRuleStatuses", "PutOrganizationConfigRule":
if !isAWSErr(r.Error, configservice.ErrCodeOrganizationAccessDeniedException, "This action can be only made by AWS Organization's master account.") {
return
}

// We only want to retry briefly as the default max retry count would
// excessively retry when the error could be legitimate.
// We currently depend on the DefaultRetryer exponential backoff here.
// ~10 retries gives a fair backoff of a few seconds.
if r.RetryCount < 9 {
r.Retryable = aws.Bool(true)
} else {
r.Retryable = aws.Bool(false)
}
}
})

// See https://github.com/aws/aws-sdk-go/pull/1276
client.dynamodbconn.Handlers.Retry.PushBack(func(r *request.Request) {
if r.Operation.Name != "PutItem" && r.Operation.Name != "UpdateItem" && r.Operation.Name != "DeleteItem" {
Expand Down
179 changes: 179 additions & 0 deletions aws/configservice.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
package aws

import (
"fmt"
"strings"
"time"

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

func configDescribeOrganizationConfigRule(conn *configservice.ConfigService, name string) (*configservice.OrganizationConfigRule, error) {
input := &configservice.DescribeOrganizationConfigRulesInput{
OrganizationConfigRuleNames: []*string{aws.String(name)},
}

for {
output, err := conn.DescribeOrganizationConfigRules(input)

if err != nil {
return nil, err
}

for _, rule := range output.OrganizationConfigRules {
if aws.StringValue(rule.OrganizationConfigRuleName) == name {
return rule, nil
}
}

if aws.StringValue(output.NextToken) == "" {
break
}

input.NextToken = output.NextToken
}

return nil, nil
}

func configDescribeOrganizationConfigRuleStatus(conn *configservice.ConfigService, name string) (*configservice.OrganizationConfigRuleStatus, error) {
input := &configservice.DescribeOrganizationConfigRuleStatusesInput{
OrganizationConfigRuleNames: []*string{aws.String(name)},
}

for {
output, err := conn.DescribeOrganizationConfigRuleStatuses(input)

if err != nil {
return nil, err
}

for _, status := range output.OrganizationConfigRuleStatuses {
if aws.StringValue(status.OrganizationConfigRuleName) == name {
return status, nil
}
}

if aws.StringValue(output.NextToken) == "" {
break
}

input.NextToken = output.NextToken
}

return nil, nil
}

func configGetOrganizationConfigRuleDetailedStatus(conn *configservice.ConfigService, ruleName, ruleStatus string) ([]*configservice.MemberAccountStatus, error) {
input := &configservice.GetOrganizationConfigRuleDetailedStatusInput{
Filters: &configservice.StatusDetailFilters{
MemberAccountRuleStatus: aws.String(ruleStatus),
},
OrganizationConfigRuleName: aws.String(ruleName),
}
var statuses []*configservice.MemberAccountStatus

for {
output, err := conn.GetOrganizationConfigRuleDetailedStatus(input)

if err != nil {
return nil, err
}

statuses = append(statuses, output.OrganizationConfigRuleDetailedStatus...)

if aws.StringValue(output.NextToken) == "" {
break
}

input.NextToken = output.NextToken
}

return statuses, nil
}

func configRefreshOrganizationConfigRuleStatus(conn *configservice.ConfigService, name string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
status, err := configDescribeOrganizationConfigRuleStatus(conn, name)

if err != nil {
return nil, "", err
}

if status == nil {
return nil, "", fmt.Errorf("status not found")
}

if status.ErrorCode != nil {
return status, aws.StringValue(status.OrganizationRuleStatus), fmt.Errorf("%s: %s", aws.StringValue(status.ErrorCode), aws.StringValue(status.ErrorMessage))
}

switch aws.StringValue(status.OrganizationRuleStatus) {
case configservice.OrganizationRuleStatusCreateFailed, configservice.OrganizationRuleStatusDeleteFailed, configservice.OrganizationRuleStatusUpdateFailed:
// Display detailed errors for failed member accounts
memberAccountStatuses, err := configGetOrganizationConfigRuleDetailedStatus(conn, name, aws.StringValue(status.OrganizationRuleStatus))

if err != nil {
return status, aws.StringValue(status.OrganizationRuleStatus), fmt.Errorf("unable to get Organization Config Rule detailed status for showing member account errors: %s", err)
}

var errBuilder strings.Builder

for _, mas := range memberAccountStatuses {
errBuilder.WriteString(fmt.Sprintf("Account ID (%s): %s: %s\n", aws.StringValue(mas.AccountId), aws.StringValue(mas.ErrorCode), aws.StringValue(mas.ErrorMessage)))
}

return status, aws.StringValue(status.OrganizationRuleStatus), fmt.Errorf("Failed in %d account(s):\n\n%s", len(memberAccountStatuses), errBuilder.String())
}

return status, aws.StringValue(status.OrganizationRuleStatus), nil
}
}

func configWaitForOrganizationRuleStatusCreateSuccessful(conn *configservice.ConfigService, name string, timeout time.Duration) error {
stateChangeConf := &resource.StateChangeConf{
Pending: []string{configservice.OrganizationRuleStatusCreateInProgress},
Target: []string{configservice.OrganizationRuleStatusCreateSuccessful},
Refresh: configRefreshOrganizationConfigRuleStatus(conn, name),
Timeout: timeout,
Delay: 10 * time.Second,
}

_, err := stateChangeConf.WaitForState()

return err
}

func configWaitForOrganizationRuleStatusDeleteSuccessful(conn *configservice.ConfigService, name string, timeout time.Duration) error {
stateChangeConf := &resource.StateChangeConf{
Pending: []string{configservice.OrganizationRuleStatusDeleteInProgress},
Target: []string{configservice.OrganizationRuleStatusDeleteSuccessful},
Refresh: configRefreshOrganizationConfigRuleStatus(conn, name),
Timeout: timeout,
Delay: 10 * time.Second,
}

_, err := stateChangeConf.WaitForState()

if isAWSErr(err, configservice.ErrCodeNoSuchOrganizationConfigRuleException, "") {
return nil
}

return err
}

func configWaitForOrganizationRuleStatusUpdateSuccessful(conn *configservice.ConfigService, name string, timeout time.Duration) error {
stateChangeConf := &resource.StateChangeConf{
Pending: []string{configservice.OrganizationRuleStatusUpdateInProgress},
Target: []string{configservice.OrganizationRuleStatusUpdateSuccessful},
Refresh: configRefreshOrganizationConfigRuleStatus(conn, name),
Timeout: timeout,
Delay: 10 * time.Second,
}

_, err := stateChangeConf.WaitForState()

return err
}
2 changes: 2 additions & 0 deletions aws/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,8 @@ func Provider() terraform.ResourceProvider {
"aws_config_configuration_recorder": resourceAwsConfigConfigurationRecorder(),
"aws_config_configuration_recorder_status": resourceAwsConfigConfigurationRecorderStatus(),
"aws_config_delivery_channel": resourceAwsConfigDeliveryChannel(),
"aws_config_organization_custom_rule": resourceAwsConfigOrganizationCustomRule(),
"aws_config_organization_managed_rule": resourceAwsConfigOrganizationManagedRule(),
"aws_cognito_identity_pool": resourceAwsCognitoIdentityPool(),
"aws_cognito_identity_pool_roles_attachment": resourceAwsCognitoIdentityPoolRolesAttachment(),
"aws_cognito_identity_provider": resourceAwsCognitoIdentityProvider(),
Expand Down
Loading

0 comments on commit a82f045

Please sign in to comment.