Skip to content

Commit

Permalink
Merge pull request #36585 from brittandeyoung/f-aws_cloudfront_functi…
Browse files Browse the repository at this point in the history
…on-key_value_store_associations

Add `key_value_store_associations` to `aws_cloudfront_function`
  • Loading branch information
ewbankkit authored Mar 27, 2024
2 parents 3532b9f + 7008268 commit 6c1b1f7
Show file tree
Hide file tree
Showing 11 changed files with 283 additions and 92 deletions.
7 changes: 7 additions & 0 deletions .changelog/36585.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
```release-note:enhancement
resource/aws_cloudfront_function: Add `key_value_store_associations` argument
```

```release-note:enhancement
data-source/aws_cloudfront_function: Add `key_value_store_associations` attribute
```
6 changes: 4 additions & 2 deletions internal/service/cloudfront/exports_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ package cloudfront
// Exports for use in tests only.
var (
ResourceContinuousDeploymentPolicy = newResourceContinuousDeploymentPolicy
ResourceFunction = resourceFunction
ResourceKeyValueStore = newKeyValueStoreResource

FindKeyValueStoreByName = findKeyValueStoreByName
FindPublicKeyByID = findPublicKeyByID
FindFunctionByTwoPartKey = findFunctionByTwoPartKey
FindKeyValueStoreByName = findKeyValueStoreByName
FindPublicKeyByID = findPublicKeyByID
)
26 changes: 0 additions & 26 deletions internal/service/cloudfront/find.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,32 +88,6 @@ func FindFieldLevelEncryptionProfileByID(ctx context.Context, conn *cloudfront.C
return output, nil
}

func FindFunctionByNameAndStage(ctx context.Context, conn *cloudfront.CloudFront, name, stage string) (*cloudfront.DescribeFunctionOutput, error) {
input := &cloudfront.DescribeFunctionInput{
Name: aws.String(name),
Stage: aws.String(stage),
}

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

if tfawserr.ErrCodeEquals(err, cloudfront.ErrCodeNoSuchFunctionExists) {
return nil, &retry.NotFoundError{
LastError: err,
LastRequest: input,
}
}

if err != nil {
return nil, err
}

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

return output, nil
}

