Skip to content

Commit

Permalink
fix disk behaivor in compute_instance_from_template (#2695)
Browse files Browse the repository at this point in the history
  • Loading branch information
modular-magician authored and nat-henderson committed Dec 21, 2018
1 parent 4a974b2 commit 8daf949
Show file tree
Hide file tree
Showing 3 changed files with 368 additions and 7 deletions.
2 changes: 1 addition & 1 deletion google/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,8 @@ func Provider() terraform.ResourceProvider {
"google_compute_forwarding_rule": dataSourceGoogleComputeForwardingRule(),
"google_compute_image": dataSourceGoogleComputeImage(),
"google_compute_instance": dataSourceGoogleComputeInstance(),
"google_compute_instance_group": dataSourceGoogleComputeInstanceGroup(),
"google_compute_global_address": dataSourceGoogleComputeGlobalAddress(),
"google_compute_instance_group": dataSourceGoogleComputeInstanceGroup(),
"google_compute_lb_ip_ranges": dataSourceGoogleComputeLbIpRanges(),
"google_compute_network": dataSourceGoogleComputeNetwork(),
"google_compute_regions": dataSourceGoogleComputeRegions(),
Expand Down
95 changes: 89 additions & 6 deletions google/resource_compute_instance_from_template.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import (

"github.com/hashicorp/terraform/helper/schema"
strcase "github.com/stoewer/go-strcase"
computeBeta "google.golang.org/api/compute/v0.beta"
compute "google.golang.org/api/compute/v1"
)

func resourceComputeInstanceFromTemplate() *schema.Resource {
Expand Down Expand Up @@ -98,8 +100,26 @@ func resourceComputeInstanceFromTemplateCreate(d *schema.ResourceData, meta inte
return err
}

// Force send all top-level fields in case they're overridden to zero values.
tpl, err := ParseInstanceTemplateFieldValue(d.Get("source_instance_template").(string), d, config)
if err != nil {
return err
}

it, err := config.clientComputeBeta.InstanceTemplates.Get(project, tpl.Name).Do()
if err != nil {
return err
}

instance.Disks, err = adjustInstanceFromTemplateDisks(d, config, it, zone, project)
if err != nil {
return err
}

// Force send all top-level fields that have been set in case they're overridden to zero values.
// TODO: consider doing so for nested fields as well.
// Initialize ForceSendFields to empty so we don't get things that the instance resource
// always force-sends.
instance.ForceSendFields = []string{}
for f, s := range computeInstanceFromTemplateSchema() {
// It seems that GetOkExists always returns true for sets.
// TODO: confirm this and file issue against Terraform core.
Expand All @@ -116,11 +136,6 @@ func resourceComputeInstanceFromTemplateCreate(d *schema.ResourceData, meta inte
}
}

tpl, err := ParseInstanceTemplateFieldValue(d.Get("source_instance_template").(string), d, config)
if err != nil {
return err
}

log.Printf("[INFO] Requesting instance creation")
op, err := config.clientComputeBeta.Instances.Insert(project, zone.Name, instance).SourceInstanceTemplate(tpl.RelativeLink()).Do()
if err != nil {
Expand All @@ -140,3 +155,71 @@ func resourceComputeInstanceFromTemplateCreate(d *schema.ResourceData, meta inte

return resourceComputeInstanceRead(d, meta)
}

// Instances have disks spread across multiple schema properties. This function
// ensures that overriding one of these properties does not override the others.
func adjustInstanceFromTemplateDisks(d *schema.ResourceData, config *Config, it *computeBeta.InstanceTemplate, zone *compute.Zone, project string) ([]*computeBeta.AttachedDisk, error) {
disks := []*computeBeta.AttachedDisk{}
if _, hasBootDisk := d.GetOk("boot_disk"); hasBootDisk {
bootDisk, err := expandBootDisk(d, config, zone, project)
if err != nil {
return nil, err
}
disks = append(disks, bootDisk)
} else {
// boot disk was not overridden, so use the one from the instance template
for _, disk := range it.Properties.Disks {
if disk.Boot {
if dt := disk.InitializeParams.DiskType; dt != "" {
// Instances need a URL for the disk type, but instance templates
// only have the name (since they're global).
disk.InitializeParams.DiskType = fmt.Sprintf("zones/%s/diskTypes/%s", zone.Name, dt)
}
disks = append(disks, disk)
break
}
}
}

if _, hasScratchDisk := d.GetOk("scratch_disk"); hasScratchDisk {
scratchDisks, err := expandScratchDisks(d, config, zone, project)
if err != nil {
return nil, err
}
disks = append(disks, scratchDisks...)
} else {
// scratch disks were not overridden, so use the ones from the instance template
for _, disk := range it.Properties.Disks {
if disk.Type == "SCRATCH" {
disks = append(disks, disk)
}
}
}

attachedDisksCount := d.Get("attached_disk.#").(int)
if attachedDisksCount > 0 {
for i := 0; i < attachedDisksCount; i++ {
diskConfig := d.Get(fmt.Sprintf("attached_disk.%d", i)).(map[string]interface{})
disk, err := expandAttachedDisk(diskConfig, d, config)
if err != nil {
return nil, err
}

disks = append(disks, disk)
}
} else {
// attached disks were not overridden, so use the ones from the instance template
for _, disk := range it.Properties.Disks {
if !disk.Boot && disk.Type != "SCRATCH" {
if s := disk.Source; s != "" {
// Instances need a URL for the disk source, but instance templates
// only have the name (since they're global).
disk.Source = fmt.Sprintf("zones/%s/disks/%s", zone.Name, s)
}
disks = append(disks, disk)
}
}
}

return disks, nil
}
Loading

0 comments on commit 8daf949

Please sign in to comment.