diff --git a/mmv1/third_party/terraform/services/compute/compute_instance_helpers.go.tmpl b/mmv1/third_party/terraform/services/compute/compute_instance_helpers.go.tmpl index 72034159cf5f..50965b207401 100644 --- a/mmv1/third_party/terraform/services/compute/compute_instance_helpers.go.tmpl +++ b/mmv1/third_party/terraform/services/compute/compute_instance_helpers.go.tmpl @@ -1,7 +1,6 @@ package compute import ( - "encoding/json" "fmt" "log" "reflect" @@ -12,13 +11,6 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" - "google.golang.org/api/googleapi" - -{{ if eq $.TargetVersionName `ga` }} - "google.golang.org/api/compute/v1" -{{- else }} - compute "google.golang.org/api/compute/v0.beta" -{{- end }} ) func instanceSchedulingNodeAffinitiesElemSchema() *schema.Resource { @@ -136,19 +128,17 @@ func flattenIpv6AliasRange(d *schema.ResourceData, ranges []interface{}, i int) } {{- end }} -func expandScheduling(v interface{}) (*compute.Scheduling, error) { +func expandScheduling(v interface{}) (map[string]interface{}, error) { if v == nil { - // We can't set default values for lists. - return &compute.Scheduling{ - AutomaticRestart: googleapi.Bool(true), + return map[string]interface{}{ + "automaticRestart": true, }, nil } ls := v.([]interface{}) if len(ls) == 0 { - // We can't set default values for lists - return &compute.Scheduling{ - AutomaticRestart: googleapi.Bool(true), + return map[string]interface{}{ + "automaticRestart": true, }, nil } @@ -157,64 +147,59 @@ func expandScheduling(v interface{}) (*compute.Scheduling, error) { } original := ls[0].(map[string]interface{}) - scheduling := &compute.Scheduling{ - ForceSendFields: make([]string, 0, 4), - } + result := map[string]interface{}{} if v, ok := original["automatic_restart"]; ok { - scheduling.AutomaticRestart = googleapi.Bool(v.(bool)) - scheduling.ForceSendFields = append(scheduling.ForceSendFields, "AutomaticRestart") + result["automaticRestart"] = v.(bool) } if v, ok := original["preemptible"]; ok { - scheduling.Preemptible = v.(bool) - scheduling.ForceSendFields = append(scheduling.ForceSendFields, "Preemptible") + result["preemptible"] = v.(bool) } if v, ok := original["on_host_maintenance"]; ok { - scheduling.OnHostMaintenance = v.(string) - scheduling.ForceSendFields = append(scheduling.ForceSendFields, "OnHostMaintenance") + result["onHostMaintenance"] = v.(string) } if v, ok := original["node_affinities"]; ok && v != nil { naSet := v.(*schema.Set).List() - scheduling.NodeAffinities = make([]*compute.SchedulingNodeAffinity, len(ls)) - scheduling.ForceSendFields = append(scheduling.ForceSendFields, "NodeAffinities") - for _, nodeAffRaw := range naSet { - if nodeAffRaw == nil { - continue - } - nodeAff := nodeAffRaw.(map[string]interface{}) - transformed := &compute.SchedulingNodeAffinity{ - Key: nodeAff["key"].(string), - Operator: nodeAff["operator"].(string), - Values: tpgresource.ConvertStringArr(nodeAff["values"].(*schema.Set).List()), + if len(naSet) == 0 { + result["nodeAffinities"] = []interface{}{nil} + } else { + nodeAffinities := make([]interface{}, 0, len(naSet)) + for _, nodeAffRaw := range naSet { + if nodeAffRaw == nil { + continue + } + nodeAff := nodeAffRaw.(map[string]interface{}) + nodeAffinities = append(nodeAffinities, map[string]interface{}{ + "key": nodeAff["key"].(string), + "operator": nodeAff["operator"].(string), + "values": tpgresource.ConvertStringArr(nodeAff["values"].(*schema.Set).List()), + }) } - scheduling.NodeAffinities = append(scheduling.NodeAffinities, transformed) + result["nodeAffinities"] = nodeAffinities } } - if v, ok := original["min_node_cpus"]; ok { - scheduling.MinNodeCpus = int64(v.(int)) + if v, ok := original["min_node_cpus"]; ok && v.(int) != 0 { + result["minNodeCpus"] = int64(v.(int)) } if v, ok := original["provisioning_model"]; ok { - scheduling.ProvisioningModel = v.(string) - scheduling.ForceSendFields = append(scheduling.ForceSendFields, "ProvisioningModel") + result["provisioningModel"] = v.(string) } if v, ok := original["instance_termination_action"]; ok { - scheduling.InstanceTerminationAction = v.(string) - scheduling.ForceSendFields = append(scheduling.ForceSendFields, "InstanceTerminationAction") + result["instanceTerminationAction"] = v.(string) } - if v, ok := original["availability_domain"]; ok && v != nil { - scheduling.AvailabilityDomain = int64(v.(int)) + if v, ok := original["availability_domain"]; ok && v != nil && v.(int) != 0 { + result["availabilityDomain"] = int64(v.(int)) } if v, ok := original["max_run_duration"]; ok { transformedMaxRunDuration, err := expandComputeMaxRunDuration(v) if err != nil { return nil, err } - scheduling.MaxRunDuration = transformedMaxRunDuration - scheduling.ForceSendFields = append(scheduling.ForceSendFields, "MaxRunDuration") + result["maxRunDuration"] = transformedMaxRunDuration } if v, ok := original["on_instance_stop_action"]; ok { @@ -222,23 +207,21 @@ func expandScheduling(v interface{}) (*compute.Scheduling, error) { if err != nil { return nil, err } - scheduling.OnInstanceStopAction = transformedOnInstanceStopAction - scheduling.ForceSendFields = append(scheduling.ForceSendFields, "OnInstanceStopAction") + result["onInstanceStopAction"] = transformedOnInstanceStopAction } {{- if ne $.TargetVersionName "ga" }} if v, ok := original["host_error_timeout_seconds"]; ok { - scheduling.HostErrorTimeoutSeconds = int64(v.(int)) //host_error_timeout_seconds doesn't get removed correctly due to an API bug on instances.SetScheduling. - //We need to set it to NullFields as a workaround because nil is rounded to 0 + //We need to send null as a workaround because nil is rounded to 0 if v == 0 || v == nil { - scheduling.NullFields = append(scheduling.NullFields, "HostErrorTimeoutSeconds") + result["hostErrorTimeoutSeconds"] = nil } else { - scheduling.ForceSendFields = append(scheduling.ForceSendFields, "HostErrorTimeoutSeconds") + result["hostErrorTimeoutSeconds"] = int64(v.(int)) } } - if v, ok := original["maintenance_interval"]; ok { - scheduling.MaintenanceInterval = v.(string) + if v, ok := original["maintenance_interval"]; ok && v.(string) != "" { + result["maintenanceInterval"] = v.(string) } if v, ok := original["graceful_shutdown"]; ok { @@ -246,13 +229,11 @@ func expandScheduling(v interface{}) (*compute.Scheduling, error) { if err != nil { return nil, err } - scheduling.GracefulShutdown = transformedGracefulShutdown - scheduling.ForceSendFields = append(scheduling.ForceSendFields, "GracefulShutdown") + result["gracefulShutdown"] = transformedGracefulShutdown } if v, ok := original["skip_guest_os_shutdown"]; ok { - scheduling.SkipGuestOsShutdown = v.(bool) - scheduling.ForceSendFields = append(scheduling.ForceSendFields, "SkipGuestOsShutdown") + result["skipGuestOsShutdown"] = v.(bool) } if v, ok := original["preemption_notice_duration"]; ok { @@ -260,8 +241,7 @@ func expandScheduling(v interface{}) (*compute.Scheduling, error) { if err != nil { return nil, err } - scheduling.PreemptionNoticeDuration = transformedPreemptionNoticeDuration - scheduling.ForceSendFields = append(scheduling.ForceSendFields, "PreemptionNoticeDuration") + result["preemptionNoticeDuration"] = transformedPreemptionNoticeDuration } {{- end }} if v, ok := original["local_ssd_recovery_timeout"]; ok { @@ -269,39 +249,38 @@ func expandScheduling(v interface{}) (*compute.Scheduling, error) { if err != nil { return nil, err } - scheduling.LocalSsdRecoveryTimeout = transformedLocalSsdRecoveryTimeout - scheduling.ForceSendFields = append(scheduling.ForceSendFields, "LocalSsdRecoveryTimeout") + result["localSsdRecoveryTimeout"] = transformedLocalSsdRecoveryTimeout } - if v, ok := original["termination_time"]; ok { - scheduling.TerminationTime = v.(string) + if v, ok := original["termination_time"]; ok && v.(string) != "" { + result["terminationTime"] = v.(string) } - return scheduling, nil + return result, nil } -func expandComputeMaxRunDuration(v interface{}) (*compute.Duration, error) { +func expandComputeMaxRunDuration(v interface{}) (map[string]interface{}, error) { l := v.([]interface{}) - duration := compute.Duration{} if len(l) == 0 || l[0] == nil { return nil, nil } raw := l[0] original := raw.(map[string]interface{}) + result := map[string]interface{}{} transformedNanos, err := expandComputeMaxRunDurationNanos(original["nanos"]) if err != nil { return nil, err } else if val := reflect.ValueOf(transformedNanos); val.IsValid() && !tpgresource.IsEmptyValue(val) { - duration.Nanos = int64(transformedNanos.(int)) + result["nanos"] = int64(transformedNanos.(int)) } transformedSeconds, err := expandComputeMaxRunDurationSeconds(original["seconds"]) if err != nil { return nil, err } else if val := reflect.ValueOf(transformedSeconds); val.IsValid() && !tpgresource.IsEmptyValue(val) { - duration.Seconds = int64(transformedSeconds.(int)) + result["seconds"] = int64(transformedSeconds.(int)) } - return &duration, nil + return result, nil } func expandComputeMaxRunDurationNanos(v interface{}) (interface{}, error) { @@ -312,47 +291,45 @@ func expandComputeMaxRunDurationSeconds(v interface{}) (interface{}, error) { return v, nil } -func expandComputeOnInstanceStopAction(v interface{}) (*compute.SchedulingOnInstanceStopAction, error){ +func expandComputeOnInstanceStopAction(v interface{}) (map[string]interface{}, error) { l := v.([]interface{}) - onInstanceStopAction := compute.SchedulingOnInstanceStopAction{} if len(l) == 0 || l[0] == nil { return nil, nil } raw := l[0] original := raw.(map[string]interface{}) - + if d, ok := original["discard_local_ssd"]; ok { - onInstanceStopAction.DiscardLocalSsd = d.(bool) - } else { - return nil, nil + return map[string]interface{}{ + "discardLocalSsd": d.(bool), + }, nil } - - return &onInstanceStopAction, nil + return nil, nil } -func expandComputeLocalSsdRecoveryTimeout(v interface{}) (*compute.Duration, error) { +func expandComputeLocalSsdRecoveryTimeout(v interface{}) (map[string]interface{}, error) { l := v.([]interface{}) - duration := compute.Duration{} if len(l) == 0 || l[0] == nil { return nil, nil } raw := l[0] original := raw.(map[string]interface{}) + result := map[string]interface{}{} transformedNanos, err := expandComputeLocalSsdRecoveryTimeoutNanos(original["nanos"]) if err != nil { return nil, err } else if val := reflect.ValueOf(transformedNanos); val.IsValid() && !tpgresource.IsEmptyValue(val) { - duration.Nanos = int64(transformedNanos.(int)) + result["nanos"] = int64(transformedNanos.(int)) } transformedSeconds, err := expandComputeLocalSsdRecoveryTimeoutSeconds(original["seconds"]) if err != nil { return nil, err } else if val := reflect.ValueOf(transformedSeconds); val.IsValid() && !tpgresource.IsEmptyValue(val) { - duration.Seconds = int64(transformedSeconds.(int)) + result["seconds"] = int64(transformedSeconds.(int)) } - return &duration, nil + return result, nil } func expandComputeLocalSsdRecoveryTimeoutNanos(v interface{}) (interface{}, error) { @@ -364,191 +341,208 @@ func expandComputeLocalSsdRecoveryTimeoutSeconds(v interface{}) (interface{}, er } {{- if ne $.TargetVersionName "ga" }} -func expandGracefulShutdown(v interface{}) (*compute.SchedulingGracefulShutdown, error) { +func expandGracefulShutdown(v interface{}) (map[string]interface{}, error) { l := v.([]interface{}) - gracefulShutdown := compute.SchedulingGracefulShutdown{} if len(l) == 0 || l[0] == nil { return nil, nil } raw := l[0] original := raw.(map[string]interface{}) + result := map[string]interface{}{ + "enabled": original["enabled"].(bool), + } + originalMaxDuration := original["max_duration"].([]interface{}) maxDuration, err := expandGracefulShutdownMaxDuration(originalMaxDuration) if err != nil { return nil, err } if maxDuration != nil { - gracefulShutdown.MaxDuration = maxDuration + result["maxDuration"] = maxDuration } - gracefulShutdown.Enabled = original["enabled"].(bool) - gracefulShutdown.ForceSendFields = append(gracefulShutdown.ForceSendFields, "Enabled") - return &gracefulShutdown, nil + return result, nil } -func expandGracefulShutdownMaxDuration(v interface{}) (*compute.Duration, error) { +func expandGracefulShutdownMaxDuration(v interface{}) (map[string]interface{}, error) { l := v.([]interface{}) - duration := compute.Duration{} if len(l) == 0 || l[0] == nil { return nil, nil } raw := l[0] maxDurationMap := raw.(map[string]interface{}) - transformedNanos := maxDurationMap["nanos"] - transformedSeconds := maxDurationMap["seconds"] + result := map[string]interface{}{} - if val := reflect.ValueOf(transformedNanos); val.IsValid() && !tpgresource.IsEmptyValue(val) { - duration.Nanos = int64(transformedNanos.(int)) - } - if val := reflect.ValueOf(transformedSeconds); val.IsValid() && !tpgresource.IsEmptyValue(val) { - duration.Seconds = int64(transformedSeconds.(int)) + if transformedNanos := maxDurationMap["nanos"]; reflect.ValueOf(transformedNanos).IsValid() && !tpgresource.IsEmptyValue(reflect.ValueOf(transformedNanos)) { + result["nanos"] = int64(transformedNanos.(int)) } + result["seconds"] = int64(maxDurationMap["seconds"].(int)) - duration.ForceSendFields = append(duration.ForceSendFields, "Seconds") - - return &duration, nil + return result, nil } {{ end }} -func flattenScheduling(resp *compute.Scheduling) []map[string]interface{} { +func flattenScheduling(resp map[string]interface{}) []map[string]interface{} { schedulingMap := map[string]interface{}{ - "on_host_maintenance": resp.OnHostMaintenance, - "preemptible": resp.Preemptible, - "min_node_cpus": resp.MinNodeCpus, - "provisioning_model": resp.ProvisioningModel, - "instance_termination_action": resp.InstanceTerminationAction, - "availability_domain": resp.AvailabilityDomain, - "termination_time": resp.TerminationTime, + "on_host_maintenance": resp["onHostMaintenance"], + "preemptible": resp["preemptible"], + "min_node_cpus": getInt(resp["minNodeCpus"]), + "provisioning_model": resp["provisioningModel"], + "instance_termination_action": resp["instanceTerminationAction"], + "availability_domain": getInt(resp["availabilityDomain"]), + "termination_time": resp["terminationTime"], } - if resp.AutomaticRestart != nil { - schedulingMap["automatic_restart"] = *resp.AutomaticRestart + if ar, ok := resp["automaticRestart"].(bool); ok { + schedulingMap["automatic_restart"] = ar } - if resp.MaxRunDuration != nil { - schedulingMap["max_run_duration"] = flattenComputeMaxRunDuration(resp.MaxRunDuration) + if maxRun, ok := resp["maxRunDuration"].(map[string]interface{}); ok { + schedulingMap["max_run_duration"] = flattenComputeMaxRunDuration(maxRun) } - if resp.OnInstanceStopAction != nil { - schedulingMap["on_instance_stop_action"] = flattenOnInstanceStopAction(resp.OnInstanceStopAction) + if ois, ok := resp["onInstanceStopAction"].(map[string]interface{}); ok { + schedulingMap["on_instance_stop_action"] = flattenOnInstanceStopAction(ois) } {{ if ne $.TargetVersionName `ga` -}} - schedulingMap["skip_guest_os_shutdown"] = resp.SkipGuestOsShutdown + schedulingMap["skip_guest_os_shutdown"] = resp["skipGuestOsShutdown"] - if resp.HostErrorTimeoutSeconds != 0 { - schedulingMap["host_error_timeout_seconds"] = resp.HostErrorTimeoutSeconds + if h := getInt(resp["hostErrorTimeoutSeconds"]); h != 0 { + schedulingMap["host_error_timeout_seconds"] = h } - if resp.MaintenanceInterval != "" { - schedulingMap["maintenance_interval"] = resp.MaintenanceInterval + if mi, ok := resp["maintenanceInterval"].(string); ok && mi != "" { + schedulingMap["maintenance_interval"] = mi } - if resp.GracefulShutdown != nil { - schedulingMap["graceful_shutdown"] = flattenGracefulShutdown(resp.GracefulShutdown) + if gs, ok := resp["gracefulShutdown"].(map[string]interface{}); ok { + schedulingMap["graceful_shutdown"] = flattenGracefulShutdown(gs) } - if resp.PreemptionNoticeDuration != nil { - schedulingMap["preemption_notice_duration"] = flattenComputePreemptionNoticeDuration(resp.PreemptionNoticeDuration) + if pnd, ok := resp["preemptionNoticeDuration"].(map[string]interface{}); ok { + schedulingMap["preemption_notice_duration"] = flattenComputePreemptionNoticeDuration(pnd) } {{- end }} - if resp.LocalSsdRecoveryTimeout != nil { - schedulingMap["local_ssd_recovery_timeout"] = flattenComputeLocalSsdRecoveryTimeout(resp.LocalSsdRecoveryTimeout) + if lsrt, ok := resp["localSsdRecoveryTimeout"].(map[string]interface{}); ok { + schedulingMap["local_ssd_recovery_timeout"] = flattenComputeLocalSsdRecoveryTimeout(lsrt) } nodeAffinities := schema.NewSet(schema.HashResource(instanceSchedulingNodeAffinitiesElemSchema()), nil) - for _, na := range resp.NodeAffinities { - nodeAffinities.Add(map[string]interface{}{ - "key": na.Key, - "operator": na.Operator, - "values": schema.NewSet(schema.HashString, tpgresource.ConvertStringArrToInterface(na.Values)), - }) + if nodeAffRaw, ok := resp["nodeAffinities"].([]interface{}); ok { + for _, raw := range nodeAffRaw { + na, ok := raw.(map[string]interface{}) + if !ok { + continue + } + valuesRaw, _ := na["values"].([]interface{}) + values := make([]string, 0, len(valuesRaw)) + for _, v := range valuesRaw { + if s, ok := v.(string); ok { + values = append(values, s) + } + } + nodeAffinities.Add(map[string]interface{}{ + "key": na["key"], + "operator": na["operator"], + "values": schema.NewSet(schema.HashString, tpgresource.ConvertStringArrToInterface(values)), + }) + } } schedulingMap["node_affinities"] = nodeAffinities return []map[string]interface{}{schedulingMap} } -func flattenComputeMaxRunDuration(v *compute.Duration) []interface{} { +func flattenComputeMaxRunDuration(v map[string]interface{}) []interface{} { if v == nil { return nil } transformed := make(map[string]interface{}) - transformed["nanos"] = v.Nanos - transformed["seconds"] = v.Seconds + transformed["nanos"] = getInt(v["nanos"]) + transformed["seconds"] = getInt(v["seconds"]) return []interface{}{transformed} } -func flattenOnInstanceStopAction(v *compute.SchedulingOnInstanceStopAction) []interface{} { +func flattenOnInstanceStopAction(v map[string]interface{}) []interface{} { if v == nil { return nil } transformed := make(map[string]interface{}) - transformed["discard_local_ssd"] = v.DiscardLocalSsd + transformed["discard_local_ssd"] = v["discardLocalSsd"] return []interface{}{transformed} } -func flattenComputeLocalSsdRecoveryTimeout(v *compute.Duration) []interface{} { +func flattenComputeLocalSsdRecoveryTimeout(v map[string]interface{}) []interface{} { if v == nil { return nil } transformed := make(map[string]interface{}) - transformed["nanos"] = v.Nanos - transformed["seconds"] = v.Seconds + transformed["nanos"] = getInt(v["nanos"]) + transformed["seconds"] = getInt(v["seconds"]) return []interface{}{transformed} } {{ if ne $.TargetVersionName `ga` -}} -func flattenGracefulShutdown(v *compute.SchedulingGracefulShutdown) []interface{} { +func flattenGracefulShutdown(v map[string]interface{}) []interface{} { if v == nil { return nil } transformed := make(map[string]interface{}) - transformed["enabled"] = v.Enabled - transformed["max_duration"] = flattenGracefulShutdownMaxDuration(v.MaxDuration) + transformed["enabled"] = v["enabled"] + if md, ok := v["maxDuration"].(map[string]interface{}); ok { + transformed["max_duration"] = flattenGracefulShutdownMaxDuration(md) + } return []interface{}{transformed} } -func flattenGracefulShutdownMaxDuration(v *compute.Duration) []interface{} { +func flattenGracefulShutdownMaxDuration(v map[string]interface{}) []interface{} { if v == nil { return nil } transformed := make(map[string]interface{}) - transformed["nanos"] = v.Nanos - transformed["seconds"] = v.Seconds + transformed["nanos"] = getInt(v["nanos"]) + transformed["seconds"] = getInt(v["seconds"]) return []interface{}{transformed} } -func expandComputePreemptionNoticeDuration(v interface{}) (*compute.Duration, error) { +func expandComputePreemptionNoticeDuration(v interface{}) (map[string]interface{}, error) { l := v.([]interface{}) - duration := compute.Duration{} if len(l) == 0 || l[0] == nil { return nil, nil } raw := l[0] original := raw.(map[string]interface{}) + result := map[string]interface{}{} if transformedNanos, ok := original["nanos"]; ok && transformedNanos != nil { - duration.Nanos = int64(transformedNanos.(int)) + if n := int64(transformedNanos.(int)); n != 0 { + result["nanos"] = n + } } if transformedSeconds, ok := original["seconds"]; ok && transformedSeconds != nil { - duration.Seconds = int64(transformedSeconds.(int)) + if s := int64(transformedSeconds.(int)); s != 0 { + result["seconds"] = s + } } - return &duration, nil + if len(result) == 0 { + return nil, nil + } + return result, nil } -func flattenComputePreemptionNoticeDuration(v *compute.Duration) []interface{} { +func flattenComputePreemptionNoticeDuration(v map[string]interface{}) []interface{} { if v == nil { return nil } transformed := make(map[string]interface{}) - transformed["nanos"] = v.Nanos - transformed["seconds"] = v.Seconds + transformed["nanos"] = getInt(v["nanos"]) + transformed["seconds"] = getInt(v["seconds"]) return []interface{}{transformed} } {{- end }} @@ -793,6 +787,22 @@ func getInterfaceSlice(v interface{}) []interface{} { return s } +func getInt(v interface{}) int64 { + switch t := v.(type) { + case int: + return int64(t) + case int64: + return t + case float64: + return int64(t) + case string: + i, _ := strconv.ParseInt(t, 10, 64) + return i + default: + return 0 + } +} + {{ if ne $.TargetVersionName `ga` -}} // firstAccessConfigSecurityPolicy returns the securityPolicy of the first // access config in the list, or "" if absent. @@ -812,27 +822,6 @@ func firstAccessConfigSecurityPolicy(accessConfigs []interface{}) string { } {{- end }} -// networkInterfacesToInterface converts a slice of typed Apiary network -// interface structs into the []interface{} of JSON-shaped maps expected by -// flattenNetworkInterfaces. This bridges callers that still read the instance -// via the typed compute client; once those reads migrate to SendRequest the -// response is already in this shape and the adapter can be dropped. -func networkInterfacesToInterface(networkInterfaces []*compute.NetworkInterface) ([]interface{}, error) { - result := make([]interface{}, 0, len(networkInterfaces)) - for _, ni := range networkInterfaces { - b, err := json.Marshal(ni) - if err != nil { - return nil, err - } - var m map[string]interface{} - if err := json.Unmarshal(b, &m); err != nil { - return nil, err - } - result = append(result, m) - } - return result, nil -} - func expandAccessConfigs(configs []interface{}) []interface{} { acs := make([]interface{}, len(configs)) for i, raw := range configs { @@ -988,61 +977,6 @@ func expandNetworkInterfaces(d tpgresource.TerraformResourceData, config *transp return ifaces, nil } -// convertViaJSON marshals a map-based representation and unmarshals it into the -// typed Apiary struct (slice). Used by the typed adapters below so the shared -// helpers file does not depend on tpgresource.Convert, which is not available in -// the tgc/tgc_next tpgresource packages. -func convertViaJSON(in, out interface{}) error { - bytes, err := json.Marshal(in) - if err != nil { - return err - } - return json.Unmarshal(bytes, out) -} - -// expandNetworkInterfacesTyped adapts the map-based expandNetworkInterfaces -// output to the typed []*compute.NetworkInterface still required by callers that -// build Apiary request structs directly or read typed fields. -func expandNetworkInterfacesTyped(d tpgresource.TerraformResourceData, config *transport_tpg.Config) ([]*compute.NetworkInterface, error) { - expanded, err := expandNetworkInterfaces(d, config) - if err != nil { - return nil, err - } - ifaces := make([]*compute.NetworkInterface, 0, len(expanded)) - if err := convertViaJSON(expanded, &ifaces); err != nil { - return nil, fmt.Errorf("Error converting network interfaces: %s", err) - } - return ifaces, nil -} - -// expandAccessConfigsTyped / expandIpv6AccessConfigsTyped / expandAliasIpRangesTyped -// adapt the map-based expanders back to the typed Apiary slices still required by -// callers that build compute structs field-by-field. -func expandAccessConfigsTyped(configs []interface{}) ([]*compute.AccessConfig, error) { - return accessConfigsToTyped(expandAccessConfigs(configs)) -} - -func expandIpv6AccessConfigsTyped(configs []interface{}) ([]*compute.AccessConfig, error) { - return accessConfigsToTyped(expandIpv6AccessConfigs(configs)) -} - -func accessConfigsToTyped(expanded []interface{}) ([]*compute.AccessConfig, error) { - acs := make([]*compute.AccessConfig, 0, len(expanded)) - if err := convertViaJSON(expanded, &acs); err != nil { - return nil, fmt.Errorf("Error converting access configs: %s", err) - } - return acs, nil -} - -func expandAliasIpRangesTyped(ranges []interface{}) ([]*compute.AliasIpRange, error) { - expanded := expandAliasIpRanges(ranges) - out := make([]*compute.AliasIpRange, 0, len(expanded)) - if err := convertViaJSON(expanded, &out); err != nil { - return nil, fmt.Errorf("Error converting alias ip ranges: %s", err) - } - return out, nil -} - func flattenServiceAccounts(serviceAccounts []interface{}) []map[string]interface{} { result := make([]map[string]interface{}, len(serviceAccounts)) for i, raw := range serviceAccounts { @@ -1077,35 +1011,6 @@ func expandServiceAccounts(configs []interface{}) []interface{} { return accounts } -// expandServiceAccountsTyped adapts the map-based expandServiceAccounts output -// to the typed []*compute.ServiceAccount still required by callers that build -// Apiary request structs directly. -func expandServiceAccountsTyped(configs []interface{}) []*compute.ServiceAccount { - expanded := expandServiceAccounts(configs) - accounts := make([]*compute.ServiceAccount, len(expanded)) - for i, raw := range expanded { - data := raw.(map[string]interface{}) - accounts[i] = &compute.ServiceAccount{ - Email: data["email"].(string), - Scopes: data["scopes"].([]string), - } - } - return accounts -} - -// serviceAccountsToInterface adapts typed []*compute.ServiceAccount decoded from -// an Apiary response into the []interface{} form accepted by flattenServiceAccounts. -func serviceAccountsToInterface(serviceAccounts []*compute.ServiceAccount) []interface{} { - result := make([]interface{}, len(serviceAccounts)) - for i, sa := range serviceAccounts { - result[i] = map[string]interface{}{ - "email": sa.Email, - "scopes": tpgresource.ConvertStringArrToInterface(sa.Scopes), - } - } - return result -} - func flattenGuestAccelerators(accelerators []interface{}) []map[string]interface{} { acceleratorsSchema := make([]map[string]interface{}, 0, len(accelerators)) for _, raw := range accelerators { @@ -1121,20 +1026,6 @@ func flattenGuestAccelerators(accelerators []interface{}) []map[string]interface return acceleratorsSchema } -// guestAcceleratorsToInterface adapts typed []*compute.AcceleratorConfig decoded -// from an Apiary response into the []interface{} form accepted by -// flattenGuestAccelerators. -func guestAcceleratorsToInterface(accelerators []*compute.AcceleratorConfig) []interface{} { - result := make([]interface{}, len(accelerators)) - for i, a := range accelerators { - result[i] = map[string]interface{}{ - "acceleratorCount": a.AcceleratorCount, - "acceleratorType": a.AcceleratorType, - } - } - return result -} - func resourceInstanceTags(d tpgresource.TerraformResourceData) map[string]interface{} { v := d.Get("tags") if v == nil { @@ -1232,36 +1123,6 @@ func flattenAdvancedMachineFeatures(v map[string]interface{}) []map[string]inter return []map[string]interface{}{result} } -func expandAdvancedMachineFeaturesTyped(d tpgresource.TerraformResourceData) *compute.AdvancedMachineFeatures { - if _, ok := d.GetOk("advanced_machine_features"); !ok { - return nil - } - - prefix := "advanced_machine_features.0" - return &compute.AdvancedMachineFeatures{ - EnableNestedVirtualization: d.Get(prefix + ".enable_nested_virtualization").(bool), - ThreadsPerCore: int64(d.Get(prefix + ".threads_per_core").(int)), - TurboMode: d.Get(prefix + ".turbo_mode").(string), - VisibleCoreCount: int64(d.Get(prefix + ".visible_core_count").(int)), - PerformanceMonitoringUnit: d.Get(prefix + ".performance_monitoring_unit").(string), - EnableUefiNetworking: d.Get(prefix + ".enable_uefi_networking").(bool), - } -} - -func flattenAdvancedMachineFeaturesTyped(AdvancedMachineFeatures *compute.AdvancedMachineFeatures) []map[string]interface{} { - if AdvancedMachineFeatures == nil { - return nil - } - return []map[string]interface{}{{"{{"}} - "enable_nested_virtualization": AdvancedMachineFeatures.EnableNestedVirtualization, - "threads_per_core": AdvancedMachineFeatures.ThreadsPerCore, - "turbo_mode": AdvancedMachineFeatures.TurboMode, - "visible_core_count": AdvancedMachineFeatures.VisibleCoreCount, - "performance_monitoring_unit": AdvancedMachineFeatures.PerformanceMonitoringUnit, - "enable_uefi_networking": AdvancedMachineFeatures.EnableUefiNetworking, - {{"}}"}} -} - func flattenShieldedVmConfig(shieldedVmConfig map[string]interface{}) []map[string]bool { if shieldedVmConfig == nil { return nil diff --git a/mmv1/third_party/terraform/services/compute/data_source_google_compute_instance.go b/mmv1/third_party/terraform/services/compute/data_source_google_compute_instance.go index e79e94444cad..edfa76a7f3bd 100644 --- a/mmv1/third_party/terraform/services/compute/data_source_google_compute_instance.go +++ b/mmv1/third_party/terraform/services/compute/data_source_google_compute_instance.go @@ -41,7 +41,13 @@ func dataSourceGoogleComputeInstanceRead(d *schema.ResourceData, meta interface{ return transport_tpg.HandleDataSourceNotFoundError(err, d, fmt.Sprintf("Instance %s", name), id) } - md := flattenMetadataBeta(instance.Metadata) + var metadataMap map[string]interface{} + if instance.Metadata != nil { + if metadataMap, err = tpgresource.ConvertToMap(instance.Metadata); err != nil { + return fmt.Errorf("error converting metadata: %s", err) + } + } + md := flattenMetadataBeta(metadataMap) if err = d.Set("metadata", md); err != nil { return fmt.Errorf("error setting metadata: %s", err) } @@ -152,7 +158,11 @@ func dataSourceGoogleComputeInstanceRead(d *schema.ResourceData, meta interface{ return err } - err = d.Set("scheduling", flattenScheduling(instance.Scheduling)) + schedulingMap, err := tpgresource.ConvertToMap(instance.Scheduling) + if err != nil { + return fmt.Errorf("Error converting scheduling: %s", err) + } + err = d.Set("scheduling", flattenScheduling(schedulingMap)) if err != nil { return err } diff --git a/mmv1/third_party/terraform/services/compute/metadata.go.tmpl b/mmv1/third_party/terraform/services/compute/metadata.go.tmpl index 13553cef706e..d76e63bd8d07 100644 --- a/mmv1/third_party/terraform/services/compute/metadata.go.tmpl +++ b/mmv1/third_party/terraform/services/compute/metadata.go.tmpl @@ -11,12 +11,6 @@ import ( {{- end }} "sort" -{{ if eq $.TargetVersionName `ga` }} - "google.golang.org/api/compute/v1" -{{- else }} - compute "google.golang.org/api/compute/v0.beta" -{{- end }} - "github.com/hashicorp/terraform-provider-google/google/tpgresource" transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport" ) @@ -50,61 +44,61 @@ func BetaMetadataUpdate(oldMDMap map[string]interface{}, newMDMap map[string]int MetadataUpdate(oldMDMap, newMDMap, serverMD) } -func expandComputeMetadata(m map[string]interface{}) []*compute.MetadataItems { - metadata := make([]*compute.MetadataItems, 0, len(m)) +func expandComputeMetadata(m map[string]interface{}) []interface{} { + metadata := make([]interface{}, 0, len(m)) var keys []string for key := range m { keys = append(keys, key) } sort.Strings(keys) - // Append new metadata to existing metadata for _, key := range keys { v := m[key].(string) - metadata = append(metadata, &compute.MetadataItems{ - Key: key, - Value: &v, + metadata = append(metadata, map[string]interface{}{ + "key": key, + "value": v, }) } - return metadata } -func flattenMetadataBeta(metadata *compute.Metadata) map[string]string { +func flattenMetadataBeta(metadata map[string]interface{}) map[string]string { metadataMap := make(map[string]string) if metadata == nil { return metadataMap } - for _, item := range metadata.Items { - if item == nil { + items, _ := metadata["items"].([]interface{}) + for _, raw := range items { + item, ok := raw.(map[string]interface{}) + if !ok || item == nil { continue } - if item.Value == nil { - metadataMap[item.Key] = "" - } else { - metadataMap[item.Key] = *item.Value + key, _ := item["key"].(string) + if key == "" { + continue } + val, _ := item["value"].(string) + metadataMap[key] = val } return metadataMap } -// This function differs from flattenMetadataBeta only in that it takes -// compute.metadata rather than compute.metadata as an argument. It should -// be removed in favour of flattenMetadataBeta if/when all resources using it get -// beta support. -func FlattenMetadata(metadata *compute.Metadata) map[string]interface{} { +func FlattenMetadata(metadata map[string]interface{}) map[string]interface{} { metadataMap := make(map[string]interface{}) if metadata == nil { return metadataMap } - for _, item := range metadata.Items { - if item == nil { + items, _ := metadata["items"].([]interface{}) + for _, raw := range items { + item, ok := raw.(map[string]interface{}) + if !ok || item == nil { continue } - if item.Value == nil { - metadataMap[item.Key] = "" - } else { - metadataMap[item.Key] = *item.Value + key, _ := item["key"].(string) + if key == "" { + continue } + val, _ := item["value"].(string) + metadataMap[key] = val } return metadataMap } @@ -112,9 +106,7 @@ func FlattenMetadata(metadata *compute.Metadata) map[string]interface{} { // resourceInstanceMetadata builds the instance metadata as a JSON-shaped // map[string]interface{} mirroring the compute.Metadata API type (camelCase // keys: "items" -> [{"key", "value"}], "fingerprint"). Empty values are omitted -// to mirror the Apiary struct's omitempty tags, so the marshaled request body is -// byte-identical whether the map is sent directly or round-tripped through the -// typed struct via resourceInstanceMetadataTyped. +// to mirror the Apiary struct's omitempty tags. func resourceInstanceMetadata(d tpgresource.TerraformResourceData) (map[string]interface{}, error) { m := map[string]interface{}{} mdMap := d.Get("metadata").(map[string]interface{}) @@ -154,20 +146,6 @@ func resourceInstanceMetadata(d tpgresource.TerraformResourceData) (map[string]i return m, nil } -// resourceInstanceMetadataTyped adapts the map-based resourceInstanceMetadata -// output to the typed *compute.Metadata still required by callers that build -// Apiary request structs directly. -func resourceInstanceMetadataTyped(d tpgresource.TerraformResourceData) (*compute.Metadata, error) { - mdMap, err := resourceInstanceMetadata(d) - if err != nil { - return nil, err - } - m := &compute.Metadata{} - if err := convertViaJSON(mdMap, m); err != nil { - return nil, err - } - return m, nil -} {{- if ne $.TargetVersionName "ga" }} func resourceInstancePartnerMetadata(d tpgresource.TerraformResourceData) (map[string]interface{}, error) { @@ -210,9 +188,7 @@ func flattenPartnerMetadata(partnerMetadata map[string]interface{}) (map[string] // convertPartnerMetadataToCompute builds the partner metadata as a JSON-shaped // map[string]interface{} mirroring the compute.StructuredEntries API type (each -// value is the parsed entries object, or an empty object for nil). The typed -// adapter convertPartnerMetadataToComputeTyped round-trips this through -// map[string]compute.StructuredEntries for callers that build Apiary structs. +// value is the parsed entries object, or an empty object for nil). func convertPartnerMetadataToCompute(pm map[string]interface{}) (map[string]interface{}, error) { result := make(map[string]interface{}) for key, value := range pm { @@ -225,40 +201,20 @@ func convertPartnerMetadataToCompute(pm map[string]interface{}) (map[string]inte return result, nil } -// convertPartnerMetadataToComputeTyped adapts the map-based -// convertPartnerMetadataToCompute output to the typed -// map[string]compute.StructuredEntries still required by callers that build -// Apiary request structs directly. -func convertPartnerMetadataToComputeTyped(pm map[string]interface{}) (map[string]compute.StructuredEntries, error) { - pmMap, err := convertPartnerMetadataToCompute(pm) - if err != nil { - return nil, err - } - result := make(map[string]compute.StructuredEntries) - if err := convertViaJSON(pmMap, &result); err != nil { - return nil, err - } - return result, nil -} - -func convertPartnerMetadataFromCompute(pm map[string]compute.StructuredEntries) map[string]interface{} { +func convertPartnerMetadataFromCompute(pm map[string]interface{}) map[string]interface{} { result := make(map[string]interface{}) - for key, value := range pm { - if value.Entries == nil { + for key, raw := range pm { + value, ok := raw.(map[string]interface{}) + if !ok || value == nil { result[key] = nil continue } - seBytes, err := json.Marshal(value) - if err != nil { + entries, hasEntries := value["entries"] + if !hasEntries || entries == nil { result[key] = nil continue } - var m map[string]interface{} - if err := json.Unmarshal(seBytes, &m); err != nil { - result[key] = nil - continue - } - result[key] = m + result[key] = value } return result } diff --git a/mmv1/third_party/terraform/services/compute/resource_compute_instance.go.tmpl b/mmv1/third_party/terraform/services/compute/resource_compute_instance.go.tmpl index 5ee46c5a202f..1df8cba5b06e 100644 --- a/mmv1/third_party/terraform/services/compute/resource_compute_instance.go.tmpl +++ b/mmv1/third_party/terraform/services/compute/resource_compute_instance.go.tmpl @@ -1862,31 +1862,7 @@ func expandComputeInstance(project string, d *schema.ResourceData, config *trans disks = append(disks, disk) } - scheduling, err := expandScheduling(d.Get("scheduling")) - if err != nil { - return nil, fmt.Errorf("Error creating scheduling: %s", err) - } - - params, err := expandParamsTyped(d) - if err != nil { - return nil, fmt.Errorf("Error creating params: %s", err) - } - - metadata, err := resourceInstanceMetadataTyped(d) - if err != nil { - return nil, fmt.Errorf("Error creating metadata: %s", err) - } - {{ if ne $.TargetVersionName `ga` -}} - partnerMetadataMap, err := resourceInstancePartnerMetadata(d) - if err != nil { - return nil, fmt.Errorf("Error creating partner metadata: %s", err) - } - PartnerMetadata, err := convertPartnerMetadataToComputeTyped(partnerMetadataMap) - if err != nil { - return nil, fmt.Errorf("Error converting partner metadata: %s", err) - } - {{- end }} networkInterfaces, err := expandNetworkInterfacesTyped(d, config) if err != nil { @@ -1944,24 +1920,17 @@ func expandComputeInstance(project string, d *schema.ResourceData, config *trans Description: d.Get("description").(string), Disks: disks, MachineType: machineTypeUrl, - Metadata: metadata, - {{- if ne $.TargetVersionName "ga" }} - PartnerMetadata: PartnerMetadata, - {{- end }} Name: d.Get("name").(string), NetworkInterfaces: networkInterfaces, NetworkPerformanceConfig: networkPerformanceConfig, Tags: tags, - Params: params, Labels: tpgresource.ExpandEffectiveLabels(d), ServiceAccounts: expandServiceAccountsTyped(d.Get("service_account").([]interface{})), GuestAccelerators: accels, MinCpuPlatform: d.Get("min_cpu_platform").(string), - Scheduling: scheduling, DeletionProtection: d.Get("deletion_protection").(bool), Hostname: d.Get("hostname").(string), ForceSendFields: []string{"CanIpForward", "DeletionProtection"}, - AdvancedMachineFeatures: expandAdvancedMachineFeaturesTyped(d), ResourcePolicies: tpgresource.ConvertStringArr(d.Get("resource_policies").([]interface{})), ReservationAffinity: reservationAffinity, KeyRevocationActionType: d.Get("key_revocation_action_type").(string), @@ -2128,6 +2097,35 @@ func resourceComputeInstanceCreate(d *schema.ResourceData, meta interface{}) err if err != nil { return fmt.Errorf("Error converting instance: %s", err) } + schedulingBody, err := expandScheduling(d.Get("scheduling")) + if err != nil { + return fmt.Errorf("Error creating scheduling: %s", err) + } + if schedulingBody != nil { + instanceBody["scheduling"] = schedulingBody + } + if amf := expandAdvancedMachineFeatures(d); amf != nil { + instanceBody["advancedMachineFeatures"] = amf + } + if paramsBody, err := expandParams(d); err != nil { + return fmt.Errorf("Error expanding params: %s", err) + } else { + instanceBody["params"] = paramsBody + } + if metadataBody, err := resourceInstanceMetadata(d); err != nil { + return fmt.Errorf("Error expanding metadata: %s", err) + } else { + instanceBody["metadata"] = metadataBody + } + {{- if ne $.TargetVersionName "ga" }} + if partnerMetadataRaw, err := resourceInstancePartnerMetadata(d); err != nil { + return fmt.Errorf("Error expanding partner metadata: %s", err) + } else if partnerMetadataBody, err := convertPartnerMetadataToCompute(partnerMetadataRaw); err != nil { + return fmt.Errorf("Error converting partner metadata: %s", err) + } else if len(partnerMetadataBody) > 0 { + instanceBody["partnerMetadata"] = partnerMetadataBody + } + {{- end }} insertUrl, err := tpgresource.ReplaceVars(d, config, "{{"{{"}}ComputeBasePath{{"}}"}}projects/{{"{{"}}project{{"}}"}}/zones/{{"{{"}}zone{{"}}"}}/instances") if err != nil { return fmt.Errorf("Error generating URL: %s", err) @@ -2241,7 +2239,11 @@ func resourceComputeInstanceRead(d *schema.ResourceData, meta interface{}) error {{ if ne $.TargetVersionName `ga` -}} // Workaround: restore nanos from state since the API doesn't persist it (see comment above). if hadNanos { - scheduling := flattenScheduling(instance.Scheduling) + schedulingMap, err := tpgresource.ConvertToMap(instance.Scheduling) + if err != nil { + return fmt.Errorf("Error converting scheduling for nanos workaround: %s", err) + } + scheduling := flattenScheduling(schedulingMap) graceful_shutdown := scheduling[0]["graceful_shutdown"].([]interface{})[0].(map[string]interface{}) max_duration := graceful_shutdown["max_duration"].([]interface{})[0].(map[string]interface{}) max_duration["nanos"] = int64(savedNanos.(int)) @@ -2264,7 +2266,15 @@ func resourceComputeInstanceRead(d *schema.ResourceData, meta interface{}) error } func populateComputeInstanceResourceData(d *schema.ResourceData, instance *compute.Instance, project, zone string, config *transport_tpg.Config) error { - if err := d.Set("metadata", flattenMetadataBeta(instance.Metadata)); err != nil { + var metadataMap map[string]interface{} + if instance.Metadata != nil { + var err error + metadataMap, err = tpgresource.ConvertToMap(instance.Metadata) + if err != nil { + return fmt.Errorf("Error converting metadata: %s", err) + } + } + if err := d.Set("metadata", flattenMetadataBeta(metadataMap)); err != nil { return fmt.Errorf("Error setting metadata: %s", err) } @@ -2447,9 +2457,35 @@ func populateComputeInstanceResourceData(d *schema.ResourceData, instance *compu return fmt.Errorf("Error setting scratch_disk: %s", err) } - if err := d.Set("scheduling", flattenScheduling(instance.Scheduling)); err != nil { +{{ if eq $.TargetVersionName `ga` -}} + schedulingMap, err := tpgresource.ConvertToMap(instance.Scheduling) + if err != nil { + return fmt.Errorf("Error converting scheduling: %s", err) + } + if err := d.Set("scheduling", flattenScheduling(schedulingMap)); err != nil { return fmt.Errorf("Error setting scheduling: %s", err) } +{{ else -}} + // Workaroud: API doesn't update the scheduling.graceful_shutdown.max_duration.nanos field. + // To avoid diff, we need to set the value from the state not from API response. + schedulingMap, err := tpgresource.ConvertToMap(instance.Scheduling) + if err != nil { + return fmt.Errorf("Error converting scheduling: %s", err) + } + scheduling := flattenScheduling(schedulingMap) + if nanos, ok := d.GetOk("scheduling.0.graceful_shutdown.0.max_duration.0.nanos"); ok { + graceful_shutdown := scheduling[0]["graceful_shutdown"].([]interface{})[0].(map[string]interface{}) + max_duration := graceful_shutdown["max_duration"].([]interface{})[0].(map[string]interface{}) + max_duration["nanos"] = int64(nanos.(int)) + + graceful_shutdown["max_duration"] = []interface{}{max_duration} + scheduling[0]["graceful_shutdown"] = []interface{}{graceful_shutdown} + } + if err := d.Set("scheduling", scheduling); err != nil { + return fmt.Errorf("Error setting scheduling: %s", err) + } +{{- end }} + if err := d.Set("guest_accelerator", flattenGuestAccelerators(guestAcceleratorsToInterface(instance.GuestAccelerators))); err != nil { return fmt.Errorf("Error setting guest_accelerator: %s", err) } @@ -2516,7 +2552,11 @@ func populateComputeInstanceResourceData(d *schema.ResourceData, instance *compu return fmt.Errorf("Error setting confidential_instance_config: %s", err) } } - if err := d.Set("advanced_machine_features", flattenAdvancedMachineFeaturesTyped(instance.AdvancedMachineFeatures)); err != nil { + amfMap, err := tpgresource.ConvertToMap(instance.AdvancedMachineFeatures) + if err != nil { + return fmt.Errorf("Error converting advanced_machine_features: %s", err) + } + if err := d.Set("advanced_machine_features", flattenAdvancedMachineFeatures(amfMap)); err != nil { return fmt.Errorf("Error setting advanced_machine_features: %s", err) } if d.Get("desired_status") != "" { @@ -2552,7 +2592,11 @@ func populateComputeInstanceResourceData(d *schema.ResourceData, instance *compu {{- if ne $.TargetVersionName `ga` }} if instance.PartnerMetadata != nil { - partnerMetadata, err := flattenPartnerMetadata(convertPartnerMetadataFromCompute(instance.PartnerMetadata)) + partnerMetadataMap, err := tpgresource.ConvertToMap(instance.PartnerMetadata) + if err != nil { + return fmt.Errorf("Error converting partner metadata: %s", err) + } + partnerMetadata, err := flattenPartnerMetadata(convertPartnerMetadataFromCompute(partnerMetadataMap)) if err != nil { return fmt.Errorf("Error parsing partner metadata: %s", err) } @@ -2928,15 +2972,10 @@ func resourceComputeInstanceUpdate(d *schema.ResourceData, meta interface{}) err bootRequiredSchedulingChange := schedulingHasChangeRequiringReboot(d) bootNotRequiredSchedulingChange := schedulingHasChangeWithoutReboot(d) if bootNotRequiredSchedulingChange { - scheduling, err := expandScheduling(d.Get("scheduling")) + schedulingBody, err := expandScheduling(d.Get("scheduling")) if err != nil { return fmt.Errorf("Error creating request data to update scheduling: %s", err) } - - schedulingBody, err := tpgresource.ConvertToMap(scheduling) - if err != nil { - return fmt.Errorf("Error converting scheduling: %s", err) - } url, err := tpgresource.ReplaceVars(d, config, "{{"{{"}}ComputeBasePath{{"}}"}}projects/{{"{{"}}project{{"}}"}}/zones/{{"{{"}}zone{{"}}"}}/instances/{{"{{"}}name{{"}}"}}/setScheduling") if err != nil { return fmt.Errorf("Error generating URL: %s", err) @@ -3965,15 +4004,10 @@ func resourceComputeInstanceUpdate(d *schema.ResourceData, meta interface{}) err } if bootRequiredSchedulingChange { - scheduling, err := expandScheduling(d.Get("scheduling")) + schedulingBody, err := expandScheduling(d.Get("scheduling")) if err != nil { return fmt.Errorf("Error creating request data to update scheduling: %s", err) } - - schedulingBody, err := tpgresource.ConvertToMap(scheduling) - if err != nil { - return fmt.Errorf("Error converting scheduling: %s", err) - } url, err := tpgresource.ReplaceVars(d, config, "{{"{{"}}ComputeBasePath{{"}}"}}projects/{{"{{"}}project{{"}}"}}/zones/{{"{{"}}zone{{"}}"}}/instances/{{"{{"}}name{{"}}"}}/setScheduling") if err != nil { return fmt.Errorf("Error generating URL: %s", err) diff --git a/mmv1/third_party/terraform/services/compute/resource_compute_instance_from_machine_image.go.tmpl b/mmv1/third_party/terraform/services/compute/resource_compute_instance_from_machine_image.go.tmpl index b3dea620113c..98d7bc3f58fa 100644 --- a/mmv1/third_party/terraform/services/compute/resource_compute_instance_from_machine_image.go.tmpl +++ b/mmv1/third_party/terraform/services/compute/resource_compute_instance_from_machine_image.go.tmpl @@ -161,13 +161,28 @@ func resourceComputeInstanceFromMachineImageCreate(d *schema.ResourceData, meta } } - instanceBytes, err := json.Marshal(instance) + instanceBody, err := tpgresource.ConvertToMap(instance) if err != nil { - return fmt.Errorf("Error marshaling instance: %s", err) + return fmt.Errorf("Error converting instance: %s", err) } - instanceBody := map[string]interface{}{} - if err = json.Unmarshal(instanceBytes, &instanceBody); err != nil { - return fmt.Errorf("Error processing instance body: %s", err) + + metadataMap, err := resourceInstanceMetadata(d) + if err != nil { + return fmt.Errorf("Error creating metadata: %s", err) + } + if len(metadataMap) > 0 { + instanceBody["metadata"] = metadataMap + } + partnerMetadataMap, err := resourceInstancePartnerMetadata(d) + if err != nil { + return fmt.Errorf("Error creating partner metadata: %s", err) + } + if len(partnerMetadataMap) > 0 { + partnerMetadataConverted, err := convertPartnerMetadataToCompute(partnerMetadataMap) + if err != nil { + return fmt.Errorf("Error converting partner metadata: %s", err) + } + instanceBody["partnerMetadata"] = partnerMetadataConverted } sa := d.Get("service_account").([]interface{}) @@ -215,38 +230,74 @@ func resourceComputeInstanceFromMachineImageCreate(d *schema.ResourceData, meta } instanceBody["disks"] = disks - // when we make the original call to expandComputeInstance expandScheduling is called, which sets default values. - // However, we want the values to be read from the machine image instead. - if _, hasSchedule := d.GetOk("scheduling"); !hasSchedule { - if srcProps, ok := miRes["sourceInstanceProperties"].(map[string]interface{}); ok { - if schedulingRaw, ok := srcProps["scheduling"].(map[string]interface{}); ok { - // Drop zero-value fields so the marshaled body matches the - // behavior of the typed compute.Scheduling JSON tags (omitempty). - filtered := map[string]interface{}{} - for k, v := range schedulingRaw { - switch val := v.(type) { - case bool: - if val { - filtered[k] = v - } - case string: - if val != "" { - filtered[k] = v - } - case float64: - if val != 0 { - filtered[k] = v - } - case nil: - // skip - default: + // expandComputeInstance no longer sets scheduling in the typed struct, so we handle + // it explicitly here. When the user has scheduling configured, use it; otherwise + // inherit scheduling from the machine image. + if _, hasSchedule := d.GetOk("scheduling"); hasSchedule { + schedulingBody, err := expandScheduling(d.Get("scheduling")) + if err != nil { + return fmt.Errorf("Error expanding scheduling: %s", err) + } + if schedulingBody != nil { + // Strip nil Duration fields so the source machine image values are inherited + // instead of being overridden with null. Use json.Marshal to detect typed nils + // (map[string]interface{}(nil)) that are not equal to untyped nil. + for _, k := range []string{"localSsdRecoveryTimeout", "maxRunDuration", "gracefulShutdown", "preemptionNoticeDuration"} { + if v, ok := schedulingBody[k]; ok { + if b, err := json.Marshal(v); err == nil && string(b) == "null" { + delete(schedulingBody, k) + } + } + } + instanceBody["scheduling"] = schedulingBody + } + } else if srcProps, ok := miRes["sourceInstanceProperties"].(map[string]interface{}); ok { + if schedulingRaw, ok := srcProps["scheduling"].(map[string]interface{}); ok { + // Drop zero-value fields so the marshaled body matches the + // behavior of the typed compute.Scheduling JSON tags (omitempty). + filtered := map[string]interface{}{} + for k, v := range schedulingRaw { + switch val := v.(type) { + case bool: + if val { + filtered[k] = v + } + case string: + if val != "" { filtered[k] = v } + case float64: + if val != 0 { + filtered[k] = v + } + case nil: + // skip + default: + filtered[k] = v } - instanceBody["scheduling"] = filtered } + instanceBody["scheduling"] = filtered } } + if amf := expandAdvancedMachineFeatures(d); amf != nil { + instanceBody["advancedMachineFeatures"] = amf + } + + if metadataBody, err := resourceInstanceMetadata(d); err != nil { + return fmt.Errorf("Error expanding metadata: %s", err) + } else { + instanceBody["metadata"] = metadataBody + } + + if partnerMetadataRaw, err := resourceInstancePartnerMetadata(d); err != nil { + return fmt.Errorf("Error expanding partner_metadata: %s", err) + } else if partnerMetadataBody, err := convertPartnerMetadataToCompute(partnerMetadataRaw); err != nil { + return fmt.Errorf("Error converting partner_metadata: %s", err) + } else if len(partnerMetadataBody) > 0 { + instanceBody["partnerMetadata"] = partnerMetadataBody + } else { + delete(instanceBody, "partnerMetadata") + } log.Printf("[INFO] Requesting instance creation") insertURL := fmt.Sprintf("%sprojects/%s/zones/%s/instances", transport_tpg.BaseUrl(Product, config), project, z) diff --git a/mmv1/third_party/terraform/services/compute/resource_compute_instance_from_template.go.tmpl b/mmv1/third_party/terraform/services/compute/resource_compute_instance_from_template.go.tmpl index 372fc755f427..dac863ead702 100644 --- a/mmv1/third_party/terraform/services/compute/resource_compute_instance_from_template.go.tmpl +++ b/mmv1/third_party/terraform/services/compute/resource_compute_instance_from_template.go.tmpl @@ -120,6 +120,39 @@ func resourceComputeInstanceFromTemplateCreate(d *schema.ResourceData, meta inte return err } + metadataMap, err := resourceInstanceMetadata(d) + if err != nil { + return fmt.Errorf("Error creating metadata: %s", err) + } + if len(metadataMap) > 0 { + metadataBytes, err := json.Marshal(metadataMap) + if err != nil { + return fmt.Errorf("Error marshaling metadata: %s", err) + } + if err := json.Unmarshal(metadataBytes, &instance.Metadata); err != nil { + return fmt.Errorf("Error setting metadata: %s", err) + } + } +{{- if ne $.TargetVersionName "ga" }} + partnerMetadataMap, err := resourceInstancePartnerMetadata(d) + if err != nil { + return fmt.Errorf("Error creating partner metadata: %s", err) + } + if len(partnerMetadataMap) > 0 { + partnerMetadataConverted, err := convertPartnerMetadataToCompute(partnerMetadataMap) + if err != nil { + return fmt.Errorf("Error converting partner metadata: %s", err) + } + partnerMetadataBytes, err := json.Marshal(partnerMetadataConverted) + if err != nil { + return fmt.Errorf("Error marshaling partner metadata: %s", err) + } + if err := json.Unmarshal(partnerMetadataBytes, &instance.PartnerMetadata); err != nil { + return fmt.Errorf("Error setting partner metadata: %s", err) + } + } +{{- end }} + sourceInstanceTemplate:= ConvertToUniqueIdWhenPresent(d.Get("source_instance_template").(string)) tpl, err := tpgresource.ParseInstanceTemplateFieldValue(sourceInstanceTemplate, d, config) if err != nil { @@ -181,11 +214,63 @@ func resourceComputeInstanceFromTemplateCreate(d *schema.ResourceData, meta inte } } - // when we make the original call to expandComputeInstance expandScheduling is called, which sets default values. - // However, we want the values to be read from the template instead. + // expandComputeInstance no longer sets Scheduling; handle it here so the user's + // scheduling overrides are applied. When no scheduling block is set, inherit from + // the instance template. When set, convert the map-based result from expandScheduling + // into the typed struct required by the API client. if _, hasSchedule := d.GetOk("scheduling"); !hasSchedule { instance.Scheduling = it.Properties.Scheduling + } else { + schedulingMap, err := expandScheduling(d.Get("scheduling")) + if err != nil { + return fmt.Errorf("Error expanding scheduling: %s", err) + } + for _, key := range []string{"localSsdRecoveryTimeout", "maxRunDuration", "preemptionNoticeDuration"} { + if dur, ok := schedulingMap[key].(map[string]interface{}); ok { + if sec, ok := dur["seconds"]; ok { + dur["seconds"] = fmt.Sprintf("%d", getInt(sec)) + } + } + } + if gs, ok := schedulingMap["gracefulShutdown"].(map[string]interface{}); ok { + if md, ok := gs["maxDuration"].(map[string]interface{}); ok { + if sec, ok := md["seconds"]; ok { + md["seconds"] = fmt.Sprintf("%d", getInt(sec)) + } + } + } + schedulingBytes, err := json.Marshal(schedulingMap) + if err != nil { + return fmt.Errorf("Error marshaling scheduling: %s", err) + } + schedulingTyped := &compute.Scheduling{} + if err := json.Unmarshal(schedulingBytes, schedulingTyped); err != nil { + return fmt.Errorf("Error setting scheduling: %s", err) + } + instance.Scheduling = schedulingTyped + } + + {{- if ne $.TargetVersionName "ga" }} + if pm := d.Get("partner_metadata").(map[string]interface{}); len(pm) > 0 { + pmRaw, err := resourceInstancePartnerMetadata(d) + if err != nil { + return fmt.Errorf("Error expanding partner_metadata: %s", err) + } + partnerMetadataConverted, err := convertPartnerMetadataToCompute(pmRaw) + if err != nil { + return fmt.Errorf("Error converting partner_metadata: %s", err) + } + if len(partnerMetadataConverted) > 0 { + partnerMetadataBytes, err := json.Marshal(partnerMetadataConverted) + if err != nil { + return fmt.Errorf("Error marshaling partner_metadata: %s", err) + } + if err := json.Unmarshal(partnerMetadataBytes, &instance.PartnerMetadata); err != nil { + return fmt.Errorf("Error setting partner_metadata: %s", err) + } + } } + {{- end }} // Force send all top-level fields that have been set in case they're overridden to zero values. // Initialize ForceSendFields to empty so we don't get things that the instance resource diff --git a/mmv1/third_party/terraform/services/compute/resource_compute_instance_template.go.tmpl b/mmv1/third_party/terraform/services/compute/resource_compute_instance_template.go.tmpl index eb72d9af676d..aaa153dfcfcc 100644 --- a/mmv1/third_party/terraform/services/compute/resource_compute_instance_template.go.tmpl +++ b/mmv1/third_party/terraform/services/compute/resource_compute_instance_template.go.tmpl @@ -1670,7 +1670,7 @@ func resourceComputeInstanceTemplateCreate(d *schema.ResourceData, meta interfac return err } - metadata, err := resourceInstanceMetadataTyped(d) + metadataMap, err := resourceInstanceMetadata(d) if err != nil { return err } @@ -1679,7 +1679,7 @@ func resourceComputeInstanceTemplateCreate(d *schema.ResourceData, meta interfac if err != nil { return err } - PartnerMetadata, err := convertPartnerMetadataToComputeTyped(partnerMetadataMap) + partnerMetadataConverted, err := convertPartnerMetadataToCompute(partnerMetadataMap) if err != nil { return err } @@ -1734,10 +1734,6 @@ func resourceComputeInstanceTemplateCreate(d *schema.ResourceData, meta interfac MachineType: d.Get("machine_type").(string), MinCpuPlatform: d.Get("min_cpu_platform").(string), Disks: disks, - Metadata: metadata, - {{- if ne $.TargetVersionName "ga" }} - PartnerMetadata: PartnerMetadata, - {{- end }} NetworkInterfaces: networks, NetworkPerformanceConfig: networkPerformanceConfig, Scheduling: scheduling, @@ -1801,14 +1797,20 @@ func resourceComputeInstanceTemplateCreate(d *schema.ResourceData, meta interfac Name: itName, } - itBytes, err := json.Marshal(instanceTemplate) + itBody, err := tpgresource.ConvertToMap(instanceTemplate) if err != nil { - return fmt.Errorf("Error marshaling instance template: %s", err) + return fmt.Errorf("Error converting instance template: %s", err) } - var itBody map[string]interface{} - if err := json.Unmarshal(itBytes, &itBody); err != nil { - return fmt.Errorf("Error unmarshaling instance template: %s", err) + if props, ok := itBody["properties"].(map[string]interface{}); ok { + props["metadata"] = metadataMap } + {{- if ne $.TargetVersionName "ga" }} + if len(partnerMetadataConverted) > 0 { + if props, ok := itBody["properties"].(map[string]interface{}); ok { + props["partnerMetadata"] = partnerMetadataConverted + } + } + {{- end }} url, err := tpgresource.ReplaceVars(d, config, "{{"{{"}}ComputeBasePath{{"}}"}}projects/{{"{{"}}project{{"}}"}}/global/instanceTemplates") if err != nil { @@ -2152,9 +2154,14 @@ func resourceComputeInstanceTemplateRead(d *schema.ResourceData, meta interface{ return fmt.Errorf("Error setting metadata_fingerprint: %s", err) } - md := instanceTemplate.Properties.Metadata - - _md := flattenMetadataBeta(md) + metadata := instanceTemplate.Properties.Metadata + var metadataMap map[string]interface{} + if metadata != nil { + if metadataMap, err = tpgresource.ConvertToMap(metadata); err != nil { + return fmt.Errorf("Error converting metadata: %s", err) + } + } + _md := flattenMetadataBeta(metadataMap) if script, scriptExists := d.GetOk("metadata_startup_script"); scriptExists { if err = d.Set("metadata_startup_script", script); err != nil { @@ -2175,7 +2182,11 @@ func resourceComputeInstanceTemplateRead(d *schema.ResourceData, meta interface{ {{ if ne $.TargetVersionName `ga` -}} if instanceTemplate.Properties.PartnerMetadata != nil { - partnerMetadata, err := flattenPartnerMetadata(convertPartnerMetadataFromCompute(instanceTemplate.Properties.PartnerMetadata)) + partnerMetadataMap, err := tpgresource.ConvertToMap(instanceTemplate.Properties.PartnerMetadata) + if err != nil { + return fmt.Errorf("Error converting partner metadata: %s", err) + } + partnerMetadata, err := flattenPartnerMetadata(convertPartnerMetadataFromCompute(partnerMetadataMap)) if err != nil { return fmt.Errorf("Error parsing partner metadata: %s", err) } @@ -2281,7 +2292,11 @@ func resourceComputeInstanceTemplateRead(d *schema.ResourceData, meta interface{ } } if instanceTemplate.Properties.Scheduling != nil { - scheduling := flattenScheduling(instanceTemplate.Properties.Scheduling) + schedulingMap, err := tpgresource.ConvertToMap(instanceTemplate.Properties.Scheduling) + if err != nil { + return fmt.Errorf("Error converting scheduling: %s", err) + } + scheduling := flattenScheduling(schedulingMap) {{ if ne $.TargetVersionName `ga` }} // Workaroud: API doesn't update the scheduling.graceful_shutdown.max_duration.nanos field. // To avoid diff, we need to set the value from the state not from API response. @@ -2338,7 +2353,11 @@ func resourceComputeInstanceTemplateRead(d *schema.ResourceData, meta interface{ } } if instanceTemplate.Properties.AdvancedMachineFeatures != nil { - if err = d.Set("advanced_machine_features", flattenAdvancedMachineFeaturesTyped(instanceTemplate.Properties.AdvancedMachineFeatures)); err != nil { + amfMap, err := tpgresource.ConvertToMap(instanceTemplate.Properties.AdvancedMachineFeatures) + if err != nil { + return fmt.Errorf("Error converting advanced_machine_features: %s", err) + } + if err = d.Set("advanced_machine_features", flattenAdvancedMachineFeatures(amfMap)); err != nil { return fmt.Errorf("Error setting advanced_machine_features: %s", err) } } @@ -2429,10 +2448,159 @@ func expandResourceComputeInstanceTemplateScheduling(d *schema.ResourceData, met } // Make sure we have an appropriate value for OnHostMaintenance if Preemptible - if expanded.Preemptible && expanded.OnHostMaintenance == "" { - expanded.OnHostMaintenance = "TERMINATE" + preemptible, _ := expanded["preemptible"].(bool) + onHostMaintenance, _ := expanded["onHostMaintenance"].(string) + if preemptible && onHostMaintenance == "" { + expanded["onHostMaintenance"] = "TERMINATE" + } + + for _, key := range []string{"localSsdRecoveryTimeout", "maxRunDuration", "preemptionNoticeDuration"} { + if dur, ok := expanded[key].(map[string]interface{}); ok { + if sec, ok := dur["seconds"]; ok { + dur["seconds"] = strconv.FormatInt(getInt(sec), 10) + } + } + } + if gs, ok := expanded["gracefulShutdown"].(map[string]interface{}); ok { + if md, ok := gs["maxDuration"].(map[string]interface{}); ok { + if sec, ok := md["seconds"]; ok { + md["seconds"] = strconv.FormatInt(getInt(sec), 10) + } + } + } + + schedulingTyped := &compute.Scheduling{} + if err := tpgresource.Convert(expanded, schedulingTyped); err != nil { + return nil, fmt.Errorf("Error converting scheduling: %s", err) + } + for _, pair := range [][2]string{ + {"preemptible", "Preemptible"}, + {"onHostMaintenance", "OnHostMaintenance"}, + {"provisioningModel", "ProvisioningModel"}, + {"instanceTerminationAction", "InstanceTerminationAction"}, + {"skipGuestOsShutdown", "SkipGuestOsShutdown"}, + } { + if _, ok := expanded[pair[0]]; ok { + schedulingTyped.ForceSendFields = append(schedulingTyped.ForceSendFields, pair[1]) + } + } +{{- if ne $.TargetVersionName "ga" }} + if v, ok := expanded["hostErrorTimeoutSeconds"]; ok { + if v == nil { + schedulingTyped.NullFields = append(schedulingTyped.NullFields, "HostErrorTimeoutSeconds") + } else { + schedulingTyped.ForceSendFields = append(schedulingTyped.ForceSendFields, "HostErrorTimeoutSeconds") + } + } +{{- end }} + return schedulingTyped, nil +} + +// networkInterfacesToInterface converts a slice of typed Apiary network +// interface structs into the []interface{} of JSON-shaped maps expected by +// flattenNetworkInterfaces. +func networkInterfacesToInterface(networkInterfaces []*compute.NetworkInterface) ([]interface{}, error) { + result := make([]interface{}, 0, len(networkInterfaces)) + for _, ni := range networkInterfaces { + m, err := tpgresource.ConvertToMap(ni) + if err != nil { + return nil, err + } + result = append(result, m) + } + return result, nil +} + +func convertViaJSON(in, out interface{}) error { + bytes, err := json.Marshal(in) + if err != nil { + return err + } + return json.Unmarshal(bytes, out) +} + +func expandNetworkInterfacesTyped(d tpgresource.TerraformResourceData, config *transport_tpg.Config) ([]*compute.NetworkInterface, error) { + expanded, err := expandNetworkInterfaces(d, config) + if err != nil { + return nil, err + } + ifaces := make([]*compute.NetworkInterface, 0, len(expanded)) + if err := convertViaJSON(expanded, &ifaces); err != nil { + return nil, fmt.Errorf("Error converting network interfaces: %s", err) + } + return ifaces, nil +} + +func expandAccessConfigsTyped(configs []interface{}) ([]*compute.AccessConfig, error) { + return accessConfigsToTyped(expandAccessConfigs(configs)) +} + +func expandIpv6AccessConfigsTyped(configs []interface{}) ([]*compute.AccessConfig, error) { + return accessConfigsToTyped(expandIpv6AccessConfigs(configs)) +} + +func accessConfigsToTyped(expanded []interface{}) ([]*compute.AccessConfig, error) { + acs := make([]*compute.AccessConfig, 0, len(expanded)) + if err := convertViaJSON(expanded, &acs); err != nil { + return nil, fmt.Errorf("Error converting access configs: %s", err) + } + return acs, nil +} + +func expandAliasIpRangesTyped(ranges []interface{}) ([]*compute.AliasIpRange, error) { + expanded := expandAliasIpRanges(ranges) + out := make([]*compute.AliasIpRange, 0, len(expanded)) + if err := convertViaJSON(expanded, &out); err != nil { + return nil, fmt.Errorf("Error converting alias ip ranges: %s", err) + } + return out, nil +} + +func expandServiceAccountsTyped(configs []interface{}) []*compute.ServiceAccount { + expanded := expandServiceAccounts(configs) + accounts := make([]*compute.ServiceAccount, len(expanded)) + for i, raw := range expanded { + data := raw.(map[string]interface{}) + accounts[i] = &compute.ServiceAccount{ + Email: data["email"].(string), + Scopes: data["scopes"].([]string), + } + } + return accounts +} + +func serviceAccountsToInterface(serviceAccounts []*compute.ServiceAccount) []interface{} { + result := make([]interface{}, len(serviceAccounts)) + for i, sa := range serviceAccounts { + result[i] = map[string]interface{}{ + "email": sa.Email, + "scopes": tpgresource.ConvertStringArrToInterface(sa.Scopes), + } + } + return result +} + +func guestAcceleratorsToInterface(accelerators []*compute.AcceleratorConfig) []interface{} { + result := make([]interface{}, len(accelerators)) + for i, a := range accelerators { + result[i] = map[string]interface{}{ + "acceleratorCount": a.AcceleratorCount, + "acceleratorType": a.AcceleratorType, + } + } + return result +} + +func expandAdvancedMachineFeaturesTyped(d tpgresource.TerraformResourceData) *compute.AdvancedMachineFeatures { + amfMap := expandAdvancedMachineFeatures(d) + if amfMap == nil { + return nil + } + typed := &compute.AdvancedMachineFeatures{} + if err := tpgresource.Convert(amfMap, typed); err != nil { + return nil } - return expanded, nil + return typed } func resourceComputeInstanceTemplateImportState(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { diff --git a/mmv1/third_party/terraform/services/compute/resource_compute_project_metadata.go.tmpl b/mmv1/third_party/terraform/services/compute/resource_compute_project_metadata.go.tmpl index 0f1fd7cbe951..22b390b8eff0 100644 --- a/mmv1/third_party/terraform/services/compute/resource_compute_project_metadata.go.tmpl +++ b/mmv1/third_party/terraform/services/compute/resource_compute_project_metadata.go.tmpl @@ -1,7 +1,6 @@ package compute import ( - "encoding/json" "fmt" "log" "time" @@ -12,12 +11,6 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - -{{ if eq $.TargetVersionName `ga` }} - "google.golang.org/api/compute/v1" -{{- else }} - compute "google.golang.org/api/compute/v0.beta" -{{- end }} ) func ResourceComputeProjectMetadata() *schema.Resource { @@ -82,11 +75,7 @@ func resourceComputeProjectMetadataCreateOrUpdate(d *schema.ResourceData, meta i return err } - md := &compute.Metadata{ - Items: expandComputeMetadata(d.Get("metadata").(map[string]interface{})), - } - - if err = resourceComputeProjectMetadataSet(d, projectID, userAgent, config, md, d.Timeout(schema.TimeoutCreate)); err != nil { + if err = resourceComputeProjectMetadataSet(d, projectID, userAgent, config, d.Get("metadata").(map[string]interface{}), d.Timeout(schema.TimeoutCreate)); err != nil { return fmt.Errorf("SetCommonInstanceMetadata failed: %s", err) } @@ -118,7 +107,11 @@ func resourceComputeProjectMetadataRead(d *schema.ResourceData, meta interface{} return transport_tpg.HandleNotFoundError(err, d, fmt.Sprintf("Project metadata for project %q", projectId)) } - err = d.Set("metadata", FlattenMetadata(project.CommonInstanceMetadata)) + var commonInstanceMetadata map[string]interface{} + if v, ok := project["commonInstanceMetadata"].(map[string]interface{}); ok { + commonInstanceMetadata = v + } + err = d.Set("metadata", FlattenMetadata(commonInstanceMetadata)) if err != nil { return fmt.Errorf("Error setting metadata: %s", err) } @@ -154,15 +147,14 @@ func resourceComputeProjectMetadataDelete(d *schema.ResourceData, meta interface return err } - md := &compute.Metadata{} - if err = resourceComputeProjectMetadataSet(d, projectID, userAgent, config, md, d.Timeout(schema.TimeoutDelete)); err != nil { + if err = resourceComputeProjectMetadataSet(d, projectID, userAgent, config, nil, d.Timeout(schema.TimeoutDelete)); err != nil { return fmt.Errorf("SetCommonInstanceMetadata failed: %s", err) } return resourceComputeProjectMetadataRead(d, meta) } -func resourceComputeProjectMetadataSet(d *schema.ResourceData, projectID, userAgent string, config *transport_tpg.Config, md *compute.Metadata, timeout time.Duration) error { +func resourceComputeProjectMetadataSet(d *schema.ResourceData, projectID, userAgent string, config *transport_tpg.Config, mdItems map[string]interface{}, timeout time.Duration) error { createMD := func() error { log.Printf("[DEBUG] Loading project service: %s", projectID) project, err := getComputeProject(d, config, projectID, userAgent) @@ -170,13 +162,14 @@ func resourceComputeProjectMetadataSet(d *schema.ResourceData, projectID, userAg return fmt.Errorf("Error loading project '%s': %s", projectID, err) } - if project.CommonInstanceMetadata != nil { - md.Fingerprint = project.CommonInstanceMetadata.Fingerprint + body := map[string]interface{}{} + if mdItems != nil { + body["items"] = expandComputeMetadata(mdItems) } - - body, err := computeMetadataToMap(md) - if err != nil { - return fmt.Errorf("Error encoding metadata: %s", err) + if commonInstanceMetadata, ok := project["commonInstanceMetadata"].(map[string]interface{}); ok { + if fp, ok := commonInstanceMetadata["fingerprint"].(string); ok && fp != "" { + body["fingerprint"] = fp + } } url, err := tpgresource.ReplaceVars(d, config, "{{"{{"}}ComputeBasePath{{"}}"}}") @@ -198,51 +191,27 @@ func resourceComputeProjectMetadataSet(d *schema.ResourceData, projectID, userAg } log.Printf("[DEBUG] SetCommonMetadata: %v", res["selfLink"]) - return ComputeOperationWaitTime(config, res, project.Name, "SetCommonMetadata", userAgent, timeout) + projectName, _ := project["name"].(string) + return ComputeOperationWaitTime(config, res, projectName, "SetCommonMetadata", userAgent, timeout) } err := transport_tpg.MetadataRetryWrapper(createMD) return err } -func getComputeProject(d *schema.ResourceData, config *transport_tpg.Config, projectID, userAgent string) (*compute.Project, error) { +func getComputeProject(d *schema.ResourceData, config *transport_tpg.Config, projectID, userAgent string) (map[string]interface{}, error) { url, err := tpgresource.ReplaceVars(d, config, "{{"{{"}}ComputeBasePath{{"}}"}}") if err != nil { return nil, err } url = fmt.Sprintf("%sprojects/%s", url, projectID) - res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + return transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ Config: config, Method: "GET", Project: projectID, RawURL: url, UserAgent: userAgent, }) - if err != nil { - return nil, err - } - - resBytes, err := json.Marshal(res) - if err != nil { - return nil, err - } - project := &compute.Project{} - if err := json.Unmarshal(resBytes, project); err != nil { - return nil, err - } - return project, nil -} - -func computeMetadataToMap(md *compute.Metadata) (map[string]interface{}, error) { - mdBytes, err := json.Marshal(md) - if err != nil { - return nil, err - } - body := map[string]interface{}{} - if err := json.Unmarshal(mdBytes, &body); err != nil { - return nil, err - } - return body, nil } func init() { diff --git a/mmv1/third_party/terraform/services/compute/resource_compute_project_metadata_item.go.tmpl b/mmv1/third_party/terraform/services/compute/resource_compute_project_metadata_item.go.tmpl index b0d1772ce0c6..ecdcf9c18cdb 100644 --- a/mmv1/third_party/terraform/services/compute/resource_compute_project_metadata_item.go.tmpl +++ b/mmv1/third_party/terraform/services/compute/resource_compute_project_metadata_item.go.tmpl @@ -11,12 +11,6 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - -{{ if eq $.TargetVersionName `ga` }} - "google.golang.org/api/compute/v1" -{{- else }} - compute "google.golang.org/api/compute/v0.beta" -{{- end }} ) type metadataPresentBehavior bool @@ -116,7 +110,11 @@ func resourceComputeProjectMetadataItemRead(d *schema.ResourceData, meta interfa return fmt.Errorf("Error loading project '%s': %s", projectID, err) } - md := FlattenMetadata(project.CommonInstanceMetadata) + var commonInstanceMetadata map[string]interface{} + if v, ok := project["commonInstanceMetadata"].(map[string]interface{}); ok { + commonInstanceMetadata = v + } + md := FlattenMetadata(commonInstanceMetadata) val, ok := md[d.Id()] if !ok { // Resource no longer exists @@ -231,7 +229,11 @@ func updateComputeCommonInstanceMetadata(d *schema.ResourceData, config *transpo return fmt.Errorf("Error loading project '%s': %s", projectID, err) } - md := FlattenMetadata(project.CommonInstanceMetadata) + var commonInstanceMetadata map[string]interface{} + if v, ok := project["commonInstanceMetadata"].(map[string]interface{}); ok { + commonInstanceMetadata = v + } + md := FlattenMetadata(commonInstanceMetadata) val, ok := md[key] @@ -256,17 +258,13 @@ func updateComputeCommonInstanceMetadata(d *schema.ResourceData, config *transpo md[key] = *afterVal } - var fingerprint string - if project.CommonInstanceMetadata != nil { - fingerprint = project.CommonInstanceMetadata.Fingerprint + body := map[string]interface{}{ + "items": expandComputeMetadata(md), } - - body, err := computeMetadataToMap(&compute.Metadata{ - Fingerprint: fingerprint, - Items: expandComputeMetadata(md), - }) - if err != nil { - return fmt.Errorf("Error encoding metadata: %s", err) + if commonInstanceMetadata != nil { + if fp, ok := commonInstanceMetadata["fingerprint"].(string); ok && fp != "" { + body["fingerprint"] = fp + } } url, err := tpgresource.ReplaceVars(d, config, "{{"{{"}}ComputeBasePath{{"}}"}}") @@ -289,7 +287,8 @@ func updateComputeCommonInstanceMetadata(d *schema.ResourceData, config *transpo log.Printf("[DEBUG] SetCommonInstanceMetadata: %v", res["selfLink"]) - return ComputeOperationWaitTime(config, res, project.Name, "SetCommonInstanceMetadata", userAgent, timeout) + projectName, _ := project["name"].(string) + return ComputeOperationWaitTime(config, res, projectName, "SetCommonInstanceMetadata", userAgent, timeout) } return transport_tpg.MetadataRetryWrapper(updateMD) diff --git a/mmv1/third_party/terraform/services/compute/resource_compute_project_metadata_item_test.go b/mmv1/third_party/terraform/services/compute/resource_compute_project_metadata_item_test.go index 910cba683687..8fd67a3cc832 100644 --- a/mmv1/third_party/terraform/services/compute/resource_compute_project_metadata_item_test.go +++ b/mmv1/third_party/terraform/services/compute/resource_compute_project_metadata_item_test.go @@ -1,6 +1,7 @@ package compute_test import ( + "encoding/json" "fmt" "regexp" "testing" @@ -160,7 +161,12 @@ func testAccCheckProjectMetadataItemDestroyProducer(t *testing.T) func(s *terraf return err } - metadata := tpgcompute.FlattenMetadata(project.CommonInstanceMetadata) + var commonInstanceMetadataMap map[string]interface{} + if project.CommonInstanceMetadata != nil { + metaBytes, _ := json.Marshal(project.CommonInstanceMetadata) + _ = json.Unmarshal(metaBytes, &commonInstanceMetadataMap) + } + metadata := tpgcompute.FlattenMetadata(commonInstanceMetadataMap) for _, rs := range s.RootModule().Resources { if rs.Type != "google_compute_project_metadata_item" { diff --git a/mmv1/third_party/terraform/services/compute/resource_compute_region_instance_group_manager.go.tmpl b/mmv1/third_party/terraform/services/compute/resource_compute_region_instance_group_manager.go.tmpl index 2ebbf974c825..8b8435c46c19 100644 --- a/mmv1/third_party/terraform/services/compute/resource_compute_region_instance_group_manager.go.tmpl +++ b/mmv1/third_party/terraform/services/compute/resource_compute_region_instance_group_manager.go.tmpl @@ -3,7 +3,9 @@ package compute import ( "fmt" "log" +{{- if ne $.TargetVersionName "ga" }} "strconv" +{{- end }} "strings" "time" @@ -2148,21 +2150,6 @@ func flattenDistributionPolicy(distributionPolicyRaw interface{}) []string { return zones } -func getInt(v interface{}) int64 { - switch t := v.(type) { - case int: - return int64(t) - case int64: - return t - case float64: - return int64(t) - case string: - i, _ := strconv.ParseInt(t, 10, 64) - return i - default: - return 0 - } -} func flattenRegionNamedPorts(raw interface{}) []map[string]interface{} { result := make([]map[string]interface{}, 0) diff --git a/mmv1/third_party/terraform/services/compute/resource_compute_region_instance_template.go.tmpl b/mmv1/third_party/terraform/services/compute/resource_compute_region_instance_template.go.tmpl index af711ae36b06..3f32a2e24cae 100644 --- a/mmv1/third_party/terraform/services/compute/resource_compute_region_instance_template.go.tmpl +++ b/mmv1/third_party/terraform/services/compute/resource_compute_region_instance_template.go.tmpl @@ -1343,7 +1343,7 @@ func resourceComputeRegionInstanceTemplateCreate(d *schema.ResourceData, meta in if err != nil { return err } - PartnerMetadata, err := convertPartnerMetadataToComputeTyped(partnerMetadataMap) + partnerMetadata, err := convertPartnerMetadataToCompute(partnerMetadataMap) if err != nil { return err } @@ -1399,9 +1399,7 @@ func resourceComputeRegionInstanceTemplateCreate(d *schema.ResourceData, meta in if v := d.Get("key_revocation_action_type").(string); v != "" { instanceProperties["keyRevocationActionType"] = v } - if metadata != nil { - instanceProperties["metadata"] = metadata - } + instanceProperties["metadata"] = metadata if networkPerformanceConfig != nil { instanceProperties["networkPerformanceConfig"] = networkPerformanceConfig } @@ -1421,16 +1419,8 @@ func resourceComputeRegionInstanceTemplateCreate(d *schema.ResourceData, meta in instanceProperties["reservationAffinity"] = reservationAffinity } {{- if ne $.TargetVersionName "ga" }} - if len(PartnerMetadata) > 0 { - pmJSON, err := json.Marshal(PartnerMetadata) - if err != nil { - return fmt.Errorf("Error marshaling partner metadata: %s", err) - } - var pmIface interface{} - if err := json.Unmarshal(pmJSON, &pmIface); err != nil { - return fmt.Errorf("Error unmarshaling partner metadata: %s", err) - } - instanceProperties["partnerMetadata"] = pmIface + if len(partnerMetadata) > 0 { + instanceProperties["partnerMetadata"] = partnerMetadata } if dd := expandDisplayDevice(d); dd != nil { ddMap, err := tpgresource.ConvertToMap(dd) @@ -1557,6 +1547,12 @@ func resourceComputeRegionInstanceTemplateRead(d *schema.ResourceData, meta inte } delete(res, "id") + var schedulingMapFromResponse map[string]interface{} + if propsMap, ok := res["properties"].(map[string]interface{}); ok { + schedulingMapFromResponse, _ = propsMap["scheduling"].(map[string]interface{}) + delete(propsMap, "scheduling") + } + resBytes, err := json.Marshal(res) if err != nil { return fmt.Errorf("Error marshaling instance template response: %s", err) @@ -1573,9 +1569,15 @@ func resourceComputeRegionInstanceTemplateRead(d *schema.ResourceData, meta inte return fmt.Errorf("Error setting metadata_fingerprint: %s", err) } - md := instanceTemplate.Properties.Metadata - - _md := flattenMetadataBeta(md) + metadata := instanceTemplate.Properties.Metadata + var metadataMap map[string]interface{} + if metadata != nil { + var convErr error + if metadataMap, convErr = tpgresource.ConvertToMap(metadata); convErr != nil { + return fmt.Errorf("Error converting metadata: %s", convErr) + } + } + _md := flattenMetadataBeta(metadataMap) if script, scriptExists := d.GetOk("metadata_startup_script"); scriptExists { if err = d.Set("metadata_startup_script", script); err != nil { @@ -1596,7 +1598,11 @@ func resourceComputeRegionInstanceTemplateRead(d *schema.ResourceData, meta inte {{ if ne $.TargetVersionName `ga` -}} if instanceTemplate.Properties.PartnerMetadata != nil { - partnerMetadata, err := flattenPartnerMetadata(convertPartnerMetadataFromCompute(instanceTemplate.Properties.PartnerMetadata)) + partnerMetadataMap, err := tpgresource.ConvertToMap(instanceTemplate.Properties.PartnerMetadata) + if err != nil { + return fmt.Errorf("Error converting partner metadata: %s", err) + } + partnerMetadata, err := flattenPartnerMetadata(convertPartnerMetadataFromCompute(partnerMetadataMap)) if err != nil { return fmt.Errorf("Error parsing partner metadata: %s", err) } @@ -1698,8 +1704,8 @@ func resourceComputeRegionInstanceTemplateRead(d *schema.ResourceData, meta inte } } } - if instanceTemplate.Properties.Scheduling != nil { - scheduling := flattenScheduling(instanceTemplate.Properties.Scheduling) + if schedulingMapFromResponse != nil { + scheduling := flattenScheduling(schedulingMapFromResponse) {{ if ne $.TargetVersionName `ga` }} // Workaroud: API doesn't update the scheduling.graceful_shutdown.max_duration.nanos field. // To avoid diff, we need to set the value from the state not from API response. @@ -1756,7 +1762,11 @@ func resourceComputeRegionInstanceTemplateRead(d *schema.ResourceData, meta inte } } if instanceTemplate.Properties.AdvancedMachineFeatures != nil { - if err = d.Set("advanced_machine_features", flattenAdvancedMachineFeaturesTyped(instanceTemplate.Properties.AdvancedMachineFeatures)); err != nil { + amfMap, err := tpgresource.ConvertToMap(instanceTemplate.Properties.AdvancedMachineFeatures) + if err != nil { + return fmt.Errorf("Error converting advanced_machine_features: %s", err) + } + if err = d.Set("advanced_machine_features", flattenAdvancedMachineFeatures(amfMap)); err != nil { return fmt.Errorf("Error setting advanced_machine_features: %s", err) } } diff --git a/mmv1/third_party/tgc/services/compute/compute_instance.go.tmpl b/mmv1/third_party/tgc/services/compute/compute_instance.go.tmpl index 563361506d82..56bac5f244cb 100644 --- a/mmv1/third_party/tgc/services/compute/compute_instance.go.tmpl +++ b/mmv1/third_party/tgc/services/compute/compute_instance.go.tmpl @@ -9,6 +9,7 @@ package compute import ( + "encoding/json" "errors" "fmt" "strings" @@ -129,15 +130,19 @@ func expandComputeInstance(project string, d tpgresource.TerraformResourceData, } } - metadata, err := resourceInstanceMetadataTyped(d) + metadataMap, err := resourceInstanceMetadata(d) if err != nil { return nil, fmt.Errorf("Error creating metadata: %s", err) } - networkInterfaces, err := expandNetworkInterfacesTyped(d, config) + networkInterfacesRaw, err := expandNetworkInterfaces(d, config) if err != nil { return nil, fmt.Errorf("Error creating network interfaces: %s", err) } + networkInterfaces, err := expandNetworkInterfacesTyped(networkInterfacesRaw) + if err != nil { + return nil, fmt.Errorf("Error converting network interfaces: %s", err) + } accels, err := expandInstanceGuestAccelerators(d, config) if err != nil { @@ -147,8 +152,12 @@ func expandComputeInstance(project string, d tpgresource.TerraformResourceData, tagsMap := resourceInstanceTags(d) var tags *compute.Tags if tagsMap != nil { + b, err := json.Marshal(tagsMap) + if err != nil { + return nil, fmt.Errorf("Error converting tags: %s", err) + } tags = &compute.Tags{} - if err := tpgresource.Convert(tagsMap, tags); err != nil { + if err := json.Unmarshal(b, tags); err != nil { return nil, fmt.Errorf("Error converting tags: %s", err) } } @@ -159,20 +168,29 @@ func expandComputeInstance(project string, d tpgresource.TerraformResourceData, Description: d.Get("description").(string), Disks: disks, MachineType: machineTypeUrl, - Metadata: metadata, Name: d.Get("name").(string), Zone: d.Get("zone").(string), NetworkInterfaces: networkInterfaces, Tags: tags, Labels: tpgresource.ExpandLabels(d), - ServiceAccounts: expandServiceAccountsTyped(d.Get("service_account").([]interface{})), + ServiceAccounts: expandServiceAccountsForTGC(d.Get("service_account").([]interface{})), GuestAccelerators: accels, MinCpuPlatform: d.Get("min_cpu_platform").(string), Scheduling: scheduling, DeletionProtection: d.Get("deletion_protection").(bool), Hostname: d.Get("hostname").(string), ForceSendFields: []string{"CanIpForward", "DeletionProtection"}, - AdvancedMachineFeatures: expandAdvancedMachineFeaturesTyped(d), + AdvancedMachineFeatures: expandAdvancedMachineFeaturesForTGC(d), + } + if metadataMap != nil { + if err := tpgresource.Convert(metadataMap, &instance.Metadata); err != nil { + return nil, fmt.Errorf("Error converting metadata: %s", err) + } + } + if metadataMap != nil { + if err := tpgresource.Convert(metadataMap, &instance.Metadata); err != nil { + return nil, fmt.Errorf("Error converting metadata: %s", err) + } } if sicMap := expandShieldedVmConfigs(d); sicMap != nil { instance.ShieldedInstanceConfig = &compute.ShieldedInstanceConfig{ @@ -192,6 +210,47 @@ func expandComputeInstance(project string, d tpgresource.TerraformResourceData, return instance, nil } +func expandNetworkInterfacesTyped(expanded []interface{}) ([]*compute.NetworkInterface, error) { + b, err := json.Marshal(expanded) + if err != nil { + return nil, fmt.Errorf("Error converting network interfaces: %s", err) + } + var ifaces []*compute.NetworkInterface + if err := json.Unmarshal(b, &ifaces); err != nil { + return nil, fmt.Errorf("Error converting network interfaces: %s", err) + } + return ifaces, nil +} + +func expandServiceAccountsForTGC(configs []interface{}) []*compute.ServiceAccount { + expanded := expandServiceAccounts(configs) + accounts := make([]*compute.ServiceAccount, len(expanded)) + for i, raw := range expanded { + data := raw.(map[string]interface{}) + accounts[i] = &compute.ServiceAccount{ + Email: data["email"].(string), + Scopes: data["scopes"].([]string), + } + } + return accounts +} + +func expandAdvancedMachineFeaturesForTGC(d tpgresource.TerraformResourceData) *compute.AdvancedMachineFeatures { + amfMap := expandAdvancedMachineFeatures(d) + if amfMap == nil { + return nil + } + b, err := json.Marshal(amfMap) + if err != nil { + return nil + } + typed := &compute.AdvancedMachineFeatures{} + if err := json.Unmarshal(b, typed); err != nil { + return nil + } + return typed +} + func expandAttachedDisk(diskConfig map[string]interface{}, d tpgresource.TerraformResourceData, meta interface{}) (*compute.AttachedDisk, error) { config := meta.(*transport_tpg.Config) @@ -371,3 +430,11 @@ func expandScratchDisks(d tpgresource.TerraformResourceData, config *transport_t return scratchDisks, nil } + +func convertViaJSON(in, out interface{}) error { + b, err := json.Marshal(in) + if err != nil { + return err + } + return json.Unmarshal(b, out) +} diff --git a/mmv1/third_party/tgc_next/pkg/services/compute/compute_instance_tfplan2cai.go b/mmv1/third_party/tgc_next/pkg/services/compute/compute_instance_tfplan2cai.go index 0d2bb6a214c5..b755dcafe25a 100644 --- a/mmv1/third_party/tgc_next/pkg/services/compute/compute_instance_tfplan2cai.go +++ b/mmv1/third_party/tgc_next/pkg/services/compute/compute_instance_tfplan2cai.go @@ -1,6 +1,7 @@ package compute import ( + "encoding/json" "errors" "fmt" "strings" @@ -121,7 +122,7 @@ func expandComputeInstance(project string, d tpgresource.TerraformResourceData, return nil, fmt.Errorf("Error creating params: %s", err) } - metadata, err := resourceInstanceMetadataTyped(d) + metadataMap, err := resourceInstanceMetadata(d) if err != nil { return nil, fmt.Errorf("Error creating metadata: %s", err) } @@ -183,7 +184,6 @@ func expandComputeInstance(project string, d tpgresource.TerraformResourceData, Description: d.Get("description").(string), Disks: disks, MachineType: machineTypeUrl, - Metadata: metadata, Name: d.Get("name").(string), Zone: d.Get("zone").(string), NetworkInterfaces: networkInterfaces, @@ -191,18 +191,31 @@ func expandComputeInstance(project string, d tpgresource.TerraformResourceData, Tags: tags, Params: params, Labels: tpgresource.ExpandLabels(d), - ServiceAccounts: expandServiceAccountsTyped(d.Get("service_account").([]interface{})), GuestAccelerators: accels, MinCpuPlatform: d.Get("min_cpu_platform").(string), Scheduling: scheduling, DeletionProtection: d.Get("deletion_protection").(bool), Hostname: d.Get("hostname").(string), - AdvancedMachineFeatures: expandAdvancedMachineFeaturesTgcNext(d), + AdvancedMachineFeatures: expandAdvancedMachineFeaturesTypedTgcNext(d), ResourcePolicies: tpgresource.ConvertStringArr(d.Get("resource_policies").([]interface{})), ReservationAffinity: reservationAffinity, KeyRevocationActionType: d.Get("key_revocation_action_type").(string), InstanceEncryptionKey: instanceEncryptionKey, } + if serviceAccount := expandServiceAccounts(d.Get("service_account").([]interface{})); len(serviceAccount) > 0 { + if err := convertViaJSONTgcNext(serviceAccount, &instance.ServiceAccounts); err != nil { + return nil, fmt.Errorf("Error converting service_accounts: %s", err) + } + } + if metadataMap != nil { + metadataBytes, err := json.Marshal(metadataMap) + if err != nil { + return nil, fmt.Errorf("Error encoding metadata: %s", err) + } + if err := json.Unmarshal(metadataBytes, &instance.Metadata); err != nil { + return nil, fmt.Errorf("Error converting metadata: %s", err) + } + } if cic := expandConfidentialInstanceConfig(d); cic != nil { instance.ConfidentialInstanceConfig = &compute.ConfidentialInstanceConfig{ EnableConfidentialCompute: cic["enableConfidentialCompute"].(bool), @@ -579,21 +592,33 @@ func expandSchedulingTgc(v interface{}) (*compute.Scheduling, error) { scheduling.AvailabilityDomain = int64(v.(int)) } if v, ok := original["max_run_duration"]; ok { - transformedMaxRunDuration, err := expandComputeMaxRunDuration(v) + maxRunDurationMap, err := expandComputeMaxRunDuration(v) if err != nil { return nil, err } - scheduling.MaxRunDuration = transformedMaxRunDuration - scheduling.ForceSendFields = append(scheduling.ForceSendFields, "MaxRunDuration") + if maxRunDurationMap != nil { + typed := &compute.Duration{} + if err := convertViaJSONTgcNext(maxRunDurationMap, typed); err != nil { + return nil, fmt.Errorf("Error converting max_run_duration: %s", err) + } + scheduling.MaxRunDuration = typed + scheduling.ForceSendFields = append(scheduling.ForceSendFields, "MaxRunDuration") + } } if v, ok := original["on_instance_stop_action"]; ok { - transformedOnInstanceStopAction, err := expandComputeOnInstanceStopAction(v) + onInstanceStopActionMap, err := expandComputeOnInstanceStopAction(v) if err != nil { return nil, err } - scheduling.OnInstanceStopAction = transformedOnInstanceStopAction - scheduling.ForceSendFields = append(scheduling.ForceSendFields, "OnInstanceStopAction") + if onInstanceStopActionMap != nil { + typed := &compute.SchedulingOnInstanceStopAction{} + if err := convertViaJSONTgcNext(onInstanceStopActionMap, typed); err != nil { + return nil, fmt.Errorf("Error converting on_instance_stop_action: %s", err) + } + scheduling.OnInstanceStopAction = typed + scheduling.ForceSendFields = append(scheduling.ForceSendFields, "OnInstanceStopAction") + } } if v, ok := original["local_ssd_recovery_timeout"]; ok { @@ -657,10 +682,53 @@ func expandComputeLocalSsdRecoveryTimeoutTgc(v interface{}) (*compute.Duration, return duration, nil } -func expandAdvancedMachineFeaturesTgcNext(d tpgresource.TerraformResourceData) *compute.AdvancedMachineFeatures { - features := expandAdvancedMachineFeaturesTyped(d) - if features != nil && features.PerformanceMonitoringUnit == "" { - features.PerformanceMonitoringUnit = "STANDARD" +func expandAccessConfigsTyped(configs []interface{}) ([]*compute.AccessConfig, error) { + expanded := expandAccessConfigs(configs) + acs := make([]*compute.AccessConfig, 0, len(expanded)) + if err := convertViaJSONTgcNext(expanded, &acs); err != nil { + return nil, fmt.Errorf("Error converting access configs: %s", err) + } + return acs, nil +} + +func expandAliasIpRangesTyped(ranges []interface{}) ([]*compute.AliasIpRange, error) { + expanded := expandAliasIpRanges(ranges) + out := make([]*compute.AliasIpRange, 0, len(expanded)) + if err := convertViaJSONTgcNext(expanded, &out); err != nil { + return nil, fmt.Errorf("Error converting alias ip ranges: %s", err) } - return features + return out, nil +} + +func expandIpv6AccessConfigsTyped(configs []interface{}) ([]*compute.AccessConfig, error) { + expanded := expandIpv6AccessConfigs(configs) + acs := make([]*compute.AccessConfig, 0, len(expanded)) + if err := convertViaJSONTgcNext(expanded, &acs); err != nil { + return nil, fmt.Errorf("Error converting ipv6 access configs: %s", err) + } + return acs, nil +} + +func expandAdvancedMachineFeaturesTypedTgcNext(d tpgresource.TerraformResourceData) *compute.AdvancedMachineFeatures { + amfMap := expandAdvancedMachineFeatures(d) + if amfMap == nil { + return nil + } + typed := &compute.AdvancedMachineFeatures{} + if err := convertViaJSONTgcNext(amfMap, typed); err != nil { + return nil + } + return typed +} + +func convertViaJSON(in, out interface{}) error { + b, err := json.Marshal(in) + if err != nil { + return err + } + return json.Unmarshal(b, out) +} + +func convertViaJSONTgcNext(in, out interface{}) error { + return convertViaJSON(in, out) }