Skip to content

Commit

Permalink
Merge pull request #17298 from ctrawick/f-aws_config_organization_con…
Browse files Browse the repository at this point in the history
…formance_pack-add

Added AWS Config Organization Conformance Pack resource
  • Loading branch information
anGie44 authored Jul 9, 2021
2 parents f188231 + 3030e8e commit bae3b38
Show file tree
Hide file tree
Showing 8 changed files with 1,353 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .changelog/17298.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:new-resource
aws_config_organization_conformance_pack
```
17 changes: 17 additions & 0 deletions aws/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -720,6 +720,23 @@ func (c *Config) Client() (interface{}, error) {
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)
}
case "DeleteOrganizationConformancePack", "DescribeOrganizationConformancePacks", "DescribeOrganizationConformancePackStatuses", "PutOrganizationConformancePack":
if !tfawserr.ErrCodeEquals(r.Error, configservice.ErrCodeOrganizationAccessDeniedException) {
if r.Operation.Name == "DeleteOrganizationConformancePack" && tfawserr.ErrCodeEquals(err, configservice.ErrCodeResourceInUseException) {
r.Retryable = aws.Bool(true)
}
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.
Expand Down
203 changes: 203 additions & 0 deletions aws/configservice.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ const (
ConfigConformancePackCreateTimeout = 5 * time.Minute
ConfigConformancePackDeleteTimeout = 5 * time.Minute

ConfigOrganizationConformancePackCreateTimeout = 10 * time.Minute
ConfigOrganizationConformancePackUpdateTimeout = 10 * time.Minute
ConfigOrganizationConformancePackDeleteTimeout = 20 * time.Minute

ConfigConformancePackStatusNotFound = "NotFound"
ConfigConformancePackStatusUnknown = "Unknown"
)
Expand Down Expand Up @@ -135,6 +139,62 @@ func configDescribeOrganizationConfigRuleStatus(conn *configservice.ConfigServic
return nil, nil
}

func configDescribeOrganizationConformancePack(conn *configservice.ConfigService, name string) (*configservice.OrganizationConformancePack, error) {
input := &configservice.DescribeOrganizationConformancePacksInput{
OrganizationConformancePackNames: []*string{aws.String(name)},
}

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

if err != nil {
return nil, err
}

for _, pack := range output.OrganizationConformancePacks {
if aws.StringValue(pack.OrganizationConformancePackName) == name {
return pack, nil
}
}

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

input.NextToken = output.NextToken
}

return nil, nil
}

func configDescribeOrganizationConformancePackStatus(conn *configservice.ConfigService, name string) (*configservice.OrganizationConformancePackStatus, error) {
input := &configservice.DescribeOrganizationConformancePackStatusesInput{
OrganizationConformancePackNames: []*string{aws.String(name)},
}

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

if err != nil {
return nil, err
}

for _, status := range output.OrganizationConformancePackStatuses {
if aws.StringValue(status.OrganizationConformancePackName) == 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{
Expand Down Expand Up @@ -163,6 +223,35 @@ func configGetOrganizationConfigRuleDetailedStatus(conn *configservice.ConfigSer
return statuses, nil
}

func configGetOrganizationConformancePackDetailedStatus(conn *configservice.ConfigService, name, status string) ([]*configservice.OrganizationConformancePackDetailedStatus, error) {
input := &configservice.GetOrganizationConformancePackDetailedStatusInput{
Filters: &configservice.OrganizationResourceDetailedStatusFilters{
Status: aws.String(status),
},
OrganizationConformancePackName: aws.String(name),
}

var statuses []*configservice.OrganizationConformancePackDetailedStatus

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

if err != nil {
return nil, err
}

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

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

input.NextToken = output.NextToken
}

return statuses, nil
}

func configRefreshConformancePackStatus(conn *configservice.ConfigService, name string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
status, err := configDescribeConformancePackStatus(conn, name)
Expand Down Expand Up @@ -221,6 +310,78 @@ func configRefreshOrganizationConfigRuleStatus(conn *configservice.ConfigService
}
}

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

// Transient ResourceDoesNotExist error after creation caught here
// in cases where the StateChangeConf's delay time is not sufficient
if tfawserr.ErrCodeEquals(err, configservice.ErrCodeNoSuchOrganizationConformancePackException) {
return nil, "", nil
}

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

if status == nil {
return nil, "", nil
}

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

switch s := aws.StringValue(status.Status); s {
case configservice.OrganizationResourceStatusCreateFailed, configservice.OrganizationResourceStatusDeleteFailed, configservice.OrganizationResourceStatusUpdateFailed:
return status, s, configOrganizationConformancePackDetailedStatusError(conn, name, s)
}

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

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

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

if status == nil {
return nil, "", nil
}

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

switch s := aws.StringValue(status.Status); s {
case configservice.OrganizationResourceStatusCreateFailed, configservice.OrganizationResourceStatusDeleteFailed, configservice.OrganizationResourceStatusUpdateFailed:
return status, s, configOrganizationConformancePackDetailedStatusError(conn, name, s)
}

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

func configOrganizationConformancePackDetailedStatusError(conn *configservice.ConfigService, name, status string) error {
memberAccountStatuses, err := configGetOrganizationConformancePackDetailedStatus(conn, name, status)

if err != nil {
return fmt.Errorf("unable to get Config Organization Conformance Pack detailed status for showing member account errors: %w", 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 fmt.Errorf("Failed in %d account(s):\n\n%s", len(memberAccountStatuses), errBuilder.String())
}

func configWaitForConformancePackStateCreateComplete(conn *configservice.ConfigService, name string) error {
stateChangeConf := resource.StateChangeConf{
Pending: []string{configservice.ConformancePackStateCreateInProgress},
Expand Down Expand Up @@ -256,6 +417,48 @@ func configWaitForConformancePackStateDeleteComplete(conn *configservice.ConfigS
return err
}

func configWaitForOrganizationConformancePackStatusCreateSuccessful(conn *configservice.ConfigService, name string) error {
stateChangeConf := resource.StateChangeConf{
Pending: []string{configservice.OrganizationResourceStatusCreateInProgress},
Target: []string{configservice.OrganizationResourceStatusCreateSuccessful},
Timeout: ConfigOrganizationConformancePackCreateTimeout,
Refresh: configRefreshOrganizationConformancePackCreationStatus(conn, name),
// Include a delay to help avoid ResourceDoesNotExist errors
Delay: 30 * time.Second,
}

_, err := stateChangeConf.WaitForState()

return err

}

func configWaitForOrganizationConformancePackStatusUpdateSuccessful(conn *configservice.ConfigService, name string) error {
stateChangeConf := resource.StateChangeConf{
Pending: []string{configservice.OrganizationResourceStatusUpdateInProgress},
Target: []string{configservice.OrganizationResourceStatusUpdateSuccessful},
Timeout: ConfigOrganizationConformancePackUpdateTimeout,
Refresh: configRefreshOrganizationConformancePackStatus(conn, name),
}

_, err := stateChangeConf.WaitForState()

return err
}

func configWaitForOrganizationConformancePackStatusDeleteSuccessful(conn *configservice.ConfigService, name string) error {
stateChangeConf := resource.StateChangeConf{
Pending: []string{configservice.OrganizationResourceStatusDeleteInProgress},
Target: []string{configservice.OrganizationResourceStatusDeleteSuccessful},
Timeout: ConfigOrganizationConformancePackDeleteTimeout,
Refresh: configRefreshOrganizationConformancePackStatus(conn, name),
}

_, err := stateChangeConf.WaitForState()

return err
}

func configWaitForOrganizationRuleStatusCreateSuccessful(conn *configservice.ConfigService, name string, timeout time.Duration) error {
stateChangeConf := &resource.StateChangeConf{
Pending: []string{configservice.OrganizationRuleStatusCreateInProgress},
Expand Down
1 change: 1 addition & 0 deletions aws/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -578,6 +578,7 @@ func Provider() *schema.Provider {
"aws_config_configuration_recorder_status": resourceAwsConfigConfigurationRecorderStatus(),
"aws_config_conformance_pack": resourceAwsConfigConformancePack(),
"aws_config_delivery_channel": resourceAwsConfigDeliveryChannel(),
"aws_config_organization_conformance_pack": resourceAwsConfigOrganizationConformancePack(),
"aws_config_organization_custom_rule": resourceAwsConfigOrganizationCustomRule(),
"aws_config_organization_managed_rule": resourceAwsConfigOrganizationManagedRule(),
"aws_config_remediation_configuration": resourceAwsConfigRemediationConfiguration(),
Expand Down
Loading

0 comments on commit bae3b38

Please sign in to comment.