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

service/cloudformation: New Resource and Data Source: aws_cloudformation_type #18579

Merged
merged 5 commits into from
Apr 20, 2021
Merged
Show file tree
Hide file tree
Changes from 4 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
7 changes: 7 additions & 0 deletions .changelog/18579.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
```release-note:new-resource
aws_cloudformation_type
```

```release-note:new-data-source
aws_cloudformation_type
```
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ log.txt
markdown-link-check*.txt
changelog.tmp
terraform-provider-aws
aws/testdata/service/cloudformation/examplecompany-exampleservice-exampleresource/bin/handler

# Test exclusions
!command/test-fixtures/**/*.tfstate
Expand Down
163 changes: 163 additions & 0 deletions aws/data_source_aws_cloudformation_type.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
package aws

import (
"context"
"fmt"
"regexp"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/cloudformation"
"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"
)

func dataSourceAwsCloudFormationType() *schema.Resource {
return &schema.Resource{
ReadWithoutTimeout: dataSourceAwsCloudFormationTypeRead,

Schema: map[string]*schema.Schema{
"arn": {
Type: schema.TypeString,
Optional: true,
Computed: true,
},
"default_version_id": {
Type: schema.TypeString,
Computed: true,
},
"deprecated_status": {
Type: schema.TypeString,
Computed: true,
},
"description": {
Type: schema.TypeString,
Computed: true,
},
"documentation_url": {
Type: schema.TypeString,
Computed: true,
},
"execution_role_arn": {
Type: schema.TypeString,
Computed: true,
},
"is_default_version": {
Type: schema.TypeBool,
Computed: true,
},
"logging_config": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"log_group_name": {
Type: schema.TypeString,
Computed: true,
},
"log_role_arn": {
Type: schema.TypeString,
Computed: true,
},
},
},
},
"provisioning_type": {
Type: schema.TypeString,
Computed: true,
},
"schema": {
Type: schema.TypeString,
Computed: true,
},
"source_url": {
Type: schema.TypeString,
Computed: true,
},
"type": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ValidateFunc: validation.StringInSlice(cloudformation.RegistryType_Values(), false),
},
"type_arn": {
Type: schema.TypeString,
Computed: true,
},
"type_name": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ValidateFunc: validation.All(
validation.StringLenBetween(10, 204),
validation.StringMatch(regexp.MustCompile(`[A-Za-z0-9]{2,64}::[A-Za-z0-9]{2,64}::[A-Za-z0-9]{2,64}(::MODULE){0,1}`), "three alphanumeric character sections separated by double colons (::)"),
),
},
"version_id": {
Type: schema.TypeString,
Optional: true,
},
"visibility": {
Type: schema.TypeString,
Computed: true,
},
},
}
}

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

input := &cloudformation.DescribeTypeInput{}

if v, ok := d.GetOk("arn"); ok {
input.Arn = aws.String(v.(string))
}

if v, ok := d.GetOk("type"); ok {
input.Type = aws.String(v.(string))
}

if v, ok := d.GetOk("type_name"); ok {
input.TypeName = aws.String(v.(string))
}

if v, ok := d.GetOk("version_id"); ok {
input.VersionId = aws.String(v.(string))
}

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

if err != nil {
return diag.FromErr(fmt.Errorf("error reading CloudFormation Type: %w", err))
}

if output == nil {
return diag.FromErr(fmt.Errorf("error reading CloudFormation Type: empty response"))
}

d.SetId(aws.StringValue(output.Arn))

d.Set("arn", output.Arn)
d.Set("default_version_id", output.DefaultVersionId)
d.Set("deprecated_status", output.DeprecatedStatus)
d.Set("description", output.Description)
d.Set("documentation_url", output.DocumentationUrl)
d.Set("execution_role_arn", output.ExecutionRoleArn)
d.Set("is_default_version", output.IsDefaultVersion)
if output.LoggingConfig != nil {
if err := d.Set("logging_config", []interface{}{flattenCloudformationLoggingConfig(output.LoggingConfig)}); err != nil {
return diag.FromErr(fmt.Errorf("error setting logging_config: %w", err))
}
} else {
d.Set("logging_config", nil)
}
d.Set("provisioning_type", output.ProvisioningType)
d.Set("schema", output.Schema)
d.Set("source_url", output.SourceUrl)
d.Set("type", output.Type)
d.Set("type_name", output.TypeName)
d.Set("visibility", output.Visibility)

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

