mirror of
https://github.com/letic/terraform-provider-google.git
synced 2024-07-05 17:52:38 +00:00
![Nic Cope](/assets/img/avatar_default.png)
* Move AliasIpRange helpers into utils To reflect the fact they'll be used by multiple resources. * Pass Config to build helpers, not meta It's the only thing meta is used for. * Refactor getNetwork util methods to return early for the happy path. * Update compute APIs compute.Instance.MinCpuPlatform is now GA. * Fix panic in TestComputeInstanceMigrateState This seemed to be a pre-existing issue, i.e. I could repro it in master. --- FAIL: TestComputeInstanceMigrateState (0.00s) panic: interface conversion: interface {} is nil, not *google.Config [recovered] panic: interface conversion: interface {} is nil, not *google.Config goroutine 85 [running]: testing.tRunner.func1(0xc4205d60f0) /usr/local/Cellar/go/1.9.1/libexec/src/testing/testing.go:711 +0x2d2 panic(0x203acc0, 0xc4205d2080) /usr/local/Cellar/go/1.9.1/libexec/src/runtime/panic.go:491 +0x283 github.com/terraform-providers/terraform-provider-google/google.migrateStateV3toV4(0xc4205f2000, 0x0, 0x0, 0x0, 0x48, 0xc4205f2000) /Users/negz/control/go/src/github.com/terraform-providers/terraform-provider-google/google/resource_compute_instance_migrate.go:182 +0x2405 github.com/terraform-providers/terraform-provider-google/google.resourceComputeInstanceMigrateState(0x2, 0xc4205f2000, 0x0, 0x0, 0x0, 0x0, 0xe0000000000) /Users/negz/control/go/src/github.com/terraform-providers/terraform-provider-google/google/resource_compute_instance_migrate.go:48 +0x21a github.com/terraform-providers/terraform-provider-google/google.runInstanceMigrateTest(0xc4205d60f0, 0x2260816, 0x8, 0x227d23a, 0x20, 0x2, 0xc4205ec0f0, 0xc4205ec120, 0x0, 0x0) /Users/negz/control/go/src/github.com/terraform-providers/terraform-provider-google/google/resource_compute_instance_migrate_test.go:803 +0xc1 github.com/terraform-providers/terraform-provider-google/google.TestComputeInstanceMigrateState(0xc4205d60f0) /Users/negz/control/go/src/github.com/terraform-providers/terraform-provider-google/google/resource_compute_instance_migrate_test.go:71 +0xc84 testing.tRunner(0xc4205d60f0, 0x22d81c0) /usr/local/Cellar/go/1.9.1/libexec/src/testing/testing.go:746 +0xd0 created by testing.(*T).Run /usr/local/Cellar/go/1.9.1/libexec/src/testing/testing.go:789 +0x2de FAIL github.com/terraform-providers/terraform-provider-google/google 0.035s * Use only the v1 API for resource_compute_instance Alias IP ranges, Accelerators, and min CPU platform are now GA. * Move common instance code into utils.go Methods used by both resource_compute_instance and resource_compute_instance_template are currently spread between their respective files, and utils.go. This commit moves them all into utils.go for the sake of consistency. It may be worth considering an instance_common.go file or similar. * Unify compute_instance and compute_instance_template network_interface and service_account code This has the side effect of enabling Alias IP range support for compute_instance_templates. * Add tests for compute instance template Alias IP ranges * Mark instance template region as computed We compute it from the subnet its network interfaces are in. Note this is not new behaviour - I believe it was erroneously missing the computed flag. * Support guest accelerators for instance templates Since most of the code is already there. * Add a test for using 'address' rather than 'network_ip' for instance templates * Don't mark assigned_nat_ip as deprecated * Remove network_interface schema fields that don't make sense for a compute instance template * Add newline after count in instance template docs * Don't try to dedupe guest accelerator expansion code The API calls to Google to create guest accelerators take different values for instances and instance templates. Instance templates don't have a zone and can thus *only* be passed a guest accelerator name. * Use ParseNetworkFieldValue instead of getNetworkLink * Add support for parsing regional fields, and subnetworks specifically Currently unused because subnetworks may have a separate project from that of the instance using them, which complicates looking up the project field. * Fall back to provider region when parsing regional field values Also slightly refactors getXFromSchema field helper functions for readability. * Revert to assigned_nat_ip in compute instance docs * Add beta scaffolding to compute instance and compute instance template Note these resources don't currently use beta features - this is futureproofing. * Fix indentation in comment about instance template alias IP ranges * Consolidate metadata helper functions in metadata.go * Move compute instance (and template) related helpers into their own file
222 lines
6.8 KiB
Go
222 lines
6.8 KiB
Go
package google
|
|
|
|
import (
|
|
"fmt"
|
|
"regexp"
|
|
|
|
"github.com/hashicorp/terraform/helper/schema"
|
|
computeBeta "google.golang.org/api/compute/v0.beta"
|
|
)
|
|
|
|
func expandAliasIpRanges(ranges []interface{}) []*computeBeta.AliasIpRange {
|
|
ipRanges := make([]*computeBeta.AliasIpRange, 0, len(ranges))
|
|
for _, raw := range ranges {
|
|
data := raw.(map[string]interface{})
|
|
ipRanges = append(ipRanges, &computeBeta.AliasIpRange{
|
|
IpCidrRange: data["ip_cidr_range"].(string),
|
|
SubnetworkRangeName: data["subnetwork_range_name"].(string),
|
|
})
|
|
}
|
|
return ipRanges
|
|
}
|
|
|
|
func flattenAliasIpRange(ranges []*computeBeta.AliasIpRange) []map[string]interface{} {
|
|
rangesSchema := make([]map[string]interface{}, 0, len(ranges))
|
|
for _, ipRange := range ranges {
|
|
rangesSchema = append(rangesSchema, map[string]interface{}{
|
|
"ip_cidr_range": ipRange.IpCidrRange,
|
|
"subnetwork_range_name": ipRange.SubnetworkRangeName,
|
|
})
|
|
}
|
|
return rangesSchema
|
|
}
|
|
|
|
func flattenScheduling(scheduling *computeBeta.Scheduling) []map[string]interface{} {
|
|
result := make([]map[string]interface{}, 0, 1)
|
|
schedulingMap := map[string]interface{}{
|
|
"on_host_maintenance": scheduling.OnHostMaintenance,
|
|
"preemptible": scheduling.Preemptible,
|
|
}
|
|
if scheduling.AutomaticRestart != nil {
|
|
schedulingMap["automatic_restart"] = *scheduling.AutomaticRestart
|
|
}
|
|
result = append(result, schedulingMap)
|
|
return result
|
|
}
|
|
|
|
func getProjectAndRegionFromSubnetworkLink(subnetwork string) (string, string) {
|
|
r := regexp.MustCompile(SubnetworkLinkRegex)
|
|
if !r.MatchString(subnetwork) {
|
|
return "", ""
|
|
}
|
|
|
|
matches := r.FindStringSubmatch(subnetwork)
|
|
return matches[1], matches[2]
|
|
}
|
|
|
|
func flattenAccessConfigs(accessConfigs []*computeBeta.AccessConfig) ([]map[string]interface{}, string) {
|
|
flattened := make([]map[string]interface{}, len(accessConfigs))
|
|
natIP := ""
|
|
for i, ac := range accessConfigs {
|
|
flattened[i] = map[string]interface{}{
|
|
"nat_ip": ac.NatIP,
|
|
"assigned_nat_ip": ac.NatIP,
|
|
}
|
|
if natIP == "" {
|
|
natIP = ac.NatIP
|
|
}
|
|
}
|
|
return flattened, natIP
|
|
}
|
|
|
|
func flattenNetworkInterfaces(networkInterfaces []*computeBeta.NetworkInterface) ([]map[string]interface{}, string, string, string) {
|
|
flattened := make([]map[string]interface{}, len(networkInterfaces))
|
|
var region, internalIP, externalIP string
|
|
|
|
for i, iface := range networkInterfaces {
|
|
var ac []map[string]interface{}
|
|
ac, externalIP = flattenAccessConfigs(iface.AccessConfigs)
|
|
|
|
var project string
|
|
project, region = getProjectAndRegionFromSubnetworkLink(iface.Subnetwork)
|
|
|
|
flattened[i] = map[string]interface{}{
|
|
"address": iface.NetworkIP,
|
|
"network_ip": iface.NetworkIP,
|
|
"network": iface.Network,
|
|
"subnetwork": iface.Subnetwork,
|
|
"subnetwork_project": project,
|
|
"access_config": ac,
|
|
"alias_ip_range": flattenAliasIpRange(iface.AliasIpRanges),
|
|
}
|
|
// Instance template interfaces never have names, so they're absent
|
|
// in the instance template network_interface schema. We want to use the
|
|
// same flattening code for both resource types, so we avoid trying to
|
|
// set the name field when it's not set at the GCE end.
|
|
if iface.Name != "" {
|
|
flattened[i]["name"] = iface.Name
|
|
}
|
|
if internalIP == "" {
|
|
internalIP = iface.NetworkIP
|
|
}
|
|
}
|
|
return flattened, region, internalIP, externalIP
|
|
}
|
|
|
|
func expandAccessConfigs(configs []interface{}) []*computeBeta.AccessConfig {
|
|
acs := make([]*computeBeta.AccessConfig, len(configs))
|
|
for i, raw := range configs {
|
|
data := raw.(map[string]interface{})
|
|
acs[i] = &computeBeta.AccessConfig{
|
|
Type: "ONE_TO_ONE_NAT",
|
|
NatIP: data["nat_ip"].(string),
|
|
}
|
|
}
|
|
return acs
|
|
}
|
|
|
|
func expandNetworkInterfaces(d *schema.ResourceData, config *Config) ([]*computeBeta.NetworkInterface, error) {
|
|
project, err := getProject(d, config)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
region, err := getRegion(d, config)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
configs := d.Get("network_interface").([]interface{})
|
|
ifaces := make([]*computeBeta.NetworkInterface, len(configs))
|
|
for i, raw := range configs {
|
|
data := raw.(map[string]interface{})
|
|
|
|
network := data["network"].(string)
|
|
subnetwork := data["subnetwork"].(string)
|
|
if (network == "" && subnetwork == "") || (network != "" && subnetwork != "") {
|
|
return nil, fmt.Errorf("exactly one of network or subnetwork must be provided")
|
|
}
|
|
|
|
nf, err := ParseNetworkFieldValue(network, d, config)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cannot determine selflink for subnetwork '%s': %s", subnetwork, err)
|
|
}
|
|
|
|
subnetworkProject := data["subnetwork_project"].(string)
|
|
subnetLink, err := getSubnetworkLink(config, project, region, subnetworkProject, subnetwork)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cannot determine selflink for subnetwork '%s': %s", subnetwork, err)
|
|
}
|
|
|
|
ifaces[i] = &computeBeta.NetworkInterface{
|
|
NetworkIP: data["network_ip"].(string),
|
|
Network: nf.RelativeLink(),
|
|
Subnetwork: subnetLink,
|
|
AccessConfigs: expandAccessConfigs(data["access_config"].([]interface{})),
|
|
AliasIpRanges: expandAliasIpRanges(data["alias_ip_range"].([]interface{})),
|
|
}
|
|
|
|
// network_ip is deprecated. We want address to win if both are set.
|
|
if data["address"].(string) != "" {
|
|
ifaces[i].NetworkIP = data["address"].(string)
|
|
}
|
|
|
|
}
|
|
return ifaces, nil
|
|
}
|
|
|
|
func flattenServiceAccounts(serviceAccounts []*computeBeta.ServiceAccount) []map[string]interface{} {
|
|
result := make([]map[string]interface{}, len(serviceAccounts))
|
|
for i, serviceAccount := range serviceAccounts {
|
|
result[i] = map[string]interface{}{
|
|
"email": serviceAccount.Email,
|
|
"scopes": schema.NewSet(stringScopeHashcode, convertStringArrToInterface(serviceAccount.Scopes)),
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
func expandServiceAccounts(configs []interface{}) []*computeBeta.ServiceAccount {
|
|
accounts := make([]*computeBeta.ServiceAccount, len(configs))
|
|
for i, raw := range configs {
|
|
data := raw.(map[string]interface{})
|
|
|
|
accounts[i] = &computeBeta.ServiceAccount{
|
|
Email: data["email"].(string),
|
|
Scopes: canonicalizeServiceScopes(convertStringSet(data["scopes"].(*schema.Set))),
|
|
}
|
|
|
|
if accounts[i].Email == "" {
|
|
accounts[i].Email = "default"
|
|
}
|
|
}
|
|
return accounts
|
|
}
|
|
|
|
func flattenGuestAccelerators(accelerators []*computeBeta.AcceleratorConfig) []map[string]interface{} {
|
|
acceleratorsSchema := make([]map[string]interface{}, len(accelerators))
|
|
for i, accelerator := range accelerators {
|
|
acceleratorsSchema[i] = map[string]interface{}{
|
|
"count": accelerator.AcceleratorCount,
|
|
"type": accelerator.AcceleratorType,
|
|
}
|
|
}
|
|
return acceleratorsSchema
|
|
}
|
|
|
|
func resourceInstanceTags(d *schema.ResourceData) *computeBeta.Tags {
|
|
// Calculate the tags
|
|
var tags *computeBeta.Tags
|
|
if v := d.Get("tags"); v != nil {
|
|
vs := v.(*schema.Set)
|
|
tags = new(computeBeta.Tags)
|
|
tags.Items = make([]string, vs.Len())
|
|
for i, v := range vs.List() {
|
|
tags.Items[i] = v.(string)
|
|
}
|
|
|
|
tags.Fingerprint = d.Get("tags_fingerprint").(string)
|
|
}
|
|
|
|
return tags
|
|
}
|