Add scratch_disk property to google_compute_instance and deprecate disk (#123)

* Add scratch_disk property to google_compute_instance

* docs for scratch_disk

* limit scope of scratchDisks array by using bool, test formatting

* add slash back to disk check
This commit is contained in:
Dana Hoffman 2017-06-28 15:43:58 -07:00 committed by GitHub
parent 549e1314f9
commit 32bf0df2d0
3 changed files with 160 additions and 7 deletions

View File

@ -107,10 +107,27 @@ func resourceComputeInstance() *schema.Resource {
}, },
}, },
"disk": &schema.Schema{ "scratch_disk": &schema.Schema{
Type: schema.TypeList, Type: schema.TypeList,
Optional: true, Optional: true,
ForceNew: true, ForceNew: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"interface": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Default: "SCSI",
ValidateFunc: validation.StringInSlice([]string{"SCSI", "NVME"}, false),
},
},
},
},
"disk": &schema.Schema{
Type: schema.TypeList,
Optional: true,
ForceNew: true,
Deprecated: "Use boot_disk, scratch_disk, and attached_disk instead",
Elem: &schema.Resource{ Elem: &schema.Resource{
Schema: map[string]*schema.Schema{ Schema: map[string]*schema.Schema{
// TODO(mitchellh): one of image or disk is required // TODO(mitchellh): one of image or disk is required
@ -499,6 +516,15 @@ func resourceComputeInstanceCreate(d *schema.ResourceData, meta interface{}) err
disks = append(disks, bootDisk) disks = append(disks, bootDisk)
} }
var hasScratchDisk bool
if _, hasScratchDisk := d.GetOk("scratch_disk"); hasScratchDisk {
scratchDisks, err := expandScratchDisks(d, config, zone)
if err != nil {
return err
}
disks = append(disks, scratchDisks...)
}
disksCount := d.Get("disk.#").(int) disksCount := d.Get("disk.#").(int)
attachedDisksCount := d.Get("attached_disk.#").(int) attachedDisksCount := d.Get("attached_disk.#").(int)
@ -545,6 +571,9 @@ func resourceComputeInstanceCreate(d *schema.ResourceData, meta interface{}) err
if v, ok := d.GetOk(prefix + ".scratch"); ok { if v, ok := d.GetOk(prefix + ".scratch"); ok {
if v.(bool) { if v.(bool) {
if hasScratchDisk {
return fmt.Errorf("Cannot set scratch disks using both `scratch_disk` and `disk` properties")
}
disk.Type = "SCRATCH" disk.Type = "SCRATCH"
} }
} }
@ -960,11 +989,12 @@ func resourceComputeInstanceRead(d *schema.ResourceData, meta interface{}) error
disksCount := d.Get("disk.#").(int) disksCount := d.Get("disk.#").(int)
attachedDisksCount := d.Get("attached_disk.#").(int) attachedDisksCount := d.Get("attached_disk.#").(int)
scratchDisksCount := d.Get("scratch_disk.#").(int)
if _, ok := d.GetOk("boot_disk"); ok { if _, ok := d.GetOk("boot_disk"); ok {
disksCount++ disksCount++
} }
if expectedDisks := disksCount + attachedDisksCount; len(instance.Disks) != expectedDisks { if expectedDisks := disksCount + attachedDisksCount + scratchDisksCount; len(instance.Disks) != expectedDisks {
return fmt.Errorf("Expected %d disks, API returned %d", expectedDisks, len(instance.Disks)) return fmt.Errorf("Expected %d disks, API returned %d", expectedDisks, len(instance.Disks))
} }
@ -975,13 +1005,20 @@ func resourceComputeInstanceRead(d *schema.ResourceData, meta interface{}) error
dIndex := 0 dIndex := 0
adIndex := 0 adIndex := 0
sIndex := 0
disks := make([]map[string]interface{}, 0, disksCount) disks := make([]map[string]interface{}, 0, disksCount)
attachedDisks := make([]map[string]interface{}, 0, attachedDisksCount) attachedDisks := make([]map[string]interface{}, 0, attachedDisksCount)
scratchDisks := make([]map[string]interface{}, 0, scratchDisksCount)
for _, disk := range instance.Disks { for _, disk := range instance.Disks {
if _, ok := d.GetOk("boot_disk"); ok && disk.Boot { if _, ok := d.GetOk("boot_disk"); ok && disk.Boot {
// This disk is a boot disk and there is a boot disk set in the config, therefore // This disk is a boot disk and there is a boot disk set in the config, therefore
// this is the boot disk set in the config. // this is the boot disk set in the config.
d.Set("boot_disk", flattenBootDisk(d, disk)) d.Set("boot_disk", flattenBootDisk(d, disk))
} else if _, ok := d.GetOk("scratch_disk"); ok && disk.Type == "SCRATCH" {
// This disk is a scratch disk and there are scratch disks set in the config, therefore
// this is a scratch disk set in the config.
scratchDisks = append(scratchDisks, flattenScratchDisk(disk))
sIndex++
} else if _, ok := attachedDiskSources[disk.Source]; !ok { } else if _, ok := attachedDiskSources[disk.Source]; !ok {
di := map[string]interface{}{ di := map[string]interface{}{
"disk": d.Get(fmt.Sprintf("disk.%d.disk", dIndex)), "disk": d.Get(fmt.Sprintf("disk.%d.disk", dIndex)),
@ -1013,6 +1050,7 @@ func resourceComputeInstanceRead(d *schema.ResourceData, meta interface{}) error
} }
d.Set("disk", disks) d.Set("disk", disks)
d.Set("attached_disk", attachedDisks) d.Set("attached_disk", attachedDisks)
d.Set("scratch_disk", scratchDisks)
d.Set("self_link", instance.SelfLink) d.Set("self_link", instance.SelfLink)
d.SetId(instance.Name) d.SetId(instance.Name)
@ -1371,3 +1409,32 @@ func flattenBootDisk(d *schema.ResourceData, disk *compute.AttachedDisk) []map[s
return []map[string]interface{}{result} return []map[string]interface{}{result}
} }
func expandScratchDisks(d *schema.ResourceData, config *Config, zone *compute.Zone) ([]*compute.AttachedDisk, error) {
diskType, err := readDiskType(config, zone, "local-ssd")
if err != nil {
return nil, fmt.Errorf("Error loading disk type 'local-ssd': %s", err)
}
n := d.Get("scratch_disk.#").(int)
scratchDisks := make([]*compute.AttachedDisk, 0, n)
for i := 0; i < n; i++ {
scratchDisks = append(scratchDisks, &compute.AttachedDisk{
AutoDelete: true,
Type: "SCRATCH",
Interface: d.Get(fmt.Sprintf("scratch_disk.%d.interface", i)).(string),
InitializeParams: &compute.AttachedDiskInitializeParams{
DiskType: diskType.SelfLink,
},
})
}
return scratchDisks, nil
}
func flattenScratchDisk(disk *compute.AttachedDisk) map[string]interface{} {
result := map[string]interface{}{
"interface": disk.Interface,
}
return result
}

View File

@ -347,6 +347,27 @@ func TestAccComputeInstance_local_ssd(t *testing.T) {
}) })
} }
func TestAccComputeInstance_scratchDisk(t *testing.T) {
var instance compute.Instance
var instanceName = fmt.Sprintf("instance-test-%s", acctest.RandString(10))
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckComputeInstanceDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccComputeInstance_scratchDisk(instanceName),
Check: resource.ComposeTestCheckFunc(
testAccCheckComputeInstanceExists(
"google_compute_instance.scratch", &instance),
testAccCheckComputeInstanceScratchDisk(&instance, []string{"NVME", "SCSI"}),
),
},
},
})
}
func TestAccComputeInstance_update_deprecated_network(t *testing.T) { func TestAccComputeInstance_update_deprecated_network(t *testing.T) {
var instance compute.Instance var instance compute.Instance
var instanceName = fmt.Sprintf("instance-test-%s", acctest.RandString(10)) var instanceName = fmt.Sprintf("instance-test-%s", acctest.RandString(10))
@ -794,7 +815,7 @@ func testAccCheckComputeInstanceDisk(instance *compute.Instance, source string,
} }
for _, disk := range instance.Disks { for _, disk := range instance.Disks {
if strings.HasSuffix(disk.Source, source) && disk.AutoDelete == delete && disk.Boot == boot { if strings.HasSuffix(disk.Source, "/"+source) && disk.AutoDelete == delete && disk.Boot == boot {
return nil return nil
} }
} }
@ -821,6 +842,34 @@ func testAccCheckComputeInstanceBootDisk(instance *compute.Instance, source stri
} }
} }
func testAccCheckComputeInstanceScratchDisk(instance *compute.Instance, interfaces []string) resource.TestCheckFunc {
return func(s *terraform.State) error {
if instance.Disks == nil {
return fmt.Errorf("no disks")
}
i := 0
for _, disk := range instance.Disks {
if disk.Type == "SCRATCH" {
if i >= len(interfaces) {
return fmt.Errorf("Expected %d scratch disks, found more", len(interfaces))
}
if disk.Interface != interfaces[i] {
return fmt.Errorf("Mismatched interface on scratch disk #%d, expected: %q, found: %q",
i, interfaces[i], disk.Interface)
}
i++
}
}
if i != len(interfaces) {
return fmt.Errorf("Expected %d scratch disks, found %d", len(interfaces), i)
}
return nil
}
}
func testAccCheckComputeInstanceDiskEncryptionKey(n string, instance *compute.Instance) resource.TestCheckFunc { func testAccCheckComputeInstanceDiskEncryptionKey(n string, instance *compute.Instance) resource.TestCheckFunc {
return func(s *terraform.State) error { return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n] rs, ok := s.RootModule().Resources[n]
@ -1380,6 +1429,35 @@ resource "google_compute_instance" "local-ssd" {
`, instance) `, instance)
} }
func testAccComputeInstance_scratchDisk(instance string) string {
return fmt.Sprintf(`
resource "google_compute_instance" "scratch" {
name = "%s"
machine_type = "n1-standard-1"
zone = "us-central1-a"
boot_disk {
initialize_params {
image = "debian-8-jessie-v20160803"
}
}
scratch_disk {
interface = "NVME"
}
scratch_disk {
interface = "SCSI"
}
network_interface {
network = "default"
}
}
`, instance)
}
func testAccComputeInstance_service_account(instance string) string { func testAccComputeInstance_service_account(instance string) string {
return fmt.Sprintf(` return fmt.Sprintf(`
resource "google_compute_instance" "foobar" { resource "google_compute_instance" "foobar" {

View File

@ -76,6 +76,9 @@ The following arguments are supported:
- - - - - -
* `scratch_disk` - (Optional) Scratch disks to attach to the instance. This can be
specified multiple times for multiple scratch disks. Structure is documented below.
* `can_ip_forward` - (Optional) Whether to allow sending and receiving of * `can_ip_forward` - (Optional) Whether to allow sending and receiving of
packets with non-matching source or destination IPs. packets with non-matching source or destination IPs.
This defaults to false. This defaults to false.
@ -85,9 +88,6 @@ The following arguments are supported:
* `description` - (Optional) A brief description of this resource. * `description` - (Optional) A brief description of this resource.
* `disk` - (Optional) Disks to attach to the instance. This can be specified
multiple times for multiple disks. Structure is documented below.
* `labels` - (Optional) A set of key/value label pairs to assign to the instance. * `labels` - (Optional) A set of key/value label pairs to assign to the instance.
* `metadata` - (Optional) Metadata key/value pairs to make available from * `metadata` - (Optional) Metadata key/value pairs to make available from
@ -112,6 +112,9 @@ The following arguments are supported:
--- ---
* `disk` - (DEPRECATED) Disks to attach to the instance. This can be specified
multiple times for multiple disks. Structure is documented below.
* `network` - (DEPRECATED) Networks to attach to the instance. This * `network` - (DEPRECATED) Networks to attach to the instance. This
can be specified multiple times for multiple networks. Structure is can be specified multiple times for multiple networks. Structure is
documented below. documented below.
@ -151,7 +154,12 @@ The `initialize_params` block supports:
`global/images/family/{family}`, `family/{family}`, `{project}/{family}`, `global/images/family/{family}`, `family/{family}`, `{project}/{family}`,
`{project}/{image}`, `{family}`, or `{image}`. `{project}/{image}`, `{family}`, or `{image}`.
The `disk` block supports: (Note that either disk or image is required, unless The `scratch_disk` block supports:
* `interface` - (Optional) The disk interface to use for attaching this disk; either SCSI or NVME.
Defaults to SCSI.
(DEPRECATED) The `disk` block supports: (Note that either disk or image is required, unless
the type is "local-ssd", in which case scratch must be true). the type is "local-ssd", in which case scratch must be true).
* `disk` - The name of the existing disk (such as those managed by * `disk` - The name of the existing disk (such as those managed by