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 and data source aws_cloudcontrolapi_resource #21110

Merged
merged 33 commits into from
Sep 30, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
0e08f1a
Run 'GOPRIVATE=github.com/hashicorp/aws-sdk-go-private,github.com/has…
ewbankkit Sep 15, 2021
cc841e4
docs/resource/aws_cloudformation_resource: Clarify schema argument usage
bflad Apr 21, 2021
2ce5740
New Data Source: aws_cloudformation_resource
bflad Apr 21, 2021
8e85ac6
service/cloudformation: Various docs and tests improvements
bflad Apr 21, 2021
50514fa
tests/resource/aws_cloudformation_resource: Fix terrafmt issue
bflad Apr 21, 2021
f3b722c
resource/aws_cloudformation_resource: Use pointer type in SetNew()
bflad Apr 22, 2021
5d7f1e7
Use 'https://github.com/hashicorp/aws-sdk-go-private/tree/f-cloudapi-…
ewbankkit Jul 20, 2021
ea43080
Simplified JSON Patch document generation.
ewbankkit Jul 20, 2021
c1bb87b
CloudFormation now reverting boolean value to property default.
ewbankkit Jul 20, 2021
ec4636b
Run 'go mod download github.com/hashicorp/terraform-plugin-sdk/v2 && …
ewbankkit Sep 15, 2021
99a5a02
Run 'go mod edit -replace=github.com/aws/aws-sdk-go=github.com/hashic…
ewbankkit Sep 15, 2021
785b317
Rename files 'cloudformation_resource' -> 'cloudcontrol_resource'.
ewbankkit Sep 15, 2021
c0f95f9
Add new service 'cloudcontrolapi'.
ewbankkit Sep 15, 2021
9418f97
Rename files 'cloudcontrol_resource' -> 'cloudcontrolapi_resource'.
ewbankkit Sep 15, 2021
d40bafb
Get the code building with new package.
ewbankkit Sep 15, 2021
d7c44e8
Run 'GOPRIVATE=github.com/hashicorp/aws-cloudformation-resource-schem…
ewbankkit Sep 15, 2021
4928d33
Rename functions 'CloudFormationResource' -> 'CloudControlApiResource'.
ewbankkit Sep 16, 2021
cbe77bc
Rename resources 'aws_cloudformation_resource' -> 'aws_cloudcontrolap…
ewbankkit Sep 16, 2021
a335baf
Tidy up CloudFormation Type, Stack and StackSet finders.
ewbankkit Sep 16, 2021
12e3009
Add and use 'internal/service/cloudcontrolapi/finder'.
ewbankkit Sep 16, 2021
7654f4a
r/aws_serverlessapplicationrepository_cloudformation_stack: Add 'find…
ewbankkit Sep 16, 2021
fff5439
Use 'internal/service/cloudformation/finder' for StackSet and StackIn…
ewbankkit Sep 17, 2021
5398cb1
Run 'GOPRIVATE=github.com/hashicorp/aws-cloudformation-resource-schem…
ewbankkit Sep 17, 2021
cebc3d7
r/aws_cloudcontrolapi_resource: Sanitize the CloudFormation type schema.
ewbankkit Sep 17, 2021
e4b6e36
Santitize the schema by rewriting all 'pattern' regexes to the empty …
ewbankkit Sep 18, 2021
4c21513
Revert "Santitize the schema by rewriting all 'pattern' regexes to th…
ewbankkit Sep 20, 2021
b64906f
Revert "r/aws_cloudcontrolapi_resource: Sanitize the CloudFormation t…
ewbankkit Sep 20, 2021
c8e28ad
r/aws_cloudcontrolapi_resource: Don't persist the sanitized schema in…
ewbankkit Sep 20, 2021
39c11e4
r/aws_cloudcontrolapi_resource: Change error message for 'TestAccAwsC…
ewbankkit Sep 20, 2021
2f8e351
Rename 'aws/internal/service/cloudcontrolapi' to 'aws/internal/servic…
ewbankkit Sep 22, 2021
e9f6d51
Remove use of private AWS SDK.
ewbankkit Sep 30, 2021
571867d
Add CHANGELOG entry.
ewbankkit Sep 30, 2021
48dc210
Skip any Cloud Control API acceptance tests that return 'UnsupportedA…
ewbankkit Sep 30, 2021
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
7 changes: 7 additions & 0 deletions .changelog/21110.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
```release-note:resource
aws_cloudcontrolapi_resource
```

