From f8c5a286087f0e757f8f4764a520ea42c213db3d Mon Sep 17 00:00:00 2001 From: emily Date: Thu, 28 Mar 2019 18:03:46 +0000 Subject: [PATCH] Add backend bucket signed URL key (for CDN) support Signed-off-by: Modular Magician --- google-beta/provider_compute_gen.go | 59 ++-- .../resource_compute_backend_bucket.go | 77 +++++ ...e_compute_backend_bucket_signed_url_key.go | 287 ++++++++++++++++++ ...pute_backend_bucket_signed_url_key_test.go | 119 ++++++++ .../resource_compute_backend_bucket_test.go | 78 ++--- .../r/compute_backend_bucket.html.markdown | 17 ++ ...ackend_bucket_signed_url_key.html.markdown | 106 +++++++ 7 files changed, 657 insertions(+), 86 deletions(-) create mode 100644 google-beta/resource_compute_backend_bucket_signed_url_key.go create mode 100644 google-beta/resource_compute_backend_bucket_signed_url_key_test.go create mode 100644 website/docs/r/compute_backend_bucket_signed_url_key.html.markdown diff --git a/google-beta/provider_compute_gen.go b/google-beta/provider_compute_gen.go index 1193955b04..4e85673457 100644 --- a/google-beta/provider_compute_gen.go +++ b/google-beta/provider_compute_gen.go @@ -17,33 +17,34 @@ package google import "github.com/hashicorp/terraform/helper/schema" var GeneratedComputeResourcesMap = map[string]*schema.Resource{ - "google_compute_address": resourceComputeAddress(), - "google_compute_autoscaler": resourceComputeAutoscaler(), - "google_compute_backend_bucket": resourceComputeBackendBucket(), - "google_compute_disk": resourceComputeDisk(), - "google_compute_firewall": resourceComputeFirewall(), - "google_compute_forwarding_rule": resourceComputeForwardingRule(), - "google_compute_global_address": resourceComputeGlobalAddress(), - "google_compute_http_health_check": resourceComputeHttpHealthCheck(), - "google_compute_https_health_check": resourceComputeHttpsHealthCheck(), - "google_compute_health_check": resourceComputeHealthCheck(), - "google_compute_image": resourceComputeImage(), - "google_compute_interconnect_attachment": resourceComputeInterconnectAttachment(), - "google_compute_network": resourceComputeNetwork(), - "google_compute_region_autoscaler": resourceComputeRegionAutoscaler(), - "google_compute_region_disk": resourceComputeRegionDisk(), - "google_compute_route": resourceComputeRoute(), - "google_compute_router": resourceComputeRouter(), - "google_compute_snapshot": resourceComputeSnapshot(), - "google_compute_ssl_certificate": resourceComputeSslCertificate(), - "google_compute_managed_ssl_certificate": resourceComputeManagedSslCertificate(), - "google_compute_ssl_policy": resourceComputeSslPolicy(), - "google_compute_subnetwork": resourceComputeSubnetwork(), - "google_compute_target_http_proxy": resourceComputeTargetHttpProxy(), - "google_compute_target_https_proxy": resourceComputeTargetHttpsProxy(), - "google_compute_target_ssl_proxy": resourceComputeTargetSslProxy(), - "google_compute_target_tcp_proxy": resourceComputeTargetTcpProxy(), - "google_compute_vpn_gateway": resourceComputeVpnGateway(), - "google_compute_url_map": resourceComputeUrlMap(), - "google_compute_vpn_tunnel": resourceComputeVpnTunnel(), + "google_compute_address": resourceComputeAddress(), + "google_compute_autoscaler": resourceComputeAutoscaler(), + "google_compute_backend_bucket": resourceComputeBackendBucket(), + "google_compute_backend_bucket_signed_url_key": resourceComputeBackendBucketSignedUrlKey(), + "google_compute_disk": resourceComputeDisk(), + "google_compute_firewall": resourceComputeFirewall(), + "google_compute_forwarding_rule": resourceComputeForwardingRule(), + "google_compute_global_address": resourceComputeGlobalAddress(), + "google_compute_http_health_check": resourceComputeHttpHealthCheck(), + "google_compute_https_health_check": resourceComputeHttpsHealthCheck(), + "google_compute_health_check": resourceComputeHealthCheck(), + "google_compute_image": resourceComputeImage(), + "google_compute_interconnect_attachment": resourceComputeInterconnectAttachment(), + "google_compute_network": resourceComputeNetwork(), + "google_compute_region_autoscaler": resourceComputeRegionAutoscaler(), + "google_compute_region_disk": resourceComputeRegionDisk(), + "google_compute_route": resourceComputeRoute(), + "google_compute_router": resourceComputeRouter(), + "google_compute_snapshot": resourceComputeSnapshot(), + "google_compute_ssl_certificate": resourceComputeSslCertificate(), + "google_compute_managed_ssl_certificate": resourceComputeManagedSslCertificate(), + "google_compute_ssl_policy": resourceComputeSslPolicy(), + "google_compute_subnetwork": resourceComputeSubnetwork(), + "google_compute_target_http_proxy": resourceComputeTargetHttpProxy(), + "google_compute_target_https_proxy": resourceComputeTargetHttpsProxy(), + "google_compute_target_ssl_proxy": resourceComputeTargetSslProxy(), + "google_compute_target_tcp_proxy": resourceComputeTargetTcpProxy(), + "google_compute_vpn_gateway": resourceComputeVpnGateway(), + "google_compute_url_map": resourceComputeUrlMap(), + "google_compute_vpn_tunnel": resourceComputeVpnTunnel(), } diff --git a/google-beta/resource_compute_backend_bucket.go b/google-beta/resource_compute_backend_bucket.go index 4ce8b55ff1..74baea5fb2 100644 --- a/google-beta/resource_compute_backend_bucket.go +++ b/google-beta/resource_compute_backend_bucket.go @@ -18,6 +18,7 @@ import ( "fmt" "log" "reflect" + "strconv" "time" "github.com/hashicorp/terraform/helper/schema" @@ -52,6 +53,21 @@ func resourceComputeBackendBucket() *schema.Resource { ForceNew: true, ValidateFunc: validateRegexp(`^(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?)$`), }, + "cdn_policy": { + Type: schema.TypeList, + Computed: true, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "signed_url_cache_max_age_sec": { + Type: schema.TypeInt, + Optional: true, + Default: 3600, + }, + }, + }, + }, "description": { Type: schema.TypeString, Optional: true, @@ -88,6 +104,12 @@ func resourceComputeBackendBucketCreate(d *schema.ResourceData, meta interface{} } else if v, ok := d.GetOkExists("bucket_name"); !isEmptyValue(reflect.ValueOf(bucketNameProp)) && (ok || !reflect.DeepEqual(v, bucketNameProp)) { obj["bucketName"] = bucketNameProp } + cdnPolicyProp, err := expandComputeBackendBucketCdnPolicy(d.Get("cdn_policy"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("cdn_policy"); !isEmptyValue(reflect.ValueOf(cdnPolicyProp)) && (ok || !reflect.DeepEqual(v, cdnPolicyProp)) { + obj["cdnPolicy"] = cdnPolicyProp + } descriptionProp, err := expandComputeBackendBucketDescription(d.Get("description"), d, config) if err != nil { return err @@ -174,6 +196,9 @@ func resourceComputeBackendBucketRead(d *schema.ResourceData, meta interface{}) if err := d.Set("bucket_name", flattenComputeBackendBucketBucketName(res["bucketName"], d)); err != nil { return fmt.Errorf("Error reading BackendBucket: %s", err) } + if err := d.Set("cdn_policy", flattenComputeBackendBucketCdnPolicy(res["cdnPolicy"], d)); err != nil { + return fmt.Errorf("Error reading BackendBucket: %s", err) + } if err := d.Set("creation_timestamp", flattenComputeBackendBucketCreationTimestamp(res["creationTimestamp"], d)); err != nil { return fmt.Errorf("Error reading BackendBucket: %s", err) } @@ -203,6 +228,12 @@ func resourceComputeBackendBucketUpdate(d *schema.ResourceData, meta interface{} } else if v, ok := d.GetOkExists("bucket_name"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, bucketNameProp)) { obj["bucketName"] = bucketNameProp } + cdnPolicyProp, err := expandComputeBackendBucketCdnPolicy(d.Get("cdn_policy"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("cdn_policy"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, cdnPolicyProp)) { + obj["cdnPolicy"] = cdnPolicyProp + } descriptionProp, err := expandComputeBackendBucketDescription(d.Get("description"), d, config) if err != nil { return err @@ -312,6 +343,29 @@ func flattenComputeBackendBucketBucketName(v interface{}, d *schema.ResourceData return v } +func flattenComputeBackendBucketCdnPolicy(v interface{}, d *schema.ResourceData) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["signed_url_cache_max_age_sec"] = + flattenComputeBackendBucketCdnPolicySignedUrlCacheMaxAgeSec(original["signedUrlCacheMaxAgeSec"], d) + return []interface{}{transformed} +} +func flattenComputeBackendBucketCdnPolicySignedUrlCacheMaxAgeSec(v interface{}, d *schema.ResourceData) interface{} { + // Handles the string fixed64 format + if strVal, ok := v.(string); ok { + if intVal, err := strconv.ParseInt(strVal, 10, 64); err == nil { + return intVal + } // let terraform core handle it if we can't convert the string to an int. + } + return v +} + func flattenComputeBackendBucketCreationTimestamp(v interface{}, d *schema.ResourceData) interface{} { return v } @@ -332,6 +386,29 @@ func expandComputeBackendBucketBucketName(v interface{}, d TerraformResourceData return v, nil } +func expandComputeBackendBucketCdnPolicy(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedSignedUrlCacheMaxAgeSec, err := expandComputeBackendBucketCdnPolicySignedUrlCacheMaxAgeSec(original["signed_url_cache_max_age_sec"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedSignedUrlCacheMaxAgeSec); val.IsValid() && !isEmptyValue(val) { + transformed["signedUrlCacheMaxAgeSec"] = transformedSignedUrlCacheMaxAgeSec + } + + return transformed, nil +} + +func expandComputeBackendBucketCdnPolicySignedUrlCacheMaxAgeSec(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + func expandComputeBackendBucketDescription(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { return v, nil } diff --git a/google-beta/resource_compute_backend_bucket_signed_url_key.go b/google-beta/resource_compute_backend_bucket_signed_url_key.go new file mode 100644 index 0000000000..4c1ab5add2 --- /dev/null +++ b/google-beta/resource_compute_backend_bucket_signed_url_key.go @@ -0,0 +1,287 @@ +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated by Magic Modules and manual +// changes will be clobbered when the file is regenerated. +// +// Please read more about how to change this file in +// .github/CONTRIBUTING.md. +// +// ---------------------------------------------------------------------------- + +package google + +import ( + "fmt" + "log" + "reflect" + "time" + + "github.com/hashicorp/terraform/helper/schema" + "google.golang.org/api/compute/v1" +) + +func resourceComputeBackendBucketSignedUrlKey() *schema.Resource { + return &schema.Resource{ + Create: resourceComputeBackendBucketSignedUrlKeyCreate, + Read: resourceComputeBackendBucketSignedUrlKeyRead, + Delete: resourceComputeBackendBucketSignedUrlKeyDelete, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(240 * time.Second), + Delete: schema.DefaultTimeout(240 * time.Second), + }, + + Schema: map[string]*schema.Schema{ + "backend_bucket": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + DiffSuppressFunc: compareSelfLinkOrResourceName, + }, + "key_value": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Sensitive: true, + }, + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validateRegexp(`^(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?)$`), + }, + "project": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + }, + } +} + +func resourceComputeBackendBucketSignedUrlKeyCreate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + obj := make(map[string]interface{}) + keyNameProp, err := expandComputeBackendBucketSignedUrlKeyName(d.Get("name"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("name"); !isEmptyValue(reflect.ValueOf(keyNameProp)) && (ok || !reflect.DeepEqual(v, keyNameProp)) { + obj["keyName"] = keyNameProp + } + keyValueProp, err := expandComputeBackendBucketSignedUrlKeyKeyValue(d.Get("key_value"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("key_value"); !isEmptyValue(reflect.ValueOf(keyValueProp)) && (ok || !reflect.DeepEqual(v, keyValueProp)) { + obj["keyValue"] = keyValueProp + } + backendBucketProp, err := expandComputeBackendBucketSignedUrlKeyBackendBucket(d.Get("backend_bucket"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("backend_bucket"); !isEmptyValue(reflect.ValueOf(backendBucketProp)) && (ok || !reflect.DeepEqual(v, backendBucketProp)) { + obj["backendBucket"] = backendBucketProp + } + + lockName, err := replaceVars(d, config, "signedUrlKey/{{project}}/backendBuckets/{{backend_bucket}}/") + if err != nil { + return err + } + mutexKV.Lock(lockName) + defer mutexKV.Unlock(lockName) + + url, err := replaceVars(d, config, "https://www.googleapis.com/compute/beta/projects/{{project}}/global/backendBuckets/{{backend_bucket}}/addSignedUrlKey") + if err != nil { + return err + } + + log.Printf("[DEBUG] Creating new BackendBucketSignedUrlKey: %#v", obj) + res, err := sendRequestWithTimeout(config, "POST", url, obj, d.Timeout(schema.TimeoutCreate)) + if err != nil { + return fmt.Errorf("Error creating BackendBucketSignedUrlKey: %s", err) + } + + // Store the ID now + id, err := replaceVars(d, config, "{{name}}") + if err != nil { + return fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + project, err := getProject(d, config) + if err != nil { + return err + } + op := &compute.Operation{} + err = Convert(res, op) + if err != nil { + return err + } + + waitErr := computeOperationWaitTime( + config.clientCompute, op, project, "Creating BackendBucketSignedUrlKey", + int(d.Timeout(schema.TimeoutCreate).Minutes())) + + if waitErr != nil { + // The resource didn't actually create + d.SetId("") + return fmt.Errorf("Error waiting to create BackendBucketSignedUrlKey: %s", waitErr) + } + + log.Printf("[DEBUG] Finished creating BackendBucketSignedUrlKey %q: %#v", d.Id(), res) + + return resourceComputeBackendBucketSignedUrlKeyRead(d, meta) +} + +func resourceComputeBackendBucketSignedUrlKeyRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + url, err := replaceVars(d, config, "https://www.googleapis.com/compute/beta/projects/{{project}}/global/backendBuckets/{{backend_bucket}}") + if err != nil { + return err + } + + res, err := sendRequest(config, "GET", url, nil) + if err != nil { + return handleNotFoundError(err, d, fmt.Sprintf("ComputeBackendBucketSignedUrlKey %q", d.Id())) + } + + res, err = flattenNestedComputeBackendBucketSignedUrlKey(d, meta, res) + if err != nil { + return err + } + + if res == nil { + // Object isn't there any more - remove it from the state. + log.Printf("[DEBUG] Removing ComputeBackendBucketSignedUrlKey because it couldn't be matched.") + d.SetId("") + return nil + } + + project, err := getProject(d, config) + if err != nil { + return err + } + if err := d.Set("project", project); err != nil { + return fmt.Errorf("Error reading BackendBucketSignedUrlKey: %s", err) + } + + if err := d.Set("name", flattenComputeBackendBucketSignedUrlKeyName(res["keyName"], d)); err != nil { + return fmt.Errorf("Error reading BackendBucketSignedUrlKey: %s", err) + } + + return nil +} + +func resourceComputeBackendBucketSignedUrlKeyDelete(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + lockName, err := replaceVars(d, config, "signedUrlKey/{{project}}/backendBuckets/{{backend_bucket}}/") + if err != nil { + return err + } + mutexKV.Lock(lockName) + defer mutexKV.Unlock(lockName) + + url, err := replaceVars(d, config, "https://www.googleapis.com/compute/beta/projects/{{project}}/global/backendBuckets/{{backend_bucket}}/deleteSignedUrlKey?keyName={{name}}") + if err != nil { + return err + } + + var obj map[string]interface{} + log.Printf("[DEBUG] Deleting BackendBucketSignedUrlKey %q", d.Id()) + res, err := sendRequestWithTimeout(config, "POST", url, obj, d.Timeout(schema.TimeoutDelete)) + if err != nil { + return handleNotFoundError(err, d, "BackendBucketSignedUrlKey") + } + + project, err := getProject(d, config) + if err != nil { + return err + } + op := &compute.Operation{} + err = Convert(res, op) + if err != nil { + return err + } + + err = computeOperationWaitTime( + config.clientCompute, op, project, "Deleting BackendBucketSignedUrlKey", + int(d.Timeout(schema.TimeoutDelete).Minutes())) + + if err != nil { + return err + } + + log.Printf("[DEBUG] Finished deleting BackendBucketSignedUrlKey %q: %#v", d.Id(), res) + return nil +} + +func flattenComputeBackendBucketSignedUrlKeyName(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func expandComputeBackendBucketSignedUrlKeyName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeBackendBucketSignedUrlKeyKeyValue(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeBackendBucketSignedUrlKeyBackendBucket(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + f, err := parseGlobalFieldValue("backendBuckets", v.(string), "project", d, config, true) + if err != nil { + return nil, fmt.Errorf("Invalid value for backend_bucket: %s", err) + } + return f.RelativeLink(), nil +} + +func flattenNestedComputeBackendBucketSignedUrlKey(d *schema.ResourceData, meta interface{}, res map[string]interface{}) (map[string]interface{}, error) { + var v interface{} + var ok bool + + v, ok = res["cdnPolicy"] + if !ok || v == nil { + return nil, nil + } + res = v.(map[string]interface{}) + + v, ok = res["signedUrlKeyNames"] + if !ok || v == nil { + return nil, nil + } + + // Final nested resource is either a list of resources we need to filter + // or just the resource itself, which we return. + switch v.(type) { + case []interface{}: + break + case map[string]interface{}: + return v.(map[string]interface{}), nil + default: + return nil, fmt.Errorf("invalid value for cdnPolicy.signedUrlKeyNames: %v", v) + } + + items := v.([]interface{}) + for _, vRaw := range items { + // If only an id is given in parent resource, + // construct a resource map for that id KV pair. + item := map[string]interface{}{"keyName": vRaw} + itemIdV, err := expandComputeBackendBucketSignedUrlKeyName(d.Get("name"), d, meta.(*Config)) + if err != nil { + return nil, err + } + actualIdV := flattenComputeBackendBucketSignedUrlKeyName(item["keyName"], d) + log.Printf("[DEBUG] Checking if item's keyName (%#v) is equal to resource's (%#v)", itemIdV, actualIdV) + if !reflect.DeepEqual(itemIdV, actualIdV) { + continue + } + return item, nil + } + return nil, nil +} diff --git a/google-beta/resource_compute_backend_bucket_signed_url_key_test.go b/google-beta/resource_compute_backend_bucket_signed_url_key_test.go new file mode 100644 index 0000000000..23aaeaa903 --- /dev/null +++ b/google-beta/resource_compute_backend_bucket_signed_url_key_test.go @@ -0,0 +1,119 @@ +package google + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform/helper/acctest" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" + "strings" +) + +func TestAccComputeBackendBucketSignedUrlKey_basic(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(10), + } + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckComputeBackendBucketSignedUrlKeyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccComputeBackendBucketSignedUrlKey_basic(context), + Check: testAccCheckComputeBackendBucketSignedUrlKeyCreated, + }, + }, + }) +} + +func testAccComputeBackendBucketSignedUrlKey_basic(context map[string]interface{}) string { + return Nprintf(` +resource "google_compute_backend_bucket_signed_url_key" "backend_key" { + name = "test-key-%{random_suffix}" + key_value = "iAmAFakeKeyRandomBytes==" + backend_bucket = "${google_compute_backend_bucket.test_backend.name}" +} + +resource "google_compute_backend_bucket" "test_backend" { + name = "test-signed-backend-bucket-%{random_suffix}" + description = "Contains beautiful images" + bucket_name = "${google_storage_bucket.bucket.name}" + enable_cdn = true +} + +resource "google_storage_bucket" "bucket" { + name = "test-storage-bucket-%{random_suffix}" + location = "EU" +} +`, context) +} + +func testAccCheckComputeBackendBucketSignedUrlKeyDestroy(s *terraform.State) error { + exists, err := checkComputeBackendBucketSignedUrlKeyExists(s) + if err != nil && !isGoogleApiErrorWithCode(err, 404) { + return err + } + if exists { + return fmt.Errorf("ComputeBackendBucketSignedUrlKey still exists") + } + return nil +} + +func testAccCheckComputeBackendBucketSignedUrlKeyCreated(s *terraform.State) error { + exists, err := checkComputeBackendBucketSignedUrlKeyExists(s) + if err != nil { + return err + } + if !exists { + return fmt.Errorf("expected ComputeBackendBucketSignedUrlKey to have been created") + } + return nil +} + +func checkComputeBackendBucketSignedUrlKeyExists(s *terraform.State) (bool, error) { + for name, rs := range s.RootModule().Resources { + if rs.Type != "google_compute_backend_bucket_signed_url_key" { + continue + } + if strings.HasPrefix(name, "data.") { + continue + } + + config := testAccProvider.Meta().(*Config) + keyName := rs.Primary.ID + + url, err := replaceVarsForTest(rs, "https://www.googleapis.com/compute/v1/projects/{{project}}/global/backendBuckets/{{backend_bucket}}") + if err != nil { + return false, err + } + + res, err := sendRequest(config, "GET", url, nil) + if err == nil { + policyRaw, ok := res["cdnPolicy"] + if !ok { + return false, nil + } + + policy := policyRaw.(map[string]interface{}) + keyNames, ok := policy["signedUrlKeyNames"] + if !ok { + return false, nil + } + + // Because the sensitive key value is not returned, all we can do is verify a + // key with this name exists and assume the key value hasn't been changed. + for _, k := range keyNames.([]interface{}) { + if k.(string) == keyName { + // Just return empty map to indicate key was found + return true, nil + } + } + } + } + + return false, nil +} diff --git a/google-beta/resource_compute_backend_bucket_test.go b/google-beta/resource_compute_backend_bucket_test.go index 7aa39d1590..a32ad17d77 100644 --- a/google-beta/resource_compute_backend_bucket_test.go +++ b/google-beta/resource_compute_backend_bucket_test.go @@ -6,8 +6,6 @@ import ( "github.com/hashicorp/terraform/helper/acctest" "github.com/hashicorp/terraform/helper/resource" - "github.com/hashicorp/terraform/terraform" - "google.golang.org/api/compute/v1" ) func TestAccComputeBackendBucket_basicModified(t *testing.T) { @@ -16,7 +14,6 @@ func TestAccComputeBackendBucket_basicModified(t *testing.T) { backendName := fmt.Sprintf("tf-test-%s", acctest.RandString(10)) storageName := fmt.Sprintf("tf-test-%s", acctest.RandString(10)) secondStorageName := fmt.Sprintf("tf-test-%s", acctest.RandString(10)) - var svc compute.BackendBucket resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -25,62 +22,30 @@ func TestAccComputeBackendBucket_basicModified(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccComputeBackendBucket_basic(backendName, storageName), - Check: resource.ComposeTestCheckFunc( - testAccCheckComputeBackendBucketExists( - "google_compute_backend_bucket.foobar", &svc), - ), + }, + { + ResourceName: "google_compute_backend_bucket.foobar", + ImportState: true, + ImportStateVerify: true, }, { Config: testAccComputeBackendBucket_basicModified( backendName, storageName, secondStorageName), - Check: resource.ComposeTestCheckFunc( - testAccCheckComputeBackendBucketExists( - "google_compute_backend_bucket.foobar", &svc), - ), + }, + { + ResourceName: "google_compute_backend_bucket.foobar", + ImportState: true, + ImportStateVerify: true, }, }, }) - - if svc.BucketName != secondStorageName { - t.Errorf("Expected BucketName to be %q, got %q", secondStorageName, svc.BucketName) - } -} - -func testAccCheckComputeBackendBucketExists(n string, svc *compute.BackendBucket) resource.TestCheckFunc { - return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[n] - if !ok { - return fmt.Errorf("Not found: %s", n) - } - - if rs.Primary.ID == "" { - return fmt.Errorf("No ID is set") - } - - config := testAccProvider.Meta().(*Config) - - found, err := config.clientCompute.BackendBuckets.Get( - config.Project, rs.Primary.ID).Do() - if err != nil { - return err - } - - if found.Name != rs.Primary.ID { - return fmt.Errorf("Backend bucket %s not found", rs.Primary.ID) - } - - *svc = *found - - return nil - } } -func TestAccComputeBackendBucket_withCdnEnabled(t *testing.T) { +func TestAccComputeBackendBucket_withCdnPolicy(t *testing.T) { t.Parallel() backendName := fmt.Sprintf("tf-test-%s", acctest.RandString(10)) storageName := fmt.Sprintf("tf-test-%s", acctest.RandString(10)) - var svc compute.BackendBucket resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -88,19 +53,15 @@ func TestAccComputeBackendBucket_withCdnEnabled(t *testing.T) { CheckDestroy: testAccCheckComputeBackendBucketDestroy, Steps: []resource.TestStep{ { - Config: testAccComputeBackendBucket_withCdnEnabled( - backendName, storageName), - Check: resource.ComposeTestCheckFunc( - testAccCheckComputeBackendBucketExists( - "google_compute_backend_bucket.foobar", &svc), - ), + Config: testAccComputeBackendBucket_withCdnPolicy(backendName, storageName), + }, + { + ResourceName: "google_compute_backend_bucket.foobar", + ImportState: true, + ImportStateVerify: true, }, }, }) - - if svc.EnableCdn != true { - t.Errorf("Expected EnableCdn == true, got %t", svc.EnableCdn) - } } func testAccComputeBackendBucket_basic(backendName, storageName string) string { @@ -136,12 +97,15 @@ resource "google_storage_bucket" "bucket_two" { `, backendName, bucketOne, bucketTwo) } -func testAccComputeBackendBucket_withCdnEnabled(backendName, storageName string) string { +func testAccComputeBackendBucket_withCdnPolicy(backendName, storageName string) string { return fmt.Sprintf(` resource "google_compute_backend_bucket" "foobar" { name = "%s" bucket_name = "${google_storage_bucket.bucket.name}" enable_cdn = true + cdn_policy { + signed_url_cache_max_age_sec = 1000 + } } resource "google_storage_bucket" "bucket" { diff --git a/website/docs/r/compute_backend_bucket.html.markdown b/website/docs/r/compute_backend_bucket.html.markdown index 90e922900f..de058b7a0c 100644 --- a/website/docs/r/compute_backend_bucket.html.markdown +++ b/website/docs/r/compute_backend_bucket.html.markdown @@ -82,6 +82,10 @@ The following arguments are supported: - - - +* `cdn_policy` - + (Optional) + Cloud CDN configuration for this Backend Bucket. Structure is documented below. + * `description` - (Optional) An optional textual description of the resource; provided by the @@ -94,6 +98,19 @@ The following arguments are supported: If it is not provided, the provider project is used. +The `cdn_policy` block supports: + +* `signed_url_cache_max_age_sec` - + (Optional) + Maximum number of seconds the response to a signed URL request will + be considered fresh. Defaults to 1hr (3600s). After this time period, + the response will be revalidated before being served. + When serving responses to signed URL requests, + Cloud CDN will internally behave as though + all responses from this backend had a "Cache-Control: public, + max-age=[TTL]" header, regardless of any existing Cache-Control + header. The actual headers served in responses will not be altered. + ## Attributes Reference In addition to the arguments listed above, the following computed attributes are exported: diff --git a/website/docs/r/compute_backend_bucket_signed_url_key.html.markdown b/website/docs/r/compute_backend_bucket_signed_url_key.html.markdown new file mode 100644 index 0000000000..6423b54c7b --- /dev/null +++ b/website/docs/r/compute_backend_bucket_signed_url_key.html.markdown @@ -0,0 +1,106 @@ +--- +# ---------------------------------------------------------------------------- +# +# *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +# +# ---------------------------------------------------------------------------- +# +# This file is automatically generated by Magic Modules and manual +# changes will be clobbered when the file is regenerated. +# +# Please read more about how to change this file in +# .github/CONTRIBUTING.md. +# +# ---------------------------------------------------------------------------- +layout: "google" +page_title: "Google: google_compute_backend_bucket_signed_url_key" +sidebar_current: "docs-google-compute-backend-bucket-signed-url-key" +description: |- + A key for signing Cloud CDN signed URLs for BackendBuckets. +--- + +# google\_compute\_backend\_bucket\_signed\_url\_key + +A key for signing Cloud CDN signed URLs for BackendBuckets. + + +To get more information about BackendBucketSignedUrlKey, see: + +* [API documentation](https://cloud.google.com/compute/docs/reference/rest/v1/backendBuckets) +* How-to Guides + * [Using Signed URLs](https://cloud.google.com/cdn/docs/using-signed-urls/) + +~> **Warning:** All arguments including the key's value will be stored in the raw +state as plain-text. [Read more about sensitive data in state](/docs/state/sensitive-data.html). +Because the API does not return the sensitive key value, +we cannot confirm or reverse changes to a key outside of Terraform. + +## Example Usage - Backend Bucket Signed Url Key + + +```hcl +resource "google_compute_backend_bucket_signed_url_key" "backend_key" { + name = "test-key" + key_value = "pPsVemX8GM46QVeezid6Rw==" + backend_bucket = "${google_compute_backend_bucket.test_backend.name}" +} + +resource "google_compute_backend_bucket" "test_backend" { + name = "test-signed-backend-bucket" + description = "Contains beautiful images" + bucket_name = "${google_storage_bucket.bucket.name}" + enable_cdn = true +} + +resource "google_storage_bucket" "bucket" { + name = "test-storage-bucket" + location = "EU" +} +``` + +## Argument Reference + +The following arguments are supported: + + +* `name` - + (Required) + Name of the signed URL key. + +* `key_value` - + (Required) + 128-bit key value used for signing the URL. The key value must be a + valid RFC 4648 Section 5 base64url encoded string. + +* `backend_bucket` - + (Required) + The backend bucket this signed URL key belongs. + + +- - - + +* `project` - (Optional) The ID of the project in which the resource belongs. + If it is not provided, the provider project is used. + + + +## Timeouts + +This resource provides the following +[Timeouts](/docs/configuration/resources.html#timeouts) configuration options: + +- `create` - Default is 4 minutes. +- `delete` - Default is 4 minutes. + +## Import + +BackendBucketSignedUrlKey can be imported using any of these accepted formats: + +``` +$ terraform import google_compute_backend_bucket_signed_url_key.default projects/{{project}}/global/backendBuckets/{{backend_bucket}}/{{name}} +$ terraform import google_compute_backend_bucket_signed_url_key.default {{project}}/{{backend_bucket}}/{{name}} +$ terraform import google_compute_backend_bucket_signed_url_key.default {{backend_bucket}}/{{name}} +``` + +-> If you're importing a resource with beta features, make sure to include `-provider=google-beta` +as an argument so that Terraform uses the correct provider to import your resource.