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
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"] = flattenLambdaFunctionAssociations(dcb.LambdaFunctionAssociations)
ZsoltPath marked this conversation as resolved.
Show resolved Hide resolved
}
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["lambda_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",
"funtion_arn": "arn:aws:cloudfront::999999999:function/function1", //lintignore:AWSAT003,AWSAT005
},
map[string]interface{}{
"event_type": "origin-response",
ZsoltPath marked this conversation as resolved.
Show resolved Hide resolved
"funtion_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-request"; *lfa.Items[0].EventType != et {
t.Fatalf("Expected first Item's EventType to be %q, got %q", et, *lfa.Items[0].EventType)
}
if et := "origin-response"; *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
100 changes: 100 additions & 0 deletions aws/data_source_aws_cloudfront_function.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package aws

import (
"log"
"time"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"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,
},
"version": {
ZsoltPath marked this conversation as resolved.
Show resolved Hide resolved
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)),
}

log.Printf("[DEBUG] Get Cloudfront Function: %s", d.Id())
ZsoltPath marked this conversation as resolved.
Show resolved Hide resolved

GetFunctionOutput, err := conn.GetFunction(params)
ZsoltPath marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == cloudfront.ErrCodeNoSuchFunctionExists && !d.IsNewResource() {
d.SetId("")
return nil
}
return err
ZsoltPath marked this conversation as resolved.
Show resolved Hide resolved
}

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

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

log.Printf("[DEBUG] Fetching Cloudfront Function: %s", d.Id())
ZsoltPath marked this conversation as resolved.
Show resolved Hide resolved

DescribeFunctionOutput, err := conn.DescribeFunction(describeParams)
ZsoltPath marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return err
}

d.Set("version", DescribeFunctionOutput.ETag)
ZsoltPath marked this conversation as resolved.
Show resolved Hide resolved
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) },
ZsoltPath marked this conversation as resolved.
Show resolved Hide resolved
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, "version", resourceName, "version"),
),
},
},
})
}

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