```release-note:new-data-source
aws_cloudcontrolapi_resource
```
2 changes: 2 additions & 0 deletions .github/labeler-issue-triage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ service/chime:
- '((\*|-) ?`?|(data|resource) "?)aws_chime_'
service/cloud9:
- '((\*|-) ?`?|(data|resource) "?)aws_cloud9_'
service/cloudcontrolapi:
- '((\*|-) ?`?|(data|resource) "?)aws_cloudcontrolapi_'
service/clouddirectory:
- '((\*|-) ?`?|(data|resource) "?)aws_clouddirectory_'
service/cloudformation:
Expand Down
4 changes: 4 additions & 0 deletions .github/labeler-pr-triage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,10 @@ service/cloud9:
- 'aws/internal/service/cloud9/**/*'
- '**/*_cloud9_*'
- '**/cloud9_*'
service/cloudcontrolapi:
- 'aws/internal/service/cloudcontrolapi/**/*'
- '**/*_cloudcontrolapi_*'
- '**/cloudcontrolapi_*'
service/clouddirectory:
- 'aws/internal/service/clouddirectory/**/*'
- '**/*_clouddirectory_*'
Expand Down
3 changes: 3 additions & 0 deletions aws/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
"github.com/aws/aws-sdk-go/service/budgets"
"github.com/aws/aws-sdk-go/service/chime"
"github.com/aws/aws-sdk-go/service/cloud9"
"github.com/aws/aws-sdk-go/service/cloudcontrolapi"
"github.com/aws/aws-sdk-go/service/cloudformation"
"github.com/aws/aws-sdk-go/service/cloudfront"
"github.com/aws/aws-sdk-go/service/cloudhsmv2"
Expand Down Expand Up @@ -242,6 +243,7 @@ type AWSClient struct {
cfconn *cloudformation.CloudFormation
chimeconn *chime.Chime
cloud9conn *cloud9.Cloud9
cloudcontrolapiconn *cloudcontrolapi.CloudControlApi
cloudfrontconn *cloudfront.CloudFront
cloudhsmv2conn *cloudhsmv2.CloudHSMV2
cloudsearchconn *cloudsearch.CloudSearch
Expand Down Expand Up @@ -497,6 +499,7 @@ func (c *Config) Client() (interface{}, error) {
cfconn: cloudformation.New(sess.Copy(&aws.Config{Endpoint: aws.String(c.Endpoints["cloudformation"])})),
chimeconn: chime.New(sess.Copy(&aws.Config{Endpoint: aws.String(c.Endpoints["chime"])})),
cloud9conn: cloud9.New(sess.Copy(&aws.Config{Endpoint: aws.String(c.Endpoints["cloud9"])})),
cloudcontrolapiconn: cloudcontrolapi.New(sess.Copy(&aws.Config{Endpoint: aws.String(c.Endpoints["cloudcontrolapi"])})),
cloudfrontconn: cloudfront.New(sess.Copy(&aws.Config{Endpoint: aws.String(c.Endpoints["cloudfront"])})),
cloudhsmv2conn: cloudhsmv2.New(sess.Copy(&aws.Config{Endpoint: aws.String(c.Endpoints["cloudhsm"])})),
cloudsearchconn: cloudsearch.New(sess.Copy(&aws.Config{Endpoint: aws.String(c.Endpoints["cloudsearch"])})),
Expand Down
65 changes: 65 additions & 0 deletions aws/data_source_aws_cloudcontrolapi_resource.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package aws

import (
"context"
"fmt"
"regexp"

"github.com/aws/aws-sdk-go/aws"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/service/cloudcontrol/finder"
)

func dataSourceAwsCloudControlApiResource() *schema.Resource {
return &schema.Resource{
ReadContext: dataSourceAwsCloudControlApiResourceRead,

Schema: map[string]*schema.Schema{
"identifier": {
Type: schema.TypeString,
Required: true,
},
"properties": {
Type: schema.TypeString,
Computed: true,
},
"role_arn": {
Type: schema.TypeString,
Optional: true,
},
"type_name": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringMatch(regexp.MustCompile(`[A-Za-z0-9]{2,64}::[A-Za-z0-9]{2,64}::[A-Za-z0-9]{2,64}`), "must be three alphanumeric sections separated by double colons (::)"),
},
"type_version_id": {
Type: schema.TypeString,
Optional: true,
},
},
}
}

func dataSourceAwsCloudControlApiResourceRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
conn := meta.(*AWSClient).cloudcontrolapiconn

identifier := d.Get("identifier").(string)
resourceDescription, err := finder.ResourceByID(ctx, conn,
identifier,
d.Get("type_name").(string),
d.Get("type_version_id").(string),
d.Get("role_arn").(string),
)

if err != nil {
return diag.FromErr(fmt.Errorf("error reading Cloud Control API Resource (%s): %w", identifier, err))
}

d.SetId(aws.StringValue(resourceDescription.Identifier))

d.Set("properties", resourceDescription.Properties)

return nil
}
50 changes: 50 additions & 0 deletions aws/data_source_aws_cloudcontrolapi_resource_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package aws

