From 04002f5406d57681f3b76b4408c30a6a42b56221 Mon Sep 17 00:00:00 2001 From: Chris Sng Date: Mon, 9 Sep 2019 17:21:39 +0000 Subject: [PATCH] Allow updating of resource policies in compute_disk Signed-off-by: Modular Magician --- google/provider.go | 6 +- ...compute_disk_resource_policy_attachment.go | 331 +++++++ ...te_disk_resource_policy_attachment_test.go | 80 ++ google/resource_compute_resource_policy.go | 876 ++++++++++++++++++ ..._compute_resource_policy_generated_test.go | 143 +++ google/utils.go | 13 +- google/utils_test.go | 34 - ...k_resource_policy_attachment.html.markdown | 81 ++ .../r/compute_resource_policy.html.markdown | 238 +++++ 9 files changed, 1754 insertions(+), 48 deletions(-) create mode 100644 google/resource_compute_disk_resource_policy_attachment.go create mode 100644 google/resource_compute_disk_resource_policy_attachment_test.go create mode 100644 google/resource_compute_resource_policy.go create mode 100644 google/resource_compute_resource_policy_generated_test.go create mode 100644 website/docs/r/compute_disk_resource_policy_attachment.html.markdown create mode 100644 website/docs/r/compute_resource_policy.html.markdown diff --git a/google/provider.go b/google/provider.go index 2a51a49d308..328b1fa1d9a 100644 --- a/google/provider.go +++ b/google/provider.go @@ -414,9 +414,9 @@ func Provider() terraform.ResourceProvider { return provider } -// Generated resources: 78 +// Generated resources: 80 // Generated IAM resources: 18 -// Total generated resources: 96 +// Total generated resources: 98 func ResourceMap() map[string]*schema.Resource { resourceMap, _ := ResourceMapWithErrors() return resourceMap @@ -445,6 +445,7 @@ func ResourceMapWithErrors() (map[string]*schema.Resource, error) { "google_compute_backend_service": resourceComputeBackendService(), "google_compute_region_backend_service": resourceComputeRegionBackendService(), "google_compute_backend_service_signed_url_key": resourceComputeBackendServiceSignedUrlKey(), + "google_compute_disk_resource_policy_attachment": resourceComputeDiskResourcePolicyAttachment(), "google_compute_disk": resourceComputeDisk(), "google_compute_firewall": resourceComputeFirewall(), "google_compute_forwarding_rule": resourceComputeForwardingRule(), @@ -462,6 +463,7 @@ func ResourceMapWithErrors() (map[string]*schema.Resource, error) { "google_compute_node_template": resourceComputeNodeTemplate(), "google_compute_region_autoscaler": resourceComputeRegionAutoscaler(), "google_compute_region_disk": resourceComputeRegionDisk(), + "google_compute_resource_policy": resourceComputeResourcePolicy(), "google_compute_route": resourceComputeRoute(), "google_compute_router": resourceComputeRouter(), "google_compute_snapshot": resourceComputeSnapshot(), diff --git a/google/resource_compute_disk_resource_policy_attachment.go b/google/resource_compute_disk_resource_policy_attachment.go new file mode 100644 index 00000000000..4746d1a8f97 --- /dev/null +++ b/google/resource_compute_disk_resource_policy_attachment.go @@ -0,0 +1,331 @@ +// ---------------------------------------------------------------------------- +// +// *** 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 resourceComputeDiskResourcePolicyAttachment() *schema.Resource { + return &schema.Resource{ + Create: resourceComputeDiskResourcePolicyAttachmentCreate, + Read: resourceComputeDiskResourcePolicyAttachmentRead, + Delete: resourceComputeDiskResourcePolicyAttachmentDelete, + + Importer: &schema.ResourceImporter{ + State: resourceComputeDiskResourcePolicyAttachmentImport, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(4 * time.Minute), + Delete: schema.DefaultTimeout(4 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "disk": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + DiffSuppressFunc: compareSelfLinkOrResourceName, + }, + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "zone": { + Type: schema.TypeString, + Computed: true, + Optional: true, + ForceNew: true, + DiffSuppressFunc: compareSelfLinkOrResourceName, + }, + "project": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + }, + } +} + +func resourceComputeDiskResourcePolicyAttachmentCreate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + obj := make(map[string]interface{}) + nameProp, err := expandComputeDiskResourcePolicyAttachmentName(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 + } + + obj, err = resourceComputeDiskResourcePolicyAttachmentEncoder(d, meta, obj) + if err != nil { + return err + } + + url, err := replaceVars(d, config, "{{ComputeBasePath}}projects/{{project}}/zones/{{zone}}/disks/{{disk}}/addResourcePolicies") + if err != nil { + return err + } + + log.Printf("[DEBUG] Creating new DiskResourcePolicyAttachment: %#v", obj) + project, err := getProject(d, config) + if err != nil { + return err + } + res, err := sendRequestWithTimeout(config, "POST", project, url, obj, d.Timeout(schema.TimeoutCreate)) + if err != nil { + return fmt.Errorf("Error creating DiskResourcePolicyAttachment: %s", err) + } + + // Store the ID now + id, err := replaceVars(d, config, "{{project}}/{{zone}}/{{disk}}/{{name}}") + if err != nil { + return fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + op := &compute.Operation{} + err = Convert(res, op) + if err != nil { + return err + } + + waitErr := computeOperationWaitTime( + config.clientCompute, op, project, "Creating DiskResourcePolicyAttachment", + int(d.Timeout(schema.TimeoutCreate).Minutes())) + + if waitErr != nil { + // The resource didn't actually create + d.SetId("") + return fmt.Errorf("Error waiting to create DiskResourcePolicyAttachment: %s", waitErr) + } + + log.Printf("[DEBUG] Finished creating DiskResourcePolicyAttachment %q: %#v", d.Id(), res) + + return resourceComputeDiskResourcePolicyAttachmentRead(d, meta) +} + +func resourceComputeDiskResourcePolicyAttachmentRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + url, err := replaceVars(d, config, "{{ComputeBasePath}}projects/{{project}}/zones/{{zone}}/disks/{{disk}}") + if err != nil { + return err + } + + project, err := getProject(d, config) + if err != nil { + return err + } + res, err := sendRequest(config, "GET", project, url, nil) + if err != nil { + return handleNotFoundError(err, d, fmt.Sprintf("ComputeDiskResourcePolicyAttachment %q", d.Id())) + } + + res, err = flattenNestedComputeDiskResourcePolicyAttachment(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 ComputeDiskResourcePolicyAttachment because it couldn't be matched.") + d.SetId("") + return nil + } + + res, err = resourceComputeDiskResourcePolicyAttachmentDecoder(d, meta, res) + if err != nil { + return err + } + + if res == nil { + // Decoding the object has resulted in it being gone. It may be marked deleted + log.Printf("[DEBUG] Removing ComputeDiskResourcePolicyAttachment because it no longer exists.") + d.SetId("") + return nil + } + + if err := d.Set("project", project); err != nil { + return fmt.Errorf("Error reading DiskResourcePolicyAttachment: %s", err) + } + + if err := d.Set("name", flattenComputeDiskResourcePolicyAttachmentName(res["name"], d)); err != nil { + return fmt.Errorf("Error reading DiskResourcePolicyAttachment: %s", err) + } + + return nil +} + +func resourceComputeDiskResourcePolicyAttachmentDelete(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + project, err := getProject(d, config) + if err != nil { + return err + } + + url, err := replaceVars(d, config, "{{ComputeBasePath}}projects/{{project}}/zones/{{zone}}/disks/{{disk}}/removeResourcePolicies") + if err != nil { + return err + } + + var obj map[string]interface{} + obj = make(map[string]interface{}) + + // projects/{project}/regions/{region}/resourcePolicies/{resourceId} + region := getRegionFromZone(d.Get("zone").(string)) + + name, err := expandComputeDiskResourcePolicyAttachmentName(d.Get("name"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("name"); !isEmptyValue(reflect.ValueOf(name)) && (ok || !reflect.DeepEqual(v, name)) { + obj["resourcePolicies"] = []interface{}{fmt.Sprintf("projects/%s/regions/%s/resourcePolicies/%s", project, region, name)} + } + log.Printf("[DEBUG] Deleting DiskResourcePolicyAttachment %q", d.Id()) + + res, err := sendRequestWithTimeout(config, "POST", project, url, obj, d.Timeout(schema.TimeoutDelete)) + if err != nil { + return handleNotFoundError(err, d, "DiskResourcePolicyAttachment") + } + + op := &compute.Operation{} + err = Convert(res, op) + if err != nil { + return err + } + + err = computeOperationWaitTime( + config.clientCompute, op, project, "Deleting DiskResourcePolicyAttachment", + int(d.Timeout(schema.TimeoutDelete).Minutes())) + + if err != nil { + return err + } + + log.Printf("[DEBUG] Finished deleting DiskResourcePolicyAttachment %q: %#v", d.Id(), res) + return nil +} + +func resourceComputeDiskResourcePolicyAttachmentImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + config := meta.(*Config) + if err := parseImportId([]string{ + "projects/(?P[^/]+)/zones/(?P[^/]+)/disks/(?P[^/]+)/(?P[^/]+)", + "(?P[^/]+)/(?P[^/]+)/(?P[^/]+)/(?P[^/]+)", + "(?P[^/]+)/(?P[^/]+)/(?P[^/]+)", + "(?P[^/]+)/(?P[^/]+)", + }, d, config); err != nil { + return nil, err + } + + // Replace import id for the resource id + id, err := replaceVars(d, config, "{{project}}/{{zone}}/{{disk}}/{{name}}") + if err != nil { + return nil, fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + return []*schema.ResourceData{d}, nil +} + +func flattenComputeDiskResourcePolicyAttachmentName(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func expandComputeDiskResourcePolicyAttachmentName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func resourceComputeDiskResourcePolicyAttachmentEncoder(d *schema.ResourceData, meta interface{}, obj map[string]interface{}) (map[string]interface{}, error) { + config := meta.(*Config) + project, err := getProject(d, config) + if err != nil { + return nil, err + } + + region := getRegionFromZone(d.Get("zone").(string)) + + obj["resourcePolicies"] = []interface{}{fmt.Sprintf("projects/%s/regions/%s/resourcePolicies/%s", project, region, obj["name"])} + delete(obj, "name") + return obj, nil +} + +func flattenNestedComputeDiskResourcePolicyAttachment(d *schema.ResourceData, meta interface{}, res map[string]interface{}) (map[string]interface{}, error) { + var v interface{} + var ok bool + + v, ok = res["resourcePolicies"] + if !ok || v == nil { + return nil, nil + } + + switch v.(type) { + case []interface{}: + break + case map[string]interface{}: + // Construct list out of single nested resource + v = []interface{}{v} + default: + return nil, fmt.Errorf("expected list or map for value resourcePolicies. Actual value: %v", v) + } + + expectedName, err := expandComputeDiskResourcePolicyAttachmentName(d.Get("name"), d, meta.(*Config)) + if err != nil { + return nil, err + } + + // Search list for this resource. + items := v.([]interface{}) + for _, itemRaw := range items { + if itemRaw == nil { + continue + } + // List response only contains the ID - construct a response object. + item := map[string]interface{}{ + "name": itemRaw, + } + + // Decode list item before comparing. + item, err := resourceComputeDiskResourcePolicyAttachmentDecoder(d, meta, item) + if err != nil { + return nil, err + } + + itemName := flattenComputeDiskResourcePolicyAttachmentName(item["name"], d) + if !reflect.DeepEqual(itemName, expectedName) { + log.Printf("[DEBUG] Skipping item with name= %#v, looking for %#v)", itemName, expectedName) + continue + } + log.Printf("[DEBUG] Found item for resource %q: %#v)", d.Id(), item) + return item, nil + } + + return nil, nil +} + +func resourceComputeDiskResourcePolicyAttachmentDecoder(d *schema.ResourceData, meta interface{}, res map[string]interface{}) (map[string]interface{}, error) { + res["name"] = GetResourceNameFromSelfLink(res["name"].(string)) + return res, nil +} diff --git a/google/resource_compute_disk_resource_policy_attachment_test.go b/google/resource_compute_disk_resource_policy_attachment_test.go new file mode 100644 index 00000000000..fbfbeab0714 --- /dev/null +++ b/google/resource_compute_disk_resource_policy_attachment_test.go @@ -0,0 +1,80 @@ +package google + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform/helper/acctest" + "github.com/hashicorp/terraform/helper/resource" +) + +func TestAccComputeDiskResourcePolicyAttachment_basic(t *testing.T) { + t.Parallel() + + diskName := fmt.Sprintf("tf-test-%s", acctest.RandString(10)) + policyName := fmt.Sprintf("tf-test-policy-%s", acctest.RandString(10)) + policyName2 := fmt.Sprintf("tf-test-policy-%s", acctest.RandString(10)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccComputeDiskResourcePolicyAttachment_basic(diskName, policyName), + }, + { + ResourceName: "google_compute_disk_resource_policy_attachment.foobar", + // ImportStateId: fmt.Sprintf("projects/%s/regions/%s/resourcePolicies/%s", getTestProjectFromEnv(), "us-central1", policyName), + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccComputeDiskResourcePolicyAttachment_basic(diskName, policyName2), + }, + { + ResourceName: "google_compute_disk_resource_policy_attachment.foobar", + // ImportStateId: fmt.Sprintf("projects/%s/regions/%s/resourcePolicies/%s", getTestProjectFromEnv(), "us-central1", policyName), + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccComputeDiskResourcePolicyAttachment_basic(diskName, policyName string) string { + return fmt.Sprintf(` +data "google_compute_image" "my_image" { + family = "debian-9" + project = "debian-cloud" +} + +resource "google_compute_disk" "foobar" { + name = "%s" + image = "${data.google_compute_image.my_image.self_link}" + size = 50 + type = "pd-ssd" + zone = "us-central1-a" + labels = { + my-label = "my-label-value" + } +} + +resource "google_compute_resource_policy" "foobar" { + name = "%s" + region = "us-central1" + snapshot_schedule_policy { + schedule { + daily_schedule { + days_in_cycle = 1 + start_time = "04:00" + } + } + } +} + +resource "google_compute_disk_resource_policy_attachment" "foobar" { + name = google_compute_resource_policy.foobar.name + disk = google_compute_disk.foobar.name + zone = "us-central1-a" +}`, diskName, policyName) +} diff --git a/google/resource_compute_resource_policy.go b/google/resource_compute_resource_policy.go new file mode 100644 index 00000000000..dedf452cae6 --- /dev/null +++ b/google/resource_compute_resource_policy.go @@ -0,0 +1,876 @@ +// ---------------------------------------------------------------------------- +// +// *** 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" + "strconv" + "time" + + "github.com/hashicorp/terraform/helper/schema" + "github.com/hashicorp/terraform/helper/validation" + "google.golang.org/api/compute/v1" +) + +func resourceComputeResourcePolicy() *schema.Resource { + return &schema.Resource{ + Create: resourceComputeResourcePolicyCreate, + Read: resourceComputeResourcePolicyRead, + Delete: resourceComputeResourcePolicyDelete, + + Importer: &schema.ResourceImporter{ + State: resourceComputeResourcePolicyImport, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(4 * time.Minute), + Delete: schema.DefaultTimeout(4 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "region": { + Type: schema.TypeString, + Computed: true, + Optional: true, + ForceNew: true, + DiffSuppressFunc: compareSelfLinkOrResourceName, + }, + "snapshot_schedule_policy": { + Type: schema.TypeList, + Optional: true, + ForceNew: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "schedule": { + Type: schema.TypeList, + Required: true, + ForceNew: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "daily_schedule": { + Type: schema.TypeList, + Optional: true, + ForceNew: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "days_in_cycle": { + Type: schema.TypeInt, + Required: true, + ForceNew: true, + }, + "start_time": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + }, + }, + }, + "hourly_schedule": { + Type: schema.TypeList, + Optional: true, + ForceNew: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "hours_in_cycle": { + Type: schema.TypeInt, + Required: true, + ForceNew: true, + }, + "start_time": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + }, + }, + }, + "weekly_schedule": { + Type: schema.TypeList, + Optional: true, + ForceNew: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "day_of_weeks": { + Type: schema.TypeSet, + Required: true, + ForceNew: true, + MinItems: 1, + MaxItems: 7, + Elem: computeResourcePolicySnapshotSchedulePolicyScheduleWeeklyScheduleDayOfWeeksSchema(), + // Default schema.HashSchema is used. + }, + }, + }, + }, + }, + }, + }, + "retention_policy": { + Type: schema.TypeList, + Optional: true, + ForceNew: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "max_retention_days": { + Type: schema.TypeInt, + Required: true, + ForceNew: true, + }, + "on_source_disk_delete": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice([]string{"KEEP_AUTO_SNAPSHOTS", "APPLY_RETENTION_POLICY", ""}, false), + Default: "KEEP_AUTO_SNAPSHOTS", + }, + }, + }, + }, + "snapshot_properties": { + Type: schema.TypeList, + Optional: true, + ForceNew: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "guest_flush": { + Type: schema.TypeBool, + Optional: true, + ForceNew: true, + }, + "labels": { + Type: schema.TypeMap, + Optional: true, + ForceNew: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "storage_locations": { + Type: schema.TypeSet, + Optional: true, + ForceNew: true, + MaxItems: 1, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Set: schema.HashString, + }, + }, + }, + }, + }, + }, + }, + "project": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + "self_link": { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func computeResourcePolicySnapshotSchedulePolicyScheduleWeeklyScheduleDayOfWeeksSchema() *schema.Resource { + return &schema.Resource{ + Schema: map[string]*schema.Schema{ + "day": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice([]string{"MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY", "SATURDAY", "SUNDAY"}, false), + }, + "start_time": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + }, + } +} + +func resourceComputeResourcePolicyCreate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + obj := make(map[string]interface{}) + nameProp, err := expandComputeResourcePolicyName(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 + } + snapshotSchedulePolicyProp, err := expandComputeResourcePolicySnapshotSchedulePolicy(d.Get("snapshot_schedule_policy"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("snapshot_schedule_policy"); !isEmptyValue(reflect.ValueOf(snapshotSchedulePolicyProp)) && (ok || !reflect.DeepEqual(v, snapshotSchedulePolicyProp)) { + obj["snapshotSchedulePolicy"] = snapshotSchedulePolicyProp + } + regionProp, err := expandComputeResourcePolicyRegion(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 + } + + url, err := replaceVars(d, config, "{{ComputeBasePath}}projects/{{project}}/regions/{{region}}/resourcePolicies") + if err != nil { + return err + } + + log.Printf("[DEBUG] Creating new ResourcePolicy: %#v", obj) + project, err := getProject(d, config) + if err != nil { + return err + } + res, err := sendRequestWithTimeout(config, "POST", project, url, obj, d.Timeout(schema.TimeoutCreate)) + if err != nil { + return fmt.Errorf("Error creating ResourcePolicy: %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) + + op := &compute.Operation{} + err = Convert(res, op) + if err != nil { + return err + } + + waitErr := computeOperationWaitTime( + config.clientCompute, op, project, "Creating ResourcePolicy", + int(d.Timeout(schema.TimeoutCreate).Minutes())) + + if waitErr != nil { + // The resource didn't actually create + d.SetId("") + return fmt.Errorf("Error waiting to create ResourcePolicy: %s", waitErr) + } + + log.Printf("[DEBUG] Finished creating ResourcePolicy %q: %#v", d.Id(), res) + + return resourceComputeResourcePolicyRead(d, meta) +} + +func resourceComputeResourcePolicyRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + url, err := replaceVars(d, config, "{{ComputeBasePath}}projects/{{project}}/regions/{{region}}/resourcePolicies/{{name}}") + if err != nil { + return err + } + + project, err := getProject(d, config) + if err != nil { + return err + } + res, err := sendRequest(config, "GET", project, url, nil) + if err != nil { + return handleNotFoundError(err, d, fmt.Sprintf("ComputeResourcePolicy %q", d.Id())) + } + + if err := d.Set("project", project); err != nil { + return fmt.Errorf("Error reading ResourcePolicy: %s", err) + } + + if err := d.Set("name", flattenComputeResourcePolicyName(res["name"], d)); err != nil { + return fmt.Errorf("Error reading ResourcePolicy: %s", err) + } + if err := d.Set("snapshot_schedule_policy", flattenComputeResourcePolicySnapshotSchedulePolicy(res["snapshotSchedulePolicy"], d)); err != nil { + return fmt.Errorf("Error reading ResourcePolicy: %s", err) + } + if err := d.Set("region", flattenComputeResourcePolicyRegion(res["region"], d)); err != nil { + return fmt.Errorf("Error reading ResourcePolicy: %s", err) + } + if err := d.Set("self_link", ConvertSelfLinkToV1(res["selfLink"].(string))); err != nil { + return fmt.Errorf("Error reading ResourcePolicy: %s", err) + } + + return nil +} + +func resourceComputeResourcePolicyDelete(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + project, err := getProject(d, config) + if err != nil { + return err + } + + url, err := replaceVars(d, config, "{{ComputeBasePath}}projects/{{project}}/regions/{{region}}/resourcePolicies/{{name}}") + if err != nil { + return err + } + + var obj map[string]interface{} + log.Printf("[DEBUG] Deleting ResourcePolicy %q", d.Id()) + + res, err := sendRequestWithTimeout(config, "DELETE", project, url, obj, d.Timeout(schema.TimeoutDelete)) + if err != nil { + return handleNotFoundError(err, d, "ResourcePolicy") + } + + op := &compute.Operation{} + err = Convert(res, op) + if err != nil { + return err + } + + err = computeOperationWaitTime( + config.clientCompute, op, project, "Deleting ResourcePolicy", + int(d.Timeout(schema.TimeoutDelete).Minutes())) + + if err != nil { + return err + } + + log.Printf("[DEBUG] Finished deleting ResourcePolicy %q: %#v", d.Id(), res) + return nil +} + +func resourceComputeResourcePolicyImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + config := meta.(*Config) + if err := parseImportId([]string{ + "projects/(?P[^/]+)/regions/(?P[^/]+)/resourcePolicies/(?P[^/]+)", + "(?P[^/]+)/(?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 flattenComputeResourcePolicyName(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenComputeResourcePolicySnapshotSchedulePolicy(v interface{}, d *schema.ResourceData) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["schedule"] = + flattenComputeResourcePolicySnapshotSchedulePolicySchedule(original["schedule"], d) + transformed["retention_policy"] = + flattenComputeResourcePolicySnapshotSchedulePolicyRetentionPolicy(original["retentionPolicy"], d) + transformed["snapshot_properties"] = + flattenComputeResourcePolicySnapshotSchedulePolicySnapshotProperties(original["snapshotProperties"], d) + return []interface{}{transformed} +} +func flattenComputeResourcePolicySnapshotSchedulePolicySchedule(v interface{}, d *schema.ResourceData) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["hourly_schedule"] = + flattenComputeResourcePolicySnapshotSchedulePolicyScheduleHourlySchedule(original["hourlySchedule"], d) + transformed["daily_schedule"] = + flattenComputeResourcePolicySnapshotSchedulePolicyScheduleDailySchedule(original["dailySchedule"], d) + transformed["weekly_schedule"] = + flattenComputeResourcePolicySnapshotSchedulePolicyScheduleWeeklySchedule(original["weeklySchedule"], d) + return []interface{}{transformed} +} +func flattenComputeResourcePolicySnapshotSchedulePolicyScheduleHourlySchedule(v interface{}, d *schema.ResourceData) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["hours_in_cycle"] = + flattenComputeResourcePolicySnapshotSchedulePolicyScheduleHourlyScheduleHoursInCycle(original["hoursInCycle"], d) + transformed["start_time"] = + flattenComputeResourcePolicySnapshotSchedulePolicyScheduleHourlyScheduleStartTime(original["startTime"], d) + return []interface{}{transformed} +} +func flattenComputeResourcePolicySnapshotSchedulePolicyScheduleHourlyScheduleHoursInCycle(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 flattenComputeResourcePolicySnapshotSchedulePolicyScheduleHourlyScheduleStartTime(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenComputeResourcePolicySnapshotSchedulePolicyScheduleDailySchedule(v interface{}, d *schema.ResourceData) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["days_in_cycle"] = + flattenComputeResourcePolicySnapshotSchedulePolicyScheduleDailyScheduleDaysInCycle(original["daysInCycle"], d) + transformed["start_time"] = + flattenComputeResourcePolicySnapshotSchedulePolicyScheduleDailyScheduleStartTime(original["startTime"], d) + return []interface{}{transformed} +} +func flattenComputeResourcePolicySnapshotSchedulePolicyScheduleDailyScheduleDaysInCycle(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 flattenComputeResourcePolicySnapshotSchedulePolicyScheduleDailyScheduleStartTime(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenComputeResourcePolicySnapshotSchedulePolicyScheduleWeeklySchedule(v interface{}, d *schema.ResourceData) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["day_of_weeks"] = + flattenComputeResourcePolicySnapshotSchedulePolicyScheduleWeeklyScheduleDayOfWeeks(original["dayOfWeeks"], d) + return []interface{}{transformed} +} +func flattenComputeResourcePolicySnapshotSchedulePolicyScheduleWeeklyScheduleDayOfWeeks(v interface{}, d *schema.ResourceData) interface{} { + if v == nil { + return v + } + l := v.([]interface{}) + transformed := schema.NewSet(schema.HashResource(computeResourcePolicySnapshotSchedulePolicyScheduleWeeklyScheduleDayOfWeeksSchema()), []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{}{ + "start_time": flattenComputeResourcePolicySnapshotSchedulePolicyScheduleWeeklyScheduleDayOfWeeksStartTime(original["startTime"], d), + "day": flattenComputeResourcePolicySnapshotSchedulePolicyScheduleWeeklyScheduleDayOfWeeksDay(original["day"], d), + }) + } + return transformed +} +func flattenComputeResourcePolicySnapshotSchedulePolicyScheduleWeeklyScheduleDayOfWeeksStartTime(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenComputeResourcePolicySnapshotSchedulePolicyScheduleWeeklyScheduleDayOfWeeksDay(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenComputeResourcePolicySnapshotSchedulePolicyRetentionPolicy(v interface{}, d *schema.ResourceData) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["max_retention_days"] = + flattenComputeResourcePolicySnapshotSchedulePolicyRetentionPolicyMaxRetentionDays(original["maxRetentionDays"], d) + transformed["on_source_disk_delete"] = + flattenComputeResourcePolicySnapshotSchedulePolicyRetentionPolicyOnSourceDiskDelete(original["onSourceDiskDelete"], d) + return []interface{}{transformed} +} +func flattenComputeResourcePolicySnapshotSchedulePolicyRetentionPolicyMaxRetentionDays(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 flattenComputeResourcePolicySnapshotSchedulePolicyRetentionPolicyOnSourceDiskDelete(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenComputeResourcePolicySnapshotSchedulePolicySnapshotProperties(v interface{}, d *schema.ResourceData) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["labels"] = + flattenComputeResourcePolicySnapshotSchedulePolicySnapshotPropertiesLabels(original["labels"], d) + transformed["storage_locations"] = + flattenComputeResourcePolicySnapshotSchedulePolicySnapshotPropertiesStorageLocations(original["storageLocations"], d) + transformed["guest_flush"] = + flattenComputeResourcePolicySnapshotSchedulePolicySnapshotPropertiesGuestFlush(original["guestFlush"], d) + return []interface{}{transformed} +} +func flattenComputeResourcePolicySnapshotSchedulePolicySnapshotPropertiesLabels(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenComputeResourcePolicySnapshotSchedulePolicySnapshotPropertiesStorageLocations(v interface{}, d *schema.ResourceData) interface{} { + if v == nil { + return v + } + return schema.NewSet(schema.HashString, v.([]interface{})) +} + +func flattenComputeResourcePolicySnapshotSchedulePolicySnapshotPropertiesGuestFlush(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenComputeResourcePolicyRegion(v interface{}, d *schema.ResourceData) interface{} { + if v == nil { + return v + } + return ConvertSelfLinkToV1(v.(string)) +} + +func expandComputeResourcePolicyName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeResourcePolicySnapshotSchedulePolicy(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedSchedule, err := expandComputeResourcePolicySnapshotSchedulePolicySchedule(original["schedule"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedSchedule); val.IsValid() && !isEmptyValue(val) { + transformed["schedule"] = transformedSchedule + } + + transformedRetentionPolicy, err := expandComputeResourcePolicySnapshotSchedulePolicyRetentionPolicy(original["retention_policy"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedRetentionPolicy); val.IsValid() && !isEmptyValue(val) { + transformed["retentionPolicy"] = transformedRetentionPolicy + } + + transformedSnapshotProperties, err := expandComputeResourcePolicySnapshotSchedulePolicySnapshotProperties(original["snapshot_properties"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedSnapshotProperties); val.IsValid() && !isEmptyValue(val) { + transformed["snapshotProperties"] = transformedSnapshotProperties + } + + return transformed, nil +} + +func expandComputeResourcePolicySnapshotSchedulePolicySchedule(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedHourlySchedule, err := expandComputeResourcePolicySnapshotSchedulePolicyScheduleHourlySchedule(original["hourly_schedule"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedHourlySchedule); val.IsValid() && !isEmptyValue(val) { + transformed["hourlySchedule"] = transformedHourlySchedule + } + + transformedDailySchedule, err := expandComputeResourcePolicySnapshotSchedulePolicyScheduleDailySchedule(original["daily_schedule"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedDailySchedule); val.IsValid() && !isEmptyValue(val) { + transformed["dailySchedule"] = transformedDailySchedule + } + + transformedWeeklySchedule, err := expandComputeResourcePolicySnapshotSchedulePolicyScheduleWeeklySchedule(original["weekly_schedule"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedWeeklySchedule); val.IsValid() && !isEmptyValue(val) { + transformed["weeklySchedule"] = transformedWeeklySchedule + } + + return transformed, nil +} + +func expandComputeResourcePolicySnapshotSchedulePolicyScheduleHourlySchedule(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedHoursInCycle, err := expandComputeResourcePolicySnapshotSchedulePolicyScheduleHourlyScheduleHoursInCycle(original["hours_in_cycle"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedHoursInCycle); val.IsValid() && !isEmptyValue(val) { + transformed["hoursInCycle"] = transformedHoursInCycle + } + + transformedStartTime, err := expandComputeResourcePolicySnapshotSchedulePolicyScheduleHourlyScheduleStartTime(original["start_time"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedStartTime); val.IsValid() && !isEmptyValue(val) { + transformed["startTime"] = transformedStartTime + } + + return transformed, nil +} + +func expandComputeResourcePolicySnapshotSchedulePolicyScheduleHourlyScheduleHoursInCycle(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeResourcePolicySnapshotSchedulePolicyScheduleHourlyScheduleStartTime(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeResourcePolicySnapshotSchedulePolicyScheduleDailySchedule(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedDaysInCycle, err := expandComputeResourcePolicySnapshotSchedulePolicyScheduleDailyScheduleDaysInCycle(original["days_in_cycle"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedDaysInCycle); val.IsValid() && !isEmptyValue(val) { + transformed["daysInCycle"] = transformedDaysInCycle + } + + transformedStartTime, err := expandComputeResourcePolicySnapshotSchedulePolicyScheduleDailyScheduleStartTime(original["start_time"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedStartTime); val.IsValid() && !isEmptyValue(val) { + transformed["startTime"] = transformedStartTime + } + + return transformed, nil +} + +func expandComputeResourcePolicySnapshotSchedulePolicyScheduleDailyScheduleDaysInCycle(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeResourcePolicySnapshotSchedulePolicyScheduleDailyScheduleStartTime(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeResourcePolicySnapshotSchedulePolicyScheduleWeeklySchedule(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedDayOfWeeks, err := expandComputeResourcePolicySnapshotSchedulePolicyScheduleWeeklyScheduleDayOfWeeks(original["day_of_weeks"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedDayOfWeeks); val.IsValid() && !isEmptyValue(val) { + transformed["dayOfWeeks"] = transformedDayOfWeeks + } + + return transformed, nil +} + +func expandComputeResourcePolicySnapshotSchedulePolicyScheduleWeeklyScheduleDayOfWeeks(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{}) + + transformedStartTime, err := expandComputeResourcePolicySnapshotSchedulePolicyScheduleWeeklyScheduleDayOfWeeksStartTime(original["start_time"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedStartTime); val.IsValid() && !isEmptyValue(val) { + transformed["startTime"] = transformedStartTime + } + + transformedDay, err := expandComputeResourcePolicySnapshotSchedulePolicyScheduleWeeklyScheduleDayOfWeeksDay(original["day"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedDay); val.IsValid() && !isEmptyValue(val) { + transformed["day"] = transformedDay + } + + req = append(req, transformed) + } + return req, nil +} + +func expandComputeResourcePolicySnapshotSchedulePolicyScheduleWeeklyScheduleDayOfWeeksStartTime(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeResourcePolicySnapshotSchedulePolicyScheduleWeeklyScheduleDayOfWeeksDay(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeResourcePolicySnapshotSchedulePolicyRetentionPolicy(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedMaxRetentionDays, err := expandComputeResourcePolicySnapshotSchedulePolicyRetentionPolicyMaxRetentionDays(original["max_retention_days"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedMaxRetentionDays); val.IsValid() && !isEmptyValue(val) { + transformed["maxRetentionDays"] = transformedMaxRetentionDays + } + + transformedOnSourceDiskDelete, err := expandComputeResourcePolicySnapshotSchedulePolicyRetentionPolicyOnSourceDiskDelete(original["on_source_disk_delete"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedOnSourceDiskDelete); val.IsValid() && !isEmptyValue(val) { + transformed["onSourceDiskDelete"] = transformedOnSourceDiskDelete + } + + return transformed, nil +} + +func expandComputeResourcePolicySnapshotSchedulePolicyRetentionPolicyMaxRetentionDays(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeResourcePolicySnapshotSchedulePolicyRetentionPolicyOnSourceDiskDelete(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeResourcePolicySnapshotSchedulePolicySnapshotProperties(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedLabels, err := expandComputeResourcePolicySnapshotSchedulePolicySnapshotPropertiesLabels(original["labels"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedLabels); val.IsValid() && !isEmptyValue(val) { + transformed["labels"] = transformedLabels + } + + transformedStorageLocations, err := expandComputeResourcePolicySnapshotSchedulePolicySnapshotPropertiesStorageLocations(original["storage_locations"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedStorageLocations); val.IsValid() && !isEmptyValue(val) { + transformed["storageLocations"] = transformedStorageLocations + } + + transformedGuestFlush, err := expandComputeResourcePolicySnapshotSchedulePolicySnapshotPropertiesGuestFlush(original["guest_flush"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedGuestFlush); val.IsValid() && !isEmptyValue(val) { + transformed["guestFlush"] = transformedGuestFlush + } + + return transformed, nil +} + +func expandComputeResourcePolicySnapshotSchedulePolicySnapshotPropertiesLabels(v interface{}, d TerraformResourceData, config *Config) (map[string]string, error) { + if v == nil { + return map[string]string{}, nil + } + m := make(map[string]string) + for k, val := range v.(map[string]interface{}) { + m[k] = val.(string) + } + return m, nil +} + +func expandComputeResourcePolicySnapshotSchedulePolicySnapshotPropertiesStorageLocations(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + v = v.(*schema.Set).List() + return v, nil +} + +func expandComputeResourcePolicySnapshotSchedulePolicySnapshotPropertiesGuestFlush(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeResourcePolicyRegion(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 +} diff --git a/google/resource_compute_resource_policy_generated_test.go b/google/resource_compute_resource_policy_generated_test.go new file mode 100644 index 00000000000..91ee4b8c239 --- /dev/null +++ b/google/resource_compute_resource_policy_generated_test.go @@ -0,0 +1,143 @@ +// ---------------------------------------------------------------------------- +// +// *** 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 TestAccComputeResourcePolicy_resourcePolicyBasicExample(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: testAccCheckComputeResourcePolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccComputeResourcePolicy_resourcePolicyBasicExample(context), + }, + { + ResourceName: "google_compute_resource_policy.foo", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccComputeResourcePolicy_resourcePolicyBasicExample(context map[string]interface{}) string { + return Nprintf(` +resource "google_compute_resource_policy" "foo" { + name = "policy%{random_suffix}" + region = "us-central1" + snapshot_schedule_policy { + schedule { + daily_schedule { + days_in_cycle = 1 + start_time = "04:00" + } + } + } +} +`, context) +} + +func TestAccComputeResourcePolicy_resourcePolicyFullExample(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: testAccCheckComputeResourcePolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccComputeResourcePolicy_resourcePolicyFullExample(context), + }, + { + ResourceName: "google_compute_resource_policy.bar", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccComputeResourcePolicy_resourcePolicyFullExample(context map[string]interface{}) string { + return Nprintf(` +resource "google_compute_resource_policy" "bar" { + name = "policy%{random_suffix}" + region = "us-central1" + snapshot_schedule_policy { + schedule { + hourly_schedule { + hours_in_cycle = 20 + start_time = "23:00" + } + } + retention_policy { + max_retention_days = 10 + on_source_disk_delete = "KEEP_AUTO_SNAPSHOTS" + } + snapshot_properties { + labels = { + my_label = "value" + } + storage_locations = ["us"] + guest_flush = true + } + } +} +`, context) +} + +func testAccCheckComputeResourcePolicyDestroy(s *terraform.State) error { + for name, rs := range s.RootModule().Resources { + if rs.Type != "google_compute_resource_policy" { + continue + } + if strings.HasPrefix(name, "data.") { + continue + } + + config := testAccProvider.Meta().(*Config) + + url, err := replaceVarsForTest(config, rs, "{{ComputeBasePath}}projects/{{project}}/regions/{{region}}/resourcePolicies/{{name}}") + if err != nil { + return err + } + + _, err = sendRequest(config, "GET", "", url, nil) + if err == nil { + return fmt.Errorf("ComputeResourcePolicy still exists at %s", url) + } + } + + return nil +} diff --git a/google/utils.go b/google/utils.go index a2d154fb4f7..a89207838ad 100644 --- a/google/utils.go +++ b/google/utils.go @@ -361,7 +361,7 @@ func retryTimeDuration(retryFunc func() error, duration time.Duration, errorRetr if err == nil { return nil } - for _, e := range getAllTypes(err, &googleapi.Error{}, &url.Error{}) { + for _, e := range errwrap.GetAllType(err, &googleapi.Error{}) { if isRetryableError(e, errorRetryPredicates) { return resource.RetryableError(e) } @@ -370,17 +370,6 @@ func retryTimeDuration(retryFunc func() error, duration time.Duration, errorRetr }) } -func getAllTypes(err error, args ...interface{}) []error { - var result []error - for _, v := range args { - subResult := errwrap.GetAllType(err, v) - if subResult != nil { - result = append(result, subResult...) - } - } - return result -} - func isRetryableError(err error, retryPredicates []func(e error) (bool, string)) bool { // These operations are always hitting googleapis.com - they should rarely diff --git a/google/utils_test.go b/google/utils_test.go index 87f5c5051e2..25f3c11d5fc 100644 --- a/google/utils_test.go +++ b/google/utils_test.go @@ -1,7 +1,6 @@ package google import ( - "net/url" "reflect" "strings" "testing" @@ -529,36 +528,3 @@ func TestRetryTimeDuration_noretry(t *testing.T) { t.Errorf("expected error function to be called exactly once, but was called %d times", i) } } - -type TimeoutError struct { - timeout bool -} - -func (e *TimeoutError) Timeout() bool { - return e.timeout -} - -func (e *TimeoutError) Error() string { - return "timeout error" -} - -func TestRetryTimeDuration_URLTimeoutsShouldRetry(t *testing.T) { - runCount := 0 - retryFunc := func() error { - runCount++ - if runCount == 1 { - return &url.Error{ - Err: &TimeoutError{timeout: true}, - } - } - return nil - } - err := retryTimeDuration(retryFunc, 1*time.Minute) - if err != nil { - t.Errorf("unexpected error: got '%v' want 'nil'", err) - } - expectedRunCount := 2 - if runCount != expectedRunCount { - t.Errorf("expected the retryFunc to be called %v time(s), instead was called %v time(s)", expectedRunCount, runCount) - } -} diff --git a/website/docs/r/compute_disk_resource_policy_attachment.html.markdown b/website/docs/r/compute_disk_resource_policy_attachment.html.markdown new file mode 100644 index 00000000000..965952ad4e4 --- /dev/null +++ b/website/docs/r/compute_disk_resource_policy_attachment.html.markdown @@ -0,0 +1,81 @@ +--- +# ---------------------------------------------------------------------------- +# +# *** 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_disk_resource_policy_attachment" +sidebar_current: "docs-google-compute-disk-resource-policy-attachment" +description: |- + Disk resource policies define a schedule for taking snapshots and a + retention period for these snapshots. +--- + +# google\_compute\_disk\_resource\_policy\_attachment + +Disk resource policies define a schedule for taking snapshots and a +retention period for these snapshots. + + + +## Argument Reference + +The following arguments are supported: + + +* `name` - + (Required) + The resource policy to be attached to the disk for scheduling snapshot + creation. Do not specify the self link. + +* `disk` - + (Required) + The name of the disk in which the resource policies are attached to. + + +- - - + + +* `zone` - + (Optional) + A reference to the zone where the disk resides. + +* `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 + +DiskResourcePolicyAttachment can be imported using any of these accepted formats: + +``` +$ terraform import google_compute_disk_resource_policy_attachment.default projects/{{project}}/zones/{{zone}}/disks/{{disk}}/{{name}} +$ terraform import google_compute_disk_resource_policy_attachment.default {{project}}/{{zone}}/{{disk}}/{{name}} +$ terraform import google_compute_disk_resource_policy_attachment.default {{zone}}/{{disk}}/{{name}} +$ terraform import google_compute_disk_resource_policy_attachment.default {{disk}}/{{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. + +## User Project Overrides + +This resource supports [User Project Overrides](https://www.terraform.io/docs/providers/google/provider_reference.html#user_project_override). diff --git a/website/docs/r/compute_resource_policy.html.markdown b/website/docs/r/compute_resource_policy.html.markdown new file mode 100644 index 00000000000..f1a647ddc90 --- /dev/null +++ b/website/docs/r/compute_resource_policy.html.markdown @@ -0,0 +1,238 @@ +--- +# ---------------------------------------------------------------------------- +# +# *** 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_resource_policy" +sidebar_current: "docs-google-compute-resource-policy" +description: |- + A policy that can be attached to a resource to specify or schedule actions on that resource. +--- + +# google\_compute\_resource\_policy + +A policy that can be attached to a resource to specify or schedule actions on that resource. + + + + +## Example Usage - Resource Policy Basic + + +```hcl +resource "google_compute_resource_policy" "foo" { + name = "policy" + region = "us-central1" + snapshot_schedule_policy { + schedule { + daily_schedule { + days_in_cycle = 1 + start_time = "04:00" + } + } + } +} +``` + +## Example Usage - Resource Policy Full + + +```hcl +resource "google_compute_resource_policy" "bar" { + name = "policy" + region = "us-central1" + snapshot_schedule_policy { + schedule { + hourly_schedule { + hours_in_cycle = 20 + start_time = "23:00" + } + } + retention_policy { + max_retention_days = 10 + on_source_disk_delete = "KEEP_AUTO_SNAPSHOTS" + } + snapshot_properties { + labels = { + my_label = "value" + } + storage_locations = ["us"] + guest_flush = true + } + } +} +``` + +## Argument Reference + +The following arguments are supported: + + +* `name` - + (Required) + The name of the resource, provided by the client when initially creating + the resource. The resource 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. + + +- - - + + +* `snapshot_schedule_policy` - + (Optional) + Policy for creating snapshots of persistent disks. Structure is documented below. + +* `region` - + (Optional) + Region where resource policy resides. + +* `project` - (Optional) The ID of the project in which the resource belongs. + If it is not provided, the provider project is used. + + +The `snapshot_schedule_policy` block supports: + +* `schedule` - + (Required) + Contains one of an `hourlySchedule`, `dailySchedule`, or `weeklySchedule`. Structure is documented below. + +* `retention_policy` - + (Optional) + Retention policy applied to snapshots created by this resource policy. Structure is documented below. + +* `snapshot_properties` - + (Optional) + Properties with which the snapshots are created, such as labels. Structure is documented below. + + +The `schedule` block supports: + +* `hourly_schedule` - + (Optional) + The policy will execute every nth hour starting at the specified time. Structure is documented below. + +* `daily_schedule` - + (Optional) + The policy will execute every nth day at the specified time. Structure is documented below. + +* `weekly_schedule` - + (Optional) + Allows specifying a snapshot time for each day of the week. Structure is documented below. + + +The `hourly_schedule` block supports: + +* `hours_in_cycle` - + (Required) + The number of hours between snapshots. + +* `start_time` - + (Required) + Time within the window to start the operations. + It must be in format "HH:MM", + where HH : [00-23] and MM : [00-00] GMT. + +The `daily_schedule` block supports: + +* `days_in_cycle` - + (Required) + The number of days between snapshots. + +* `start_time` - + (Required) + This must be in UTC format that resolves to one of + 00:00, 04:00, 08:00, 12:00, 16:00, or 20:00. For example, + both 13:00-5 and 08:00 are valid. + +The `weekly_schedule` block supports: + +* `day_of_weeks` - + (Required) + May contain up to seven (one for each day of the week) snapshot times. Structure is documented below. + + +The `day_of_weeks` block supports: + +* `start_time` - + (Required) + Time within the window to start the operations. + It must be in format "HH:MM", where HH : [00-23] and MM : [00-00] GMT. + +* `day` - + (Required) + The day of the week to create the snapshot. e.g. MONDAY + +The `retention_policy` block supports: + +* `max_retention_days` - + (Required) + Maximum age of the snapshot that is allowed to be kept. + +* `on_source_disk_delete` - + (Optional) + Specifies the behavior to apply to scheduled snapshots when + the source disk is deleted. + Valid options are KEEP_AUTO_SNAPSHOTS and APPLY_RETENTION_POLICY + +The `snapshot_properties` block supports: + +* `labels` - + (Optional) + A set of key-value pairs. + +* `storage_locations` - + (Optional) + GCS bucket location in which to store the snapshot (regional or multi-regional). + +* `guest_flush` - + (Optional) + Whether to perform a 'guest aware' snapshot. + + +## 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 + +ResourcePolicy can be imported using any of these accepted formats: + +``` +$ terraform import google_compute_resource_policy.default projects/{{project}}/regions/{{region}}/resourcePolicies/{{name}} +$ terraform import google_compute_resource_policy.default {{project}}/{{region}}/{{name}} +$ terraform import google_compute_resource_policy.default {{region}}/{{name}} +$ terraform import google_compute_resource_policy.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. + +## User Project Overrides + +This resource supports [User Project Overrides](https://www.terraform.io/docs/providers/google/provider_reference.html#user_project_override).