diff --git a/google-beta/provider_compute_gen.go b/google-beta/provider_compute_gen.go index fa141f2f406..466744017c1 100644 --- a/google-beta/provider_compute_gen.go +++ b/google-beta/provider_compute_gen.go @@ -17,35 +17,36 @@ 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_backend_bucket_signed_url_key": resourceComputeBackendBucketSignedUrlKey(), - "google_compute_backend_service": resourceComputeBackendService(), - "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_backend_service": resourceComputeBackendService(), + "google_compute_backend_service_signed_url_key": resourceComputeBackendServiceSignedUrlKey(), + "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_service_signed_url_key.go b/google-beta/resource_compute_backend_service_signed_url_key.go new file mode 100644 index 00000000000..25bdf6b1147 --- /dev/null +++ b/google-beta/resource_compute_backend_service_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 resourceComputeBackendServiceSignedUrlKey() *schema.Resource { + return &schema.Resource{ + Create: resourceComputeBackendServiceSignedUrlKeyCreate, + Read: resourceComputeBackendServiceSignedUrlKeyRead, + Delete: resourceComputeBackendServiceSignedUrlKeyDelete, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(240 * time.Second), + Delete: schema.DefaultTimeout(240 * time.Second), + }, + + Schema: map[string]*schema.Schema{ + "backend_service": { + 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 resourceComputeBackendServiceSignedUrlKeyCreate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + obj := make(map[string]interface{}) + keyNameProp, err := expandComputeBackendServiceSignedUrlKeyName(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 := expandComputeBackendServiceSignedUrlKeyKeyValue(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 + } + backendServiceProp, err := expandComputeBackendServiceSignedUrlKeyBackendService(d.Get("backend_service"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("backend_service"); !isEmptyValue(reflect.ValueOf(backendServiceProp)) && (ok || !reflect.DeepEqual(v, backendServiceProp)) { + obj["backendService"] = backendServiceProp + } + + lockName, err := replaceVars(d, config, "signedUrlKey/{{project}}/backendServices/{{backend_service}}/") + 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/backendServices/{{backend_service}}/addSignedUrlKey") + if err != nil { + return err + } + + log.Printf("[DEBUG] Creating new BackendServiceSignedUrlKey: %#v", obj) + res, err := sendRequestWithTimeout(config, "POST", url, obj, d.Timeout(schema.TimeoutCreate)) + if err != nil { + return fmt.Errorf("Error creating BackendServiceSignedUrlKey: %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 BackendServiceSignedUrlKey", + int(d.Timeout(schema.TimeoutCreate).Minutes())) + + if waitErr != nil { + // The resource didn't actually create + d.SetId("") + return fmt.Errorf("Error waiting to create BackendServiceSignedUrlKey: %s", waitErr) + } + + log.Printf("[DEBUG] Finished creating BackendServiceSignedUrlKey %q: %#v", d.Id(), res) + + return resourceComputeBackendServiceSignedUrlKeyRead(d, meta) +} + +func resourceComputeBackendServiceSignedUrlKeyRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + url, err := replaceVars(d, config, "https://www.googleapis.com/compute/beta/projects/{{project}}/global/backendServices/{{backend_service}}") + if err != nil { + return err + } + + res, err := sendRequest(config, "GET", url, nil) + if err != nil { + return handleNotFoundError(err, d, fmt.Sprintf("ComputeBackendServiceSignedUrlKey %q", d.Id())) + } + + res, err = flattenNestedComputeBackendServiceSignedUrlKey(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 ComputeBackendServiceSignedUrlKey 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 BackendServiceSignedUrlKey: %s", err) + } + + if err := d.Set("name", flattenComputeBackendServiceSignedUrlKeyName(res["keyName"], d)); err != nil { + return fmt.Errorf("Error reading BackendServiceSignedUrlKey: %s", err) + } + + return nil +} + +func resourceComputeBackendServiceSignedUrlKeyDelete(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + lockName, err := replaceVars(d, config, "signedUrlKey/{{project}}/backendServices/{{backend_service}}/") + 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/backendServices/{{backend_service}}/deleteSignedUrlKey?keyName={{name}}") + if err != nil { + return err + } + + var obj map[string]interface{} + log.Printf("[DEBUG] Deleting BackendServiceSignedUrlKey %q", d.Id()) + res, err := sendRequestWithTimeout(config, "POST", url, obj, d.Timeout(schema.TimeoutDelete)) + if err != nil { + return handleNotFoundError(err, d, "BackendServiceSignedUrlKey") + } + + 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 BackendServiceSignedUrlKey", + int(d.Timeout(schema.TimeoutDelete).Minutes())) + + if err != nil { + return err + } + + log.Printf("[DEBUG] Finished deleting BackendServiceSignedUrlKey %q: %#v", d.Id(), res) + return nil +} + +func flattenComputeBackendServiceSignedUrlKeyName(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func expandComputeBackendServiceSignedUrlKeyName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeBackendServiceSignedUrlKeyKeyValue(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeBackendServiceSignedUrlKeyBackendService(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + f, err := parseGlobalFieldValue("backendServices", v.(string), "project", d, config, true) + if err != nil { + return nil, fmt.Errorf("Invalid value for backend_service: %s", err) + } + return f.RelativeLink(), nil +} + +func flattenNestedComputeBackendServiceSignedUrlKey(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 := expandComputeBackendServiceSignedUrlKeyName(d.Get("name"), d, meta.(*Config)) + if err != nil { + return nil, err + } + actualIdV := flattenComputeBackendServiceSignedUrlKeyName(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_service_signed_url_key_test.go b/google-beta/resource_compute_backend_service_signed_url_key_test.go new file mode 100644 index 00000000000..7d22301aca6 --- /dev/null +++ b/google-beta/resource_compute_backend_service_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 TestAccComputeBackendServiceSignedUrlKey_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: testAccCheckComputeBackendServiceSignedUrlKeyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccComputeBackendServiceSignedUrlKey_basic(context), + Check: testAccCheckComputeBackendServiceSignedUrlKeyCreated, + }, + }, + }) +} + +func testAccComputeBackendServiceSignedUrlKey_basic(context map[string]interface{}) string { + return Nprintf(` +resource "google_compute_backend_service_signed_url_key" "backend_key" { + name = "testkey-%{random_suffix}" + key_value = "iAmAFakeKeyRandomBytes==" + backend_service = "${google_compute_backend_service.test_bs.name}" +} + +resource "google_compute_backend_service" "test_bs" { + name = "testbs-%{random_suffix}" + health_checks = ["${google_compute_http_health_check.zero.self_link}"] +} + +resource "google_compute_http_health_check" "zero" { + name = "test-check-%{random_suffix}" + request_path = "/" + check_interval_sec = 1 + timeout_sec = 1 +} +`, context) +} + +func testAccCheckComputeBackendServiceSignedUrlKeyDestroy(s *terraform.State) error { + exists, err := checkComputeBackendServiceSignedUrlKeyExists(s) + if err != nil && !isGoogleApiErrorWithCode(err, 404) { + return err + } + if exists { + return fmt.Errorf("ComputeBackendServiceSignedUrlKey still exists") + } + return nil +} + +func testAccCheckComputeBackendServiceSignedUrlKeyCreated(s *terraform.State) error { + exists, err := checkComputeBackendServiceSignedUrlKeyExists(s) + if err != nil { + return err + } + if !exists { + return fmt.Errorf("expected ComputeBackendServiceSignedUrlKey to have been created") + } + return nil +} + +func checkComputeBackendServiceSignedUrlKeyExists(s *terraform.State) (bool, error) { + for name, rs := range s.RootModule().Resources { + if rs.Type != "google_compute_backend_service_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/backendServices/{{backend_service}}") + 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/website/docs/r/compute_backend_service_signed_url_key.html.markdown b/website/docs/r/compute_backend_service_signed_url_key.html.markdown new file mode 100644 index 00000000000..f33bc8a6a8b --- /dev/null +++ b/website/docs/r/compute_backend_service_signed_url_key.html.markdown @@ -0,0 +1,139 @@ +--- +# ---------------------------------------------------------------------------- +# +# *** 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_service_signed_url_key" +sidebar_current: "docs-google-compute-backend-service-signed-url-key" +description: |- + A key for signing Cloud CDN signed URLs for Backend Services. +--- + +# google\_compute\_backend\_service\_signed\_url\_key + +A key for signing Cloud CDN signed URLs for Backend Services. + + +To get more information about BackendServiceSignedUrlKey, see: + +* [API documentation](https://cloud.google.com/compute/docs/reference/rest/v1/backendServices) +* 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 Service Signed Url Key + + +```hcl +resource "google_compute_backend_service_signed_url_key" "backend_key" { + name = "test-key" + key_value = "pPsVemX8GM46QVeezid6Rw==" + backend_service = "${google_compute_backend_service.example_backend.name}" +} + +resource "google_compute_backend_service" "example_backend" { + name = "my-backend-service" + description = "Our company website" + port_name = "http" + protocol = "HTTP" + timeout_sec = 10 + enable_cdn = true + + backend { + group = "${google_compute_instance_group_manager.webservers.instance_group}" + } + + health_checks = ["${google_compute_http_health_check.default.self_link}"] +} + +resource "google_compute_instance_group_manager" "webservers" { + name = "my-webservers" + instance_template = "${google_compute_instance_template.webserver.self_link}" + base_instance_name = "webserver" + zone = "us-central1-f" + target_size = 1 +} + +resource "google_compute_instance_template" "webserver" { + name = "standard-webserver" + machine_type = "n1-standard-1" + + network_interface { + network = "default" + } + + disk { + source_image = "debian-cloud/debian-9" + auto_delete = true + boot = true + } +} + +resource "google_compute_http_health_check" "default" { + name = "test" + request_path = "/" + check_interval_sec = 1 + timeout_sec = 1 +} +``` + +## 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_service` - + (Required) + The backend service 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 + +BackendServiceSignedUrlKey can be imported using any of these accepted formats: + +``` +$ terraform import google_compute_backend_service_signed_url_key.default projects/{{project}}/global/backendServices/{{backend_service}}/{{name}} +$ terraform import google_compute_backend_service_signed_url_key.default {{project}}/{{backend_service}}/{{name}} +$ terraform import google_compute_backend_service_signed_url_key.default {{backend_service}}/{{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.