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

Add key_value_store_associations to aws_cloudfront_function #36585

Merged
Show file tree
Hide file tree
Changes from all 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/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
Loading