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

resource aws_cloudfront_function #19315

Merged
merged 16 commits into from
May 17, 2021
11 changes: 11 additions & 0 deletions .changelog/19315.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
```release-note:enhancement
resource/aws_cloudfront_distribution: Add `function_association` argument
```

```release-note:new-resource
aws_cloudfront_function
```

```release-note:new-data-source
aws_cloudfront_function
```
67 changes: 67 additions & 0 deletions aws/cloudfront_distribution_configuration_structure.go
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,10 @@ func expandCloudFrontDefaultCacheBehavior(m map[string]interface{}) *cloudfront.
dcb.LambdaFunctionAssociations = expandLambdaFunctionAssociations(v.(*schema.Set).List())
}

if v, ok := m["function_association"]; ok {
dcb.FunctionAssociations = expandFunctionAssociations(v.(*schema.Set).List())
}

if v, ok := m["smooth_streaming"]; ok {
dcb.SmoothStreaming = aws.Bool(v.(bool))
}
Expand Down Expand Up @@ -277,6 +281,10 @@ func expandCacheBehavior(m map[string]interface{}) *cloudfront.CacheBehavior {
cb.LambdaFunctionAssociations = expandLambdaFunctionAssociations(v.(*schema.Set).List())
}

if v, ok := m["function_association"]; ok {
cb.FunctionAssociations = expandFunctionAssociations(v.(*schema.Set).List())
}

