Skip to content

Commit 32bf0df

Browse files
authored
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
1 parent 549e131 commit 32bf0df

File tree

3 files changed

+160
-7
lines changed

3 files changed

+160
-7
lines changed

google/resource_compute_instance.go

+69-2
Original file line numberDiff line numberDiff line change
@@ -107,10 +107,27 @@ func resourceComputeInstance() *schema.Resource {
107107
},
108108
},
109109

110-
"disk": &schema.Schema{
110+
"scratch_disk": &schema.Schema{
111111
Type: schema.TypeList,
112112
Optional: true,
113113
ForceNew: true,
114+
Elem: &schema.Resource{
115+
Schema: map[string]*schema.Schema{
116+
"interface": &schema.Schema{
117+
Type: schema.TypeString,
118+
Optional: true,
119+
Default: "SCSI",
120+
ValidateFunc: validation.StringInSlice([]string{"SCSI", "NVME"}, false),
121+
},
122+
},
123+
},
124+
},
125+
126+
"disk": &schema.Schema{
127+
Type: schema.TypeList,
128+
Optional: true,
129+
ForceNew: true,
130+
Deprecated: "Use boot_disk, scratch_disk, and attached_disk instead",
114131
Elem: &schema.Resource{
115132
Schema: map[string]*schema.Schema{
116133
// TODO(mitchellh): one of image or disk is required
@@ -499,6 +516,15 @@ func resourceComputeInstanceCreate(d *schema.ResourceData, meta interface{}) err
499516
disks = append(disks, bootDisk)
500517
}
501518

519+
var hasScratchDisk bool
520+
if _, hasScratchDisk := d.GetOk("scratch_disk"); hasScratchDisk {
521+
scratchDisks, err := expandScratchDisks(d, config, zone)
522+
if err != nil {
523+
return err
524+
}
525+
disks = append(disks, scratchDisks...)
526+
}
527+
502528
disksCount := d.Get("disk.#").(int)
503529
attachedDisksCount := d.Get("attached_disk.#").(int)
504530

@@ -545,6 +571,9 @@ func resourceComputeInstanceCreate(d *schema.ResourceData, meta interface{}) err
545571

546572
if v, ok := d.GetOk(prefix + ".scratch"); ok {
547573
if v.(bool) {
574+
if hasScratchDisk {
575+
return fmt.Errorf("Cannot set scratch disks using both `scratch_disk` and `disk` properties")
576+
}
548577
disk.Type = "SCRATCH"
549578
}
550579
}
@@ -960,11 +989,12 @@ func resourceComputeInstanceRead(d *schema.ResourceData, meta interface{}) error
960989

961990
disksCount := d.Get("disk.#").(int)
962991
attachedDisksCount := d.Get("attached_disk.#").(int)
992+
scratchDisksCount := d.Get("scratch_disk.#").(int)
963993

964994
if _, ok := d.GetOk("boot_disk"); ok {
965995
disksCount++
966996
}
967-
if expectedDisks := disksCount + attachedDisksCount; len(instance.Disks) != expectedDisks {
997+
if expectedDisks := disksCount + attachedDisksCount + scratchDisksCount; len(instance.Disks) != expectedDisks {
968998
return fmt.Errorf("Expected %d disks, API returned %d", expectedDisks, len(instance.Disks))
969999
}
9701000

@@ -975,13 +1005,20 @@ func resourceComputeInstanceRead(d *schema.ResourceData, meta interface{}) error
9751005

9761006
dIndex := 0
9771007
adIndex := 0
1008+
sIndex := 0
9781009
disks := make([]map[string]interface{}, 0, disksCount)
9791010
attachedDisks := make([]map[string]interface{}, 0, attachedDisksCount)
1011+
scratchDisks := make([]map[string]interface{}, 0, scratchDisksCount)
9801012
for _, disk := range instance.Disks {
9811013
if _, ok := d.GetOk("boot_disk"); ok && disk.Boot {
9821014
// This disk is a boot disk and there is a boot disk set in the config, therefore
9831015
// this is the boot disk set in the config.
9841016
d.Set("boot_disk", flattenBootDisk(d, disk))
1017+
} else if _, ok := d.GetOk("scratch_disk"); ok && disk.Type == "SCRATCH" {
1018+
// This disk is a scratch disk and there are scratch disks set in the config, therefore
1019+
// this is a scratch disk set in the config.
1020+
scratchDisks = append(scratchDisks, flattenScratchDisk(disk))
1021+
sIndex++
9851022
} else if _, ok := attachedDiskSources[disk.Source]; !ok {
9861023
di := map[string]interface{}{
9871024
"disk": d.Get(fmt.Sprintf("disk.%d.disk", dIndex)),
@@ -1013,6 +1050,7 @@ func resourceComputeInstanceRead(d *schema.ResourceData, meta interface{}) error
10131050
}
10141051
d.Set("disk", disks)
10151052
d.Set("attached_disk", attachedDisks)
1053+
d.Set("scratch_disk", scratchDisks)
10161054

10171055
d.Set("self_link", instance.SelfLink)
10181056
d.SetId(instance.Name)
@@ -1371,3 +1409,32 @@ func flattenBootDisk(d *schema.ResourceData, disk *compute.AttachedDisk) []map[s
13711409

13721410
return []map[string]interface{}{result}
13731411
}
1412+
1413+
func expandScratchDisks(d *schema.ResourceData, config *Config, zone *compute.Zone) ([]*compute.AttachedDisk, error) {
1414+
diskType, err := readDiskType(config, zone, "local-ssd")
1415+
if err != nil {
1416+
return nil, fmt.Errorf("Error loading disk type 'local-ssd': %s", err)
1417+
}
1418+
1419+
n := d.Get("scratch_disk.#").(int)
1420+
scratchDisks := make([]*compute.AttachedDisk, 0, n)
1421+
for i := 0; i < n; i++ {
1422+
scratchDisks = append(scratchDisks, &compute.AttachedDisk{
1423+
AutoDelete: true,
1424+
Type: "SCRATCH",
1425+
Interface: d.Get(fmt.Sprintf("scratch_disk.%d.interface", i)).(string),
1426+
InitializeParams: &compute.AttachedDiskInitializeParams{
1427+
DiskType: diskType.SelfLink,
1428+
},
1429+
})
1430+
}
1431+
1432+
return scratchDisks, nil
1433+
}
1434+
1435+
func flattenScratchDisk(disk *compute.AttachedDisk) map[string]interface{} {
1436+
result := map[string]interface{}{
1437+
"interface": disk.Interface,
1438+
}
1439+
return result
1440+
}

google/resource_compute_instance_test.go

+79-1
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,27 @@ func TestAccComputeInstance_local_ssd(t *testing.T) {
347347
})
348348
}
349349

350+
func TestAccComputeInstance_scratchDisk(t *testing.T) {
351+
var instance compute.Instance
352+
var instanceName = fmt.Sprintf("instance-test-%s", acctest.RandString(10))
353+
354+
resource.Test(t, resource.TestCase{
355+
PreCheck: func() { testAccPreCheck(t) },
356+
Providers: testAccProviders,
357+
CheckDestroy: testAccCheckComputeInstanceDestroy,
358+
Steps: []resource.TestStep{
359+
resource.TestStep{
360+
Config: testAccComputeInstance_scratchDisk(instanceName),
361+
Check: resource.ComposeTestCheckFunc(
362+
testAccCheckComputeInstanceExists(
363+
"google_compute_instance.scratch", &instance),
364+
testAccCheckComputeInstanceScratchDisk(&instance, []string{"NVME", "SCSI"}),
365+
),
366+
},
367+
},
368+
})
369+
}
370+
350371
func TestAccComputeInstance_update_deprecated_network(t *testing.T) {
351372
var instance compute.Instance
352373
var instanceName = fmt.Sprintf("instance-test-%s", acctest.RandString(10))
@@ -794,7 +815,7 @@ func testAccCheckComputeInstanceDisk(instance *compute.Instance, source string,
794815
}
795816

796817
for _, disk := range instance.Disks {
797-
if strings.HasSuffix(disk.Source, source) && disk.AutoDelete == delete && disk.Boot == boot {
818+
if strings.HasSuffix(disk.Source, "/"+source) && disk.AutoDelete == delete && disk.Boot == boot {
798819
return nil
799820
}
800821
}
@@ -821,6 +842,34 @@ func testAccCheckComputeInstanceBootDisk(instance *compute.Instance, source stri
821842
}
822843
}
823844

845+
func testAccCheckComputeInstanceScratchDisk(instance *compute.Instance, interfaces []string) resource.TestCheckFunc {
846+
return func(s *terraform.State) error {
847+
if instance.Disks == nil {
848+
return fmt.Errorf("no disks")
849+
}
850+
851+
i := 0
852+
for _, disk := range instance.Disks {
853+
if disk.Type == "SCRATCH" {
854+
if i >= len(interfaces) {
855+
return fmt.Errorf("Expected %d scratch disks, found more", len(interfaces))
856+
}
857+
if disk.Interface != interfaces[i] {
858+
return fmt.Errorf("Mismatched interface on scratch disk #%d, expected: %q, found: %q",
859+
i, interfaces[i], disk.Interface)
860+
}
861+
i++
862+
}
863+
}
864+
865+
if i != len(interfaces) {
866+
return fmt.Errorf("Expected %d scratch disks, found %d", len(interfaces), i)
867+
}
868+
869+
return nil
870+
}
871+
}
872+
824873
func testAccCheckComputeInstanceDiskEncryptionKey(n string, instance *compute.Instance) resource.TestCheckFunc {
825874
return func(s *terraform.State) error {
826875
rs, ok := s.RootModule().Resources[n]
@@ -1380,6 +1429,35 @@ resource "google_compute_instance" "local-ssd" {
13801429
`, instance)
13811430
}
13821431

1432+
func testAccComputeInstance_scratchDisk(instance string) string {
1433+
return fmt.Sprintf(`
1434+
resource "google_compute_instance" "scratch" {
1435+
name = "%s"
1436+
machine_type = "n1-standard-1"
1437+
zone = "us-central1-a"
1438+
1439+
boot_disk {
1440+
initialize_params {
1441+
image = "debian-8-jessie-v20160803"
1442+
}
1443+
}
1444+
1445+
scratch_disk {
1446+
interface = "NVME"
1447+
}
1448+
1449+
scratch_disk {
1450+
interface = "SCSI"
1451+
}
1452+
1453+
network_interface {
1454+
network = "default"
1455+
}
1456+
1457+
}
1458+
`, instance)
1459+
}
1460+
13831461
func testAccComputeInstance_service_account(instance string) string {
13841462
return fmt.Sprintf(`
13851463
resource "google_compute_instance" "foobar" {

website/docs/r/compute_instance.html.markdown

+12-4
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,9 @@ The following arguments are supported:
7676

7777
- - -
7878

79+
* `scratch_disk` - (Optional) Scratch disks to attach to the instance. This can be
80+
specified multiple times for multiple scratch disks. Structure is documented below.
81+
7982
* `can_ip_forward` - (Optional) Whether to allow sending and receiving of
8083
packets with non-matching source or destination IPs.
8184
This defaults to false.
@@ -85,9 +88,6 @@ The following arguments are supported:
8588

8689
* `description` - (Optional) A brief description of this resource.
8790

88-
* `disk` - (Optional) Disks to attach to the instance. This can be specified
89-
multiple times for multiple disks. Structure is documented below.
90-
9191
* `labels` - (Optional) A set of key/value label pairs to assign to the instance.
9292

9393
* `metadata` - (Optional) Metadata key/value pairs to make available from
@@ -112,6 +112,9 @@ The following arguments are supported:
112112

113113
---
114114

115+
* `disk` - (DEPRECATED) Disks to attach to the instance. This can be specified
116+
multiple times for multiple disks. Structure is documented below.
117+
115118
* `network` - (DEPRECATED) Networks to attach to the instance. This
116119
can be specified multiple times for multiple networks. Structure is
117120
documented below.
@@ -151,7 +154,12 @@ The `initialize_params` block supports:
151154
`global/images/family/{family}`, `family/{family}`, `{project}/{family}`,
152155
`{project}/{image}`, `{family}`, or `{image}`.
153156

154-
The `disk` block supports: (Note that either disk or image is required, unless
157+
The `scratch_disk` block supports:
158+
159+
* `interface` - (Optional) The disk interface to use for attaching this disk; either SCSI or NVME.
160+
Defaults to SCSI.
161+
162+
(DEPRECATED) The `disk` block supports: (Note that either disk or image is required, unless
155163
the type is "local-ssd", in which case scratch must be true).
156164

157165
* `disk` - The name of the existing disk (such as those managed by

0 commit comments

Comments
 (0)