Skip to content

Commit

Permalink
add gVNIC support for instance template (#4655) (#8842)
Browse files Browse the repository at this point in the history
Signed-off-by: Modular Magician <[email protected]>
  • Loading branch information
modular-magician authored Apr 5, 2021
1 parent c3fcf43 commit 4f6049c
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 74 deletions.
3 changes: 3 additions & 0 deletions .changelog/4655.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:enhancement
compute: added gVNIC support for `google_compute_instance_template`
```
83 changes: 9 additions & 74 deletions google/resource_compute_instance_template.go
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,13 @@ func resourceComputeInstanceTemplate() *schema.Resource {
Computed: true,
Description: `The name of the network_interface.`,
},
"nic_type": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
ValidateFunc: validation.StringInSlice([]string{"GVNIC", "VIRTIO_NET"}, false),
Description: `The type of vNIC to be used on this interface. Possible values:GVNIC, VIRTIO_NET`,
},
"access_config": {
Type: schema.TypeList,
Optional: true,
Expand Down Expand Up @@ -847,7 +854,7 @@ func resourceComputeInstanceTemplateCreate(d *schema.ResourceData, meta interfac
return err
}

networks, err := expandComputeInstanceTemplateNetworkInterfaces(d, config)
networks, err := expandNetworkInterfaces(d, config)
if err != nil {
return err
}
Expand Down Expand Up @@ -1211,7 +1218,7 @@ func resourceComputeInstanceTemplateRead(d *schema.ResourceData, meta interface{
return fmt.Errorf("Error setting project: %s", err)
}
if instanceTemplate.Properties.NetworkInterfaces != nil {
networkInterfaces, region, _, _, err := flattenComputeInstanceTemplateNetworkInterfaces(d, config, instanceTemplate.Properties.NetworkInterfaces)
networkInterfaces, region, _, _, err := flattenNetworkInterfaces(d, config, instanceTemplate.Properties.NetworkInterfaces)
if err != nil {
return err
}
Expand Down Expand Up @@ -1336,75 +1343,3 @@ func resourceComputeInstanceTemplateImportState(d *schema.ResourceData, meta int

return []*schema.ResourceData{d}, nil
}

// this func could be replaced by flattenNetworkInterfaces once NicType is supported
func flattenComputeInstanceTemplateNetworkInterfaces(d *schema.ResourceData, config *Config, networkInterfaces []*computeBeta.NetworkInterface) ([]map[string]interface{}, string, string, string, error) {
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)

subnet, err := ParseSubnetworkFieldValue(iface.Subnetwork, d, config)
if err != nil {
return nil, "", "", "", err
}
region = subnet.Region

flattened[i] = map[string]interface{}{
"network_ip": iface.NetworkIP,
"network": ConvertSelfLinkToV1(iface.Network),
"subnetwork": ConvertSelfLinkToV1(iface.Subnetwork),
"subnetwork_project": subnet.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, nil
}

// this func could be replaced by expandNetworkInterfaces once NicType is supported
func expandComputeInstanceTemplateNetworkInterfaces(d TerraformResourceData, config *Config) ([]*computeBeta.NetworkInterface, error) {
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 == "" {
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 self_link for network %q: %s", network, err)
}

subnetProjectField := fmt.Sprintf("network_interface.%d.subnetwork_project", i)
sf, err := ParseSubnetworkFieldValueWithProjectField(subnetwork, subnetProjectField, d, config)
if err != nil {
return nil, fmt.Errorf("cannot determine self_link for subnetwork %q: %s", subnetwork, err)
}

ifaces[i] = &computeBeta.NetworkInterface{
NetworkIP: data["network_ip"].(string),
Network: nf.RelativeLink(),
Subnetwork: sf.RelativeLink(),
AccessConfigs: expandAccessConfigs(data["access_config"].([]interface{})),
AliasIpRanges: expandAliasIpRanges(data["alias_ip_range"].([]interface{})),
}
}
return ifaces, nil
}
86 changes: 86 additions & 0 deletions google/resource_compute_instance_template_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -925,6 +925,35 @@ func TestAccComputeInstanceTemplate_resourcePolicies(t *testing.T) {
})
}

func TestAccComputeInstanceTemplate_nictype_update(t *testing.T) {
t.Parallel()

var instanceTemplate computeBeta.InstanceTemplate
var instanceTemplateName = fmt.Sprintf("tf-test-%s", randString(t, 10))

vcrTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckComputeInstanceDestroyProducer(t),
Steps: []resource.TestStep{
{
Config: testAccComputeInstanceTemplate_nictype(instanceTemplateName, instanceTemplateName, "GVNIC"),
Check: resource.ComposeTestCheckFunc(
testAccCheckComputeInstanceTemplateExists(
t, "google_compute_instance_template.foobar", &instanceTemplate),
),
},
{
Config: testAccComputeInstanceTemplate_nictype(instanceTemplateName, instanceTemplateName, "VIRTIO_NET"),
Check: resource.ComposeTestCheckFunc(
testAccCheckComputeInstanceTemplateExists(
t, "google_compute_instance_template.foobar", &instanceTemplate),
),
},
},
})
}

func testAccCheckComputeInstanceTemplateDestroyProducer(t *testing.T) func(s *terraform.State) error {
return func(s *terraform.State) error {
config := googleProviderConfig(t)
Expand Down Expand Up @@ -2301,3 +2330,60 @@ resource "google_compute_resource_policy" "foo" {
}
`, suffix, policyName)
}

func testAccComputeInstanceTemplate_nictype(image, instance, nictype string) string {
return fmt.Sprintf(`
resource "google_compute_image" "example" {
name = "%s"
raw_disk {
source = "https://storage.googleapis.com/bosh-gce-raw-stemcells/bosh-stemcell-97.98-google-kvm-ubuntu-xenial-go_agent-raw-1557960142.tar.gz"
}
guest_os_features {
type = "SECURE_BOOT"
}
guest_os_features {
type = "MULTI_IP_SUBNET"
}
guest_os_features {
type = "GVNIC"
}
}
resource "google_compute_instance_template" "foobar" {
name = "instancet-test-%s"
machine_type = "e2-medium"
can_ip_forward = false
tags = ["foo", "bar"]
disk {
source_image = google_compute_image.example.name
auto_delete = true
boot = true
}
network_interface {
network = "default"
nic_type = "%s"
}
scheduling {
preemptible = false
automatic_restart = true
}
metadata = {
foo = "bar"
}
service_account {
scopes = ["userinfo-email", "compute-ro", "storage-ro"]
}
labels = {
my_label = "foobar"
}
}
`, image, instance, nictype)
}
2 changes: 2 additions & 0 deletions website/docs/r/compute_instance_template.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,8 @@ The `network_interface` block supports:
array of alias IP ranges for this network interface. Can only be specified for network
interfaces on subnet-mode networks. Structure documented below.

* `nic_type` - (Optional) The type of vNIC to be used on this interface. Possible values: GVNIC, VIRTIO_NET.

The `access_config` block supports:

* `nat_ip` - (Optional) The IP address that will be 1:1 mapped to the instance's
Expand Down

0 comments on commit 4f6049c

Please sign in to comment.