if v, ok := m["smooth_streaming"]; ok {
cb.SmoothStreaming = aws.Bool(v.(bool))
}
Expand Down Expand Up @@ -320,6 +328,9 @@ func flattenCloudFrontDefaultCacheBehavior(dcb *cloudfront.DefaultCacheBehavior)
if len(dcb.LambdaFunctionAssociations.Items) > 0 {
m["lambda_function_association"] = flattenLambdaFunctionAssociations(dcb.LambdaFunctionAssociations)
}
if len(dcb.FunctionAssociations.Items) > 0 {
m["function_association"] = flattenFunctionAssociations(dcb.FunctionAssociations)
}
if dcb.MaxTTL != nil {
m["max_ttl"] = aws.Int64Value(dcb.MaxTTL)
}
Expand Down Expand Up @@ -363,6 +374,9 @@ func flattenCacheBehavior(cb *cloudfront.CacheBehavior) map[string]interface{} {
if len(cb.LambdaFunctionAssociations.Items) > 0 {
m["lambda_function_association"] = flattenLambdaFunctionAssociations(cb.LambdaFunctionAssociations)
}
if len(cb.FunctionAssociations.Items) > 0 {
m["function_association"] = flattenFunctionAssociations(cb.FunctionAssociations)
}
if cb.MaxTTL != nil {
m["max_ttl"] = int(*cb.MaxTTL)
}
Expand Down Expand Up @@ -433,6 +447,14 @@ func lambdaFunctionAssociationHash(v interface{}) int {
return hashcode.String(buf.String())
}

func functionAssociationHash(v interface{}) int {
var buf bytes.Buffer
m := v.(map[string]interface{})
buf.WriteString(fmt.Sprintf("%s-", m["event_type"].(string)))
buf.WriteString(m["function_arn"].(string))
return hashcode.String(buf.String())
}

func expandLambdaFunctionAssociations(v interface{}) *cloudfront.LambdaFunctionAssociations {
if v == nil {
return &cloudfront.LambdaFunctionAssociations{
Expand Down Expand Up @@ -464,6 +486,34 @@ func expandLambdaFunctionAssociation(lf map[string]interface{}) *cloudfront.Lamb
return &lfa
}

func expandFunctionAssociations(v interface{}) *cloudfront.FunctionAssociations {
if v == nil {
return &cloudfront.FunctionAssociations{
Quantity: aws.Int64(0),
}
}

s := v.([]interface{})
var fa cloudfront.FunctionAssociations
fa.Quantity = aws.Int64(int64(len(s)))
fa.Items = make([]*cloudfront.FunctionAssociation, len(s))
for i, f := range s {
fa.Items[i] = expandFunctionAssociation(f.(map[string]interface{}))
}
return &fa
}

func expandFunctionAssociation(f map[string]interface{}) *cloudfront.FunctionAssociation {
var fa cloudfront.FunctionAssociation
if v, ok := f["event_type"]; ok {
fa.EventType = aws.String(v.(string))
}
if v, ok := f["function_arn"]; ok {
fa.FunctionARN = aws.String(v.(string))
}
return &fa
}

func flattenLambdaFunctionAssociations(lfa *cloudfront.LambdaFunctionAssociations) *schema.Set {
s := schema.NewSet(lambdaFunctionAssociationHash, []interface{}{})
for _, v := range lfa.Items {
Expand All @@ -482,6 +532,23 @@ func flattenLambdaFunctionAssociation(lfa *cloudfront.LambdaFunctionAssociation)
return m
}

func flattenFunctionAssociations(fa *cloudfront.FunctionAssociations) *schema.Set {
s := schema.NewSet(functionAssociationHash, []interface{}{})
for _, v := range fa.Items {
s.Add(flattenFunctionAssociation(v))
}
return s
}

func flattenFunctionAssociation(fa *cloudfront.FunctionAssociation) map[string]interface{} {
m := map[string]interface{}{}
if fa != nil {
m["event_type"] = aws.StringValue(fa.EventType)
m["function_arn"] = aws.StringValue(fa.FunctionARN)
}
return m
}

func expandForwardedValues(m map[string]interface{}) *cloudfront.ForwardedValues {
if len(m) < 1 {
return nil
Expand Down
60 changes: 60 additions & 0 deletions aws/cloudfront_distribution_configuration_structure_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ func defaultCacheBehaviorConf() map[string]interface{} {
"min_ttl": 0,
"trusted_signers": trustedSignersConf(),
"lambda_function_association": lambdaFunctionAssociationsConf(),
"function_association": functionAssociationsConf(),
"max_ttl": 31536000,
"smooth_streaming": false,
"default_ttl": 86400,
Expand Down Expand Up @@ -51,6 +52,21 @@ func lambdaFunctionAssociationsConf() *schema.Set {
return schema.NewSet(lambdaFunctionAssociationHash, x)
}

func functionAssociationsConf() *schema.Set {
x := []interface{}{
map[string]interface{}{
"event_type": "viewer-request",
"function_arn": "arn:aws:cloudfront::999999999:function/function1", //lintignore:AWSAT003,AWSAT005
},
map[string]interface{}{
"event_type": "viewer-response",
"function_arn": "arn:aws:cloudfront::999999999:function/function2", //lintignore:AWSAT003,AWSAT005
},
}

return schema.NewSet(functionAssociationHash, x)
}

func forwardedValuesConf() map[string]interface{} {
return map[string]interface{}{
"query_string": true,
Expand Down Expand Up @@ -304,6 +320,9 @@ func TestCloudFrontStructure_expandCloudFrontDefaultCacheBehavior(t *testing.T)
if *dcb.LambdaFunctionAssociations.Quantity != 2 {
t.Fatalf("Expected LambdaFunctionAssociations to be 2, got %v", *dcb.LambdaFunctionAssociations.Quantity)
}
if *dcb.FunctionAssociations.Quantity != 2 {
t.Fatalf("Expected FunctionAssociations to be 2, got %v", *dcb.FunctionAssociations.Quantity)
}
if !reflect.DeepEqual(dcb.AllowedMethods.Items, expandStringSet(allowedMethodsConf())) {
t.Fatalf("Expected AllowedMethods.Items to be %v, got %v", allowedMethodsConf().List(), dcb.AllowedMethods.Items)
}
Expand Down Expand Up @@ -391,6 +410,47 @@ func TestCloudFrontStructure_expandlambdaFunctionAssociations_empty(t *testing.T
}
}

func TestCloudFrontStructure_expandFunctionAssociations(t *testing.T) {
data := functionAssociationsConf()
lfa := expandFunctionAssociations(data.List())
if *lfa.Quantity != 2 {
t.Fatalf("Expected Quantity to be 2, got %v", *lfa.Quantity)
}
if len(lfa.Items) != 2 {
t.Fatalf("Expected Items to be len 2, got %v", len(lfa.Items))
}
if et := "viewer-response"; *lfa.Items[0].EventType != et {
t.Fatalf("Expected first Item's EventType to be %q, got %q", et, *lfa.Items[0].EventType)
}
if et := "viewer-request"; *lfa.Items[1].EventType != et {
t.Fatalf("Expected second Item's EventType to be %q, got %q", et, *lfa.Items[1].EventType)
}
}

func TestCloudFrontStructure_flattenFunctionAssociations(t *testing.T) {
in := functionAssociationsConf()
lfa := expandFunctionAssociations(in.List())
out := flattenFunctionAssociations(lfa)

if !reflect.DeepEqual(in.List(), out.List()) {
t.Fatalf("Expected out to be %v, got %v", in, out)
}
}

func TestCloudFrontStructure_expandFunctionAssociations_empty(t *testing.T) {
data := new(schema.Set)
lfa := expandFunctionAssociations(data.List())
if *lfa.Quantity != 0 {
t.Fatalf("Expected Quantity to be 0, got %v", *lfa.Quantity)
}
if len(lfa.Items) != 0 {
t.Fatalf("Expected Items to be len 0, got %v", len(lfa.Items))
}
if !reflect.DeepEqual(lfa.Items, []*cloudfront.FunctionAssociation{}) {
t.Fatalf("Expected Items to be empty, got %v", lfa.Items)
}
}

func TestCloudFrontStructure_expandForwardedValues(t *testing.T) {
data := forwardedValuesConf()
fv := expandForwardedValues(data)
Expand Down
91 changes: 91 additions & 0 deletions aws/data_source_aws_cloudfront_function.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package aws

import (
"fmt"
"time"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/cloudfront"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

func dataSourceAwsCloudFrontFunction() *schema.Resource {
return &schema.Resource{
Read: dataSourceAwsCloudFrontFunctionRead,

Schema: map[string]*schema.Schema{
"code": {
Type: schema.TypeString,
Computed: true,
},
"comment": {
Type: schema.TypeString,
Computed: true,
},
"name": {
Type: schema.TypeString,
Required: true,
},
"runtime": {
Type: schema.TypeString,
Computed: true,
},
"status": {
Type: schema.TypeString,
Computed: true,
},
"arn": {
Type: schema.TypeString,
Computed: true,
},
"etag": {
Type: schema.TypeString,
Computed: true,
},
"stage": {
Type: schema.TypeString,
Computed: true,
},
"last_modified": {
Type: schema.TypeString,
Computed: true,
},
},
}
}

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

params := &cloudfront.GetFunctionInput{
Name: aws.String(d.Get("name").(string)),
}

getFunctionOutput, err := conn.GetFunction(params)
if err != nil {
return fmt.Errorf("error getting CloudFront Function (%s): %w", d.Get("name").(string), err)
}

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

describeParams := &cloudfront.DescribeFunctionInput{
Name: aws.String(d.Get("name").(string)),
}

describeFunctionOutput, err := conn.DescribeFunction(describeParams)
if err != nil {
return err
}

d.Set("etag", describeFunctionOutput.ETag)
d.Set("arn", describeFunctionOutput.FunctionSummary.FunctionMetadata.FunctionARN)
d.Set("last_modified", describeFunctionOutput.FunctionSummary.FunctionMetadata.LastModifiedTime.Format(time.RFC3339))
d.Set("stage", describeFunctionOutput.FunctionSummary.FunctionMetadata.Stage)
d.Set("comment", describeFunctionOutput.FunctionSummary.FunctionConfig.Comment)
d.Set("runtime", describeFunctionOutput.FunctionSummary.FunctionConfig.Runtime)
d.Set("status", describeFunctionOutput.FunctionSummary.Status)

d.SetId(d.Get("name").(string))

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

import (
"fmt"
"testing"

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

func TestAccDataSourceAWSCloudfrontFunction_basic(t *testing.T) {
rName := acctest.RandomWithPrefix("tf-acc-test")
dataSourceName := "data.aws_cloudfront_function.test"
resourceName := "aws_cloudfront_function.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t); testAccPartitionHasServicePreCheck(cloudfront.EndpointsID, t) },
ErrorCheck: testAccErrorCheck(t, cloudfront.EndpointsID),
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccDataSourceAWSCloudfrontFunctionConfigBasic(rName),
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttrPair(dataSourceName, "arn", resourceName, "arn"),
resource.TestCheckResourceAttrPair(dataSourceName, "code", resourceName, "code"),
resource.TestCheckResourceAttrPair(dataSourceName, "comment", resourceName, "comment"),
resource.TestCheckResourceAttrPair(dataSourceName, "last_modified", resourceName, "last_modified"),
ewbankkit marked this conversation as resolved.
Show resolved Hide resolved
resource.TestCheckResourceAttrPair(dataSourceName, "name", resourceName, "name"),
resource.TestCheckResourceAttrPair(dataSourceName, "runtime", resourceName, "runtime"),
resource.TestCheckResourceAttrPair(dataSourceName, "stage", resourceName, "stage"),
resource.TestCheckResourceAttrPair(dataSourceName, "status", resourceName, "status"),
resource.TestCheckResourceAttrPair(dataSourceName, "etag", resourceName, "etag"),
),
},
},
})
}

func testAccDataSourceAWSCloudfrontFunctionConfigBasic(rName string) string {
return fmt.Sprintf(`
resource "aws_cloudfront_function" "test" {
name = "%s"
runtime = "cloudfront-js-1.0"
comment = "%s"
code = <<-EOT
function handler(event) {
var response = {
statusCode: 302,
statusDescription: 'Found',
headers: {
'cloudfront-functions': { value: 'generated-by-CloudFront-Functions' },
'location': { value: 'https://aws.amazon.com/cloudfront/' }
}
};
return response;
}
EOT
}

data "aws_cloudfront_function" "test" {
name = aws_cloudfront_function.test.name
}
`, rName, rName)
}
2 changes: 2 additions & 0 deletions aws/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ func Provider() *schema.Provider {
"aws_cloudformation_type": dataSourceAwsCloudFormationType(),
"aws_cloudfront_cache_policy": dataSourceAwsCloudFrontCachePolicy(),
"aws_cloudfront_distribution": dataSourceAwsCloudFrontDistribution(),
"aws_cloudfront_function": dataSourceAwsCloudFrontFunction(),
"aws_cloudfront_origin_request_policy": dataSourceAwsCloudFrontOriginRequestPolicy(),
"aws_cloudhsm_v2_cluster": dataSourceCloudHsmV2Cluster(),
"aws_cloudtrail_service_account": dataSourceAwsCloudTrailServiceAccount(),
Expand Down Expand Up @@ -521,6 +522,7 @@ func Provider() *schema.Provider {
"aws_cloudformation_type": resourceAwsCloudFormationType(),
"aws_cloudfront_cache_policy": resourceAwsCloudFrontCachePolicy(),
"aws_cloudfront_distribution": resourceAwsCloudFrontDistribution(),
"aws_cloudfront_function": resourceAwsCloudFrontFunction(),
"aws_cloudfront_key_group": resourceAwsCloudFrontKeyGroup(),
"aws_cloudfront_origin_access_identity": resourceAwsCloudFrontOriginAccessIdentity(),
"aws_cloudfront_origin_request_policy": resourceAwsCloudFrontOriginRequestPolicy(),
Expand Down
Loading