func FindMonitoringSubscriptionByDistributionID(ctx context.Context, conn *cloudfront.CloudFront, id string) (*cloudfront.GetMonitoringSubscriptionOutput, error) {
input := &cloudfront.GetMonitoringSubscriptionInput{
DistributionId: aws.String(id),
Expand Down
120 changes: 99 additions & 21 deletions internal/service/cloudfront/function.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,23 @@ import (
"github.com/aws/aws-sdk-go/service/cloudfront"
"github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
"github.com/hashicorp/terraform-provider-aws/internal/conns"
"github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag"
"github.com/hashicorp/terraform-provider-aws/internal/tfresource"
"github.com/hashicorp/terraform-provider-aws/internal/verify"
)

// @SDKResource("aws_cloudfront_function")
func ResourceFunction() *schema.Resource {
// @SDKResource("aws_cloudfront_function", name="Function")
func resourceFunction() *schema.Resource {
return &schema.Resource{
CreateWithoutTimeout: resourceFunctionCreate,
ReadWithoutTimeout: resourceFunctionRead,
UpdateWithoutTimeout: resourceFunctionUpdate,
DeleteWithoutTimeout: resourceFunctionDelete,

Importer: &schema.ResourceImporter{
StateContext: schema.ImportStatePassthroughContext,
},
Expand All @@ -46,6 +49,14 @@ func ResourceFunction() *schema.Resource {
Type: schema.TypeString,
Computed: true,
},
"key_value_store_associations": {
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Schema{
Type: schema.TypeString,
ValidateFunc: verify.ValidARN,
},
},
"live_stage_etag": {
Type: schema.TypeString,
Computed: true,
Expand Down Expand Up @@ -87,7 +98,10 @@ func resourceFunctionCreate(ctx context.Context, d *schema.ResourceData, meta in
Name: aws.String(functionName),
}

log.Printf("[DEBUG] Creating CloudFront Function: %s", functionName)
if v, ok := d.GetOk("key_value_store_associations"); ok {
input.FunctionConfig.KeyValueStoreAssociations = expandKeyValueStoreAssociations(v.(*schema.Set).List())
}

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

if err != nil {
Expand All @@ -102,7 +116,6 @@ func resourceFunctionCreate(ctx context.Context, d *schema.ResourceData, meta in
IfMatch: output.ETag,
}

log.Printf("[DEBUG] Publishing CloudFront Function: %s", input)
_, err := conn.PublishFunctionWithContext(ctx, input)

if err != nil {
Expand All @@ -117,7 +130,7 @@ func resourceFunctionRead(ctx context.Context, d *schema.ResourceData, meta inte
var diags diag.Diagnostics
conn := meta.(*conns.AWSClient).CloudFrontConn(ctx)

describeFunctionOutput, err := FindFunctionByNameAndStage(ctx, conn, d.Id(), cloudfront.FunctionStageDevelopment)
outputDF, err := findFunctionByTwoPartKey(ctx, conn, d.Id(), cloudfront.FunctionStageDevelopment)

if !d.IsNewResource() && tfresource.NotFound(err) {
log.Printf("[WARN] CloudFront Function (%s) not found, removing from state", d.Id())
Expand All @@ -129,14 +142,17 @@ func resourceFunctionRead(ctx context.Context, d *schema.ResourceData, meta inte
return sdkdiag.AppendErrorf(diags, "reading CloudFront Function (%s) DEVELOPMENT stage: %s", d.Id(), err)
}

d.Set("arn", describeFunctionOutput.FunctionSummary.FunctionMetadata.FunctionARN)
d.Set("comment", describeFunctionOutput.FunctionSummary.FunctionConfig.Comment)
d.Set("etag", describeFunctionOutput.ETag)
d.Set("name", describeFunctionOutput.FunctionSummary.Name)
d.Set("runtime", describeFunctionOutput.FunctionSummary.FunctionConfig.Runtime)
d.Set("status", describeFunctionOutput.FunctionSummary.Status)
d.Set("arn", outputDF.FunctionSummary.FunctionMetadata.FunctionARN)
d.Set("comment", outputDF.FunctionSummary.FunctionConfig.Comment)
d.Set("etag", outputDF.ETag)
if err := d.Set("key_value_store_associations", flattenKeyValueStoreAssociations(outputDF.FunctionSummary.FunctionConfig.KeyValueStoreAssociations)); err != nil {
return sdkdiag.AppendErrorf(diags, "setting key_value_store_associations: %s", err)
}
d.Set("name", outputDF.FunctionSummary.Name)
d.Set("runtime", outputDF.FunctionSummary.FunctionConfig.Runtime)
d.Set("status", outputDF.FunctionSummary.Status)

getFunctionOutput, err := conn.GetFunctionWithContext(ctx, &cloudfront.GetFunctionInput{
outputGF, err := conn.GetFunctionWithContext(ctx, &cloudfront.GetFunctionInput{
Name: aws.String(d.Id()),
Stage: aws.String(cloudfront.FunctionStageDevelopment),
})
Expand All @@ -145,16 +161,16 @@ func resourceFunctionRead(ctx context.Context, d *schema.ResourceData, meta inte
return sdkdiag.AppendErrorf(diags, "reading CloudFront Function (%s) DEVELOPMENT stage code: %s", d.Id(), err)
}

d.Set("code", string(getFunctionOutput.FunctionCode))
d.Set("code", string(outputGF.FunctionCode))

describeFunctionOutput, err = FindFunctionByNameAndStage(ctx, conn, d.Id(), cloudfront.FunctionStageLive)
outputDF, err = findFunctionByTwoPartKey(ctx, conn, d.Id(), cloudfront.FunctionStageLive)

if tfresource.NotFound(err) {
d.Set("live_stage_etag", "")
} else if err != nil {
return sdkdiag.AppendErrorf(diags, "reading CloudFront Function (%s) LIVE stage: %s", d.Id(), err)
} else {
d.Set("live_stage_etag", describeFunctionOutput.ETag)
d.Set("live_stage_etag", outputDF.ETag)
}

return diags
Expand All @@ -165,18 +181,21 @@ func resourceFunctionUpdate(ctx context.Context, d *schema.ResourceData, meta in
conn := meta.(*conns.AWSClient).CloudFrontConn(ctx)
etag := d.Get("etag").(string)

if d.HasChanges("code", "comment", "runtime") {
if d.HasChanges("code", "comment", "key_value_store_associations", "runtime") {
input := &cloudfront.UpdateFunctionInput{
FunctionCode: []byte(d.Get("code").(string)),
FunctionConfig: &cloudfront.FunctionConfig{
Comment: aws.String(d.Get("comment").(string)),
Runtime: aws.String(d.Get("runtime").(string)),
},
Name: aws.String(d.Id()),
IfMatch: aws.String(etag),
Name: aws.String(d.Id()),
}

if v, ok := d.GetOk("key_value_store_associations"); ok {
input.FunctionConfig.KeyValueStoreAssociations = expandKeyValueStoreAssociations(v.(*schema.Set).List())
}

log.Printf("[INFO] Updating CloudFront Function: %s", d.Id())
output, err := conn.UpdateFunctionWithContext(ctx, input)

if err != nil {
Expand All @@ -188,11 +207,10 @@ func resourceFunctionUpdate(ctx context.Context, d *schema.ResourceData, meta in

if d.Get("publish").(bool) {
input := &cloudfront.PublishFunctionInput{
Name: aws.String(d.Id()),
IfMatch: aws.String(etag),
Name: aws.String(d.Id()),
}

log.Printf("[DEBUG] Publishing CloudFront Function: %s", d.Id())
_, err := conn.PublishFunctionWithContext(ctx, input)

if err != nil {
Expand All @@ -209,8 +227,8 @@ func resourceFunctionDelete(ctx context.Context, d *schema.ResourceData, meta in

log.Printf("[INFO] Deleting CloudFront Function: %s", d.Id())
_, err := conn.DeleteFunctionWithContext(ctx, &cloudfront.DeleteFunctionInput{
Name: aws.String(d.Id()),
IfMatch: aws.String(d.Get("etag").(string)),
Name: aws.String(d.Id()),
})

if tfawserr.ErrCodeEquals(err, cloudfront.ErrCodeNoSuchFunctionExists) {
Expand All @@ -223,3 +241,63 @@ func resourceFunctionDelete(ctx context.Context, d *schema.ResourceData, meta in

return diags
}

func findFunctionByTwoPartKey(ctx context.Context, conn *cloudfront.CloudFront, name, stage string) (*cloudfront.DescribeFunctionOutput, error) {
input := &cloudfront.DescribeFunctionInput{
Name: aws.String(name),
Stage: aws.String(stage),
}

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

if tfawserr.ErrCodeEquals(err, cloudfront.ErrCodeNoSuchFunctionExists) {
return nil, &retry.NotFoundError{
LastError: err,
LastRequest: input,
}
}

if err != nil {
return nil, err
}

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

return output, nil
}

func expandKeyValueStoreAssociations(tfList []interface{}) *cloudfront.KeyValueStoreAssociations {
if len(tfList) == 0 {
return nil
}

var items []*cloudfront.KeyValueStoreAssociation

for _, tfItem := range tfList {
item := tfItem.(string)

items = append(items, &cloudfront.KeyValueStoreAssociation{
KeyValueStoreARN: aws.String(item),
})
}

return &cloudfront.KeyValueStoreAssociations{
Items: items,
Quantity: aws.Int64(int64(len(items))),
}
}

func flattenKeyValueStoreAssociations(input *cloudfront.KeyValueStoreAssociations) []string {
if input == nil {
return nil
}

var items []string

for _, item := range input.Items {
items = append(items, aws.StringValue(item.KeyValueStoreARN))
}
return items
}
56 changes: 28 additions & 28 deletions internal/service/cloudfront/function_data_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ import (
"github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag"
)

// @SDKDataSource("aws_cloudfront_function")
func DataSourceFunction() *schema.Resource {
// @SDKDataSource("aws_cloudfront_function", name="Function")
func dataSourceFunction() *schema.Resource {
return &schema.Resource{
ReadWithoutTimeout: dataSourceFunctionRead,

Expand All @@ -26,43 +26,42 @@ func DataSourceFunction() *schema.Resource {
Type: schema.TypeString,
Computed: true,
},

"etag": {
"code": {
Type: schema.TypeString,
Computed: true,
},

"code": {
"comment": {
Type: schema.TypeString,
Computed: true,
},

"comment": {
"etag": {
Type: schema.TypeString,
Computed: true,
},

"key_value_store_associations": {
Type: schema.TypeSet,
Computed: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
"last_modified_time": {
Type: schema.TypeString,
Computed: true,
},

"name": {
Type: schema.TypeString,
Required: true,
},

"runtime": {
Type: schema.TypeString,
Computed: true,
},

"stage": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringInSlice(cloudfront.FunctionStage_Values(), false),
},

"status": {
Type: schema.TypeString,
Computed: true,
Expand All @@ -77,33 +76,34 @@ func dataSourceFunctionRead(ctx context.Context, d *schema.ResourceData, meta in

name := d.Get("name").(string)
stage := d.Get("stage").(string)

describeFunctionOutput, err := FindFunctionByNameAndStage(ctx, conn, name, stage)
outputDF, err := findFunctionByTwoPartKey(ctx, conn, name, stage)

if err != nil {
return sdkdiag.AppendErrorf(diags, "describing CloudFront Function (%s/%s): %s", name, stage, err)
return sdkdiag.AppendErrorf(diags, "reading CloudFront Function (%s) %s stage: %s", name, stage, err)
}

d.Set("arn", describeFunctionOutput.FunctionSummary.FunctionMetadata.FunctionARN)
d.Set("comment", describeFunctionOutput.FunctionSummary.FunctionConfig.Comment)
d.Set("etag", describeFunctionOutput.ETag)
d.Set("last_modified_time", describeFunctionOutput.FunctionSummary.FunctionMetadata.LastModifiedTime.Format(time.RFC3339))
d.Set("name", describeFunctionOutput.FunctionSummary.Name)
d.Set("runtime", describeFunctionOutput.FunctionSummary.FunctionConfig.Runtime)
d.Set("status", describeFunctionOutput.FunctionSummary.Status)
d.SetId(aws.StringValue(outputDF.FunctionSummary.Name))
d.Set("arn", outputDF.FunctionSummary.FunctionMetadata.FunctionARN)
d.Set("comment", outputDF.FunctionSummary.FunctionConfig.Comment)
d.Set("etag", outputDF.ETag)
if err := d.Set("key_value_store_associations", flattenKeyValueStoreAssociations(outputDF.FunctionSummary.FunctionConfig.KeyValueStoreAssociations)); err != nil {
return sdkdiag.AppendErrorf(diags, "setting key_value_store_associations: %s", err)
}
d.Set("last_modified_time", outputDF.FunctionSummary.FunctionMetadata.LastModifiedTime.Format(time.RFC3339))
d.Set("name", outputDF.FunctionSummary.Name)
d.Set("runtime", outputDF.FunctionSummary.FunctionConfig.Runtime)
d.Set("status", outputDF.FunctionSummary.Status)

getFunctionOutput, err := conn.GetFunctionWithContext(ctx, &cloudfront.GetFunctionInput{
outputGF, err := conn.GetFunctionWithContext(ctx, &cloudfront.GetFunctionInput{
Name: aws.String(name),
Stage: aws.String(stage),
})

if err != nil {
return sdkdiag.AppendErrorf(diags, "getting CloudFront Function (%s): %s", d.Id(), err)
return sdkdiag.AppendErrorf(diags, "reading CloudFront Function (%s) %s stage code: %s", name, stage, err)
}

d.Set("code", string(getFunctionOutput.FunctionCode))

d.SetId(aws.StringValue(describeFunctionOutput.FunctionSummary.Name))
d.Set("code", string(outputGF.FunctionCode))

return diags
}
Loading

0 comments on commit 6c1b1f7

Please sign in to comment.