Skip to content

Commit

Permalink
Merge pull request #19320 from suzuki-shunsuke/feat/appconfig_configu…
Browse files Browse the repository at this point in the history
…ration_profile

feat: add appconfig_configuration_profile
  • Loading branch information
anGie44 authored Jul 12, 2021
2 parents b3e107e + a0d51c5 commit dece377
Show file tree
Hide file tree
Showing 8 changed files with 1,019 additions and 8 deletions.
3 changes: 3 additions & 0 deletions .changelog/19320.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:new-resource
aws_appconfig_configuration_profile
```
1 change: 1 addition & 0 deletions aws/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,7 @@ func Provider() *schema.Provider {
"aws_appautoscaling_policy": resourceAwsAppautoscalingPolicy(),
"aws_appautoscaling_scheduled_action": resourceAwsAppautoscalingScheduledAction(),
"aws_appconfig_application": resourceAwsAppconfigApplication(),
"aws_appconfig_configuration_profile": resourceAwsAppconfigConfigurationProfile(),
"aws_appconfig_environment": resourceAwsAppconfigEnvironment(),
"aws_appmesh_gateway_route": resourceAwsAppmeshGatewayRoute(),
"aws_appmesh_mesh": resourceAwsAppmeshMesh(),
Expand Down
373 changes: 373 additions & 0 deletions aws/resource_aws_appconfig_configuration_profile.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,373 @@
package aws

import (
"fmt"
"log"
"regexp"
"strings"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/arn"
"github.com/aws/aws-sdk-go/service/appconfig"
"github.com/hashicorp/aws-sdk-go-base/tfawserr"
"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/keyvaluetags"
)

func resourceAwsAppconfigConfigurationProfile() *schema.Resource {
return &schema.Resource{
Create: resourceAwsAppconfigConfigurationProfileCreate,
Read: resourceAwsAppconfigConfigurationProfileRead,
Update: resourceAwsAppconfigConfigurationProfileUpdate,
Delete: resourceAwsAppconfigConfigurationProfileDelete,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},

Schema: map[string]*schema.Schema{
"application_id": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validation.StringMatch(regexp.MustCompile(`[a-z0-9]{4,7}`), ""),
},
"arn": {
Type: schema.TypeString,
Computed: true,
},
"configuration_profile_id": {
Type: schema.TypeString,
Computed: true,
},
"description": {
Type: schema.TypeString,
Optional: true,
ValidateFunc: validation.StringLenBetween(0, 1024),
},
"location_uri": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validation.StringLenBetween(1, 2048),
},
"name": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringLenBetween(1, 64),
},
"retrieval_role_arn": {
Type: schema.TypeString,
Optional: true,
ValidateFunc: validateArn,
},
"tags": tagsSchema(),
"tags_all": tagsSchemaComputed(),
"validator": {
Type: schema.TypeSet,
Optional: true,
MaxItems: 2,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"content": {
Type: schema.TypeString,
Optional: true,
Sensitive: true,
ValidateFunc: validation.Any(
validation.StringIsJSON,
validateArn,
),
DiffSuppressFunc: suppressEquivalentJsonDiffs,
},
"type": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringInSlice(appconfig.ValidatorType_Values(), false),
},
},
},
},
},
CustomizeDiff: SetTagsDiff,
}
}

func resourceAwsAppconfigConfigurationProfileCreate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).appconfigconn
defaultTagsConfig := meta.(*AWSClient).DefaultTagsConfig
tags := defaultTagsConfig.MergeTags(keyvaluetags.New(d.Get("tags").(map[string]interface{})))

appId := d.Get("application_id").(string)
name := d.Get("name").(string)

input := &appconfig.CreateConfigurationProfileInput{
ApplicationId: aws.String(appId),
LocationUri: aws.String(d.Get("location_uri").(string)),
Name: aws.String(name),
Tags: tags.IgnoreAws().AppconfigTags(),
}

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

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

if v, ok := d.GetOk("validator"); ok && v.(*schema.Set).Len() > 0 {
input.Validators = expandAppconfigValidators(v.(*schema.Set).List())
}

profile, err := conn.CreateConfigurationProfile(input)

if err != nil {
return fmt.Errorf("error creating AppConfig Configuration Profile (%s) for Application (%s): %w", name, appId, err)
}

if profile == nil {
return fmt.Errorf("error creating AppConfig Configuration Profile (%s) for Application (%s): empty response", name, appId)
}

d.SetId(fmt.Sprintf("%s:%s", aws.StringValue(profile.Id), aws.StringValue(profile.ApplicationId)))

return resourceAwsAppconfigConfigurationProfileRead(d, meta)
}

func resourceAwsAppconfigConfigurationProfileRead(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).appconfigconn
defaultTagsConfig := meta.(*AWSClient).DefaultTagsConfig
ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig

confProfID, appID, err := resourceAwsAppconfigConfigurationProfileParseID(d.Id())

if err != nil {
return err
}

input := &appconfig.GetConfigurationProfileInput{
ApplicationId: aws.String(appID),
ConfigurationProfileId: aws.String(confProfID),
}

output, err := conn.GetConfigurationProfile(input)

if !d.IsNewResource() && tfawserr.ErrCodeEquals(err, appconfig.ErrCodeResourceNotFoundException) {
log.Printf("[WARN] AppConfig Configuration Profile (%s) for Application (%s) not found, removing from state", confProfID, appID)
d.SetId("")
return nil
}

if err != nil {
return fmt.Errorf("error getting AppConfig Configuration Profile (%s) for Application (%s): %w", confProfID, appID, err)
}

if output == nil {
return fmt.Errorf("error getting AppConfig Configuration Profile (%s) for Application (%s): empty response", confProfID, appID)
}

d.Set("application_id", output.ApplicationId)
d.Set("configuration_profile_id", output.Id)
d.Set("description", output.Description)
d.Set("location_uri", output.LocationUri)
d.Set("name", output.Name)

d.Set("retrieval_role_arn", output.RetrievalRoleArn)

if err := d.Set("validator", flattenAwsAppconfigValidators(output.Validators)); err != nil {
return fmt.Errorf("error setting validator: %w", err)
}

arn := arn.ARN{
AccountID: meta.(*AWSClient).accountid,
Partition: meta.(*AWSClient).partition,
Region: meta.(*AWSClient).region,
Resource: fmt.Sprintf("application/%s/configurationprofile/%s", appID, confProfID),
Service: "appconfig",
}.String()

d.Set("arn", arn)

tags, err := keyvaluetags.AppconfigListTags(conn, arn)

if err != nil {
return fmt.Errorf("error listing tags for AppConfig Configuration Profile (%s): %w", d.Id(), err)
}

tags = tags.IgnoreAws().IgnoreConfig(ignoreTagsConfig)

//lintignore:AWSR002
if err := d.Set("tags", tags.RemoveDefaultConfig(defaultTagsConfig).Map()); err != nil {
return fmt.Errorf("error setting tags: %w", err)
}

if err := d.Set("tags_all", tags.Map()); err != nil {
return fmt.Errorf("error setting tags_all: %w", err)
}

return nil
}

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

if d.HasChangesExcept("tags", "tags_all") {
confProfID, appID, err := resourceAwsAppconfigConfigurationProfileParseID(d.Id())

if err != nil {
return err
}

updateInput := &appconfig.UpdateConfigurationProfileInput{
ApplicationId: aws.String(appID),
ConfigurationProfileId: aws.String(confProfID),
}

if d.HasChange("description") {
updateInput.Description = aws.String(d.Get("description").(string))
}

if d.HasChange("name") {
updateInput.Name = aws.String(d.Get("name").(string))
}

if d.HasChange("retrieval_role_arn") {
updateInput.RetrievalRoleArn = aws.String(d.Get("retrieval_role_arn").(string))
}

if d.HasChange("validator") {
updateInput.Validators = expandAppconfigValidators(d.Get("validator").(*schema.Set).List())
}

_, err = conn.UpdateConfigurationProfile(updateInput)

if err != nil {
return fmt.Errorf("error updating AppConfig Configuration Profile (%s) for Application (%s): %w", confProfID, appID, err)
}
}

if d.HasChange("tags_all") {
o, n := d.GetChange("tags_all")
if err := keyvaluetags.AppconfigUpdateTags(conn, d.Get("arn").(string), o, n); err != nil {
return fmt.Errorf("error updating AppConfig Configuration Profile (%s) tags: %w", d.Get("arn").(string), err)
}
}

return resourceAwsAppconfigConfigurationProfileRead(d, meta)
}

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

confProfID, appID, err := resourceAwsAppconfigConfigurationProfileParseID(d.Id())

if err != nil {
return err
}

input := &appconfig.DeleteConfigurationProfileInput{
ApplicationId: aws.String(appID),
ConfigurationProfileId: aws.String(confProfID),
}

_, err = conn.DeleteConfigurationProfile(input)

if tfawserr.ErrCodeEquals(err, appconfig.ErrCodeResourceNotFoundException) {
return nil
}

if err != nil {
return fmt.Errorf("error deleting AppConfig Configuration Profile (%s) for Application (%s): %w", confProfID, appID, err)
}

return nil
}

func resourceAwsAppconfigConfigurationProfileParseID(id string) (string, string, error) {
parts := strings.Split(id, ":")

if len(parts) != 2 || parts[0] == "" || parts[1] == "" {
return "", "", fmt.Errorf("unexpected format of ID (%q), expected configurationProfileID:applicationID", id)
}

return parts[0], parts[1], nil
}

func expandAppconfigValidator(tfMap map[string]interface{}) *appconfig.Validator {
if tfMap == nil {
return nil
}

validator := &appconfig.Validator{}

// AppConfig API supports empty content
if v, ok := tfMap["content"].(string); ok {
validator.Content = aws.String(v)
}

if v, ok := tfMap["type"].(string); ok && v != "" {
validator.Type = aws.String(v)
}

return validator
}

func expandAppconfigValidators(tfList []interface{}) []*appconfig.Validator {
// AppConfig API requires a 0 length slice instead of a nil value
// when updating from N validators to 0/nil validators
validators := make([]*appconfig.Validator, 0)

for _, tfMapRaw := range tfList {
tfMap, ok := tfMapRaw.(map[string]interface{})

if !ok {
continue
}

validator := expandAppconfigValidator(tfMap)

if validator == nil {
continue
}

validators = append(validators, validator)
}

return validators
}

func flattenAwsAppconfigValidator(validator *appconfig.Validator) map[string]interface{} {
if validator == nil {
return nil
}

tfMap := map[string]interface{}{}

if v := validator.Content; v != nil {
tfMap["content"] = aws.StringValue(v)
}

if v := validator.Type; v != nil {
tfMap["type"] = aws.StringValue(v)
}

return tfMap
}

func flattenAwsAppconfigValidators(validators []*appconfig.Validator) []interface{} {
if len(validators) == 0 {
return nil
}

var tfList []interface{}

for _, validator := range validators {
if validator == nil {
continue
}

tfList = append(tfList, flattenAwsAppconfigValidator(validator))
}

return tfList
}
Loading

0 comments on commit dece377

Please sign in to comment.