Skip to content

Commit

Permalink
Merge pull request #138 from terraform-providers/fix-#78
Browse files Browse the repository at this point in the history
Fix #78: Cannot specify target container when adding disks to a virtual machine resource
  • Loading branch information
PacoDw authored Jun 19, 2020
2 parents 8f2d6bb + f14d392 commit 9d3e86b
Show file tree
Hide file tree
Showing 8 changed files with 361 additions and 103 deletions.
17 changes: 17 additions & 0 deletions client/v3/v3_structs.go
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,20 @@ type VMDiskDeviceProperties struct {
DiskAddress *DiskAddress `json:"disk_address,omitempty" mapstructure:"disk_address,omitempty"`
}

// StorageContainerReference references to a kind. Either one of (kind, uuid) or url needs to be specified.
type StorageContainerReference struct {
URL string `json:"url,omitempty"`
Kind string `json:"kind,omitempty"`
UUID string `json:"uuid,omitempty"`
Name string `json:"name,omitempty"`
}

// VMStorageConfig specifies the storage configuration parameters for VM disks.
type VMStorageConfig struct {
FlashMode string `json:"flash_mode,omitempty"`
StorageContainerReference *StorageContainerReference `json:"storage_container_reference,omitempty"`
}

// VMDisk VirtualMachine Disk (VM Disk).
type VMDisk struct {
DataSourceReference *Reference `json:"data_source_reference,omitempty" mapstructure:"data_source_reference,omitempty"`
Expand All @@ -212,6 +226,9 @@ type VMDisk struct {
UUID *string `json:"uuid,omitempty" mapstructure:"uuid,omitempty"`

VolumeGroupReference *Reference `json:"volume_group_reference,omitempty" mapstructure:"volume_group_reference,omitempty"`

// This preference specifies the storage configuration parameters for VM disks.
StorageConfig *VMStorageConfig `json:"storage_config,omitempty" mapstructure:"storage_config,omitempty"`
}

// VMResources VM Resources Definition.
Expand Down
43 changes: 41 additions & 2 deletions nutanix/data_source_nutanix_virtual_machine.go
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,43 @@ func dataSourceNutanixVirtualMachine() *schema.Resource {
Type: schema.TypeInt,
Computed: true,
},
"storage_config": {
Type: schema.TypeList,
Computed: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"flash_mode": {
Type: schema.TypeString,
Computed: true,
},
"storage_container_reference": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"url": {
Type: schema.TypeString,
Computed: true,
},
"kind": {
Type: schema.TypeString,
Computed: true,
},
"name": {
Type: schema.TypeString,
Computed: true,
},
"uuid": {
Type: schema.TypeString,
Computed: true,
},
},
},
},
},
},
},
"device_properties": {
Type: schema.TypeList,
Computed: true,
Expand Down Expand Up @@ -570,7 +607,6 @@ func dataSourceNutanixVirtualMachine() *schema.Resource {
},
},
},

"volume_group_reference": {
Type: schema.TypeMap,
Computed: true,
Expand Down Expand Up @@ -665,6 +701,9 @@ func dataSourceNutanixVirtualMachineRead(d *schema.ResourceData, meta interface{
if err := d.Set("parent_reference", flattenReferenceValues(resp.Status.Resources.ParentReference)); err != nil {
return err
}
if err := d.Set("disk_list", flattenDiskList(resp.Status.Resources.DiskList)); err != nil {
return err
}

diskAddress := make(map[string]interface{})
mac := ""
Expand Down Expand Up @@ -753,7 +792,7 @@ func dataSourceNutanixVirtualMachineRead(d *schema.ResourceData, meta interface{
d.Set("vga_console_enabled", utils.BoolValue(resp.Status.Resources.VgaConsoleEnabled))
d.SetId(utils.StringValue(resp.Metadata.UUID))

return d.Set("disk_list", setDiskList(resp.Status.Resources.DiskList, resp.Status.Resources.GuestCustomization))
return nil
}

func resourceDatasourceVirtualMachineInstanceStateUpgradeV0(is map[string]interface{}, meta interface{}) (map[string]interface{}, error) {
Expand Down
72 changes: 68 additions & 4 deletions nutanix/data_source_nutanix_virtual_machine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,70 @@ func TestAccNutanixVirtualMachineDataSource_WithDisk(t *testing.T) {
})
}

func TestAccNutanixVirtualMachineDataSource_withDiskContainer(t *testing.T) {
datasourceName := "data.nutanix_virtual_machine.nutanix_virtual_machine"
vmName := acctest.RandomWithPrefix("test-dou-vm")

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccVMDataSourceWithDiskContainer(vmName),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet(datasourceName, "vm_id"),
resource.TestCheckResourceAttrSet(datasourceName, "disk_list.#"),
resource.TestCheckResourceAttrSet(datasourceName, "disk_list.0.disk_size_bytes"),
resource.TestCheckResourceAttrSet(datasourceName, "disk_list.0.disk_size_mib"),
resource.TestCheckResourceAttrSet(datasourceName, "disk_list.0.storage_config.#"),
resource.TestCheckResourceAttrSet(datasourceName, "disk_list.0.storage_config.0.storage_container_reference.#"),
resource.TestCheckResourceAttrSet(datasourceName, "disk_list.0.storage_config.0.storage_container_reference.0.kind"),
resource.TestCheckResourceAttrSet(datasourceName, "disk_list.0.storage_config.0.storage_container_reference.0.uuid"),
resource.TestCheckResourceAttrSet(datasourceName, "disk_list.0.storage_config.0.storage_container_reference.0.name"),
),
},
},
})
}

