provider/google: add attached_disk field to google_compute_instance (#13443)

This commit is contained in:
Dana Hoffman 2017-04-25 13:20:02 -07:00 committed by GitHub
parent 9c42866887
commit e7c3575499
2 changed files with 190 additions and 17 deletions

View File

@ -28,7 +28,7 @@ func resourceComputeInstance() *schema.Resource {
Schema: map[string]*schema.Schema{ Schema: map[string]*schema.Schema{
"disk": &schema.Schema{ "disk": &schema.Schema{
Type: schema.TypeList, Type: schema.TypeList,
Required: true, Optional: true,
ForceNew: true, ForceNew: true,
Elem: &schema.Resource{ Elem: &schema.Resource{
Schema: map[string]*schema.Schema{ Schema: map[string]*schema.Schema{
@ -91,6 +91,40 @@ func resourceComputeInstance() *schema.Resource {
}, },
}, },
// Preferred way of adding persistent disks to an instance.
// Use this instead of `disk` when possible.
"attached_disk": &schema.Schema{
Type: schema.TypeList,
Optional: true,
ForceNew: true, // TODO(danawillow): Remove this, support attaching/detaching
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"source": &schema.Schema{
Type: schema.TypeString,
Required: true,
},
"device_name": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Computed: true,
},
"disk_encryption_key_raw": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Sensitive: true,
ForceNew: true,
},
"disk_encryption_key_sha256": &schema.Schema{
Type: schema.TypeString,
Computed: true,
},
},
},
},
"machine_type": &schema.Schema{ "machine_type": &schema.Schema{
Type: schema.TypeString, Type: schema.TypeString,
Required: true, Required: true,
@ -371,7 +405,11 @@ func resourceComputeInstanceCreate(d *schema.ResourceData, meta interface{}) err
// Build up the list of disks // Build up the list of disks
disksCount := d.Get("disk.#").(int) disksCount := d.Get("disk.#").(int)
disks := make([]*compute.AttachedDisk, 0, disksCount) attachedDisksCount := d.Get("attached_disk.#").(int)
if disksCount+attachedDisksCount == 0 {
return fmt.Errorf("At least one disk or attached_disk must be set")
}
disks := make([]*compute.AttachedDisk, 0, disksCount+attachedDisksCount)
for i := 0; i < disksCount; i++ { for i := 0; i < disksCount; i++ {
prefix := fmt.Sprintf("disk.%d", i) prefix := fmt.Sprintf("disk.%d", i)
@ -457,6 +495,28 @@ func resourceComputeInstanceCreate(d *schema.ResourceData, meta interface{}) err
disks = append(disks, &disk) disks = append(disks, &disk)
} }
for i := 0; i < attachedDisksCount; i++ {
prefix := fmt.Sprintf("attached_disk.%d", i)
disk := compute.AttachedDisk{
Source: d.Get(prefix + ".source").(string),
AutoDelete: false, // Don't allow autodelete; let terraform handle disk deletion
}
disk.Boot = i == 0 && disksCount == 0 // TODO(danawillow): This is super hacky, let's just add a boot field.
if v, ok := d.GetOk(prefix + ".device_name"); ok {
disk.DeviceName = v.(string)
}
if v, ok := d.GetOk(prefix + ".disk_encryption_key_raw"); ok {
disk.DiskEncryptionKey = &compute.CustomerEncryptionKey{
RawKey: v.(string),
}
}
disks = append(disks, &disk)
}
networksCount := d.Get("network.#").(int) networksCount := d.Get("network.#").(int)
networkInterfacesCount := d.Get("network_interface.#").(int) networkInterfacesCount := d.Get("network_interface.#").(int)
@ -791,24 +851,54 @@ func resourceComputeInstanceRead(d *schema.ResourceData, meta interface{}) error
d.Set("tags_fingerprint", instance.Tags.Fingerprint) d.Set("tags_fingerprint", instance.Tags.Fingerprint)
} }
disks := make([]map[string]interface{}, 0, 1) disksCount := d.Get("disk.#").(int)
for i, disk := range instance.Disks { attachedDisksCount := d.Get("attached_disk.#").(int)
di := map[string]interface{}{ disks := make([]map[string]interface{}, 0, disksCount)
"disk": d.Get(fmt.Sprintf("disk.%d.disk", i)), attachedDisks := make([]map[string]interface{}, 0, attachedDisksCount)
"image": d.Get(fmt.Sprintf("disk.%d.image", i)),
"type": d.Get(fmt.Sprintf("disk.%d.type", i)), if expectedDisks := disksCount + attachedDisksCount; len(instance.Disks) != expectedDisks {
"scratch": d.Get(fmt.Sprintf("disk.%d.scratch", i)), return fmt.Errorf("Expected %d disks, API returned %d", expectedDisks, len(instance.Disks))
"auto_delete": d.Get(fmt.Sprintf("disk.%d.auto_delete", i)), }
"size": d.Get(fmt.Sprintf("disk.%d.size", i)),
"device_name": d.Get(fmt.Sprintf("disk.%d.device_name", i)), attachedDiskSources := make(map[string]struct{}, attachedDisksCount)
"disk_encryption_key_raw": d.Get(fmt.Sprintf("disk.%d.disk_encryption_key_raw", i)), for i := 0; i < attachedDisksCount; i++ {
attachedDiskSources[d.Get(fmt.Sprintf("attached_disk.%d.source", i)).(string)] = struct{}{}
}
dIndex := 0
adIndex := 0
for _, disk := range instance.Disks {
if _, ok := attachedDiskSources[disk.Source]; !ok {
di := map[string]interface{}{
"disk": d.Get(fmt.Sprintf("disk.%d.disk", dIndex)),
"image": d.Get(fmt.Sprintf("disk.%d.image", dIndex)),
"type": d.Get(fmt.Sprintf("disk.%d.type", dIndex)),
"scratch": d.Get(fmt.Sprintf("disk.%d.scratch", dIndex)),
"auto_delete": d.Get(fmt.Sprintf("disk.%d.auto_delete", dIndex)),
"size": d.Get(fmt.Sprintf("disk.%d.size", dIndex)),
"device_name": d.Get(fmt.Sprintf("disk.%d.device_name", dIndex)),
"disk_encryption_key_raw": d.Get(fmt.Sprintf("disk.%d.disk_encryption_key_raw", dIndex)),
}
if disk.DiskEncryptionKey != nil && disk.DiskEncryptionKey.Sha256 != "" {
di["disk_encryption_key_sha256"] = disk.DiskEncryptionKey.Sha256
}
disks = append(disks, di)
dIndex++
} else {
di := map[string]interface{}{
"source": disk.Source,
"device_name": disk.DeviceName,
"disk_encryption_key_raw": d.Get(fmt.Sprintf("attached_disk.%d.disk_encryption_key_raw", adIndex)),
}
if disk.DiskEncryptionKey != nil && disk.DiskEncryptionKey.Sha256 != "" {
di["disk_encryption_key_sha256"] = disk.DiskEncryptionKey.Sha256
}
attachedDisks = append(attachedDisks, di)
adIndex++
} }
if disk.DiskEncryptionKey != nil && disk.DiskEncryptionKey.Sha256 != "" {
di["disk_encryption_key_sha256"] = disk.DiskEncryptionKey.Sha256
}
disks = append(disks, di)
} }
d.Set("disk", disks) d.Set("disk", disks)
d.Set("attached_disk", attachedDisks)
d.Set("self_link", instance.SelfLink) d.Set("self_link", instance.SelfLink)
d.SetId(instance.Name) d.SetId(instance.Name)

View File

@ -244,6 +244,44 @@ func TestAccComputeInstance_diskEncryption(t *testing.T) {
}) })
} }
func TestAccComputeInstance_attachedDisk(t *testing.T) {
var instance compute.Instance
var instanceName = fmt.Sprintf("instance-test-%s", acctest.RandString(10))
var diskName = fmt.Sprintf("instance-testd-%s", acctest.RandString(10))
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckComputeInstanceDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccComputeInstance_attachedDisk(diskName, instanceName),
Check: resource.ComposeTestCheckFunc(
testAccCheckComputeInstanceExists(
"google_compute_instance.foobar", &instance),
testAccCheckComputeInstanceDisk(&instance, diskName, false, true),
),
},
},
})
}
func TestAccComputeInstance_noDisk(t *testing.T) {
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_noDisk(instanceName),
ExpectError: regexp.MustCompile("At least one disk or attached_disk must be set"),
},
},
})
}
func TestAccComputeInstance_local_ssd(t *testing.T) { func TestAccComputeInstance_local_ssd(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))
@ -1121,6 +1159,51 @@ func testAccComputeInstance_disks_encryption(disk, instance string) string {
}`, disk, instance) }`, disk, instance)
} }
func testAccComputeInstance_attachedDisk(disk, instance string) string {
return fmt.Sprintf(`
resource "google_compute_disk" "foobar" {
name = "%s"
size = 10
type = "pd-ssd"
zone = "us-central1-a"
}
resource "google_compute_instance" "foobar" {
name = "%s"
machine_type = "n1-standard-1"
zone = "us-central1-a"
attached_disk {
source = "${google_compute_disk.foobar.self_link}"
}
network_interface {
network = "default"
}
metadata {
foo = "bar"
}
}`, disk, instance)
}
func testAccComputeInstance_noDisk(instance string) string {
return fmt.Sprintf(`
resource "google_compute_instance" "foobar" {
name = "%s"
machine_type = "n1-standard-1"
zone = "us-central1-a"
network_interface {
network = "default"
}
metadata {
foo = "bar"
}
}`, instance)
}
func testAccComputeInstance_local_ssd(instance string) string { func testAccComputeInstance_local_ssd(instance string) string {
return fmt.Sprintf(` return fmt.Sprintf(`
resource "google_compute_instance" "local-ssd" { resource "google_compute_instance" "local-ssd" {