diff --git a/google/provider.go b/google/provider.go index 471683f7..e849ca02 100644 --- a/google/provider.go +++ b/google/provider.go @@ -176,7 +176,6 @@ func ResourceMapWithErrors() (map[string]*schema.Resource, error) { "google_compute_network_peering": resourceComputeNetworkPeering(), "google_compute_project_metadata": resourceComputeProjectMetadata(), "google_compute_project_metadata_item": resourceComputeProjectMetadataItem(), - "google_compute_region_backend_service": resourceComputeRegionBackendService(), "google_compute_region_instance_group_manager": resourceComputeRegionInstanceGroupManager(), "google_compute_router_interface": resourceComputeRouterInterface(), "google_compute_router_nat": resourceComputeRouterNat(), diff --git a/google/provider_compute_gen.go b/google/provider_compute_gen.go index f75db130..e918a57f 100644 --- a/google/provider_compute_gen.go +++ b/google/provider_compute_gen.go @@ -22,6 +22,7 @@ var GeneratedComputeResourcesMap = map[string]*schema.Resource{ "google_compute_backend_bucket": resourceComputeBackendBucket(), "google_compute_backend_bucket_signed_url_key": resourceComputeBackendBucketSignedUrlKey(), "google_compute_backend_service": resourceComputeBackendService(), + "google_compute_region_backend_service": resourceComputeRegionBackendService(), "google_compute_backend_service_signed_url_key": resourceComputeBackendServiceSignedUrlKey(), "google_compute_disk": resourceComputeDisk(), "google_compute_firewall": resourceComputeFirewall(), diff --git a/google/resource_compute_region_backend_service.go b/google/resource_compute_region_backend_service.go index 9c7a7768..a597ba07 100644 --- a/google/resource_compute_region_backend_service.go +++ b/google/resource_compute_region_backend_service.go @@ -1,14 +1,28 @@ +// ---------------------------------------------------------------------------- +// +// *** 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 ( - "bytes" - "errors" "fmt" "log" + "reflect" + "strconv" + "time" - "github.com/hashicorp/terraform/helper/hashcode" "github.com/hashicorp/terraform/helper/schema" - computeBeta "google.golang.org/api/compute/v0.beta" + "github.com/hashicorp/terraform/helper/validation" "google.golang.org/api/compute/v1" ) @@ -19,93 +33,109 @@ func resourceComputeRegionBackendService() *schema.Resource { Update: resourceComputeRegionBackendServiceUpdate, Delete: resourceComputeRegionBackendServiceDelete, - Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - ValidateFunc: validateGCPName, - }, + Importer: &schema.ResourceImporter{ + State: resourceComputeRegionBackendServiceImport, + }, + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(240 * time.Second), + Update: schema.DefaultTimeout(240 * time.Second), + Delete: schema.DefaultTimeout(240 * time.Second), + }, + + SchemaVersion: 1, + + Schema: map[string]*schema.Schema{ "health_checks": { Type: schema.TypeSet, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, Required: true, MinItems: 1, MaxItems: 1, - }, - - "backend": { - Type: schema.TypeSet, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "group": { - Type: schema.TypeString, - Optional: true, - DiffSuppressFunc: compareSelfLinkRelativePaths, - }, - "description": { - Type: schema.TypeString, - Optional: true, - }, - }, + Elem: &schema.Schema{ + Type: schema.TypeString, }, + Set: selfLinkRelativePathHash, + }, + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "backend": { + Type: schema.TypeSet, Optional: true, - Set: resourceGoogleComputeRegionBackendServiceBackendHash, + Elem: computeRegionBackendServiceBackendSchema(), + Set: resourceGoogleComputeBackendServiceBackendHash, + }, + "connection_draining_timeout_sec": { + Type: schema.TypeInt, + Optional: true, + Default: 0, }, "description": { Type: schema.TypeString, Optional: true, }, - + "load_balancing_scheme": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{"INTERNAL", ""}, false), + Default: "INTERNAL", + }, + "protocol": { + Type: schema.TypeString, + Computed: true, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{"TCP", "UDP", ""}, false), + }, + "region": { + Type: schema.TypeString, + Computed: true, + Optional: true, + ForceNew: true, + DiffSuppressFunc: compareSelfLinkOrResourceName, + }, + "session_affinity": { + Type: schema.TypeString, + Computed: true, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{"NONE", "CLIENT_IP", "CLIENT_IP_PROTO", "CLIENT_IP_PORT_PROTO", ""}, false), + }, + "timeout_sec": { + Type: schema.TypeInt, + Computed: true, + Optional: true, + }, "fingerprint": { Type: schema.TypeString, Computed: true, }, - "project": { Type: schema.TypeString, Optional: true, Computed: true, ForceNew: true, }, - - "protocol": { - Type: schema.TypeString, - Optional: true, - Computed: true, - }, - - "session_affinity": { - Type: schema.TypeString, - Optional: true, - Computed: true, - }, - - "region": { - Type: schema.TypeString, - Optional: true, - Computed: true, - ForceNew: true, - }, - "self_link": { Type: schema.TypeString, Computed: true, }, + }, + } +} - "timeout_sec": { - Type: schema.TypeInt, +func computeRegionBackendServiceBackendSchema() *schema.Resource { + return &schema.Resource{ + Schema: map[string]*schema.Schema{ + "description": { + Type: schema.TypeString, Optional: true, - Computed: true, }, - - "connection_draining_timeout_sec": { - Type: schema.TypeInt, - Optional: true, - Default: 0, + "group": { + Type: schema.TypeString, + Optional: true, + DiffSuppressFunc: compareSelfLinkRelativePaths, }, }, } @@ -114,76 +144,113 @@ func resourceComputeRegionBackendService() *schema.Resource { func resourceComputeRegionBackendServiceCreate(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - hc := d.Get("health_checks").(*schema.Set).List() - healthChecks := make([]string, 0, len(hc)) - for _, v := range hc { - healthChecks = append(healthChecks, v.(string)) + obj := make(map[string]interface{}) + nameProp, err := expandComputeRegionBackendServiceName(d.Get("name"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("name"); !isEmptyValue(reflect.ValueOf(nameProp)) && (ok || !reflect.DeepEqual(v, nameProp)) { + obj["name"] = nameProp + } + healthChecksProp, err := expandComputeRegionBackendServiceHealthChecks(d.Get("health_checks"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("health_checks"); !isEmptyValue(reflect.ValueOf(healthChecksProp)) && (ok || !reflect.DeepEqual(v, healthChecksProp)) { + obj["healthChecks"] = healthChecksProp + } + backendsProp, err := expandComputeRegionBackendServiceBackend(d.Get("backend"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("backend"); !isEmptyValue(reflect.ValueOf(backendsProp)) && (ok || !reflect.DeepEqual(v, backendsProp)) { + obj["backends"] = backendsProp + } + descriptionProp, err := expandComputeRegionBackendServiceDescription(d.Get("description"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("description"); !isEmptyValue(reflect.ValueOf(descriptionProp)) && (ok || !reflect.DeepEqual(v, descriptionProp)) { + obj["description"] = descriptionProp + } + fingerprintProp, err := expandComputeRegionBackendServiceFingerprint(d.Get("fingerprint"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("fingerprint"); !isEmptyValue(reflect.ValueOf(fingerprintProp)) && (ok || !reflect.DeepEqual(v, fingerprintProp)) { + obj["fingerprint"] = fingerprintProp + } + protocolProp, err := expandComputeRegionBackendServiceProtocol(d.Get("protocol"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("protocol"); !isEmptyValue(reflect.ValueOf(protocolProp)) && (ok || !reflect.DeepEqual(v, protocolProp)) { + obj["protocol"] = protocolProp + } + sessionAffinityProp, err := expandComputeRegionBackendServiceSessionAffinity(d.Get("session_affinity"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("session_affinity"); !isEmptyValue(reflect.ValueOf(sessionAffinityProp)) && (ok || !reflect.DeepEqual(v, sessionAffinityProp)) { + obj["sessionAffinity"] = sessionAffinityProp + } + regionProp, err := expandComputeRegionBackendServiceRegion(d.Get("region"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("region"); !isEmptyValue(reflect.ValueOf(regionProp)) && (ok || !reflect.DeepEqual(v, regionProp)) { + obj["region"] = regionProp + } + timeoutSecProp, err := expandComputeRegionBackendServiceTimeoutSec(d.Get("timeout_sec"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("timeout_sec"); !isEmptyValue(reflect.ValueOf(timeoutSecProp)) && (ok || !reflect.DeepEqual(v, timeoutSecProp)) { + obj["timeoutSec"] = timeoutSecProp + } + connectionDrainingProp, err := expandComputeRegionBackendServiceConnectionDraining(d, config) + if err != nil { + return err + } else if !isEmptyValue(reflect.ValueOf(connectionDrainingProp)) { + obj["connectionDraining"] = connectionDrainingProp + } + loadBalancingSchemeProp, err := expandComputeRegionBackendServiceLoadBalancingScheme(d.Get("load_balancing_scheme"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("load_balancing_scheme"); !isEmptyValue(reflect.ValueOf(loadBalancingSchemeProp)) && (ok || !reflect.DeepEqual(v, loadBalancingSchemeProp)) { + obj["loadBalancingScheme"] = loadBalancingSchemeProp } - service := computeBeta.BackendService{ - Name: d.Get("name").(string), - HealthChecks: healthChecks, - LoadBalancingScheme: "INTERNAL", + url, err := replaceVars(d, config, "https://www.googleapis.com/compute/v1/projects/{{project}}/regions/{{region}}/backendServices") + if err != nil { + return err } - var err error - if v, ok := d.GetOk("backend"); ok { - service.Backends, err = expandBackends(v.(*schema.Set).List()) - if err != nil { - return err - } + log.Printf("[DEBUG] Creating new RegionBackendService: %#v", obj) + res, err := sendRequestWithTimeout(config, "POST", url, obj, d.Timeout(schema.TimeoutCreate)) + if err != nil { + return fmt.Errorf("Error creating RegionBackendService: %s", err) } - if v, ok := d.GetOk("description"); ok { - service.Description = v.(string) - } - - if v, ok := d.GetOk("protocol"); ok { - service.Protocol = v.(string) - } - - if v, ok := d.GetOk("session_affinity"); ok { - service.SessionAffinity = v.(string) - } - - if v, ok := d.GetOk("timeout_sec"); ok { - service.TimeoutSec = int64(v.(int)) - } - - if v, ok := d.GetOk("connection_draining_timeout_sec"); ok { - connectionDraining := &computeBeta.ConnectionDraining{ - DrainingTimeoutSec: int64(v.(int)), - } - - service.ConnectionDraining = connectionDraining + // 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 } - - region, err := getRegion(d, config) + op := &compute.Operation{} + err = Convert(res, op) if err != nil { return err } - log.Printf("[DEBUG] Creating new Region Backend Service: %#v", service) + waitErr := computeOperationWaitTime( + config.clientCompute, op, project, "Creating RegionBackendService", + int(d.Timeout(schema.TimeoutCreate).Minutes())) - op, err := config.clientComputeBeta.RegionBackendServices.Insert( - project, region, &service).Do() - if err != nil { - return fmt.Errorf("Error creating backend service: %s", err) + if waitErr != nil { + // The resource didn't actually create + d.SetId("") + return fmt.Errorf("Error waiting to create RegionBackendService: %s", waitErr) } - log.Printf("[DEBUG] Waiting for new backend service, operation: %#v", op) - - d.SetId(service.Name) - - err = computeSharedOperationWait(config.clientCompute, op, project, "Creating Region Backend Service") - if err != nil { - return err - } + log.Printf("[DEBUG] Finished creating RegionBackendService %q: %#v", d.Id(), res) return resourceComputeRegionBackendServiceRead(d, meta) } @@ -191,36 +258,64 @@ func resourceComputeRegionBackendServiceCreate(d *schema.ResourceData, meta inte func resourceComputeRegionBackendServiceRead(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) + url, err := replaceVars(d, config, "https://www.googleapis.com/compute/v1/projects/{{project}}/regions/{{region}}/backendServices/{{name}}") + if err != nil { + return err + } + + res, err := sendRequest(config, "GET", url, nil) + if err != nil { + return handleNotFoundError(err, d, fmt.Sprintf("ComputeRegionBackendService %q", d.Id())) + } + project, err := getProject(d, config) if err != nil { return err } - - region, err := getRegion(d, config) - if err != nil { - return err + if err := d.Set("project", project); err != nil { + return fmt.Errorf("Error reading RegionBackendService: %s", err) } - service, err := config.clientCompute.RegionBackendServices.Get( - project, region, d.Id()).Do() - if err != nil { - return handleNotFoundError(err, d, fmt.Sprintf("Region Backend Service %q", d.Get("name").(string))) + if err := d.Set("name", flattenComputeRegionBackendServiceName(res["name"], d)); err != nil { + return fmt.Errorf("Error reading RegionBackendService: %s", err) } - - d.Set("description", service.Description) - d.Set("protocol", service.Protocol) - d.Set("session_affinity", service.SessionAffinity) - d.Set("timeout_sec", service.TimeoutSec) - d.Set("connection_draining_timeout_sec", service.ConnectionDraining.DrainingTimeoutSec) - d.Set("fingerprint", service.Fingerprint) - d.Set("self_link", service.SelfLink) - err = d.Set("backend", flattenRegionBackends(service.Backends)) - if err != nil { - return err + if err := d.Set("health_checks", flattenComputeRegionBackendServiceHealthChecks(res["healthChecks"], d)); err != nil { + return fmt.Errorf("Error reading RegionBackendService: %s", err) + } + if err := d.Set("backend", flattenComputeRegionBackendServiceBackend(res["backends"], d)); err != nil { + return fmt.Errorf("Error reading RegionBackendService: %s", err) + } + if err := d.Set("description", flattenComputeRegionBackendServiceDescription(res["description"], d)); err != nil { + return fmt.Errorf("Error reading RegionBackendService: %s", err) + } + if err := d.Set("fingerprint", flattenComputeRegionBackendServiceFingerprint(res["fingerprint"], d)); err != nil { + return fmt.Errorf("Error reading RegionBackendService: %s", err) + } + if err := d.Set("protocol", flattenComputeRegionBackendServiceProtocol(res["protocol"], d)); err != nil { + return fmt.Errorf("Error reading RegionBackendService: %s", err) + } + if err := d.Set("session_affinity", flattenComputeRegionBackendServiceSessionAffinity(res["sessionAffinity"], d)); err != nil { + return fmt.Errorf("Error reading RegionBackendService: %s", err) + } + if err := d.Set("region", flattenComputeRegionBackendServiceRegion(res["region"], d)); err != nil { + return fmt.Errorf("Error reading RegionBackendService: %s", err) + } + if err := d.Set("timeout_sec", flattenComputeRegionBackendServiceTimeoutSec(res["timeoutSec"], d)); err != nil { + return fmt.Errorf("Error reading RegionBackendService: %s", err) + } + if v, ok := res["connectionDraining"].(map[string]interface{}); res["connectionDraining"] != nil && ok { + if err := d.Set("connection_draining_timeout_sec", flattenComputeRegionBackendServiceConnectionDrainingConnection_draining_timeout_sec(v["drainingTimeoutSec"], d)); err != nil { + return fmt.Errorf("Error reading RegionBackendService: %s", err) + } + } else { + d.Set("connection_draining_timeout_sec", nil) + } + if err := d.Set("load_balancing_scheme", flattenComputeRegionBackendServiceLoadBalancingScheme(res["loadBalancingScheme"], d)); err != nil { + return fmt.Errorf("Error reading RegionBackendService: %s", err) + } + if err := d.Set("self_link", ConvertSelfLinkToV1(res["selfLink"].(string))); err != nil { + return fmt.Errorf("Error reading RegionBackendService: %s", err) } - d.Set("health_checks", service.HealthChecks) - d.Set("project", project) - d.Set("region", region) return nil } @@ -228,67 +323,100 @@ func resourceComputeRegionBackendServiceRead(d *schema.ResourceData, meta interf func resourceComputeRegionBackendServiceUpdate(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) + obj := make(map[string]interface{}) + nameProp, err := expandComputeRegionBackendServiceName(d.Get("name"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("name"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, nameProp)) { + obj["name"] = nameProp + } + healthChecksProp, err := expandComputeRegionBackendServiceHealthChecks(d.Get("health_checks"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("health_checks"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, healthChecksProp)) { + obj["healthChecks"] = healthChecksProp + } + backendsProp, err := expandComputeRegionBackendServiceBackend(d.Get("backend"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("backend"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, backendsProp)) { + obj["backends"] = backendsProp + } + descriptionProp, err := expandComputeRegionBackendServiceDescription(d.Get("description"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("description"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, descriptionProp)) { + obj["description"] = descriptionProp + } + fingerprintProp, err := expandComputeRegionBackendServiceFingerprint(d.Get("fingerprint"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("fingerprint"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, fingerprintProp)) { + obj["fingerprint"] = fingerprintProp + } + protocolProp, err := expandComputeRegionBackendServiceProtocol(d.Get("protocol"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("protocol"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, protocolProp)) { + obj["protocol"] = protocolProp + } + sessionAffinityProp, err := expandComputeRegionBackendServiceSessionAffinity(d.Get("session_affinity"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("session_affinity"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, sessionAffinityProp)) { + obj["sessionAffinity"] = sessionAffinityProp + } + regionProp, err := expandComputeRegionBackendServiceRegion(d.Get("region"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("region"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, regionProp)) { + obj["region"] = regionProp + } + timeoutSecProp, err := expandComputeRegionBackendServiceTimeoutSec(d.Get("timeout_sec"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("timeout_sec"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, timeoutSecProp)) { + obj["timeoutSec"] = timeoutSecProp + } + connectionDrainingProp, err := expandComputeRegionBackendServiceConnectionDraining(d, config) + if err != nil { + return err + } else if !isEmptyValue(reflect.ValueOf(connectionDrainingProp)) { + obj["connectionDraining"] = connectionDrainingProp + } + loadBalancingSchemeProp, err := expandComputeRegionBackendServiceLoadBalancingScheme(d.Get("load_balancing_scheme"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("load_balancing_scheme"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, loadBalancingSchemeProp)) { + obj["loadBalancingScheme"] = loadBalancingSchemeProp + } + + url, err := replaceVars(d, config, "https://www.googleapis.com/compute/v1/projects/{{project}}/regions/{{region}}/backendServices/{{name}}") + if err != nil { + return err + } + + log.Printf("[DEBUG] Updating RegionBackendService %q: %#v", d.Id(), obj) + res, err := sendRequestWithTimeout(config, "PUT", url, obj, d.Timeout(schema.TimeoutUpdate)) + + if err != nil { + return fmt.Errorf("Error updating RegionBackendService %q: %s", d.Id(), err) + } + project, err := getProject(d, config) if err != nil { return err } - - region, err := getRegion(d, config) + op := &compute.Operation{} + err = Convert(res, op) if err != nil { return err } - hc := d.Get("health_checks").(*schema.Set).List() - healthChecks := make([]string, 0, len(hc)) - for _, v := range hc { - healthChecks = append(healthChecks, v.(string)) - } + err = computeOperationWaitTime( + config.clientCompute, op, project, "Updating RegionBackendService", + int(d.Timeout(schema.TimeoutUpdate).Minutes())) - service := computeBeta.BackendService{ - Name: d.Get("name").(string), - Fingerprint: d.Get("fingerprint").(string), - HealthChecks: healthChecks, - LoadBalancingScheme: "INTERNAL", - } - - // Optional things - if v, ok := d.GetOk("backend"); ok { - service.Backends, err = expandBackends(v.(*schema.Set).List()) - if err != nil { - return err - } - } - if v, ok := d.GetOk("description"); ok { - service.Description = v.(string) - } - if v, ok := d.GetOk("protocol"); ok { - service.Protocol = v.(string) - } - if v, ok := d.GetOk("session_affinity"); ok { - service.SessionAffinity = v.(string) - } - if v, ok := d.GetOk("timeout_sec"); ok { - service.TimeoutSec = int64(v.(int)) - } - - if d.HasChange("connection_draining_timeout_sec") { - connectionDraining := &computeBeta.ConnectionDraining{ - DrainingTimeoutSec: int64(d.Get("connection_draining_timeout_sec").(int)), - } - - service.ConnectionDraining = connectionDraining - } - - log.Printf("[DEBUG] Updating existing Backend Service %q: %#v", d.Id(), service) - op, err := config.clientComputeBeta.RegionBackendServices.Update( - project, region, d.Id(), &service).Do() - if err != nil { - return fmt.Errorf("Error updating backend service: %s", err) - } - - d.SetId(service.Name) - - err = computeSharedOperationWait(config.clientCompute, op, project, "Updating Backend Service") if err != nil { return err } @@ -299,124 +427,236 @@ func resourceComputeRegionBackendServiceUpdate(d *schema.ResourceData, meta inte func resourceComputeRegionBackendServiceDelete(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) + url, err := replaceVars(d, config, "https://www.googleapis.com/compute/v1/projects/{{project}}/regions/{{region}}/backendServices/{{name}}") + if err != nil { + return err + } + + var obj map[string]interface{} + log.Printf("[DEBUG] Deleting RegionBackendService %q", d.Id()) + res, err := sendRequestWithTimeout(config, "DELETE", url, obj, d.Timeout(schema.TimeoutDelete)) + if err != nil { + return handleNotFoundError(err, d, "RegionBackendService") + } + project, err := getProject(d, config) if err != nil { return err } - - region, err := getRegion(d, config) + op := &compute.Operation{} + err = Convert(res, op) if err != nil { return err } - log.Printf("[DEBUG] Deleting backend service %s", d.Id()) - op, err := config.clientCompute.RegionBackendServices.Delete( - project, region, d.Id()).Do() - if err != nil { - return fmt.Errorf("Error deleting backend service: %s", err) - } + err = computeOperationWaitTime( + config.clientCompute, op, project, "Deleting RegionBackendService", + int(d.Timeout(schema.TimeoutDelete).Minutes())) - err = computeOperationWait(config.clientCompute, op, project, "Deleting Backend Service") if err != nil { return err } - d.SetId("") + log.Printf("[DEBUG] Finished deleting RegionBackendService %q: %#v", d.Id(), res) return nil } -func resourceGoogleComputeRegionBackendServiceBackendHash(v interface{}) int { +func resourceComputeRegionBackendServiceImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + config := meta.(*Config) + if err := parseImportId([]string{"projects/(?P[^/]+)/regions/(?P[^/]+)/backendServices/(?P[^/]+)", "(?P[^/]+)/(?P[^/]+)/(?P[^/]+)", "(?P[^/]+)"}, d, config); err != nil { + return nil, err + } + + // Replace import id for the resource id + id, err := replaceVars(d, config, "{{name}}") + if err != nil { + return nil, fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + return []*schema.ResourceData{d}, nil +} + +func flattenComputeRegionBackendServiceName(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenComputeRegionBackendServiceHealthChecks(v interface{}, d *schema.ResourceData) interface{} { if v == nil { - return 0 + return v } + return convertAndMapStringArr(v.([]interface{}), ConvertSelfLinkToV1) +} - var buf bytes.Buffer - m := v.(map[string]interface{}) +func flattenComputeRegionBackendServiceBackend(v interface{}, d *schema.ResourceData) interface{} { + if v == nil { + return v + } + l := v.([]interface{}) + transformed := schema.NewSet(resourceGoogleComputeBackendServiceBackendHash, []interface{}{}) + for _, raw := range l { + original := raw.(map[string]interface{}) + if len(original) < 1 { + // Do not include empty json objects coming back from the api + continue + } + transformed.Add(map[string]interface{}{ + "description": flattenComputeRegionBackendServiceBackendDescription(original["description"], d), + "group": flattenComputeRegionBackendServiceBackendGroup(original["group"], d), + }) + } + return transformed +} +func flattenComputeRegionBackendServiceBackendDescription(v interface{}, d *schema.ResourceData) interface{} { + return v +} - if group, err := getRelativePath(m["group"].(string)); err != nil { - log.Printf("[WARN] Error on retrieving relative path of instance group: %s", err) - buf.WriteString(fmt.Sprintf("%s-", m["group"].(string))) +func flattenComputeRegionBackendServiceBackendGroup(v interface{}, d *schema.ResourceData) interface{} { + if v == nil { + return v + } + return ConvertSelfLinkToV1(v.(string)) +} + +func flattenComputeRegionBackendServiceDescription(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenComputeRegionBackendServiceFingerprint(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenComputeRegionBackendServiceProtocol(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenComputeRegionBackendServiceSessionAffinity(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenComputeRegionBackendServiceRegion(v interface{}, d *schema.ResourceData) interface{} { + if v == nil { + return v + } + return NameFromSelfLinkStateFunc(v) +} + +func flattenComputeRegionBackendServiceTimeoutSec(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 flattenComputeRegionBackendServiceConnectionDrainingConnection_draining_timeout_sec(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 flattenComputeRegionBackendServiceLoadBalancingScheme(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func expandComputeRegionBackendServiceName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionBackendServiceHealthChecks(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + v = v.(*schema.Set).List() + return v, nil +} + +func expandComputeRegionBackendServiceBackend(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + v = v.(*schema.Set).List() + l := v.([]interface{}) + req := make([]interface{}, 0, len(l)) + for _, raw := range l { + if raw == nil { + continue + } + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedDescription, err := expandComputeRegionBackendServiceBackendDescription(original["description"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedDescription); val.IsValid() && !isEmptyValue(val) { + transformed["description"] = transformedDescription + } + + transformedGroup, err := expandComputeRegionBackendServiceBackendGroup(original["group"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedGroup); val.IsValid() && !isEmptyValue(val) { + transformed["group"] = transformedGroup + } + + req = append(req, transformed) + } + return req, nil +} + +func expandComputeRegionBackendServiceBackendDescription(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionBackendServiceBackendGroup(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionBackendServiceDescription(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionBackendServiceFingerprint(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionBackendServiceProtocol(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionBackendServiceSessionAffinity(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionBackendServiceRegion(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + f, err := parseGlobalFieldValue("regions", v.(string), "project", d, config, true) + if err != nil { + return nil, fmt.Errorf("Invalid value for region: %s", err) + } + return f.RelativeLink(), nil +} + +func expandComputeRegionBackendServiceTimeoutSec(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionBackendServiceConnectionDraining(d TerraformResourceData, config *Config) (interface{}, error) { + transformed := make(map[string]interface{}) + // Note that nesting flattened objects won't work because we don't handle them properly here. + transformedConnection_draining_timeout_sec, err := expandComputeRegionBackendServiceConnectionDrainingConnection_draining_timeout_sec(d.Get("connection_draining_timeout_sec"), d, config) + if err != nil { + return nil, err } else { - buf.WriteString(fmt.Sprintf("%s-", group)) + transformed["drainingTimeoutSec"] = transformedConnection_draining_timeout_sec } - if v, ok := m["description"]; ok { - buf.WriteString(fmt.Sprintf("%s-", v.(string))) - } - - return hashcode.String(buf.String()) + return transformed, nil } -func flattenRegionBackends(backends []*compute.Backend) []map[string]interface{} { - result := make([]map[string]interface{}, 0, len(backends)) - - for _, b := range backends { - data := make(map[string]interface{}) - - data["description"] = b.Description - data["group"] = b.Group - result = append(result, data) - } - - return result +func expandComputeRegionBackendServiceConnectionDrainingConnection_draining_timeout_sec(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil } -func expandBackends(configured []interface{}) ([]*computeBeta.Backend, error) { - backends := make([]*computeBeta.Backend, 0, len(configured)) - - for _, raw := range configured { - data := raw.(map[string]interface{}) - - g, ok := data["group"] - if !ok { - return nil, errors.New("google_compute_backend_service.backend.group must be set") - } - - b := computeBeta.Backend{ - Group: g.(string), - } - - if v, ok := data["balancing_mode"]; ok { - b.BalancingMode = v.(string) - } - if v, ok := data["capacity_scaler"]; ok { - b.CapacityScaler = v.(float64) - b.ForceSendFields = append(b.ForceSendFields, "CapacityScaler") - } - if v, ok := data["description"]; ok { - b.Description = v.(string) - } - if v, ok := data["max_rate"]; ok { - b.MaxRate = int64(v.(int)) - if b.MaxRate == 0 { - b.NullFields = append(b.NullFields, "MaxRate") - } - } - if v, ok := data["max_rate_per_instance"]; ok { - b.MaxRatePerInstance = v.(float64) - if b.MaxRatePerInstance == 0 { - b.NullFields = append(b.NullFields, "MaxRatePerInstance") - } - } - if v, ok := data["max_connections"]; ok { - b.MaxConnections = int64(v.(int)) - if b.MaxConnections == 0 { - b.NullFields = append(b.NullFields, "MaxConnections") - } - } - if v, ok := data["max_connections_per_instance"]; ok { - b.MaxConnectionsPerInstance = int64(v.(int)) - if b.MaxConnectionsPerInstance == 0 { - b.NullFields = append(b.NullFields, "MaxConnectionsPerInstance") - } - } - if v, ok := data["max_utilization"]; ok { - b.MaxUtilization = v.(float64) - b.ForceSendFields = append(b.ForceSendFields, "MaxUtilization") - } - - backends = append(backends, &b) - } - - return backends, nil +func expandComputeRegionBackendServiceLoadBalancingScheme(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil } diff --git a/google/resource_compute_region_backend_service_generated_test.go b/google/resource_compute_region_backend_service_generated_test.go new file mode 100644 index 00000000..b5e3cd1b --- /dev/null +++ b/google/resource_compute_region_backend_service_generated_test.go @@ -0,0 +1,96 @@ +// ---------------------------------------------------------------------------- +// +// *** 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" + "strings" + "testing" + + "github.com/hashicorp/terraform/helper/acctest" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" +) + +func TestAccComputeRegionBackendService_regionBackendServiceBasicExample(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: testAccCheckComputeRegionBackendServiceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccComputeRegionBackendService_regionBackendServiceBasicExample(context), + }, + { + ResourceName: "google_compute_region_backend_service.default", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccComputeRegionBackendService_regionBackendServiceBasicExample(context map[string]interface{}) string { + return Nprintf(` +resource "google_compute_region_backend_service" "default" { + name = "region-backend-service-%{random_suffix}" + region = "us-central1" + health_checks = ["${google_compute_health_check.default.self_link}"] + connection_draining_timeout_sec = 10 + session_affinity = "CLIENT_IP" +} + +resource "google_compute_health_check" "default" { + name = "health-check-%{random_suffix}" + check_interval_sec = 1 + timeout_sec = 1 + + tcp_health_check { + port = "80" + } +} +`, context) +} + +func testAccCheckComputeRegionBackendServiceDestroy(s *terraform.State) error { + for name, rs := range s.RootModule().Resources { + if rs.Type != "google_compute_region_backend_service" { + continue + } + if strings.HasPrefix(name, "data.") { + continue + } + + config := testAccProvider.Meta().(*Config) + + url, err := replaceVarsForTest(rs, "https://www.googleapis.com/compute/v1/projects/{{project}}/regions/{{region}}/backendServices/{{name}}") + if err != nil { + return err + } + + _, err = sendRequest(config, "GET", url, nil) + if err == nil { + return fmt.Errorf("ComputeRegionBackendService still exists at %s", url) + } + } + + return nil +} diff --git a/google/resource_compute_region_backend_service_test.go b/google/resource_compute_region_backend_service_test.go index c9358174..01436229 100644 --- a/google/resource_compute_region_backend_service_test.go +++ b/google/resource_compute_region_backend_service_test.go @@ -120,33 +120,6 @@ func TestAccComputeRegionBackendService_withBackendAndUpdate(t *testing.T) { } } -func TestAccComputeRegionBackendService_withConnectionDraining(t *testing.T) { - t.Parallel() - - serviceName := fmt.Sprintf("tf-test-%s", acctest.RandString(10)) - checkName := fmt.Sprintf("tf-test-%s", acctest.RandString(10)) - var svc compute.BackendService - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckComputeRegionBackendServiceDestroy, - Steps: []resource.TestStep{ - { - Config: testAccComputeRegionBackendService_withConnectionDraining(serviceName, checkName, 10), - Check: resource.ComposeTestCheckFunc( - testAccCheckComputeRegionBackendServiceExists( - "google_compute_region_backend_service.foobar", &svc), - ), - }, - }, - }) - - if svc.ConnectionDraining.DrainingTimeoutSec != 10 { - t.Errorf("Expected ConnectionDraining.DrainingTimeoutSec == 10, got %d", svc.ConnectionDraining.DrainingTimeoutSec) - } -} - func TestAccComputeRegionBackendService_withConnectionDrainingAndUpdate(t *testing.T) { t.Parallel() @@ -181,52 +154,6 @@ func TestAccComputeRegionBackendService_withConnectionDrainingAndUpdate(t *testi } } -func TestAccComputeRegionBackendService_withSessionAffinity(t *testing.T) { - t.Parallel() - - serviceName := fmt.Sprintf("tf-test-%s", acctest.RandString(10)) - checkName := fmt.Sprintf("tf-test-%s", acctest.RandString(10)) - var svc compute.BackendService - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckComputeRegionBackendServiceDestroy, - Steps: []resource.TestStep{ - { - Config: testAccComputeRegionBackendService_withSessionAffinity( - serviceName, checkName), - Check: resource.ComposeTestCheckFunc( - testAccCheckComputeRegionBackendServiceExists( - "google_compute_region_backend_service.foobar", &svc), - ), - }, - }, - }) - - if svc.SessionAffinity != "CLIENT_IP" { - t.Errorf("Expected Protocol to be CLIENT_IP, got %q", svc.SessionAffinity) - } -} - -func testAccCheckComputeRegionBackendServiceDestroy(s *terraform.State) error { - config := testAccProvider.Meta().(*Config) - - for _, rs := range s.RootModule().Resources { - if rs.Type != "google_compute_region_backend_service" { - continue - } - - _, err := config.clientCompute.RegionBackendServices.Get( - config.Project, config.Region, rs.Primary.ID).Do() - if err == nil { - return fmt.Errorf("Backend service still exists") - } - } - - return nil -} - func testAccCheckComputeRegionBackendServiceExists(n string, svc *compute.BackendService) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] @@ -361,28 +288,6 @@ resource "google_compute_health_check" "default" { `, serviceName, timeout, igName, itName, checkName) } -func testAccComputeRegionBackendService_withSessionAffinity(serviceName, checkName string) string { - return fmt.Sprintf(` -resource "google_compute_region_backend_service" "foobar" { - name = "%s" - health_checks = ["${google_compute_health_check.zero.self_link}"] - region = "us-central1" - session_affinity = "CLIENT_IP" - -} - -resource "google_compute_health_check" "zero" { - name = "%s" - check_interval_sec = 1 - timeout_sec = 1 - - tcp_health_check { - port = "80" - } -} -`, serviceName, checkName) -} - func testAccComputeRegionBackendService_withConnectionDraining(serviceName, checkName string, drainingTimeout int64) string { return fmt.Sprintf(` resource "google_compute_region_backend_service" "foobar" { diff --git a/website/docs/r/compute_region_backend_service.html.markdown b/website/docs/r/compute_region_backend_service.html.markdown index fb8f3d87..903d3dfe 100644 --- a/website/docs/r/compute_region_backend_service.html.markdown +++ b/website/docs/r/compute_region_backend_service.html.markdown @@ -1,62 +1,59 @@ --- +# ---------------------------------------------------------------------------- +# +# *** 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_region_backend_service" sidebar_current: "docs-google-compute-region-backend-service" description: |- - Creates a Region Backend Service resource for Google Compute Engine. + A Region Backend Service defines a regionally-scoped group of virtual + machines that will serve traffic for load balancing. --- # google\_compute\_region\_backend\_service -A Region Backend Service defines a regionally-scoped group of virtual machines that will serve traffic for load balancing. -For more information see [the official documentation](https://cloud.google.com/compute/docs/load-balancing/internal/) -and [API](https://cloud.google.com/compute/docs/reference/latest/regionBackendServices). +A Region Backend Service defines a regionally-scoped group of virtual +machines that will serve traffic for load balancing. -~> **Note**: Region backend services can only be used when using internal load balancing. For external load balancing, use - [`google_compute_backend_service`](compute_backend_service.html) instead. +Region backend services can only be used when using internal load balancing. +For external load balancing, use a global backend service instead. + + +To get more information about RegionBackendService, see: + +* [API documentation](https://cloud.google.com/compute/docs/reference/latest/regionBackendServices) +* How-to Guides + * [Internal TCP/UDP Load Balancing](https://cloud.google.com/compute/docs/load-balancing/internal/) + + +## Example Usage - Region Backend Service Basic -## Example Usage ```hcl -resource "google_compute_region_backend_service" "foobar" { - name = "blablah" - description = "Hello World 1234" - protocol = "TCP" - timeout_sec = 10 - session_affinity = "CLIENT_IP" - - backend { - group = "${google_compute_region_instance_group_manager.foo.instance_group}" - } - - health_checks = ["${google_compute_health_check.default.self_link}"] -} - -resource "google_compute_region_instance_group_manager" "foo" { - name = "terraform-test" - instance_template = "${google_compute_instance_template.foobar.self_link}" - base_instance_name = "foobar" - region = "us-central1" - target_size = 1 -} - -resource "google_compute_instance_template" "foobar" { - name = "terraform-test" - machine_type = "n1-standard-1" - - network_interface { - network = "default" - } - - disk { - source_image = "debian-cloud/debian-9" - auto_delete = true - boot = true - } +resource "google_compute_region_backend_service" "default" { + name = "region-backend-service" + region = "us-central1" + health_checks = ["${google_compute_health_check.default.self_link}"] + connection_draining_timeout_sec = 10 + session_affinity = "CLIENT_IP" } resource "google_compute_health_check" "default" { - name = "test" + name = "health-check" check_interval_sec = 1 timeout_sec = 1 @@ -70,51 +67,117 @@ resource "google_compute_health_check" "default" { The following arguments are supported: -* `name` - (Required) The name of the backend service. -* `health_checks` - (Required) Specifies a list of health checks - for checking the health of the backend service. Currently at most - one health check can be specified, and a health check is required. +* `name` - + (Required) + Name of the resource. Provided by the client when the resource is + created. The name must be 1-63 characters long, and comply with + RFC1035. Specifically, the name must be 1-63 characters long and match + the regular expression `[a-z]([-a-z0-9]*[a-z0-9])?` which means the + first character must be a lowercase letter, and all following + characters must be a dash, lowercase letter, or digit, except the last + character, which cannot be a dash. + +* `health_checks` - + (Required) + The list of HealthChecks for checking the health of the backend service. + Currently at most one health check can be specified, and a health check + is required. + - - - -* `backend` - (Optional) The list of backends that serve this BackendService. - Structure is documented below. -* `description` - (Optional) The textual description for the backend service. +* `backend` - + (Optional) + The list of backends that serve this RegionBackendService. Structure is documented below. -* `project` - (Optional) The ID of the project in which the resource belongs. If it - is not provided, the provider project is used. +* `description` - + (Optional) + An optional description of this resource. -* `protocol` - (Optional) The protocol for incoming requests. Defaults to - `TCP`. +* `protocol` - + (Optional) + The protocol this BackendService uses to communicate with backends. + The possible values are TCP and UDP, and the default is TCP. -* `session_affinity` - (Optional) How to distribute load. Options are `NONE` (no - affinity), `CLIENT_IP`, `CLIENT_IP_PROTO`, or `CLIENT_IP_PORT_PROTO`. - Defaults to `NONE`. +* `session_affinity` - + (Optional) + Type of session affinity to use. The default is NONE. + Can be NONE, CLIENT_IP, CLIENT_IP_PROTO, or CLIENT_IP_PORT_PROTO. + When the protocol is UDP, this field is not used. -* `region` - (Optional) The Region in which the created address should reside. - If it is not provided, the provider region is used. +* `region` - + (Optional) + The Region in which the created backend service should reside. + If it is not provided, the provider region is used. -* `timeout_sec` - (Optional) The number of secs to wait for a backend to respond - to a request before considering the request failed. Defaults to `30`. +* `timeout_sec` - + (Optional) + How many seconds to wait for the backend before considering it a + failed request. Default is 30 seconds. Valid range is [1, 86400]. + +* `connection_draining_timeout_sec` - + (Optional) + Time for which instance will be drained (not accept new + connections, but still work to finish started). + +* `load_balancing_scheme` - + (Optional) + This signifies what the ForwardingRule will be used for and can only + be INTERNAL for RegionBackendServices +* `project` - (Optional) The ID of the project in which the resource belongs. + If it is not provided, the provider project is used. -* `connection_draining_timeout_sec` - (Optional) Time for which instance will be drained -(not accept new connections, but still work to finish started ones). Defaults to `0`. The `backend` block supports: -* `group` - (Required) The name or URI of a Compute Engine instance group - (`google_compute_region_instance_group_manager.xyz.instance_group`) that can - receive traffic. Instance groups must contain at least one instance. +* `description` - + (Optional) + An optional description of this resource. + Provide this property when you create the resource. -* `description` - (Optional) Textual description for the backend. +* `group` - + (Optional) + The fully-qualified URL of an Instance Group. This defines the list + of instances that serve traffic. Member virtual machine + instances from each instance group must live in the same zone as + the instance group itself. No two backends in a backend service + are allowed to use same Instance Group resource. + Note that you must specify an Instance Group + resource using the fully-qualified URL, rather than a + partial URL. + The instance group must be within the same region as the BackendService. ## Attributes Reference -In addition to the arguments listed above, the following computed attributes are -exported: +In addition to the arguments listed above, the following computed attributes are exported: -* `fingerprint` - The fingerprint of the backend service. +* `fingerprint` - + Fingerprint of this resource. A hash of the contents stored in this + object. This field is used in optimistic locking. * `self_link` - The URI of the created resource. + + +## Timeouts + +This resource provides the following +[Timeouts](/docs/configuration/resources.html#timeouts) configuration options: + +- `create` - Default is 4 minutes. +- `update` - Default is 4 minutes. +- `delete` - Default is 4 minutes. + +## Import + +RegionBackendService can be imported using any of these accepted formats: + +``` +$ terraform import google_compute_region_backend_service.default projects/{{project}}/regions/{{region}}/backendServices/{{name}} +$ terraform import google_compute_region_backend_service.default {{project}}/{{region}}/{{name}} +$ terraform import google_compute_region_backend_service.default {{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.