import (
"fmt"
"regexp"
"testing"

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

func TestAccAwsCloudformationTypeDataSource_Arn_Private(t *testing.T) {
rName := acctest.RandomWithPrefix("tf-acc-test")
typeName := fmt.Sprintf("HashiCorp::TerraformAwsProvider::TfAccTest%s", acctest.RandString(8))
zipPath := testAccAwsCloudformationTypeZipGenerator(t, typeName)
resourceName := "aws_cloudformation_type.test"
dataSourceName := "data.aws_cloudformation_type.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ErrorCheck: testAccErrorCheck(t, cloudformation.EndpointsID),
ProviderFactories: testAccProviderFactories,
CheckDestroy: testAccCheckAwsCloudformationTypeDestroy,
Steps: []resource.TestStep{
{
Config: testAccAwsCloudformationTypeDataSourceConfigArnPrivate(rName, zipPath, typeName),
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttrPair(dataSourceName, "arn", resourceName, "arn"),
resource.TestCheckResourceAttrPair(dataSourceName, "deprecated_status", resourceName, "deprecated_status"),
resource.TestCheckResourceAttrPair(dataSourceName, "description", resourceName, "description"),
resource.TestCheckResourceAttrPair(dataSourceName, "documentation_url", resourceName, "documentation_url"),
resource.TestCheckResourceAttrPair(dataSourceName, "execution_role_arn", resourceName, "execution_role_arn"),
resource.TestCheckResourceAttrPair(dataSourceName, "is_default_version", resourceName, "is_default_version"),
resource.TestCheckResourceAttrPair(dataSourceName, "logging_config.#", resourceName, "logging_config.#"),
resource.TestCheckResourceAttrPair(dataSourceName, "provisioning_type", resourceName, "provisioning_type"),
resource.TestCheckResourceAttrPair(dataSourceName, "schema", resourceName, "schema"),
resource.TestCheckResourceAttrPair(dataSourceName, "source_url", resourceName, "source_url"),
resource.TestCheckResourceAttrPair(dataSourceName, "type", resourceName, "type"),
resource.TestCheckResourceAttrPair(dataSourceName, "type_name", resourceName, "type_name"),
resource.TestCheckResourceAttrPair(dataSourceName, "visibility", resourceName, "visibility"),
),
},
},
})
}

func TestAccAwsCloudformationTypeDataSource_Arn_Public(t *testing.T) {
dataSourceName := "data.aws_cloudformation_type.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ErrorCheck: testAccErrorCheck(t, cloudformation.EndpointsID),
ProviderFactories: testAccProviderFactories,
CheckDestroy: nil,
Steps: []resource.TestStep{
{
Config: testAccAwsCloudformationTypeDataSourceConfigArnPublic(),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckResourceAttrRegionalARNNoAccount(dataSourceName, "arn", "cloudformation", "type/resource/AWS-Athena-WorkGroup"),
resource.TestCheckResourceAttr(dataSourceName, "deprecated_status", cloudformation.DeprecatedStatusLive),
resource.TestMatchResourceAttr(dataSourceName, "description", regexp.MustCompile(`.*`)),
resource.TestCheckResourceAttr(dataSourceName, "documentation_url", ""),
resource.TestCheckResourceAttr(dataSourceName, "is_default_version", "true"),
resource.TestCheckResourceAttr(dataSourceName, "logging_config.#", "0"),
resource.TestCheckResourceAttr(dataSourceName, "provisioning_type", cloudformation.ProvisioningTypeFullyMutable),
resource.TestMatchResourceAttr(dataSourceName, "schema", regexp.MustCompile(`^\{.*`)),
resource.TestMatchResourceAttr(dataSourceName, "source_url", regexp.MustCompile(`^https://.+`)),
resource.TestCheckResourceAttr(dataSourceName, "type", cloudformation.RegistryTypeResource),
resource.TestCheckResourceAttr(dataSourceName, "type_name", "AWS::Athena::WorkGroup"),
resource.TestCheckResourceAttr(dataSourceName, "visibility", cloudformation.VisibilityPublic),
),
},
},
})
}

func TestAccAwsCloudformationTypeDataSource_TypeName_Private(t *testing.T) {
rName := acctest.RandomWithPrefix("tf-acc-test")
typeName := fmt.Sprintf("HashiCorp::TerraformAwsProvider::TfAccTest%s", acctest.RandString(8))
zipPath := testAccAwsCloudformationTypeZipGenerator(t, typeName)
resourceName := "aws_cloudformation_type.test"
dataSourceName := "data.aws_cloudformation_type.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ErrorCheck: testAccErrorCheck(t, cloudformation.EndpointsID),
ProviderFactories: testAccProviderFactories,
CheckDestroy: testAccCheckAwsCloudformationTypeDestroy,
Steps: []resource.TestStep{
{
Config: testAccAwsCloudformationTypeDataSourceConfigTypeNamePrivate(rName, zipPath, typeName),
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttrPair(dataSourceName, "arn", resourceName, "arn"),
resource.TestCheckResourceAttrPair(dataSourceName, "deprecated_status", resourceName, "deprecated_status"),
resource.TestCheckResourceAttrPair(dataSourceName, "description", resourceName, "description"),
resource.TestCheckResourceAttrPair(dataSourceName, "documentation_url", resourceName, "documentation_url"),
resource.TestCheckResourceAttrPair(dataSourceName, "execution_role_arn", resourceName, "execution_role_arn"),
resource.TestCheckResourceAttrPair(dataSourceName, "is_default_version", resourceName, "is_default_version"),
resource.TestCheckResourceAttrPair(dataSourceName, "logging_config.#", resourceName, "logging_config.#"),
resource.TestCheckResourceAttrPair(dataSourceName, "provisioning_type", resourceName, "provisioning_type"),
resource.TestCheckResourceAttrPair(dataSourceName, "schema", resourceName, "schema"),
resource.TestCheckResourceAttrPair(dataSourceName, "source_url", resourceName, "source_url"),
resource.TestCheckResourceAttrPair(dataSourceName, "type", resourceName, "type"),
resource.TestCheckResourceAttrPair(dataSourceName, "type_name", resourceName, "type_name"),
resource.TestCheckResourceAttrPair(dataSourceName, "visibility", resourceName, "visibility"),
),
},
},
})
}

