Cleanup BackendService after generation, add omitted fields. (#3375)

<!-- This change is generated by MagicModules. -->
Original Author: @rileykarson
This commit is contained in:
The Magician 2019-04-04 13:50:31 -07:00 committed by Riley Karson
parent 0c660ba9d0
commit f6312500fe
4 changed files with 208 additions and 317 deletions

View File

@ -15,6 +15,7 @@
package google
import (
"bytes"
"fmt"
"log"
"reflect"
@ -22,11 +23,142 @@ import (
"time"
"github.com/hashicorp/errwrap"
"github.com/hashicorp/terraform/helper/hashcode"
"github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/helper/validation"
"google.golang.org/api/compute/v1"
)
func resourceGoogleComputeBackendServiceBackendHash(v interface{}) int {
if v == nil {
return 0
}
var buf bytes.Buffer
m := v.(map[string]interface{})
log.Printf("[DEBUG] hashing %v", m)
if group, err := getRelativePath(m["group"].(string)); err != nil {
log.Printf("[WARN] Error on retrieving relative path of instance group: %s", err)
buf.WriteString(fmt.Sprintf("%s-", m["group"].(string)))
} else {
buf.WriteString(fmt.Sprintf("%s-", group))
}
if v, ok := m["balancing_mode"]; ok {
if v == nil {
v = ""
}
buf.WriteString(fmt.Sprintf("%s-", v.(string)))
}
if v, ok := m["capacity_scaler"]; ok {
if v == nil {
v = 0.0
}
buf.WriteString(fmt.Sprintf("%f-", v.(float64)))
}
if v, ok := m["description"]; ok {
if v == nil {
v = ""
}
log.Printf("[DEBUG] writing description %s", v)
buf.WriteString(fmt.Sprintf("%s-", v.(string)))
}
if v, ok := m["max_rate"]; ok {
if v == nil {
v = 0
}
buf.WriteString(fmt.Sprintf("%d-", int64(v.(int))))
}
if v, ok := m["max_rate_per_instance"]; ok {
if v == nil {
v = 0.0
}
buf.WriteString(fmt.Sprintf("%f-", v.(float64)))
}
if v, ok := m["max_connections"]; ok {
if v == nil {
v = 0
}
switch v := v.(type) {
case float64:
// The Golang JSON library can't tell int values apart from floats,
// because MM doesn't give fields strong types. Since another value
// in this block was a real float, it assumed this was a float too.
// It's not.
// Note that math.Round in Go is from float64 -> float64, so it will
// be a noop. int(floatVal) truncates extra parts, so if the float64
// representation of an int falls below the real value we'll have
// the wrong value. eg if 3 was represented as 2.999999, that would
// convert to 2. So we add 0.5, ensuring that we'll truncate to the
// correct value. This wouldn't remain true if we were far enough
// from 0 that we were off by > 0.5, but no float conversion *could*
// work correctly in that case. 53-bit floating types as the only
// numeric type was not a good idea, thanks Javascript.
var vInt int
if v < 0 {
vInt = int(v - 0.5)
} else {
vInt = int(v + 0.5)
}
log.Printf("[DEBUG] writing float value %f as integer value %v", v, vInt)
buf.WriteString(fmt.Sprintf("%d-", vInt))
default:
buf.WriteString(fmt.Sprintf("%d-", int64(v.(int))))
}
}
if v, ok := m["max_connections_per_instance"]; ok {
if v == nil {
v = 0
}
switch v := v.(type) {
case float64:
// The Golang JSON library can't tell int values apart from floats,
// because MM doesn't give fields strong types. Since another value
// in this block was a real float, it assumed this was a float too.
// It's not.
// Note that math.Round in Go is from float64 -> float64, so it will
// be a noop. int(floatVal) truncates extra parts, so if the float64
// representation of an int falls below the real value we'll have
// the wrong value. eg if 3 was represented as 2.999999, that would
// convert to 2. So we add 0.5, ensuring that we'll truncate to the
// correct value. This wouldn't remain true if we were far enough
// from 0 that we were off by > 0.5, but no float conversion *could*
// work correctly in that case. 53-bit floating types as the only
// numeric type was not a good idea, thanks Javascript.
var vInt int
if v < 0 {
vInt = int(v - 0.5)
} else {
vInt = int(v + 0.5)
}
log.Printf("[DEBUG] writing float value %f as integer value %v", v, vInt)
buf.WriteString(fmt.Sprintf("%d-", vInt))
default:
buf.WriteString(fmt.Sprintf("%d-", int64(v.(int))))
}
}
if v, ok := m["max_rate_per_instance"]; ok {
if v == nil {
v = 0.0
}
buf.WriteString(fmt.Sprintf("%f-", v.(float64)))
}
log.Printf("[DEBUG] computed hash value of %v from %v", hashcode.String(buf.String()), buf.String())
return hashcode.String(buf.String())
}
func resourceComputeBackendService() *schema.Resource {
return &schema.Resource{
Create: resourceComputeBackendServiceCreate,
@ -116,6 +248,11 @@ func resourceComputeBackendService() *schema.Resource {
},
},
},
"signed_url_cache_max_age_sec": {
Type: schema.TypeInt,
Optional: true,
Default: 3600,
},
},
},
},
@ -156,6 +293,12 @@ func resourceComputeBackendService() *schema.Resource {
},
},
},
"load_balancing_scheme": {
Type: schema.TypeString,
Optional: true,
ValidateFunc: validation.StringInSlice([]string{"INTERNAL", "EXTERNAL", ""}, false),
Default: "EXTERNAL",
},
"port_name": {
Type: schema.TypeString,
Computed: true,
@ -311,6 +454,12 @@ func resourceComputeBackendServiceCreate(d *schema.ResourceData, meta interface{
} else if v, ok := d.GetOkExists("iap"); ok || !reflect.DeepEqual(v, iapProp) {
obj["iap"] = iapProp
}
loadBalancingSchemeProp, err := expandComputeBackendServiceLoadBalancingScheme(d.Get("load_balancing_scheme"), d, config)
if err != nil {
return err
} else if v, ok := d.GetOkExists("load_balancing_scheme"); !isEmptyValue(reflect.ValueOf(loadBalancingSchemeProp)) && (ok || !reflect.DeepEqual(v, loadBalancingSchemeProp)) {
obj["loadBalancingScheme"] = loadBalancingSchemeProp
}
nameProp, err := expandComputeBackendServiceName(d.Get("name"), d, config)
if err != nil {
return err
@ -475,6 +624,9 @@ func resourceComputeBackendServiceRead(d *schema.ResourceData, meta interface{})
if err := d.Set("iap", flattenComputeBackendServiceIap(res["iap"], d)); err != nil {
return fmt.Errorf("Error reading BackendService: %s", err)
}
if err := d.Set("load_balancing_scheme", flattenComputeBackendServiceLoadBalancingScheme(res["loadBalancingScheme"], d)); err != nil {
return fmt.Errorf("Error reading BackendService: %s", err)
}
if err := d.Set("name", flattenComputeBackendServiceName(res["name"], d)); err != nil {
return fmt.Errorf("Error reading BackendService: %s", err)
}
@ -558,6 +710,12 @@ func resourceComputeBackendServiceUpdate(d *schema.ResourceData, meta interface{
} else if v, ok := d.GetOkExists("iap"); ok || !reflect.DeepEqual(v, iapProp) {
obj["iap"] = iapProp
}
loadBalancingSchemeProp, err := expandComputeBackendServiceLoadBalancingScheme(d.Get("load_balancing_scheme"), d, config)
if err != nil {
return err
} else if v, ok := d.GetOkExists("load_balancing_scheme"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, loadBalancingSchemeProp)) {
obj["loadBalancingScheme"] = loadBalancingSchemeProp
}
nameProp, err := expandComputeBackendServiceName(d.Get("name"), d, config)
if err != nil {
return err
@ -808,6 +966,8 @@ func flattenComputeBackendServiceCdnPolicy(v interface{}, d *schema.ResourceData
transformed := make(map[string]interface{})
transformed["cache_key_policy"] =
flattenComputeBackendServiceCdnPolicyCacheKeyPolicy(original["cacheKeyPolicy"], d)
transformed["signed_url_cache_max_age_sec"] =
flattenComputeBackendServiceCdnPolicySignedUrlCacheMaxAgeSec(original["signedUrlCacheMaxAgeSec"], d)
return []interface{}{transformed}
}
func flattenComputeBackendServiceCdnPolicyCacheKeyPolicy(v interface{}, d *schema.ResourceData) interface{} {
@ -857,6 +1017,16 @@ func flattenComputeBackendServiceCdnPolicyCacheKeyPolicyQueryStringWhitelist(v i
return schema.NewSet(schema.HashString, v.([]interface{}))
}
func flattenComputeBackendServiceCdnPolicySignedUrlCacheMaxAgeSec(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 flattenComputeBackendServiceConnectionDrainingConnection_draining_timeout_sec(v interface{}, d *schema.ResourceData) interface{} {
// Handles the string fixed64 format
if strVal, ok := v.(string); ok {
@ -919,6 +1089,10 @@ func flattenComputeBackendServiceIapOauth2ClientSecretSha256(v interface{}, d *s
return v
}
func flattenComputeBackendServiceLoadBalancingScheme(v interface{}, d *schema.ResourceData) interface{} {
return v
}
func flattenComputeBackendServiceName(v interface{}, d *schema.ResourceData) interface{} {
return v
}
@ -1088,6 +1262,13 @@ func expandComputeBackendServiceCdnPolicy(v interface{}, d TerraformResourceData
transformed["cacheKeyPolicy"] = transformedCacheKeyPolicy
}
transformedSignedUrlCacheMaxAgeSec, err := expandComputeBackendServiceCdnPolicySignedUrlCacheMaxAgeSec(original["signed_url_cache_max_age_sec"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedSignedUrlCacheMaxAgeSec); val.IsValid() && !isEmptyValue(val) {
transformed["signedUrlCacheMaxAgeSec"] = transformedSignedUrlCacheMaxAgeSec
}
return transformed, nil
}
@ -1160,6 +1341,10 @@ func expandComputeBackendServiceCdnPolicyCacheKeyPolicyQueryStringWhitelist(v in
return v, nil
}
func expandComputeBackendServiceCdnPolicySignedUrlCacheMaxAgeSec(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
return v, nil
}
func expandComputeBackendServiceConnectionDraining(d TerraformResourceData, config *Config) (interface{}, error) {
transformed := make(map[string]interface{})
// Note that nesting flattened objects won't work because we don't handle them properly here.
@ -1239,6 +1424,10 @@ func expandComputeBackendServiceIapOauth2ClientSecretSha256(v interface{}, d Ter
return v, nil
}
func expandComputeBackendServiceLoadBalancingScheme(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
return v, nil
}
func expandComputeBackendServiceName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
return v, nil
}

View File

@ -1,222 +0,0 @@
package google
import (
"fmt"
"log"
"strconv"
"strings"
"bytes"
"github.com/hashicorp/terraform/helper/hashcode"
"github.com/hashicorp/terraform/terraform"
)
func resourceComputeBackendServiceMigrateState(
v int, is *terraform.InstanceState, meta interface{}) (*terraform.InstanceState, error) {
if is.Empty() {
log.Println("[DEBUG] Empty InstanceState; nothing to migrate.")
return is, nil
}
switch v {
case 0:
log.Println("[INFO] Found Compute Backend Service State v0; migrating to v1")
is, err := migrateBackendServiceStateV0toV1(is)
if err != nil {
return is, err
}
return is, nil
default:
return is, fmt.Errorf("Unexpected schema version: %d", v)
}
}
func migrateBackendServiceStateV0toV1(is *terraform.InstanceState) (*terraform.InstanceState, error) {
log.Printf("[DEBUG] Attributes before migration: %#v", is.Attributes)
oldHashToValue := map[string]map[string]interface{}{}
for k, v := range is.Attributes {
if !strings.HasPrefix(k, "backend.") || k == "backend.#" {
continue
}
// Key is now of the form backend.%d.%s
kParts := strings.Split(k, ".")
// Sanity check: two parts should be there and <N> should be a number
badFormat := false
if len(kParts) != 3 {
badFormat = true
} else if _, err := strconv.Atoi(kParts[1]); err != nil {
badFormat = true
}
if badFormat {
return is, fmt.Errorf("migration error: found backend key in unexpected format: %s", k)
}
if oldHashToValue[kParts[1]] == nil {
oldHashToValue[kParts[1]] = map[string]interface{}{}
}
oldHashToValue[kParts[1]][kParts[2]] = v
}
oldHashToNewHash := map[string]int{}
for k, v := range oldHashToValue {
oldHashToNewHash[k] = resourceGoogleComputeBackendServiceBackendHash(v)
}
values := map[string]string{}
for k, v := range is.Attributes {
if !strings.HasPrefix(k, "backend.") {
continue
}
if k == "backend.#" {
continue
}
// Key is now of the form backend.%d.%s
kParts := strings.Split(k, ".")
newKey := fmt.Sprintf("%s.%d.%s", kParts[0], oldHashToNewHash[kParts[1]], kParts[2])
values[newKey] = v
delete(is.Attributes, k)
}
for k, v := range values {
is.Attributes[k] = v
}
log.Printf("[DEBUG] Attributes after migration: %#v", is.Attributes)
return is, nil
}
func resourceGoogleComputeBackendServiceBackendHash(v interface{}) int {
if v == nil {
return 0
}
var buf bytes.Buffer
m := v.(map[string]interface{})
log.Printf("[DEBUG] hashing %v", m)
if group, err := getRelativePath(m["group"].(string)); err != nil {
log.Printf("[WARN] Error on retrieving relative path of instance group: %s", err)
buf.WriteString(fmt.Sprintf("%s-", m["group"].(string)))
} else {
buf.WriteString(fmt.Sprintf("%s-", group))
}
if v, ok := m["balancing_mode"]; ok {
if v == nil {
v = ""
}
buf.WriteString(fmt.Sprintf("%s-", v.(string)))
}
if v, ok := m["capacity_scaler"]; ok {
if v == nil {
v = 0.0
}
buf.WriteString(fmt.Sprintf("%f-", v.(float64)))
}
if v, ok := m["description"]; ok {
if v == nil {
v = ""
}
log.Printf("[DEBUG] writing description %s", v)
buf.WriteString(fmt.Sprintf("%s-", v.(string)))
}
if v, ok := m["max_rate"]; ok {
if v == nil {
v = 0
}
buf.WriteString(fmt.Sprintf("%d-", int64(v.(int))))
}
if v, ok := m["max_rate_per_instance"]; ok {
if v == nil {
v = 0.0
}
buf.WriteString(fmt.Sprintf("%f-", v.(float64)))
}
if v, ok := m["max_connections"]; ok {
if v == nil {
v = 0
}
switch v := v.(type) {
case float64:
// The Golang JSON library can't tell int values apart from floats,
// because MM doesn't give fields strong types. Since another value
// in this block was a real float, it assumed this was a float too.
// It's not.
// Note that math.Round in Go is from float64 -> float64, so it will
// be a noop. int(floatVal) truncates extra parts, so if the float64
// representation of an int falls below the real value we'll have
// the wrong value. eg if 3 was represented as 2.999999, that would
// convert to 2. So we add 0.5, ensuring that we'll truncate to the
// correct value. This wouldn't remain true if we were far enough
// from 0 that we were off by > 0.5, but no float conversion *could*
// work correctly in that case. 53-bit floating types as the only
// numeric type was not a good idea, thanks Javascript.
var vInt int
if v < 0 {
vInt = int(v - 0.5)
} else {
vInt = int(v + 0.5)
}
log.Printf("[DEBUG] writing float value %f as integer value %v", v, vInt)
buf.WriteString(fmt.Sprintf("%d-", vInt))
default:
buf.WriteString(fmt.Sprintf("%d-", int64(v.(int))))
}
}
if v, ok := m["max_connections_per_instance"]; ok {
if v == nil {
v = 0
}
switch v := v.(type) {
case float64:
// The Golang JSON library can't tell int values apart from floats,
// because MM doesn't give fields strong types. Since another value
// in this block was a real float, it assumed this was a float too.
// It's not.
// Note that math.Round in Go is from float64 -> float64, so it will
// be a noop. int(floatVal) truncates extra parts, so if the float64
// representation of an int falls below the real value we'll have
// the wrong value. eg if 3 was represented as 2.999999, that would
// convert to 2. So we add 0.5, ensuring that we'll truncate to the
// correct value. This wouldn't remain true if we were far enough
// from 0 that we were off by > 0.5, but no float conversion *could*
// work correctly in that case. 53-bit floating types as the only
// numeric type was not a good idea, thanks Javascript.
var vInt int
if v < 0 {
vInt = int(v - 0.5)
} else {
vInt = int(v + 0.5)
}
log.Printf("[DEBUG] writing float value %f as integer value %v", v, vInt)
buf.WriteString(fmt.Sprintf("%d-", vInt))
default:
buf.WriteString(fmt.Sprintf("%d-", int64(v.(int))))
}
}
if v, ok := m["max_rate_per_instance"]; ok {
if v == nil {
v = 0.0
}
buf.WriteString(fmt.Sprintf("%f-", v.(float64)))
}
log.Printf("[DEBUG] computed hash value of %v from %v", hashcode.String(buf.String()), buf.String())
return hashcode.String(buf.String())
}

View File

@ -1,95 +0,0 @@
package google
import (
"testing"
"github.com/hashicorp/terraform/terraform"
)
func TestComputeBackendServiceMigrateState(t *testing.T) {
cases := map[string]struct {
StateVersion int
Attributes map[string]string
ExpectedAttributes map[string]string
Meta interface{}
}{
"v0 to v1": {
StateVersion: 0,
Attributes: map[string]string{
"backend.#": "1",
"backend.242332812.group": "https://www.googleapis.com/compute/v1/projects/project_name/zones/zone_name/instances/instanceGroups/igName",
"backend.242332812.balancing_mode": "UTILIZATION",
"backend.242332812.max_utilization": "0.8",
},
ExpectedAttributes: map[string]string{
"backend.#": "1",
"backend.2573491210.group": "https://www.googleapis.com/compute/v1/projects/project_name/zones/zone_name/instances/instanceGroups/igName",
"backend.2573491210.balancing_mode": "UTILIZATION",
"backend.2573491210.max_utilization": "0.8",
},
Meta: &Config{},
},
}
for tn, tc := range cases {
is := &terraform.InstanceState{
ID: "i-abc123",
Attributes: tc.Attributes,
}
is, err := resourceComputeBackendServiceMigrateState(
tc.StateVersion, is, tc.Meta)
if err != nil {
t.Fatalf("bad: %s, err: %#v", tn, err)
}
for k, v := range tc.ExpectedAttributes {
if is.Attributes[k] != v {
t.Fatalf(
"bad: %s\n\n expected: %#v -> %#v\n got: %#v -> %#v\n in: %#v",
tn, k, v, k, is.Attributes[k], is.Attributes)
}
}
for k, v := range is.Attributes {
if tc.ExpectedAttributes[k] != v {
t.Fatalf(
"bad: %s\n\n expected: %#v -> %#v\n got: %#v -> %#v\n in: %#v",
tn, k, tc.ExpectedAttributes[k], k, v, is.Attributes)
}
}
}
}
func TestComputeBackendServiceMigrateState_empty(t *testing.T) {
cases := map[string]struct {
StateVersion int
}{
"v0": {
StateVersion: 0,
},
}
for tn, tc := range cases {
var is *terraform.InstanceState
var meta *Config
// should handle nil
is, err := resourceComputeBackendServiceMigrateState(tc.StateVersion, is, meta)
if err != nil {
t.Fatalf("bad %s, err: %#v", tn, err)
}
if is != nil {
t.Fatalf("bad %s, expected nil instancestate, got: %#v", tn, is)
}
// should handle non-nil but empty
is = &terraform.InstanceState{}
is, err = resourceComputeBackendServiceMigrateState(tc.StateVersion, is, meta)
if err != nil {
t.Fatalf("bad %s, err: %#v", tn, err)
}
}
}

View File

@ -110,6 +110,13 @@ The following arguments are supported:
(Optional)
Settings for enabling Cloud Identity Aware Proxy Structure is documented below.
* `load_balancing_scheme` -
(Optional)
Indicates whether the backend service will be used with internal or
external load balancing. A backend service created for one type of
load balancing cannot be used with the other. One of `INTERNAL` or
`EXTERNAL`. Defaults to `EXTERNAL`.
* `port_name` -
(Optional)
Name of backend port. The same name should appear in the instance
@ -228,6 +235,18 @@ The `cdn_policy` block supports:
(Optional)
The CacheKeyPolicy for this CdnPolicy. Structure is documented below.
* `signed_url_cache_max_age_sec` -
(Optional)
Maximum number of seconds the response to a signed URL request
will be considered fresh, defaults to 1hr (3600s). After this
time period, the response will be revalidated before
being served.
When serving responses to signed URL requests, Cloud CDN will
internally behave as though all responses from this backend had a
"Cache-Control: public, max-age=[TTL]" header, regardless of any
existing Cache-Control header. The actual headers served in
responses will not be altered.
The `cache_key_policy` block supports: