diff --git a/google/import.go b/google/import.go new file mode 100644 index 00000000000..248c8390b4c --- /dev/null +++ b/google/import.go @@ -0,0 +1,66 @@ +package google + +import ( + "fmt" + "regexp" + "strings" +) + +// Parse an import id extracting field values using the given list of regexes. +// They are applied in order. The first in the list is tried first. +// +// e.g: +// - projects/(?P[^/]+)/regions/(?P[^/]+)/subnetworks/(?P[^/]+) (applied first) +// - (?P[^/]+)/(?P[^/]+)/(?P[^/]+), +// - (?P[^/]+) (applied last) +func parseImportId(idRegexes []string, d TerraformResourceData, config *Config) error { + for _, idFormat := range idRegexes { + re, err := regexp.Compile(idFormat) + + if err != nil { + return fmt.Errorf("Import is not supported. Invalid regex formats.") + } + + if fieldValues := re.FindStringSubmatch(d.Id()); fieldValues != nil { + // Starting at index 1, the first match is the full string. + for i := 1; i < len(fieldValues); i++ { + fieldName := re.SubexpNames()[i] + d.Set(fieldName, fieldValues[i]) + } + + // The first id format is applied first and contains all the fields. + err := setDefaultValues(idRegexes[0], d, config) + if err != nil { + return err + } + + return nil + } + } + return fmt.Errorf("Import id %q doesn't match any of the accepted formats: %v", d.Id(), idRegexes) +} + +func setDefaultValues(idRegex string, d TerraformResourceData, config *Config) error { + if _, ok := d.GetOk("project"); !ok && strings.Contains(idRegex, "?P") { + project, err := getProject(d, config) + if err != nil { + return err + } + d.Set("project", project) + } + if _, ok := d.GetOk("region"); !ok && strings.Contains(idRegex, "?P") { + region, err := getRegion(d, config) + if err != nil { + return err + } + d.Set("region", region) + } + if _, ok := d.GetOk("zone"); !ok && strings.Contains(idRegex, "?P") { + zone, err := getZone(d, config) + if err != nil { + return err + } + d.Set("zone", zone) + } + return nil +} diff --git a/google/import_test.go b/google/import_test.go new file mode 100644 index 00000000000..2ffb990cf21 --- /dev/null +++ b/google/import_test.go @@ -0,0 +1,147 @@ +package google + +import ( + "testing" +) + +func TestParseImportId(t *testing.T) { + regionalIdRegexes := []string{ + "projects/(?P[^/]+)/regions/(?P[^/]+)/subnetworks/(?P[^/]+)", + "(?P[^/]+)/(?P[^/]+)/(?P[^/]+)", + "(?P[^/]+)", + } + zonalIdRegexes := []string{ + "projects/(?P[^/]+)/zones/(?P[^/]+)/instances/(?P[^/]+)", + "(?P[^/]+)/(?P[^/]+)/(?P[^/]+)", + "(?P[^/]+)", + } + multipleNondefaultIdRegexes := []string{ + "projects/(?P[^/]+)/zones/(?P[^/]+)/clusters/(?P[^/]+)/nodePools/(?P[^/]+)", + "(?P[^/]+)/(?P[^/]+)/(?P[^/]+)/(?P[^/]+)", + "(?P[^/]+)/(?P[^/]+)", + } + + cases := map[string]struct { + ImportId string + IdRegexes []string + Config *Config + ExpectedSchemaValues map[string]interface{} + ExpectError bool + }{ + "full self_link": { + ImportId: "https://www.googleapis.com/compute/v1/projects/my-project/regions/my-region/subnetworks/my-subnetwork", + IdRegexes: regionalIdRegexes, + ExpectedSchemaValues: map[string]interface{}{ + "project": "my-project", + "region": "my-region", + "name": "my-subnetwork", + }, + }, + "relative self_link": { + ImportId: "projects/my-project/regions/my-region/subnetworks/my-subnetwork", + IdRegexes: regionalIdRegexes, + ExpectedSchemaValues: map[string]interface{}{ + "project": "my-project", + "region": "my-region", + "name": "my-subnetwork", + }, + }, + "short id": { + ImportId: "my-project/my-region/my-subnetwork", + IdRegexes: regionalIdRegexes, + ExpectedSchemaValues: map[string]interface{}{ + "project": "my-project", + "region": "my-region", + "name": "my-subnetwork", + }, + }, + "short id with default project and region": { + ImportId: "my-subnetwork", + Config: &Config{ + Project: "default-project", + Region: "default-region", + }, + IdRegexes: regionalIdRegexes, + ExpectedSchemaValues: map[string]interface{}{ + "project": "default-project", + "region": "default-region", + "name": "my-subnetwork", + }, + }, + "short id with default project and zone": { + ImportId: "my-instance", + Config: &Config{ + Project: "default-project", + Zone: "default-zone", + }, + IdRegexes: zonalIdRegexes, + ExpectedSchemaValues: map[string]interface{}{ + "project": "default-project", + "zone": "default-zone", + "name": "my-instance", + }, + }, + "short id with two nondefault fields with default project and zone": { + ImportId: "my-cluster/my-node-pool", + Config: &Config{ + Project: "default-project", + Zone: "default-zone", + }, + IdRegexes: multipleNondefaultIdRegexes, + ExpectedSchemaValues: map[string]interface{}{ + "project": "default-project", + "zone": "default-zone", + "cluster": "my-cluster", + "name": "my-node-pool", + }, + }, + "short id with default project and region inferred from default zone": { + ImportId: "my-subnetwork", + Config: &Config{ + Project: "default-project", + Zone: "us-east1-a", + }, + IdRegexes: regionalIdRegexes, + ExpectedSchemaValues: map[string]interface{}{ + "project": "default-project", + "region": "us-east1", + "name": "my-subnetwork", + }, + }, + "invalid import id": { + ImportId: "i/n/v/a/l/i/d", + IdRegexes: regionalIdRegexes, + ExpectError: true, + }, + "provider-level defaults not set": { + ImportId: "my-subnetwork", + IdRegexes: regionalIdRegexes, + ExpectError: true, + }, + } + + for tn, tc := range cases { + d := &ResourceDataMock{ + FieldsInSchema: make(map[string]interface{}), + id: tc.ImportId, + } + config := tc.Config + if config == nil { + config = &Config{} + } + + if err := parseImportId(tc.IdRegexes, d, config); err == nil { + for k, expectedValue := range tc.ExpectedSchemaValues { + if v, ok := d.GetOk(k); ok { + if v != expectedValue { + t.Errorf("%s failed; Expected value %q for field %q, got %q", tn, expectedValue, k, v) + } + } else { + t.Errorf("%s failed; Expected a value for field %q", tn, k) + } + } + } else if !tc.ExpectError { + t.Errorf("%s failed; unexpected error: %s", tn, err) + } + } +} diff --git a/google/resource_compute_backend_bucket.go b/google/resource_compute_backend_bucket.go index 0a501f6264a..a2bbe5e3772 100644 --- a/google/resource_compute_backend_bucket.go +++ b/google/resource_compute_backend_bucket.go @@ -17,6 +17,7 @@ package google import ( "fmt" "log" + "time" "github.com/hashicorp/terraform/helper/schema" compute "google.golang.org/api/compute/v1" @@ -33,6 +34,12 @@ func resourceComputeBackendBucket() *schema.Resource { State: resourceComputeBackendBucketImport, }, + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(4 * time.Minute), + Update: schema.DefaultTimeout(4 * time.Minute), + Delete: schema.DefaultTimeout(4 * time.Minute), + }, + Schema: map[string]*schema.Schema{ "bucket_name": { Type: schema.TypeString, @@ -109,7 +116,10 @@ func resourceComputeBackendBucketCreate(d *schema.ResourceData, meta interface{} return err } - waitErr := computeOperationWait(config.clientCompute, op, project, "Creating BackendBucket") + waitErr := computeOperationWaitTime( + config.clientCompute, op, project, "Creating BackendBucket", + int(d.Timeout(schema.TimeoutCreate).Minutes())) + if waitErr != nil { // The resource didn't actually create d.SetId("") @@ -169,7 +179,8 @@ func resourceComputeBackendBucketUpdate(d *schema.ResourceData, meta interface{} } log.Printf("[DEBUG] Updating BackendBucket %q: %#v", d.Id(), obj) - res, err := Put(config, url, obj) + res, err := sendRequest(config, "PUT", url, obj) + if err != nil { return fmt.Errorf("Error updating BackendBucket %q: %s", d.Id(), err) } @@ -180,7 +191,10 @@ func resourceComputeBackendBucketUpdate(d *schema.ResourceData, meta interface{} return err } - err = computeOperationWait(config.clientCompute, op, project, "Updating BackendBucket") + err = computeOperationWaitTime( + config.clientCompute, op, project, "Updating BackendBucket", + int(d.Timeout(schema.TimeoutUpdate).Minutes())) + if err != nil { return err } @@ -213,7 +227,10 @@ func resourceComputeBackendBucketDelete(d *schema.ResourceData, meta interface{} return err } - err = computeOperationWait(config.clientCompute, op, project, "Deleting BackendBucket") + err = computeOperationWaitTime( + config.clientCompute, op, project, "Deleting BackendBucket", + int(d.Timeout(schema.TimeoutDelete).Minutes())) + if err != nil { return err } @@ -222,7 +239,16 @@ func resourceComputeBackendBucketDelete(d *schema.ResourceData, meta interface{} } func resourceComputeBackendBucketImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { - d.Set("name", d.Id()) + config := meta.(*Config) + parseImportId([]string{"projects/(?P[^/]+)/global/backendBuckets/(?P[^/]+)", "(?P[^/]+)/(?P[^/]+)", "(?P[^/]+)"}, d, config) + + // 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 } diff --git a/google/resource_compute_http_health_check.go b/google/resource_compute_http_health_check.go index e995247f3bd..d83776b2d1b 100644 --- a/google/resource_compute_http_health_check.go +++ b/google/resource_compute_http_health_check.go @@ -1,87 +1,103 @@ +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated 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" + "time" "github.com/hashicorp/terraform/helper/schema" - "google.golang.org/api/compute/v1" + compute "google.golang.org/api/compute/v1" ) func resourceComputeHttpHealthCheck() *schema.Resource { return &schema.Resource{ Create: resourceComputeHttpHealthCheckCreate, Read: resourceComputeHttpHealthCheckRead, - Delete: resourceComputeHttpHealthCheckDelete, Update: resourceComputeHttpHealthCheckUpdate, + Delete: resourceComputeHttpHealthCheckDelete, + Importer: &schema.ResourceImporter{ - State: schema.ImportStatePassthrough, + State: resourceComputeHttpHealthCheckImport, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(4 * time.Minute), + Update: schema.DefaultTimeout(4 * time.Minute), + Delete: schema.DefaultTimeout(4 * time.Minute), }, Schema: map[string]*schema.Schema{ - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Required: true, ForceNew: true, }, - - "check_interval_sec": &schema.Schema{ + "check_interval_sec": { Type: schema.TypeInt, Optional: true, Default: 5, }, - - "description": &schema.Schema{ + "description": { Type: schema.TypeString, Optional: true, }, - - "healthy_threshold": &schema.Schema{ + "healthy_threshold": { Type: schema.TypeInt, Optional: true, Default: 2, }, - - "host": &schema.Schema{ + "host": { Type: schema.TypeString, Optional: true, }, - - "port": &schema.Schema{ + "port": { Type: schema.TypeInt, Optional: true, Default: 80, }, - - "project": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - ForceNew: true, - Computed: true, - }, - - "request_path": &schema.Schema{ + "request_path": { Type: schema.TypeString, Optional: true, Default: "/", }, - - "self_link": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - }, - - "timeout_sec": &schema.Schema{ + "timeout_sec": { Type: schema.TypeInt, Optional: true, Default: 5, }, - - "unhealthy_threshold": &schema.Schema{ + "unhealthy_threshold": { Type: schema.TypeInt, Optional: true, Default: 2, }, + "creation_timestamp": { + Type: schema.TypeString, + Computed: true, + }, + "project": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + "self_link": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, }, } } @@ -94,55 +110,56 @@ func resourceComputeHttpHealthCheckCreate(d *schema.ResourceData, meta interface return err } - // Build the parameter - hchk := &compute.HttpHealthCheck{ - Name: d.Get("name").(string), - } - // Optional things - if v, ok := d.GetOk("description"); ok { - hchk.Description = v.(string) - } - if v, ok := d.GetOk("host"); ok { - hchk.Host = v.(string) - } - if v, ok := d.GetOk("request_path"); ok { - hchk.RequestPath = v.(string) - } - if v, ok := d.GetOk("check_interval_sec"); ok { - hchk.CheckIntervalSec = int64(v.(int)) - } - if v, ok := d.GetOk("healthy_threshold"); ok { - hchk.HealthyThreshold = int64(v.(int)) - } - if v, ok := d.GetOk("port"); ok { - hchk.Port = int64(v.(int)) + obj := map[string]interface{}{ + "checkIntervalSec": expandComputeHttpHealthCheckCheckIntervalSec(d.Get("check_interval_sec")), + "description": expandComputeHttpHealthCheckDescription(d.Get("description")), + "healthyThreshold": expandComputeHttpHealthCheckHealthyThreshold(d.Get("healthy_threshold")), + "host": expandComputeHttpHealthCheckHost(d.Get("host")), + "name": expandComputeHttpHealthCheckName(d.Get("name")), + "port": expandComputeHttpHealthCheckPort(d.Get("port")), + "requestPath": expandComputeHttpHealthCheckRequestPath(d.Get("request_path")), + "timeoutSec": expandComputeHttpHealthCheckTimeoutSec(d.Get("timeout_sec")), + "unhealthyThreshold": expandComputeHttpHealthCheckUnhealthyThreshold(d.Get("unhealthy_threshold")), } - if v, ok := d.GetOk("timeout_sec"); ok { - hchk.TimeoutSec = int64(v.(int)) - } - if v, ok := d.GetOk("unhealthy_threshold"); ok { - hchk.UnhealthyThreshold = int64(v.(int)) + + url, err := replaceVars(d, config, "https://www.googleapis.com/compute/v1/projects/{{project}}/global/httpHealthChecks") + if err != nil { + return err } - log.Printf("[DEBUG] HttpHealthCheck insert request: %#v", hchk) - op, err := config.clientCompute.HttpHealthChecks.Insert( - project, hchk).Do() + log.Printf("[DEBUG] Creating new HttpHealthCheck: %#v", obj) + res, err := Post(config, url, obj) if err != nil { return fmt.Errorf("Error creating HttpHealthCheck: %s", err) } - // It probably maybe worked, so store the ID now - d.SetId(hchk.Name) + // Store the ID now + id, err := replaceVars(d, config, "{{name}}") + if err != nil { + return fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) - err = computeOperationWait(config.clientCompute, op, project, "Creating Http Health Check") + op := &compute.Operation{} + err = Convert(res, op) if err != nil { return err } + waitErr := computeOperationWaitTime( + config.clientCompute, op, project, "Creating HttpHealthCheck", + int(d.Timeout(schema.TimeoutCreate).Minutes())) + + if waitErr != nil { + // The resource didn't actually create + d.SetId("") + return waitErr + } + return resourceComputeHttpHealthCheckRead(d, meta) } -func resourceComputeHttpHealthCheckUpdate(d *schema.ResourceData, meta interface{}) error { +func resourceComputeHttpHealthCheckRead(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) project, err := getProject(d, config) @@ -150,47 +167,74 @@ func resourceComputeHttpHealthCheckUpdate(d *schema.ResourceData, meta interface return err } - // Build the parameter - hchk := &compute.HttpHealthCheck{ - Name: d.Get("name").(string), - } - // Optional things - if v, ok := d.GetOk("description"); ok { - hchk.Description = v.(string) - } - if v, ok := d.GetOk("host"); ok { - hchk.Host = v.(string) - } - if v, ok := d.GetOk("request_path"); ok { - hchk.RequestPath = v.(string) + url, err := replaceVars(d, config, "https://www.googleapis.com/compute/v1/projects/{{project}}/global/httpHealthChecks/{{name}}") + if err != nil { + return err } - if v, ok := d.GetOk("check_interval_sec"); ok { - hchk.CheckIntervalSec = int64(v.(int)) + + res, err := Get(config, url) + if err != nil { + return handleNotFoundError(err, d, fmt.Sprintf("ComputeHttpHealthCheck %q", d.Id())) } - if v, ok := d.GetOk("healthy_threshold"); ok { - hchk.HealthyThreshold = int64(v.(int)) + + d.Set("check_interval_sec", flattenComputeHttpHealthCheckCheckIntervalSec(res["checkIntervalSec"])) + d.Set("creation_timestamp", flattenComputeHttpHealthCheckCreationTimestamp(res["creationTimestamp"])) + d.Set("description", flattenComputeHttpHealthCheckDescription(res["description"])) + d.Set("healthy_threshold", flattenComputeHttpHealthCheckHealthyThreshold(res["healthyThreshold"])) + d.Set("host", flattenComputeHttpHealthCheckHost(res["host"])) + d.Set("name", flattenComputeHttpHealthCheckName(res["name"])) + d.Set("port", flattenComputeHttpHealthCheckPort(res["port"])) + d.Set("request_path", flattenComputeHttpHealthCheckRequestPath(res["requestPath"])) + d.Set("timeout_sec", flattenComputeHttpHealthCheckTimeoutSec(res["timeoutSec"])) + d.Set("unhealthy_threshold", flattenComputeHttpHealthCheckUnhealthyThreshold(res["unhealthyThreshold"])) + d.Set("self_link", res["selfLink"]) + d.Set("project", project) + + return nil +} + +func resourceComputeHttpHealthCheckUpdate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + project, err := getProject(d, config) + if err != nil { + return err } - if v, ok := d.GetOk("port"); ok { - hchk.Port = int64(v.(int)) + + obj := map[string]interface{}{ + "checkIntervalSec": expandComputeHttpHealthCheckCheckIntervalSec(d.Get("check_interval_sec")), + "description": expandComputeHttpHealthCheckDescription(d.Get("description")), + "healthyThreshold": expandComputeHttpHealthCheckHealthyThreshold(d.Get("healthy_threshold")), + "host": expandComputeHttpHealthCheckHost(d.Get("host")), + "name": expandComputeHttpHealthCheckName(d.Get("name")), + "port": expandComputeHttpHealthCheckPort(d.Get("port")), + "requestPath": expandComputeHttpHealthCheckRequestPath(d.Get("request_path")), + "timeoutSec": expandComputeHttpHealthCheckTimeoutSec(d.Get("timeout_sec")), + "unhealthyThreshold": expandComputeHttpHealthCheckUnhealthyThreshold(d.Get("unhealthy_threshold")), } - if v, ok := d.GetOk("timeout_sec"); ok { - hchk.TimeoutSec = int64(v.(int)) + + url, err := replaceVars(d, config, "https://www.googleapis.com/compute/v1/projects/{{project}}/global/httpHealthChecks/{{name}}") + if err != nil { + return err } - if v, ok := d.GetOk("unhealthy_threshold"); ok { - hchk.UnhealthyThreshold = int64(v.(int)) + + log.Printf("[DEBUG] Updating HttpHealthCheck %q: %#v", d.Id(), obj) + res, err := sendRequest(config, "PUT", url, obj) + + if err != nil { + return fmt.Errorf("Error updating HttpHealthCheck %q: %s", d.Id(), err) } - log.Printf("[DEBUG] HttpHealthCheck patch request: %#v", hchk) - op, err := config.clientCompute.HttpHealthChecks.Patch( - project, hchk.Name, hchk).Do() + op := &compute.Operation{} + err = Convert(res, op) if err != nil { - return fmt.Errorf("Error patching HttpHealthCheck: %s", err) + return err } - // It probably maybe worked, so store the ID now - d.SetId(hchk.Name) + err = computeOperationWaitTime( + config.clientCompute, op, project, "Updating HttpHealthCheck", + int(d.Timeout(schema.TimeoutUpdate).Minutes())) - err = computeOperationWait(config.clientCompute, op, project, "Updating Http Health Check") if err != nil { return err } @@ -198,7 +242,7 @@ func resourceComputeHttpHealthCheckUpdate(d *schema.ResourceData, meta interface return resourceComputeHttpHealthCheckRead(d, meta) } -func resourceComputeHttpHealthCheckRead(d *schema.ResourceData, meta interface{}) error { +func resourceComputeHttpHealthCheckDelete(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) project, err := getProject(d, config) @@ -206,47 +250,120 @@ func resourceComputeHttpHealthCheckRead(d *schema.ResourceData, meta interface{} return err } - hchk, err := config.clientCompute.HttpHealthChecks.Get( - project, d.Id()).Do() + url, err := replaceVars(d, config, "https://www.googleapis.com/compute/v1/projects/{{project}}/global/httpHealthChecks/{{name}}") if err != nil { - return handleNotFoundError(err, d, fmt.Sprintf("HTTP Health Check %q", d.Get("name").(string))) + return err } - d.Set("host", hchk.Host) - d.Set("request_path", hchk.RequestPath) - d.Set("check_interval_sec", hchk.CheckIntervalSec) - d.Set("healthy_threshold", hchk.HealthyThreshold) - d.Set("port", hchk.Port) - d.Set("timeout_sec", hchk.TimeoutSec) - d.Set("unhealthy_threshold", hchk.UnhealthyThreshold) - d.Set("self_link", hchk.SelfLink) - d.Set("name", hchk.Name) - d.Set("description", hchk.Description) - d.Set("project", project) - - return nil -} - -func resourceComputeHttpHealthCheckDelete(d *schema.ResourceData, meta interface{}) error { - config := meta.(*Config) - - project, err := getProject(d, config) + log.Printf("[DEBUG] Deleting HttpHealthCheck %q", d.Id()) + res, err := Delete(config, url) if err != nil { - return err + return fmt.Errorf("Error deleting HttpHealthCheck %q: %s", d.Id(), err) } - // Delete the HttpHealthCheck - op, err := config.clientCompute.HttpHealthChecks.Delete( - project, d.Id()).Do() + op := &compute.Operation{} + err = Convert(res, op) if err != nil { - return fmt.Errorf("Error deleting HttpHealthCheck: %s", err) + return err } - err = computeOperationWait(config.clientCompute, op, project, "Deleting Http Health Check") + err = computeOperationWaitTime( + config.clientCompute, op, project, "Deleting HttpHealthCheck", + int(d.Timeout(schema.TimeoutDelete).Minutes())) + if err != nil { return err } - d.SetId("") return nil } + +func resourceComputeHttpHealthCheckImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + config := meta.(*Config) + parseImportId([]string{"projects/(?P[^/]+)/global/httpHealthChecks/(?P[^/]+)", "(?P[^/]+)/(?P[^/]+)", "(?P[^/]+)"}, d, config) + + // 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 flattenComputeHttpHealthCheckCheckIntervalSec(v interface{}) interface{} { + return v +} + +func flattenComputeHttpHealthCheckCreationTimestamp(v interface{}) interface{} { + return v +} + +func flattenComputeHttpHealthCheckDescription(v interface{}) interface{} { + return v +} + +func flattenComputeHttpHealthCheckHealthyThreshold(v interface{}) interface{} { + return v +} + +func flattenComputeHttpHealthCheckHost(v interface{}) interface{} { + return v +} + +func flattenComputeHttpHealthCheckName(v interface{}) interface{} { + return v +} + +func flattenComputeHttpHealthCheckPort(v interface{}) interface{} { + return v +} + +func flattenComputeHttpHealthCheckRequestPath(v interface{}) interface{} { + return v +} + +func flattenComputeHttpHealthCheckTimeoutSec(v interface{}) interface{} { + return v +} + +func flattenComputeHttpHealthCheckUnhealthyThreshold(v interface{}) interface{} { + return v +} + +func expandComputeHttpHealthCheckCheckIntervalSec(v interface{}) interface{} { + return v +} + +func expandComputeHttpHealthCheckDescription(v interface{}) interface{} { + return v +} + +func expandComputeHttpHealthCheckHealthyThreshold(v interface{}) interface{} { + return v +} + +func expandComputeHttpHealthCheckHost(v interface{}) interface{} { + return v +} + +func expandComputeHttpHealthCheckName(v interface{}) interface{} { + return v +} + +func expandComputeHttpHealthCheckPort(v interface{}) interface{} { + return v +} + +func expandComputeHttpHealthCheckRequestPath(v interface{}) interface{} { + return v +} + +func expandComputeHttpHealthCheckTimeoutSec(v interface{}) interface{} { + return v +} + +func expandComputeHttpHealthCheckUnhealthyThreshold(v interface{}) interface{} { + return v +} diff --git a/google/resource_compute_https_health_check.go b/google/resource_compute_https_health_check.go index d0ea44922fa..4d44f4d0fcf 100644 --- a/google/resource_compute_https_health_check.go +++ b/google/resource_compute_https_health_check.go @@ -1,87 +1,103 @@ +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated 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" + "time" "github.com/hashicorp/terraform/helper/schema" - "google.golang.org/api/compute/v1" + compute "google.golang.org/api/compute/v1" ) func resourceComputeHttpsHealthCheck() *schema.Resource { return &schema.Resource{ Create: resourceComputeHttpsHealthCheckCreate, Read: resourceComputeHttpsHealthCheckRead, - Delete: resourceComputeHttpsHealthCheckDelete, Update: resourceComputeHttpsHealthCheckUpdate, + Delete: resourceComputeHttpsHealthCheckDelete, + Importer: &schema.ResourceImporter{ - State: schema.ImportStatePassthrough, + State: resourceComputeHttpsHealthCheckImport, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(4 * time.Minute), + Update: schema.DefaultTimeout(4 * time.Minute), + Delete: schema.DefaultTimeout(4 * time.Minute), }, Schema: map[string]*schema.Schema{ - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Required: true, ForceNew: true, }, - - "check_interval_sec": &schema.Schema{ + "check_interval_sec": { Type: schema.TypeInt, Optional: true, Default: 5, }, - - "description": &schema.Schema{ + "description": { Type: schema.TypeString, Optional: true, }, - - "healthy_threshold": &schema.Schema{ + "healthy_threshold": { Type: schema.TypeInt, Optional: true, Default: 2, }, - - "host": &schema.Schema{ + "host": { Type: schema.TypeString, Optional: true, }, - - "port": &schema.Schema{ + "port": { Type: schema.TypeInt, Optional: true, Default: 443, }, - - "project": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Computed: true, - ForceNew: true, - }, - - "request_path": &schema.Schema{ + "request_path": { Type: schema.TypeString, Optional: true, Default: "/", }, - - "self_link": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - }, - - "timeout_sec": &schema.Schema{ + "timeout_sec": { Type: schema.TypeInt, Optional: true, Default: 5, }, - - "unhealthy_threshold": &schema.Schema{ + "unhealthy_threshold": { Type: schema.TypeInt, Optional: true, Default: 2, }, + "creation_timestamp": { + Type: schema.TypeString, + Computed: true, + }, + "project": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + "self_link": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, }, } } @@ -94,55 +110,56 @@ func resourceComputeHttpsHealthCheckCreate(d *schema.ResourceData, meta interfac return err } - // Build the parameter - hchk := &compute.HttpsHealthCheck{ - Name: d.Get("name").(string), - } - // Optional things - if v, ok := d.GetOk("description"); ok { - hchk.Description = v.(string) - } - if v, ok := d.GetOk("host"); ok { - hchk.Host = v.(string) - } - if v, ok := d.GetOk("request_path"); ok { - hchk.RequestPath = v.(string) - } - if v, ok := d.GetOk("check_interval_sec"); ok { - hchk.CheckIntervalSec = int64(v.(int)) - } - if v, ok := d.GetOk("healthy_threshold"); ok { - hchk.HealthyThreshold = int64(v.(int)) - } - if v, ok := d.GetOk("port"); ok { - hchk.Port = int64(v.(int)) + obj := map[string]interface{}{ + "checkIntervalSec": expandComputeHttpsHealthCheckCheckIntervalSec(d.Get("check_interval_sec")), + "description": expandComputeHttpsHealthCheckDescription(d.Get("description")), + "healthyThreshold": expandComputeHttpsHealthCheckHealthyThreshold(d.Get("healthy_threshold")), + "host": expandComputeHttpsHealthCheckHost(d.Get("host")), + "name": expandComputeHttpsHealthCheckName(d.Get("name")), + "port": expandComputeHttpsHealthCheckPort(d.Get("port")), + "requestPath": expandComputeHttpsHealthCheckRequestPath(d.Get("request_path")), + "timeoutSec": expandComputeHttpsHealthCheckTimeoutSec(d.Get("timeout_sec")), + "unhealthyThreshold": expandComputeHttpsHealthCheckUnhealthyThreshold(d.Get("unhealthy_threshold")), } - if v, ok := d.GetOk("timeout_sec"); ok { - hchk.TimeoutSec = int64(v.(int)) - } - if v, ok := d.GetOk("unhealthy_threshold"); ok { - hchk.UnhealthyThreshold = int64(v.(int)) + + url, err := replaceVars(d, config, "https://www.googleapis.com/compute/v1/projects/{{project}}/global/httpsHealthChecks") + if err != nil { + return err } - log.Printf("[DEBUG] HttpsHealthCheck insert request: %#v", hchk) - op, err := config.clientCompute.HttpsHealthChecks.Insert( - project, hchk).Do() + log.Printf("[DEBUG] Creating new HttpsHealthCheck: %#v", obj) + res, err := Post(config, url, obj) if err != nil { return fmt.Errorf("Error creating HttpsHealthCheck: %s", err) } - // It probably maybe worked, so store the ID now - d.SetId(hchk.Name) + // Store the ID now + id, err := replaceVars(d, config, "{{name}}") + if err != nil { + return fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) - err = computeOperationWait(config.clientCompute, op, project, "Creating Https Health Check") + op := &compute.Operation{} + err = Convert(res, op) if err != nil { return err } + waitErr := computeOperationWaitTime( + config.clientCompute, op, project, "Creating HttpsHealthCheck", + int(d.Timeout(schema.TimeoutCreate).Minutes())) + + if waitErr != nil { + // The resource didn't actually create + d.SetId("") + return waitErr + } + return resourceComputeHttpsHealthCheckRead(d, meta) } -func resourceComputeHttpsHealthCheckUpdate(d *schema.ResourceData, meta interface{}) error { +func resourceComputeHttpsHealthCheckRead(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) project, err := getProject(d, config) @@ -150,47 +167,74 @@ func resourceComputeHttpsHealthCheckUpdate(d *schema.ResourceData, meta interfac return err } - // Build the parameter - hchk := &compute.HttpsHealthCheck{ - Name: d.Get("name").(string), - } - // Optional things - if v, ok := d.GetOk("description"); ok { - hchk.Description = v.(string) - } - if v, ok := d.GetOk("host"); ok { - hchk.Host = v.(string) - } - if v, ok := d.GetOk("request_path"); ok { - hchk.RequestPath = v.(string) + url, err := replaceVars(d, config, "https://www.googleapis.com/compute/v1/projects/{{project}}/global/httpsHealthChecks/{{name}}") + if err != nil { + return err } - if v, ok := d.GetOk("check_interval_sec"); ok { - hchk.CheckIntervalSec = int64(v.(int)) + + res, err := Get(config, url) + if err != nil { + return handleNotFoundError(err, d, fmt.Sprintf("ComputeHttpsHealthCheck %q", d.Id())) } - if v, ok := d.GetOk("healthy_threshold"); ok { - hchk.HealthyThreshold = int64(v.(int)) + + d.Set("check_interval_sec", flattenComputeHttpsHealthCheckCheckIntervalSec(res["checkIntervalSec"])) + d.Set("creation_timestamp", flattenComputeHttpsHealthCheckCreationTimestamp(res["creationTimestamp"])) + d.Set("description", flattenComputeHttpsHealthCheckDescription(res["description"])) + d.Set("healthy_threshold", flattenComputeHttpsHealthCheckHealthyThreshold(res["healthyThreshold"])) + d.Set("host", flattenComputeHttpsHealthCheckHost(res["host"])) + d.Set("name", flattenComputeHttpsHealthCheckName(res["name"])) + d.Set("port", flattenComputeHttpsHealthCheckPort(res["port"])) + d.Set("request_path", flattenComputeHttpsHealthCheckRequestPath(res["requestPath"])) + d.Set("timeout_sec", flattenComputeHttpsHealthCheckTimeoutSec(res["timeoutSec"])) + d.Set("unhealthy_threshold", flattenComputeHttpsHealthCheckUnhealthyThreshold(res["unhealthyThreshold"])) + d.Set("self_link", res["selfLink"]) + d.Set("project", project) + + return nil +} + +func resourceComputeHttpsHealthCheckUpdate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + project, err := getProject(d, config) + if err != nil { + return err } - if v, ok := d.GetOk("port"); ok { - hchk.Port = int64(v.(int)) + + obj := map[string]interface{}{ + "checkIntervalSec": expandComputeHttpsHealthCheckCheckIntervalSec(d.Get("check_interval_sec")), + "description": expandComputeHttpsHealthCheckDescription(d.Get("description")), + "healthyThreshold": expandComputeHttpsHealthCheckHealthyThreshold(d.Get("healthy_threshold")), + "host": expandComputeHttpsHealthCheckHost(d.Get("host")), + "name": expandComputeHttpsHealthCheckName(d.Get("name")), + "port": expandComputeHttpsHealthCheckPort(d.Get("port")), + "requestPath": expandComputeHttpsHealthCheckRequestPath(d.Get("request_path")), + "timeoutSec": expandComputeHttpsHealthCheckTimeoutSec(d.Get("timeout_sec")), + "unhealthyThreshold": expandComputeHttpsHealthCheckUnhealthyThreshold(d.Get("unhealthy_threshold")), } - if v, ok := d.GetOk("timeout_sec"); ok { - hchk.TimeoutSec = int64(v.(int)) + + url, err := replaceVars(d, config, "https://www.googleapis.com/compute/v1/projects/{{project}}/global/httpsHealthChecks/{{name}}") + if err != nil { + return err } - if v, ok := d.GetOk("unhealthy_threshold"); ok { - hchk.UnhealthyThreshold = int64(v.(int)) + + log.Printf("[DEBUG] Updating HttpsHealthCheck %q: %#v", d.Id(), obj) + res, err := sendRequest(config, "PUT", url, obj) + + if err != nil { + return fmt.Errorf("Error updating HttpsHealthCheck %q: %s", d.Id(), err) } - log.Printf("[DEBUG] HttpsHealthCheck patch request: %#v", hchk) - op, err := config.clientCompute.HttpsHealthChecks.Patch( - project, hchk.Name, hchk).Do() + op := &compute.Operation{} + err = Convert(res, op) if err != nil { - return fmt.Errorf("Error patching HttpsHealthCheck: %s", err) + return err } - // It probably maybe worked, so store the ID now - d.SetId(hchk.Name) + err = computeOperationWaitTime( + config.clientCompute, op, project, "Updating HttpsHealthCheck", + int(d.Timeout(schema.TimeoutUpdate).Minutes())) - err = computeOperationWait(config.clientCompute, op, project, "Updating Https Health Check") if err != nil { return err } @@ -198,7 +242,7 @@ func resourceComputeHttpsHealthCheckUpdate(d *schema.ResourceData, meta interfac return resourceComputeHttpsHealthCheckRead(d, meta) } -func resourceComputeHttpsHealthCheckRead(d *schema.ResourceData, meta interface{}) error { +func resourceComputeHttpsHealthCheckDelete(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) project, err := getProject(d, config) @@ -206,47 +250,120 @@ func resourceComputeHttpsHealthCheckRead(d *schema.ResourceData, meta interface{ return err } - hchk, err := config.clientCompute.HttpsHealthChecks.Get( - project, d.Id()).Do() + url, err := replaceVars(d, config, "https://www.googleapis.com/compute/v1/projects/{{project}}/global/httpsHealthChecks/{{name}}") if err != nil { - return handleNotFoundError(err, d, fmt.Sprintf("HTTPS Health Check %q", d.Get("name").(string))) + return err } - d.Set("name", hchk.Name) - d.Set("description", hchk.Description) - d.Set("host", hchk.Host) - d.Set("request_path", hchk.RequestPath) - d.Set("check_interval_sec", hchk.CheckIntervalSec) - d.Set("healthy_threshold", hchk.HealthyThreshold) - d.Set("port", hchk.Port) - d.Set("timeout_sec", hchk.TimeoutSec) - d.Set("unhealthy_threshold", hchk.UnhealthyThreshold) - d.Set("project", project) - d.Set("self_link", hchk.SelfLink) - - return nil -} - -func resourceComputeHttpsHealthCheckDelete(d *schema.ResourceData, meta interface{}) error { - config := meta.(*Config) - - project, err := getProject(d, config) + log.Printf("[DEBUG] Deleting HttpsHealthCheck %q", d.Id()) + res, err := Delete(config, url) if err != nil { - return err + return fmt.Errorf("Error deleting HttpsHealthCheck %q: %s", d.Id(), err) } - // Delete the HttpsHealthCheck - op, err := config.clientCompute.HttpsHealthChecks.Delete( - project, d.Id()).Do() + op := &compute.Operation{} + err = Convert(res, op) if err != nil { - return fmt.Errorf("Error deleting HttpsHealthCheck: %s", err) + return err } - err = computeOperationWait(config.clientCompute, op, project, "Deleting Https Health Check") + err = computeOperationWaitTime( + config.clientCompute, op, project, "Deleting HttpsHealthCheck", + int(d.Timeout(schema.TimeoutDelete).Minutes())) + if err != nil { return err } - d.SetId("") return nil } + +func resourceComputeHttpsHealthCheckImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + config := meta.(*Config) + parseImportId([]string{"projects/(?P[^/]+)/global/httpsHealthChecks/(?P[^/]+)", "(?P[^/]+)/(?P[^/]+)", "(?P[^/]+)"}, d, config) + + // 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 flattenComputeHttpsHealthCheckCheckIntervalSec(v interface{}) interface{} { + return v +} + +func flattenComputeHttpsHealthCheckCreationTimestamp(v interface{}) interface{} { + return v +} + +func flattenComputeHttpsHealthCheckDescription(v interface{}) interface{} { + return v +} + +func flattenComputeHttpsHealthCheckHealthyThreshold(v interface{}) interface{} { + return v +} + +func flattenComputeHttpsHealthCheckHost(v interface{}) interface{} { + return v +} + +func flattenComputeHttpsHealthCheckName(v interface{}) interface{} { + return v +} + +func flattenComputeHttpsHealthCheckPort(v interface{}) interface{} { + return v +} + +func flattenComputeHttpsHealthCheckRequestPath(v interface{}) interface{} { + return v +} + +func flattenComputeHttpsHealthCheckTimeoutSec(v interface{}) interface{} { + return v +} + +func flattenComputeHttpsHealthCheckUnhealthyThreshold(v interface{}) interface{} { + return v +} + +func expandComputeHttpsHealthCheckCheckIntervalSec(v interface{}) interface{} { + return v +} + +func expandComputeHttpsHealthCheckDescription(v interface{}) interface{} { + return v +} + +func expandComputeHttpsHealthCheckHealthyThreshold(v interface{}) interface{} { + return v +} + +func expandComputeHttpsHealthCheckHost(v interface{}) interface{} { + return v +} + +func expandComputeHttpsHealthCheckName(v interface{}) interface{} { + return v +} + +func expandComputeHttpsHealthCheckPort(v interface{}) interface{} { + return v +} + +func expandComputeHttpsHealthCheckRequestPath(v interface{}) interface{} { + return v +} + +func expandComputeHttpsHealthCheckTimeoutSec(v interface{}) interface{} { + return v +} + +func expandComputeHttpsHealthCheckUnhealthyThreshold(v interface{}) interface{} { + return v +} diff --git a/google/transport.go b/google/transport.go index 94a6500ca30..ba7d80ca374 100644 --- a/google/transport.go +++ b/google/transport.go @@ -4,11 +4,10 @@ import ( "bytes" "encoding/json" "net/http" + "reflect" "regexp" "strings" - "reflect" - "google.golang.org/api/googleapi" ) diff --git a/website/docs/r/compute_backend_bucket.html.markdown b/website/docs/r/compute_backend_bucket.html.markdown index 82b2560e01d..54f56856028 100644 --- a/website/docs/r/compute_backend_bucket.html.markdown +++ b/website/docs/r/compute_backend_bucket.html.markdown @@ -56,6 +56,15 @@ In addition to the arguments listed above, the following computed attributes are * `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 Backend buckets can be imported using the `name`, e.g. diff --git a/website/docs/r/compute_http_health_check.html.markdown b/website/docs/r/compute_http_health_check.html.markdown index 12a5ff37387..fcb43fb7dfc 100644 --- a/website/docs/r/compute_http_health_check.html.markdown +++ b/website/docs/r/compute_http_health_check.html.markdown @@ -65,8 +65,19 @@ The following arguments are supported: In addition to the arguments listed above, the following computed attributes are exported: +* `creation_timestamp` - Creation timestamp in RFC3339 text format. + * `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 HTTP health checks can be imported using the `name`, e.g. diff --git a/website/docs/r/compute_https_health_check.html.markdown b/website/docs/r/compute_https_health_check.html.markdown index 119bed85bb8..945e741b240 100644 --- a/website/docs/r/compute_https_health_check.html.markdown +++ b/website/docs/r/compute_https_health_check.html.markdown @@ -62,8 +62,19 @@ The following arguments are supported: The following attributes are exported: +* `creation_timestamp` - Creation timestamp in RFC3339 text format. + * `self_link` - The URL 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 HTTPS health checks can be imported using the `name`, e.g.