func TestAccAwsCloudformationTypeDataSource_TypeName_Public(t *testing.T) {
dataSourceName := "data.aws_cloudformation_type.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ErrorCheck: testAccErrorCheck(t, cloudformation.EndpointsID),
ProviderFactories: testAccProviderFactories,
CheckDestroy: nil,
Steps: []resource.TestStep{
{
Config: testAccAwsCloudformationTypeDataSourceConfigTypeNamePublic(),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckResourceAttrRegionalARNNoAccount(dataSourceName, "arn", "cloudformation", "type/resource/AWS-Athena-WorkGroup"),
resource.TestCheckResourceAttr(dataSourceName, "deprecated_status", cloudformation.DeprecatedStatusLive),
resource.TestMatchResourceAttr(dataSourceName, "description", regexp.MustCompile(`.*`)),
resource.TestCheckResourceAttr(dataSourceName, "documentation_url", ""),
resource.TestCheckResourceAttr(dataSourceName, "is_default_version", "true"),
resource.TestCheckResourceAttr(dataSourceName, "logging_config.#", "0"),
resource.TestCheckResourceAttr(dataSourceName, "provisioning_type", cloudformation.ProvisioningTypeFullyMutable),
resource.TestMatchResourceAttr(dataSourceName, "schema", regexp.MustCompile(`^\{.*`)),
resource.TestMatchResourceAttr(dataSourceName, "source_url", regexp.MustCompile(`^https://.+`)),
resource.TestCheckResourceAttr(dataSourceName, "type", cloudformation.RegistryTypeResource),
resource.TestCheckResourceAttr(dataSourceName, "type_name", "AWS::Athena::WorkGroup"),
resource.TestCheckResourceAttr(dataSourceName, "visibility", cloudformation.VisibilityPublic),
),
},
},
})
}

func testAccCloudformationTypeConfigPrivateBase(rName string, zipPath string, typeName string) string {
return fmt.Sprintf(`
data "aws_partition" "current" {}

resource "aws_s3_bucket" "test" {
bucket = %[1]q
force_destroy = true
}

resource "aws_s3_bucket_object" "test" {
bucket = aws_s3_bucket.test.bucket
key = "test"
source = %[2]q
}

resource "aws_cloudformation_type" "test" {
schema_handler_package = "s3://${aws_s3_bucket_object.test.bucket}/${aws_s3_bucket_object.test.key}"
type = "RESOURCE"
type_name = %[3]q
}
`, rName, zipPath, typeName)
}

func testAccAwsCloudformationTypeDataSourceConfigArnPrivate(rName string, zipPath string, typeName string) string {
return composeConfig(
testAccCloudformationTypeConfigPrivateBase(rName, zipPath, typeName),
`
data "aws_cloudformation_type" "test" {
arn = aws_cloudformation_type.test.arn
}
`)
}

func testAccAwsCloudformationTypeDataSourceConfigArnPublic() string {
return `
data "aws_partition" "current" {}

data "aws_region" "current" {}

data "aws_cloudformation_type" "test" {
arn = "arn:${data.aws_partition.current.partition}:cloudformation:${data.aws_region.current.name}::type/resource/AWS-Athena-WorkGroup"
}
`
}

func testAccAwsCloudformationTypeDataSourceConfigTypeNamePrivate(rName string, zipPath string, typeName string) string {
return composeConfig(
testAccCloudformationTypeConfigPrivateBase(rName, zipPath, typeName),
`
data "aws_cloudformation_type" "test" {
type = aws_cloudformation_type.test.type
type_name = aws_cloudformation_type.test.type_name
}
`)
}

func testAccAwsCloudformationTypeDataSourceConfigTypeNamePublic() string {
return `
data "aws_cloudformation_type" "test" {
type = "RESOURCE"
type_name = "AWS::Athena::WorkGroup"
}
`
}
Loading