import (
"fmt"
"testing"

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

func TestAccAwsCloudControlApiResourceDataSource_basic(t *testing.T) {
rName := acctest.RandomWithPrefix("tf-acc-test")
dataSourceName := "data.aws_cloudcontrolapi_resource.test"
resourceName := "aws_cloudcontrolapi_resource.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ErrorCheck: testAccErrorCheck(t, cloudcontrolapi.EndpointsID),
ProviderFactories: testAccProviderFactories,
CheckDestroy: testAccCheckAwsCloudControlApiResourceDestroy,
Steps: []resource.TestStep{
{
Config: testAccAwsCloudControlApiResourceDataSourceConfig(rName),
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttrPair(dataSourceName, "id", resourceName, "id"),
resource.TestCheckResourceAttrPair(dataSourceName, "properties", resourceName, "properties"),
resource.TestCheckResourceAttrPair(dataSourceName, "type_name", resourceName, "type_name"),
),
},
},
})
}

func testAccAwsCloudControlApiResourceDataSourceConfig(rName string) string {
return fmt.Sprintf(`
resource "aws_cloudcontrolapi_resource" "test" {
type_name = "AWS::Logs::LogGroup"

desired_state = jsonencode({
LogGroupName = %[1]q
})
}

data "aws_cloudcontrolapi_resource" "test" {
identifier = aws_cloudcontrolapi_resource.test.id
type_name = aws_cloudcontrolapi_resource.test.type_name
}
`, rName)
}
78 changes: 78 additions & 0 deletions aws/internal/service/cloudcontrol/finder/finder.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package finder

import (
"context"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/cloudcontrolapi"
"github.com/hashicorp/aws-sdk-go-base/tfawserr"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource"
)

func ProgressEventByRequestToken(ctx context.Context, conn *cloudcontrolapi.CloudControlApi, requestToken string) (*cloudcontrolapi.ProgressEvent, error) {
input := &cloudcontrolapi.GetResourceRequestStatusInput{
RequestToken: aws.String(requestToken),
}

output, err := conn.GetResourceRequestStatusWithContext(ctx, input)

if tfawserr.ErrCodeEquals(err, cloudcontrolapi.ErrCodeRequestTokenNotFoundException) {
return nil, &resource.NotFoundError{
LastError: err,
LastRequest: input,
}
}

if err != nil {
return nil, err
}

if output == nil || output.ProgressEvent == nil {
return nil, tfresource.NewEmptyResultError(input)
}

return output.ProgressEvent, nil
}