func testAccVMDataSourceWithDiskContainer(vmName string) string {
return fmt.Sprintf(`
data "nutanix_clusters" "clusters" {}
locals {
cluster1 = [
for cluster in data.nutanix_clusters.clusters.entities :
cluster.metadata.uuid if cluster.service_list[0] != "PRISM_CENTRAL"
][0]
}
resource "nutanix_virtual_machine" "vm-disk" {
name = "%s"
cluster_uuid = local.cluster1
num_vcpus_per_socket = 1
num_sockets = 1
memory_size_mib = 186
disk_list {
# disk_size_mib = 300
disk_size_bytes = 68157440
disk_size_mib = 65
storage_config {
storage_container_reference {
kind = "storage_container"
uuid = "2bbe77bc-fd14-4697-8de1-6369757f9219"
}
}
}
}
data "nutanix_virtual_machine" "nutanix_virtual_machine" {
vm_id = nutanix_virtual_machine.vm-disk.id
}
`, vmName)
}

func testAccVMDataSourceConfig(r int) string {
return fmt.Sprintf(`
data "nutanix_clusters" "clusters" {}
Expand Down Expand Up @@ -72,25 +136,25 @@ data "nutanix_virtual_machine" "nutanix_virtual_machine" {
func testAccVMDataSourceConfigWithDisk(r int) string {
return fmt.Sprintf(`
data "nutanix_clusters" "clusters" {}
locals {
cluster1 = "${data.nutanix_clusters.clusters.entities.0.service_list.0 == "PRISM_CENTRAL"
? data.nutanix_clusters.clusters.entities.1.metadata.uuid : data.nutanix_clusters.clusters.entities.0.metadata.uuid}"
}
resource "nutanix_image" "cirros-034-disk" {
name = "test-image-dou-vm-create-%[1]d"
source_uri = "http://download.cirros-cloud.net/0.4.0/cirros-0.4.0-x86_64-disk.img"
description = "heres a tiny linux image, not an iso, but a real disk!"
}
resource "nutanix_virtual_machine" "vm1" {
name = "test-dou-vm-%[1]d"
cluster_uuid = "${local.cluster1}"
num_vcpus_per_socket = 1
num_sockets = 1
memory_size_mib = 186
disk_list {
data_source_reference = {
kind = "image"
Expand Down
119 changes: 96 additions & 23 deletions nutanix/resource_nutanix_virtual_machine.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"strings"
"time"

"github.com/spf13/cast"
v3 "github.com/terraform-providers/terraform-provider-nutanix/client/v3"
"github.com/terraform-providers/terraform-provider-nutanix/utils"

Expand Down Expand Up @@ -662,6 +663,46 @@ func resourceNutanixVirtualMachine() *schema.Resource {
Optional: true,
Computed: true,
},
"storage_config": {
Type: schema.TypeList,
Optional: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"flash_mode": {
Type: schema.TypeString,
Optional: true,
},
"storage_container_reference": {
Type: schema.TypeList,
Optional: true,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"url": {
Type: schema.TypeString,
Optional: true,
Computed: true,
},
"kind": {
Type: schema.TypeString,
Optional: true,
Default: "storage_container",
},
"name": {
Type: schema.TypeString,
Computed: true,
},
"uuid": {
Type: schema.TypeString,
Optional: true,
},
},
},
},
},
},
},
"device_properties": {
Type: schema.TypeList,
Optional: true,
Expand Down Expand Up @@ -1703,59 +1744,49 @@ func expandDiskList(d *schema.ResourceData, isCreation bool) ([]*v3.VMDisk, erro
dsk := v.([]interface{})
if len(dsk) > 0 {
dls := make([]*v3.VMDisk, len(dsk))

for k, val := range dsk {
hasDSRef := false
v := val.(map[string]interface{})
dl := &v3.VMDisk{}

// uuid
if v1, ok1 := v["uuid"]; ok1 && v1.(string) != "" {
dl.UUID = utils.StringPtr(v1.(string))
}
// storage_config
if v, ok1 := v["storage_config"]; ok1 {
dl.StorageConfig = expandStorageConfig(v.([]interface{}))
}
// device_properties
if v1, ok1 := v["device_properties"]; ok1 {
dvp := v1.([]interface{})
if len(dvp) > 0 {
d := dvp[0].(map[string]interface{})
dp := &v3.VMDiskDeviceProperties{}
if v1, ok := d["device_type"]; ok {
dp.DeviceType = utils.StringPtr(v1.(string))
}
if v2, ok := d["disk_address"]; ok && len(v2.(map[string]interface{})) > 0 {
da := v2.(map[string]interface{})
v3disk := &v3.DiskAddress{}
if di, diok := da["device_index"]; diok {
index, _ := strconv.Atoi(di.(string))
v3disk.DeviceIndex = utils.Int64Ptr(int64(index))
}
if di, diok := da["adapter_type"]; diok {
v3disk.AdapterType = utils.StringPtr(di.(string))
}
dp.DiskAddress = v3disk
}
dl.DeviceProperties = dp
}
dl.DeviceProperties = expandDeviceProperties(v1.([]interface{}))
}
// data_source_reference
if v1, ok := v["data_source_reference"]; ok && len(v1.(map[string]interface{})) != 0 {
hasDSRef = true
dsref := v1.(map[string]interface{})
dl.DataSourceReference = validateShortRef(dsref)
}
// volume_group_reference
if v1, ok := v["volume_group_reference"]; ok {
volgr := v1.(map[string]interface{})
dl.VolumeGroupReference = validateRef(volgr)
}

// disk_size_bytes
if v1, ok1 := v["disk_size_bytes"]; ok1 && v1.(int) != 0 {
if hasDSRef && isCreation {
return nil, fmt.Errorf(`"disk_list.%[1]d.disk_size_bytes": conflicts with disk_list.%[1]d.data_source_reference`, k)
}
dl.DiskSizeBytes = utils.Int64Ptr(int64(v1.(int)))
}
// disk_size_mib
if v1, ok := v["disk_size_mib"]; ok && v1.(int) != 0 {
if hasDSRef && isCreation {
return nil, fmt.Errorf(`"disk_list.%[1]d.disk_size_mib": conflicts with disk_list.%[1]d.data_source_reference`, k)
}
dl.DiskSizeMib = utils.Int64Ptr(int64(v1.(int)))
}

dls[k] = dl
}
return dls, nil
Expand All @@ -1764,6 +1795,48 @@ func expandDiskList(d *schema.ResourceData, isCreation bool) ([]*v3.VMDisk, erro
return nil, nil
}

func expandStorageConfig(storageConfig []interface{}) *v3.VMStorageConfig {
if len(storageConfig) > 0 {
v := storageConfig[0].(map[string]interface{})
scr := v["storage_container_reference"].([]interface{})[0].(map[string]interface{})

return &v3.VMStorageConfig{
FlashMode: cast.ToString(v["flash_mode"]),
StorageContainerReference: &v3.StorageContainerReference{
URL: cast.ToString(scr["url"]),
Kind: cast.ToString(scr["kind"]),
UUID: cast.ToString(scr["uuid"]),
},
}
}
return nil
}

func expandDeviceProperties(deviceProperties []interface{}) *v3.VMDiskDeviceProperties {
if len(deviceProperties) > 0 {
dp := &v3.VMDiskDeviceProperties{}
d := deviceProperties[0].(map[string]interface{})

if v, ok := d["device_type"]; ok {
dp.DeviceType = utils.StringPtr(v.(string))
}
if v, ok := d["disk_address"]; ok && len(v.(map[string]interface{})) > 0 {
da := v.(map[string]interface{})
v3disk := &v3.DiskAddress{}

if di, diOk := da["device_index"]; diOk {
v3disk.DeviceIndex = utils.Int64Ptr(cast.ToInt64(di))
}
if at, atOk := da["adapter_type"]; atOk {
v3disk.AdapterType = utils.StringPtr(at.(string))
}
dp.DiskAddress = v3disk
}
return dp
}
return nil
}

func expandSerialPortList(d *schema.ResourceData) []*v3.VMSerialPort {
if v, ok := d.GetOk("serial_port_list"); ok {
spl := v.([]interface{})
Expand Down
Loading

0 comments on commit 9d3e86b

Please sign in to comment.