From 40023c61afd9acb981eae98b1ffc128f321023e5 Mon Sep 17 00:00:00 2001 From: Roberth Kulbin Date: Tue, 18 Aug 2020 12:02:34 +0100 Subject: [PATCH] r/aws_cloudfront_origin_request_policy: new resource --- aws/provider.go | 1 + ...ce_aws_cloudfront_origin_request_policy.go | 285 ++ ...s_cloudfront_origin_request_policy_test.go | 241 ++ website/aws.erb | 3747 +++++++++++++++++ ...dfront_origin_request_policy.html.markdown | 62 + 5 files changed, 4336 insertions(+) create mode 100644 aws/resource_aws_cloudfront_origin_request_policy.go create mode 100644 aws/resource_aws_cloudfront_origin_request_policy_test.go create mode 100644 website/aws.erb create mode 100644 website/docs/r/cloudfront_origin_request_policy.html.markdown diff --git a/aws/provider.go b/aws/provider.go index 976a61f49a0..f780093ea0d 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -464,6 +464,7 @@ func Provider() *schema.Provider { "aws_cloudformation_stack_set_instance": resourceAwsCloudFormationStackSetInstance(), "aws_cloudfront_distribution": resourceAwsCloudFrontDistribution(), "aws_cloudfront_origin_access_identity": resourceAwsCloudFrontOriginAccessIdentity(), + "aws_cloudfront_origin_request_policy": resourceAwsCloudFrontOriginRequestPolicy(), "aws_cloudfront_public_key": resourceAwsCloudFrontPublicKey(), "aws_cloudtrail": resourceAwsCloudTrail(), "aws_cloudwatch_event_bus": resourceAwsCloudWatchEventBus(), diff --git a/aws/resource_aws_cloudfront_origin_request_policy.go b/aws/resource_aws_cloudfront_origin_request_policy.go new file mode 100644 index 00000000000..2ed85b474ee --- /dev/null +++ b/aws/resource_aws_cloudfront_origin_request_policy.go @@ -0,0 +1,285 @@ +package aws + +import ( + "context" + "log" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/cloudfront" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" +) + +func resourceAwsCloudFrontOriginRequestPolicy() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceAwsCloudFrontOriginRequestPolicyCreate, + ReadContext: resourceAwsCloudFrontOriginRequestPolicyRead, + UpdateContext: resourceAwsCloudFrontOriginRequestPolicyUpdate, + DeleteContext: resourceAwsCloudFrontOriginRequestPolicyDelete, + Importer: &schema.ResourceImporter{ + StateContext: schema.ImportStatePassthroughContext, + }, + + Schema: map[string]*schema.Schema{ + "comment": { + Type: schema.TypeString, + Optional: true, + }, + "cookie_behavior": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(cloudfront.OriginRequestPolicyCookieBehavior_Values(), false), + }, + "cookie_names": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "etag": { + Type: schema.TypeString, + Computed: true, + }, + "header_behavior": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(cloudfront.OriginRequestPolicyHeaderBehavior_Values(), false), + }, + "header_names": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + "query_string_behavior": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(cloudfront.OriginRequestPolicyQueryStringBehavior_Values(), false), + }, + "query_string_names": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + } +} + +func resourceAwsCloudFrontOriginRequestPolicyCreate( + ctx context.Context, + d *schema.ResourceData, + meta interface{}, +) diag.Diagnostics { + conn := meta.(*AWSClient).cloudfrontconn + + input := cloudfront.CreateOriginRequestPolicyInput{ + OriginRequestPolicyConfig: expandAwsCloudFrontOriginRequestPolicyConfig(d), + } + + output, err := conn.CreateOriginRequestPolicyWithContext(ctx, &input) + if err != nil { + return diag.Errorf("create origin request policy: %s", err) + } + + d.SetId(aws.StringValue(output.OriginRequestPolicy.Id)) + d.Set("etag", aws.StringValue(output.ETag)) + + return resourceAwsCloudFrontOriginRequestPolicyRead(ctx, d, meta) +} + +func resourceAwsCloudFrontOriginRequestPolicyRead( + ctx context.Context, + d *schema.ResourceData, + meta interface{}, +) diag.Diagnostics { + conn := meta.(*AWSClient).cloudfrontconn + id := d.Id() + + policy, etag, ok, err := getAwsCloudFrontOriginRequestPolicy(ctx, conn, id) + switch { + case err != nil: + return diag.Errorf("get origin request policy %s: %s", id, err) + case !ok: + log.Printf("[WARN] Origin Request Policy %s not found; removing from state", id) + d.SetId("") + return nil + } + + d.Set("etag", etag) + + if err := flattenAwsCloudFrontOriginRequestPolicyConfig(d, policy.OriginRequestPolicyConfig); err != nil { + return err + } + + return nil +} + +func resourceAwsCloudFrontOriginRequestPolicyUpdate( + ctx context.Context, + d *schema.ResourceData, + meta interface{}, +) diag.Diagnostics { + conn := meta.(*AWSClient).cloudfrontconn + id := d.Id() + + _, etag, ok, err := getAwsCloudFrontOriginRequestPolicy(ctx, conn, id) + switch { + case err != nil: + return diag.Errorf("get origin request policy: %s", err) + case !ok: + return diag.Errorf("origin request policy %s not found", id) + } + + input := cloudfront.UpdateOriginRequestPolicyInput{ + OriginRequestPolicyConfig: expandAwsCloudFrontOriginRequestPolicyConfig(d), + Id: aws.String(id), + IfMatch: aws.String(etag), + } + + output, err := conn.UpdateOriginRequestPolicyWithContext(ctx, &input) + if err != nil { + return diag.Errorf("update failed: %s", err) + } + + d.Set("etag", output.ETag) + + return resourceAwsCloudFrontOriginRequestPolicyRead(ctx, d, meta) +} + +func resourceAwsCloudFrontOriginRequestPolicyDelete( + ctx context.Context, + d *schema.ResourceData, + meta interface{}, +) diag.Diagnostics { + conn := meta.(*AWSClient).cloudfrontconn + id := d.Id() + + _, etag, ok, err := getAwsCloudFrontOriginRequestPolicy(ctx, conn, id) + switch { + case !ok: + log.Printf("[WARN] Origin Request Policy %s does not exist", id) + return nil + case err != nil: + return diag.Errorf("failed to get etag of origin request policy %s: %s", id, err) + } + + input := cloudfront.DeleteOriginRequestPolicyInput{ + Id: aws.String(id), + IfMatch: aws.String(etag), + } + + _, err = conn.DeleteOriginRequestPolicyWithContext(ctx, &input) + switch { + case isAWSErr(err, "NoSuchOriginRequestPolicy", ""): + log.Printf("[WARN] Origin Request Policy %s does not exist", id) + return nil + case err != nil: + return diag.Errorf("failed to delete: %s", err) + } + + return nil +} + +func getAwsCloudFrontOriginRequestPolicy( + ctx context.Context, + conn *cloudfront.CloudFront, + id string, +) (policy *cloudfront.OriginRequestPolicy, etag string, ok bool, err error) { + input := cloudfront.GetOriginRequestPolicyInput{Id: aws.String(id)} + output, err := conn.GetOriginRequestPolicyWithContext(ctx, &input) + switch { + case isAWSErr(err, "NoSuchOriginRequestPolicy", ""): + return nil, "", false, nil + case err != nil: + return nil, "", false, err + } + + return output.OriginRequestPolicy, aws.StringValue(output.ETag), true, nil +} + +func expandAwsCloudFrontOriginRequestPolicyConfig(d *schema.ResourceData) *cloudfront.OriginRequestPolicyConfig { + output := &cloudfront.OriginRequestPolicyConfig{ + Comment: nil, + CookiesConfig: &cloudfront.OriginRequestPolicyCookiesConfig{ + CookieBehavior: aws.String(d.Get("cookie_behavior").(string)), + Cookies: nil, + }, + HeadersConfig: &cloudfront.OriginRequestPolicyHeadersConfig{ + HeaderBehavior: aws.String(d.Get("header_behavior").(string)), + Headers: nil, + }, + Name: aws.String(d.Get("name").(string)), + QueryStringsConfig: &cloudfront.OriginRequestPolicyQueryStringsConfig{ + QueryStringBehavior: aws.String(d.Get("query_string_behavior").(string)), + QueryStrings: nil, + }, + } + + if v, ok := d.GetOk("comment"); ok && v != "" { + output.Comment = aws.String(v.(string)) + } + + if v, ok := d.GetOk("cookie_names"); ok { + s := v.(*schema.Set) + output.CookiesConfig.Cookies = &cloudfront.CookieNames{ + Items: expandStringList(s.List()), + Quantity: aws.Int64(int64(s.Len())), + } + } + + if v, ok := d.GetOk("header_names"); ok { + s := v.(*schema.Set) + output.HeadersConfig.Headers = &cloudfront.Headers{ + Items: expandStringList(s.List()), + Quantity: aws.Int64(int64(s.Len())), + } + } + + if v, ok := d.GetOk("query_string_names"); ok { + s := v.(*schema.Set) + output.QueryStringsConfig.QueryStrings = &cloudfront.QueryStringNames{ + Items: expandStringList(s.List()), + Quantity: aws.Int64(int64(s.Len())), + } + } + + return output +} + +func flattenAwsCloudFrontOriginRequestPolicyConfig( + d *schema.ResourceData, + config *cloudfront.OriginRequestPolicyConfig, +) diag.Diagnostics { + d.Set("comment", config.Comment) + d.Set("name", config.Name) + + d.Set("cookie_behavior", config.CookiesConfig.CookieBehavior) + if list := config.CookiesConfig.Cookies; list != nil { + value := schema.NewSet(schema.HashString, flattenStringList(list.Items)) + if err := d.Set("cookie_names", value); err != nil { + return diag.FromErr(err) + } + } + + d.Set("header_behavior", config.HeadersConfig.HeaderBehavior) + if list := config.HeadersConfig.Headers; list != nil { + value := schema.NewSet(schema.HashString, flattenStringList(list.Items)) + if err := d.Set("header_names", value); err != nil { + return diag.FromErr(err) + } + } + + d.Set("query_string_behavior", config.QueryStringsConfig.QueryStringBehavior) + if list := config.QueryStringsConfig.QueryStrings; list != nil { + value := schema.NewSet(schema.HashString, flattenStringList(list.Items)) + if err := d.Set("query_string_names", value); err != nil { + return diag.FromErr(err) + } + } + + return nil +} diff --git a/aws/resource_aws_cloudfront_origin_request_policy_test.go b/aws/resource_aws_cloudfront_origin_request_policy_test.go new file mode 100644 index 00000000000..86b45b2e031 --- /dev/null +++ b/aws/resource_aws_cloudfront_origin_request_policy_test.go @@ -0,0 +1,241 @@ +package aws + +import ( + "context" + "fmt" + "reflect" + "sort" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "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" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func testAccCheckAwsCloudFrontOriginRequestPolicyDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).cloudfrontconn + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_cloudfront_origin_request_policy" { + continue + } + + id := rs.Primary.ID + + switch _, _, ok, err := getAwsCloudFrontOriginRequestPolicy(context.Background(), conn, id); { + case err != nil: + return err + case ok: + return fmt.Errorf("origin request policy %s still exists", id) + } + } + + return nil +} + +func testAccAwsCloudFrontOriginRequestPolicyExists( + name string, + out *cloudfront.OriginRequestPolicy, + etag *string, +) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[name] + switch { + case !ok: + return fmt.Errorf("resource %s not found", name) + case rs.Primary.ID == "": + return fmt.Errorf("resource %s has not set its id", name) + } + + conn := testAccProvider.Meta().(*AWSClient).cloudfrontconn + id := rs.Primary.ID + + policy, et, ok, err := getAwsCloudFrontOriginRequestPolicy(context.Background(), conn, id) + switch { + case err != nil: + return err + case !ok: + return fmt.Errorf("resource %s (%s) has not been created", name, id) + } + + if out != nil { + *out = *policy + *etag = et + } + + return nil + } +} + +func TestAccAwsCloudFrontOriginRequestPolicy_basic(t *testing.T) { + resourceName := "aws_cloudfront_origin_request_policy.test" + randomName := "Terraform-AccTest-" + acctest.RandString(8) + policy, etag := cloudfront.OriginRequestPolicy{}, "" + + checkAttributes := func(*terraform.State) error { + sortStringPtrs := func(slice []*string) { + sort.Slice(slice, func(i, j int) bool { + return *slice[i] < *slice[j] + }) + } + + actual := *policy.OriginRequestPolicyConfig + sortStringPtrs(actual.CookiesConfig.Cookies.Items) + sortStringPtrs(actual.HeadersConfig.Headers.Items) + sortStringPtrs(actual.QueryStringsConfig.QueryStrings.Items) + + expect := cloudfront.OriginRequestPolicyConfig{ + Comment: aws.String("Greetings, programs!"), + Name: aws.String(randomName + "-Suffix"), + CookiesConfig: &cloudfront.OriginRequestPolicyCookiesConfig{ + CookieBehavior: aws.String("whitelist"), + Cookies: &cloudfront.CookieNames{ + Items: aws.StringSlice([]string{"Cookie1", "Cookie2"}), + Quantity: aws.Int64(2), + }, + }, + HeadersConfig: &cloudfront.OriginRequestPolicyHeadersConfig{ + HeaderBehavior: aws.String("whitelist"), + Headers: &cloudfront.Headers{ + Items: aws.StringSlice([]string{"X-Header-1", "X-Header-2"}), + Quantity: aws.Int64(2), + }, + }, + QueryStringsConfig: &cloudfront.OriginRequestPolicyQueryStringsConfig{ + QueryStringBehavior: aws.String("whitelist"), + QueryStrings: &cloudfront.QueryStringNames{ + Items: aws.StringSlice([]string{"test"}), + Quantity: aws.Int64(1), + }, + }, + } + + if !reflect.DeepEqual(actual, expect) { + return fmt.Errorf("Expected OriginRequestPolicyConfig:\n%#v\nGot:\n%#v", expect, actual) + } + + return nil + } + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsCloudFrontOriginRequestPolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAwsCloudFrontOriginRequestPolicyConfig_basic_create(randomName), + ResourceName: resourceName, + Check: resource.ComposeAggregateTestCheckFunc( + testAccAwsCloudFrontOriginRequestPolicyExists(resourceName, &policy, &etag), + resource.TestCheckResourceAttr(resourceName, "comment", "Greetings, programs!"), + resource.TestCheckResourceAttr(resourceName, "cookie_behavior", "none"), + resource.TestCheckResourceAttr(resourceName, "cookie_names.#", "0"), + resource.TestCheckResourceAttrPtr(resourceName, "etag", &etag), + resource.TestCheckResourceAttr(resourceName, "header_behavior", "none"), + resource.TestCheckResourceAttr(resourceName, "header_names.#", "0"), + resource.TestCheckResourceAttr(resourceName, "name", randomName), + resource.TestCheckResourceAttr(resourceName, "query_string_behavior", "none"), + resource.TestCheckResourceAttr(resourceName, "query_string_names.#", "0"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAwsCloudFrontOriginRequestPolicyConfig_basic_update(randomName + "-Suffix"), + ResourceName: resourceName, + Check: resource.ComposeAggregateTestCheckFunc( + testAccAwsCloudFrontOriginRequestPolicyExists(resourceName, &policy, &etag), + checkAttributes, + resource.TestCheckResourceAttr(resourceName, "comment", "Greetings, programs!"), + resource.TestCheckResourceAttr(resourceName, "cookie_behavior", "whitelist"), + resource.TestCheckResourceAttr(resourceName, "cookie_names.#", "2"), + resource.TestCheckResourceAttrPtr(resourceName, "etag", &etag), + resource.TestCheckResourceAttr(resourceName, "header_behavior", "whitelist"), + resource.TestCheckResourceAttr(resourceName, "header_names.#", "2"), + resource.TestCheckResourceAttr(resourceName, "name", randomName+"-Suffix"), + resource.TestCheckResourceAttr(resourceName, "query_string_behavior", "whitelist"), + resource.TestCheckResourceAttr(resourceName, "query_string_names.#", "1"), + ), + }, + }, + }) +} + +func testAccAwsCloudFrontOriginRequestPolicyConfig_basic_create(name string) string { + return fmt.Sprintf(` +resource "aws_cloudfront_origin_request_policy" "test" { + comment = "Greetings, programs!" + cookie_behavior = "none" + header_behavior = "none" + name = %[1]q + query_string_behavior = "none" +} +`, name) + +} + +func testAccAwsCloudFrontOriginRequestPolicyConfig_basic_update(name string) string { + return fmt.Sprintf(` +resource "aws_cloudfront_origin_request_policy" "test" { + comment = "Greetings, programs!" + cookie_behavior = "whitelist" + cookie_names = ["Cookie1", "Cookie2"] + header_behavior = "whitelist" + header_names = ["X-Header-1", "X-Header-2"] + name = %[1]q + query_string_behavior = "whitelist" + query_string_names = ["test"] +} +`, name) +} + +func TestAccAwsCloudFrontOriginRequestPolicy_disappears(t *testing.T) { + resourceName := "aws_cloudfront_origin_request_policy.test" + randomName := "Terraform-AccTest-" + acctest.RandString(8) + policy, etag := cloudfront.OriginRequestPolicy{}, "" + + checkDisappears := func(*terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).cloudfrontconn + input := cloudfront.DeleteOriginRequestPolicyInput{ + Id: aws.String(*policy.Id), + IfMatch: aws.String(etag), + } + _, err := conn.DeleteOriginRequestPolicy(&input) + return err + } + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsCloudFrontOriginRequestPolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAwsCloudFrontOriginRequestPolicyConfig_disappears(randomName), + ResourceName: resourceName, + Check: resource.ComposeAggregateTestCheckFunc( + testAccAwsCloudFrontOriginRequestPolicyExists(resourceName, &policy, &etag), + checkDisappears, + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func testAccAwsCloudFrontOriginRequestPolicyConfig_disappears(name string) string { + return fmt.Sprintf(` +resource "aws_cloudfront_origin_request_policy" "test" { + comment = "Greetings, programs!" + cookie_behavior = "none" + header_behavior = "none" + name = %[1]q + query_string_behavior = "none" +} +`, name) + +} diff --git a/website/aws.erb b/website/aws.erb new file mode 100644 index 00000000000..e35e93429a8 --- /dev/null +++ b/website/aws.erb @@ -0,0 +1,3747 @@ +<% wrap_layout :inner do %> + <% content_for :sidebar do %> + + <% end %> + <%= yield %> +<% end %> diff --git a/website/docs/r/cloudfront_origin_request_policy.html.markdown b/website/docs/r/cloudfront_origin_request_policy.html.markdown new file mode 100644 index 00000000000..4524d45091e --- /dev/null +++ b/website/docs/r/cloudfront_origin_request_policy.html.markdown @@ -0,0 +1,62 @@ +--- +subcategory: "CloudFront" +layout: "aws" +page_title: "AWS: aws_cloudfront_origin_request_policy" +description: |- + Provides a CloudFront Origin Request Policy resource. +--- + +# Resource: aws_cloudfront_origin_request_policy + +Provides a CloudFront Origin Request Policy resource, which determines the query string parameters, headers, and cookies that CloudFront forwards to an origin. + +Read more about origin request policies in [Controlling origin requests](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/controlling-origin-requests.html). + +## Example Usage + +### Basic usage + +```hcl +resource "aws_cloudfront_origin_request_policy" "example" { + cookie_behavior = "none" + header_behavior = "whitelist" + header_names = ["Authorization", "Host"] + name = "Example-OriginRequestPolicy" + query_string_behavior = "all" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `comment` - (Optional) A comment to describe the origin request policy. + +* `cookie_behavior` - (Required) Determines whether cookies in viewer requests are included in requests that CloudFront sends to the origin. Valid values are `none`, `whitelist`, `all`. + +* `cookie_names` - (Optional) Specifies the cookies to be handled in accordance with the cookie behavior. + +* `header_behavior` - (Required) Determines whether any HTTP headers are included in requests that CloudFront sends to the origin. Valid values are `none`, `whitelist`, `allViewer`, `allViewerAndWhitelistCloudFront`. + +* `header_names` - (Optional) Specifies the headers to be handled in accordance with the header behavior. + +* `name` - (Required) A unique name to identify the cache policy. + +* `query_string_behavior` - (Required) Determines whether any URL query strings in viewer requests are included in requests that CloudFront sends to the origin. Valid values are `none`, `whitelist`, `all`. + +* `query_string_names` - (Optional) Specifies the query string parameters to be handled in accordance with the query string behavior. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - The ID of the origin request policy. +* `etag` - The ETag of the latest version of the origin request policy. + +## Import + +Cache Policies can be imported using the `id`, e.g. + +``` +$ terraform import aws_cloudfront_origin_request_policy.default 4ae686d6-72b3-4bb5-83f0-b89276902434 +```