func ResourceByID(ctx context.Context, conn *cloudcontrolapi.CloudControlApi, resourceID, typeName, typeVersionID, roleARN string) (*cloudcontrolapi.ResourceDescription, error) {
input := &cloudcontrolapi.GetResourceInput{
Identifier: aws.String(resourceID),
TypeName: aws.String(typeName),
}
if roleARN != "" {
input.RoleArn = aws.String(roleARN)
}
if typeVersionID != "" {
input.TypeVersionId = aws.String(typeVersionID)
}

output, err := conn.GetResourceWithContext(ctx, input)

if tfawserr.ErrCodeEquals(err, cloudcontrolapi.ErrCodeResourceNotFoundException) {
return nil, &resource.NotFoundError{
LastError: err,
LastRequest: input,
}
}

// TEMPORARY:
// Some CloudFormation Resources do not correctly re-map "not found" errors, instead returning a HandlerFailureException.
// These should be reported and fixed upstream over time, but for now work around the issue.
if tfawserr.ErrMessageContains(err, cloudcontrolapi.ErrCodeHandlerFailureException, "not found") {
return nil, &resource.NotFoundError{
LastError: err,
LastRequest: input,
}
}

if err != nil {
return nil, err
}

if output == nil || output.ResourceDescription == nil {
return nil, tfresource.NewEmptyResultError(input)
}

return output.ResourceDescription, nil
}
27 changes: 27 additions & 0 deletions aws/internal/service/cloudcontrol/waiter/status.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package waiter

import (
"context"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/cloudcontrolapi"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/service/cloudcontrol/finder"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource"
)

func ProgressEventOperationStatus(ctx context.Context, conn *cloudcontrolapi.CloudControlApi, requestToken string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
output, err := finder.ProgressEventByRequestToken(ctx, conn, requestToken)

if tfresource.NotFound(err) {
return nil, "", nil
}

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

return output, aws.StringValue(output.OperationStatus), nil
}
}
33 changes: 33 additions & 0 deletions aws/internal/service/cloudcontrol/waiter/waiter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package waiter

import (
"context"
"fmt"
"time"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/cloudcontrolapi"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource"
)

func ProgressEventOperationStatusSuccess(ctx context.Context, conn *cloudcontrolapi.CloudControlApi, requestToken string, timeout time.Duration) (*cloudcontrolapi.ProgressEvent, error) {
stateConf := &resource.StateChangeConf{
Pending: []string{cloudcontrolapi.OperationStatusInProgress, cloudcontrolapi.OperationStatusPending},
Target: []string{cloudcontrolapi.OperationStatusSuccess},
Refresh: ProgressEventOperationStatus(ctx, conn, requestToken),
Timeout: timeout,
}

outputRaw, err := stateConf.WaitForStateContext(ctx)

if output, ok := outputRaw.(*cloudcontrolapi.ProgressEvent); ok {
if operationStatus := aws.StringValue(output.OperationStatus); operationStatus == cloudcontrolapi.OperationStatusFailed {
tfresource.SetLastError(err, fmt.Errorf("%s: %s", aws.StringValue(output.ErrorCode), aws.StringValue(output.StatusMessage)))
}

return output, err
}

return nil, err
}
32 changes: 32 additions & 0 deletions aws/internal/service/cloudformation/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package cloudformation

import (
"fmt"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/cloudformation"
multierror "github.com/hashicorp/go-multierror"
)

const (
ErrCodeValidationError = "ValidationError"
)

func StackSetOperationError(apiObjects []*cloudformation.StackSetOperationResultSummary) error {
var errors *multierror.Error

for _, apiObject := range apiObjects {
if apiObject == nil {
continue
}

errors = multierror.Append(errors, fmt.Errorf("Account (%s) Region (%s) Status (%s) Status Reason: %s",
aws.StringValue(apiObject.Account),
aws.StringValue(apiObject.Region),
aws.StringValue(apiObject.Status),
aws.StringValue(apiObject.StatusReason),
))
}

return errors.ErrorOrNil()
}
Loading