From 0fdc262183ed82e78824e42d05042a7b0aba7c8b Mon Sep 17 00:00:00 2001 From: The Magician Date: Wed, 25 Jul 2018 13:25:16 -0700 Subject: [PATCH] Add LabelFingerprint and Label to Address and GlobalAddress. (#1811) --- google/resource_compute_address.go | 136 +++++++++++++++++ google/resource_compute_forwarding_rule.go | 5 +- google/resource_compute_global_address.go | 142 +++++++++++++++++- website/docs/r/compute_address.html.markdown | 9 ++ .../r/compute_global_address.html.markdown | 9 ++ 5 files changed, 296 insertions(+), 5 deletions(-) diff --git a/google/resource_compute_address.go b/google/resource_compute_address.go index 96dfe498..d6e9768e 100644 --- a/google/resource_compute_address.go +++ b/google/resource_compute_address.go @@ -29,6 +29,7 @@ func resourceComputeAddress() *schema.Resource { return &schema.Resource{ Create: resourceComputeAddressCreate, Read: resourceComputeAddressRead, + Update: resourceComputeAddressUpdate, Delete: resourceComputeAddressDelete, Importer: &schema.ResourceImporter{ @@ -37,6 +38,7 @@ func resourceComputeAddress() *schema.Resource { Timeouts: &schema.ResourceTimeout{ Create: schema.DefaultTimeout(240 * time.Second), + Update: schema.DefaultTimeout(240 * time.Second), Delete: schema.DefaultTimeout(240 * time.Second), }, @@ -79,6 +81,11 @@ func resourceComputeAddress() *schema.Resource { ForceNew: true, DiffSuppressFunc: compareSelfLinkOrResourceName, }, + "labels": { + Type: schema.TypeMap, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, "region": { Type: schema.TypeString, Computed: true, @@ -90,6 +97,10 @@ func resourceComputeAddress() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "label_fingerprint": { + Type: schema.TypeString, + Computed: true, + }, "users": { Type: schema.TypeList, Computed: true, @@ -156,6 +167,12 @@ func resourceComputeAddressCreate(d *schema.ResourceData, meta interface{}) erro } else if v, ok := d.GetOkExists("subnetwork"); !isEmptyValue(reflect.ValueOf(subnetworkProp)) && (ok || !reflect.DeepEqual(v, subnetworkProp)) { obj["subnetwork"] = subnetworkProp } + labelsProp, err := expandComputeAddressLabels(d.Get("labels"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("labels"); !isEmptyValue(reflect.ValueOf(labelsProp)) && (ok || !reflect.DeepEqual(v, labelsProp)) { + obj["labels"] = labelsProp + } regionProp, err := expandComputeAddressRegion(d.Get("region"), d, config) if err != nil { return err @@ -199,6 +216,44 @@ func resourceComputeAddressCreate(d *schema.ResourceData, meta interface{}) erro log.Printf("[DEBUG] Finished creating Address %q: %#v", d.Id(), res) + if v, ok := d.GetOkExists("labels"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, labelsProp)) { + // Labels cannot be set in a create. We'll have to set them here. + err = resourceComputeAddressRead(d, meta) + if err != nil { + return err + } + + obj := make(map[string]interface{}) + // d.Get("labels") will have been overridden by the Read call. + labelsProp, err := expandComputeAddressLabels(v, d, config) + obj["labels"] = labelsProp + labelFingerprintProp := d.Get("label_fingerprint") + obj["labelFingerprint"] = labelFingerprintProp + + url, err = replaceVars(d, config, "https://www.googleapis.com/compute/beta/projects/{{project}}/regions/{{region}}/addresses/{{name}}/setLabels") + if err != nil { + return err + } + res, err = sendRequest(config, "POST", url, obj) + if err != nil { + return fmt.Errorf("Error adding labels to ComputeAddress %q: %s", d.Id(), err) + } + + err = Convert(res, op) + if err != nil { + return err + } + + err = computeOperationWaitTime( + config.clientCompute, op, project, "Updating ComputeAddress Labels", + int(d.Timeout(schema.TimeoutUpdate).Minutes())) + + if err != nil { + return err + } + + } + return resourceComputeAddressRead(d, meta) } @@ -244,6 +299,12 @@ func resourceComputeAddressRead(d *schema.ResourceData, meta interface{}) error if err := d.Set("users", flattenComputeAddressUsers(res["users"])); err != nil { return fmt.Errorf("Error reading Address: %s", err) } + if err := d.Set("labels", flattenComputeAddressLabels(res["labels"])); err != nil { + return fmt.Errorf("Error reading Address: %s", err) + } + if err := d.Set("label_fingerprint", flattenComputeAddressLabelFingerprint(res["labelFingerprint"])); err != nil { + return fmt.Errorf("Error reading Address: %s", err) + } if err := d.Set("region", flattenComputeAddressRegion(res["region"])); err != nil { return fmt.Errorf("Error reading Address: %s", err) } @@ -257,6 +318,62 @@ func resourceComputeAddressRead(d *schema.ResourceData, meta interface{}) error return nil } +func resourceComputeAddressUpdate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + project, err := getProject(d, config) + if err != nil { + return err + } + + var url string + var res map[string]interface{} + op := &compute.Operation{} + + d.Partial(true) + + if d.HasChange("labels") || d.HasChange("label_fingerprint") { + obj := make(map[string]interface{}) + labelsProp, err := expandComputeAddressLabels(d.Get("labels"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("labels"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, labelsProp)) { + obj["labels"] = labelsProp + } + labelFingerprintProp := d.Get("label_fingerprint") + obj["labelFingerprint"] = labelFingerprintProp + + url, err = replaceVars(d, config, "https://www.googleapis.com/compute/beta/projects/{{project}}/regions/{{region}}/addresses/{{name}}/setLabels") + if err != nil { + return err + } + res, err = sendRequest(config, "POST", url, obj) + if err != nil { + return fmt.Errorf("Error updating Address %q: %s", d.Id(), err) + } + + err = Convert(res, op) + if err != nil { + return err + } + + err = computeOperationWaitTime( + config.clientCompute, op, project, "Updating Address", + int(d.Timeout(schema.TimeoutUpdate).Minutes())) + + if err != nil { + return err + } + + d.SetPartial("labels") + d.SetPartial("label_fingerprint") + } + + d.Partial(false) + + return resourceComputeAddressRead(d, meta) +} + func resourceComputeAddressDelete(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) @@ -346,6 +463,14 @@ func flattenComputeAddressUsers(v interface{}) interface{} { return v } +func flattenComputeAddressLabels(v interface{}) interface{} { + return v +} + +func flattenComputeAddressLabelFingerprint(v interface{}) interface{} { + return v +} + func flattenComputeAddressRegion(v interface{}) interface{} { if v == nil { return v @@ -381,6 +506,17 @@ func expandComputeAddressSubnetwork(v interface{}, d *schema.ResourceData, confi return f.RelativeLink(), nil } +func expandComputeAddressLabels(v interface{}, d *schema.ResourceData, 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 expandComputeAddressRegion(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { f, err := parseGlobalFieldValue("regions", v.(string), "project", d, config, true) if err != nil { diff --git a/google/resource_compute_forwarding_rule.go b/google/resource_compute_forwarding_rule.go index 6180b14f..57036b71 100644 --- a/google/resource_compute_forwarding_rule.go +++ b/google/resource_compute_forwarding_rule.go @@ -323,6 +323,7 @@ func resourceComputeForwardingRuleCreate(d *schema.ResourceData, meta interface{ } obj := make(map[string]interface{}) + // d.Get("labels") will have been overridden by the Read call. labelsProp, err := expandComputeForwardingRuleLabels(v, d, config) obj["labels"] = labelsProp labelFingerprintProp := d.Get("label_fingerprint") @@ -334,7 +335,7 @@ func resourceComputeForwardingRuleCreate(d *schema.ResourceData, meta interface{ } res, err = sendRequest(config, "POST", url, obj) if err != nil { - return fmt.Errorf("Error adding labels to ForwardingRule %q: %s", d.Id(), err) + return fmt.Errorf("Error adding labels to ComputeForwardingRule %q: %s", d.Id(), err) } err = Convert(res, op) @@ -343,7 +344,7 @@ func resourceComputeForwardingRuleCreate(d *schema.ResourceData, meta interface{ } err = computeOperationWaitTime( - config.clientCompute, op, project, "Updating ForwardingRule", + config.clientCompute, op, project, "Updating ComputeForwardingRule Labels", int(d.Timeout(schema.TimeoutUpdate).Minutes())) if err != nil { diff --git a/google/resource_compute_global_address.go b/google/resource_compute_global_address.go index 480b8d40..dad10565 100644 --- a/google/resource_compute_global_address.go +++ b/google/resource_compute_global_address.go @@ -29,6 +29,7 @@ func resourceComputeGlobalAddress() *schema.Resource { return &schema.Resource{ Create: resourceComputeGlobalAddressCreate, Read: resourceComputeGlobalAddressRead, + Update: resourceComputeGlobalAddressUpdate, Delete: resourceComputeGlobalAddressDelete, Importer: &schema.ResourceImporter{ @@ -37,6 +38,7 @@ func resourceComputeGlobalAddress() *schema.Resource { Timeouts: &schema.ResourceTimeout{ Create: schema.DefaultTimeout(240 * time.Second), + Update: schema.DefaultTimeout(240 * time.Second), Delete: schema.DefaultTimeout(240 * time.Second), }, @@ -51,6 +53,11 @@ func resourceComputeGlobalAddress() *schema.Resource { Optional: true, ForceNew: true, }, + "labels": { + Type: schema.TypeMap, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, "ip_version": { Type: schema.TypeString, Optional: true, @@ -66,6 +73,10 @@ func resourceComputeGlobalAddress() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "label_fingerprint": { + Type: schema.TypeString, + Computed: true, + }, "project": { Type: schema.TypeString, Optional: true, @@ -101,6 +112,12 @@ func resourceComputeGlobalAddressCreate(d *schema.ResourceData, meta interface{} } else if v, ok := d.GetOkExists("name"); !isEmptyValue(reflect.ValueOf(nameProp)) && (ok || !reflect.DeepEqual(v, nameProp)) { obj["name"] = nameProp } + labelsProp, err := expandComputeGlobalAddressLabels(d.Get("labels"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("labels"); !isEmptyValue(reflect.ValueOf(labelsProp)) && (ok || !reflect.DeepEqual(v, labelsProp)) { + obj["labels"] = labelsProp + } ipVersionProp, err := expandComputeGlobalAddressIpVersion(d.Get("ip_version"), d, config) if err != nil { return err @@ -108,7 +125,7 @@ func resourceComputeGlobalAddressCreate(d *schema.ResourceData, meta interface{} obj["ipVersion"] = ipVersionProp } - url, err := replaceVars(d, config, "https://www.googleapis.com/compute/v1/projects/{{project}}/global/addresses") + url, err := replaceVars(d, config, "https://www.googleapis.com/compute/beta/projects/{{project}}/global/addresses") if err != nil { return err } @@ -144,6 +161,44 @@ func resourceComputeGlobalAddressCreate(d *schema.ResourceData, meta interface{} log.Printf("[DEBUG] Finished creating GlobalAddress %q: %#v", d.Id(), res) + if v, ok := d.GetOkExists("labels"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, labelsProp)) { + // Labels cannot be set in a create. We'll have to set them here. + err = resourceComputeGlobalAddressRead(d, meta) + if err != nil { + return err + } + + obj := make(map[string]interface{}) + // d.Get("labels") will have been overridden by the Read call. + labelsProp, err := expandComputeGlobalAddressLabels(v, d, config) + obj["labels"] = labelsProp + labelFingerprintProp := d.Get("label_fingerprint") + obj["labelFingerprint"] = labelFingerprintProp + + url, err = replaceVars(d, config, "https://www.googleapis.com/compute/beta/projects/{{project}}/global/addresses/{{name}}/setLabels") + if err != nil { + return err + } + res, err = sendRequest(config, "POST", url, obj) + if err != nil { + return fmt.Errorf("Error adding labels to ComputeGlobalAddress %q: %s", d.Id(), err) + } + + err = Convert(res, op) + if err != nil { + return err + } + + err = computeOperationWaitTime( + config.clientCompute, op, project, "Updating ComputeGlobalAddress Labels", + int(d.Timeout(schema.TimeoutUpdate).Minutes())) + + if err != nil { + return err + } + + } + return resourceComputeGlobalAddressRead(d, meta) } @@ -155,7 +210,7 @@ func resourceComputeGlobalAddressRead(d *schema.ResourceData, meta interface{}) return err } - url, err := replaceVars(d, config, "https://www.googleapis.com/compute/v1/projects/{{project}}/global/addresses/{{name}}") + url, err := replaceVars(d, config, "https://www.googleapis.com/compute/beta/projects/{{project}}/global/addresses/{{name}}") if err != nil { return err } @@ -177,6 +232,12 @@ func resourceComputeGlobalAddressRead(d *schema.ResourceData, meta interface{}) if err := d.Set("name", flattenComputeGlobalAddressName(res["name"])); err != nil { return fmt.Errorf("Error reading GlobalAddress: %s", err) } + if err := d.Set("labels", flattenComputeGlobalAddressLabels(res["labels"])); err != nil { + return fmt.Errorf("Error reading GlobalAddress: %s", err) + } + if err := d.Set("label_fingerprint", flattenComputeGlobalAddressLabelFingerprint(res["labelFingerprint"])); err != nil { + return fmt.Errorf("Error reading GlobalAddress: %s", err) + } if err := d.Set("ip_version", flattenComputeGlobalAddressIpVersion(res["ipVersion"])); err != nil { return fmt.Errorf("Error reading GlobalAddress: %s", err) } @@ -190,6 +251,62 @@ func resourceComputeGlobalAddressRead(d *schema.ResourceData, meta interface{}) return nil } +func resourceComputeGlobalAddressUpdate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + project, err := getProject(d, config) + if err != nil { + return err + } + + var url string + var res map[string]interface{} + op := &compute.Operation{} + + d.Partial(true) + + if d.HasChange("labels") || d.HasChange("label_fingerprint") { + obj := make(map[string]interface{}) + labelsProp, err := expandComputeGlobalAddressLabels(d.Get("labels"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("labels"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, labelsProp)) { + obj["labels"] = labelsProp + } + labelFingerprintProp := d.Get("label_fingerprint") + obj["labelFingerprint"] = labelFingerprintProp + + url, err = replaceVars(d, config, "https://www.googleapis.com/compute/beta/projects/{{project}}/global/addresses/{{name}}/setLabels") + if err != nil { + return err + } + res, err = sendRequest(config, "POST", url, obj) + if err != nil { + return fmt.Errorf("Error updating GlobalAddress %q: %s", d.Id(), err) + } + + err = Convert(res, op) + if err != nil { + return err + } + + err = computeOperationWaitTime( + config.clientCompute, op, project, "Updating GlobalAddress", + int(d.Timeout(schema.TimeoutUpdate).Minutes())) + + if err != nil { + return err + } + + d.SetPartial("labels") + d.SetPartial("label_fingerprint") + } + + d.Partial(false) + + return resourceComputeGlobalAddressRead(d, meta) +} + func resourceComputeGlobalAddressDelete(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) @@ -198,7 +315,7 @@ func resourceComputeGlobalAddressDelete(d *schema.ResourceData, meta interface{} return err } - url, err := replaceVars(d, config, "https://www.googleapis.com/compute/v1/projects/{{project}}/global/addresses/{{name}}") + url, err := replaceVars(d, config, "https://www.googleapis.com/compute/beta/projects/{{project}}/global/addresses/{{name}}") if err != nil { return err } @@ -257,6 +374,14 @@ func flattenComputeGlobalAddressName(v interface{}) interface{} { return v } +func flattenComputeGlobalAddressLabels(v interface{}) interface{} { + return v +} + +func flattenComputeGlobalAddressLabelFingerprint(v interface{}) interface{} { + return v +} + func flattenComputeGlobalAddressIpVersion(v interface{}) interface{} { return v } @@ -269,6 +394,17 @@ func expandComputeGlobalAddressName(v interface{}, d *schema.ResourceData, confi return v, nil } +func expandComputeGlobalAddressLabels(v interface{}, d *schema.ResourceData, 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 expandComputeGlobalAddressIpVersion(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { return v, nil } diff --git a/website/docs/r/compute_address.html.markdown b/website/docs/r/compute_address.html.markdown index 5152d59f..81cbff45 100644 --- a/website/docs/r/compute_address.html.markdown +++ b/website/docs/r/compute_address.html.markdown @@ -116,6 +116,10 @@ The following arguments are supported: This field can only be used with INTERNAL type with GCE_ENDPOINT/DNS_RESOLVER purposes. +* `labels` - + (Optional) + Labels to apply to this address. A list of key->value pairs. + * `region` - (Optional) The Region in which the created address should reside. @@ -134,6 +138,10 @@ In addition to the arguments listed above, the following computed attributes are * `users` - The URLs of the resources that are using this address. + +* `label_fingerprint` - + The fingerprint used for optimistic locking of this resource. Used + internally during updates. * `self_link` - The URI of the created resource. @@ -145,6 +153,7 @@ 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 diff --git a/website/docs/r/compute_global_address.html.markdown b/website/docs/r/compute_global_address.html.markdown index 2eaba100..fcd01171 100644 --- a/website/docs/r/compute_global_address.html.markdown +++ b/website/docs/r/compute_global_address.html.markdown @@ -61,6 +61,10 @@ The following arguments are supported: An optional description of this resource. Provide this property when you create the resource. +* `labels` - + (Optional) + Labels to apply to this address. A list of key->value pairs. + * `ip_version` - (Optional) The IP Version that will be used by this address. Valid options are @@ -79,6 +83,10 @@ In addition to the arguments listed above, the following computed attributes are * `creation_timestamp` - Creation timestamp in RFC3339 text format. + +* `label_fingerprint` - + The fingerprint used for optimistic locking of this resource. Used + internally during updates. * `self_link` - The URI of the created resource. @@ -88,6 +96,7 @@ 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