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

feat: add appconfig_configuration_profile #19320

Merged
merged 12 commits into from
Jul 12, 2021
Merged
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