diff --git a/client/v3/v3_structs.go b/client/v3/v3_structs.go index b41b80851..7389ce6f4 100644 --- a/client/v3/v3_structs.go +++ b/client/v3/v3_structs.go @@ -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"` @@ -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. diff --git a/nutanix/data_source_nutanix_virtual_machine.go b/nutanix/data_source_nutanix_virtual_machine.go index 720d727cf..1bb8dc28d 100644 --- a/nutanix/data_source_nutanix_virtual_machine.go +++ b/nutanix/data_source_nutanix_virtual_machine.go @@ -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, @@ -570,7 +607,6 @@ func dataSourceNutanixVirtualMachine() *schema.Resource { }, }, }, - "volume_group_reference": { Type: schema.TypeMap, Computed: true, @@ -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 := "" @@ -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) { diff --git a/nutanix/data_source_nutanix_virtual_machine_test.go b/nutanix/data_source_nutanix_virtual_machine_test.go index cd61a6ca8..ef468e07c 100644 --- a/nutanix/data_source_nutanix_virtual_machine_test.go +++ b/nutanix/data_source_nutanix_virtual_machine_test.go @@ -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" {} @@ -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" diff --git a/nutanix/resource_nutanix_virtual_machine.go b/nutanix/resource_nutanix_virtual_machine.go index fd3f0940d..4b7832b87 100644 --- a/nutanix/resource_nutanix_virtual_machine.go +++ b/nutanix/resource_nutanix_virtual_machine.go @@ -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" @@ -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, @@ -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 @@ -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{}) diff --git a/nutanix/resource_nutanix_virtual_machine_test.go b/nutanix/resource_nutanix_virtual_machine_test.go index 0f0ecf647..afbd10369 100644 --- a/nutanix/resource_nutanix_virtual_machine_test.go +++ b/nutanix/resource_nutanix_virtual_machine_test.go @@ -362,6 +362,25 @@ func TestAccNutanixVirtualMachine_cloningVM(t *testing.T) { }) } +func TestAccNutanixVirtualMachine_withDiskContainer(t *testing.T) { + r := acctest.RandInt() + + resourceName := "nutanix_virtual_machine.vm-disk" + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckNutanixVirtualMachineDestroy, + Steps: []resource.TestStep{ + { + Config: testAccNutanixVMConfigWithDiskContainer(r), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(resourceName, "disk_list.#"), + resource.TestCheckResourceAttr(resourceName, "disk_list.#", "1"), + ), + }, + }}) +} + func testAccCheckNutanixVirtualMachineExists(n string) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] @@ -927,3 +946,36 @@ func testAccNutanixVMConfigHotAdd(vmName string, cpus, sockets, memory int, hotA } `, vmName, cpus, sockets, memory, hotAdd, imageName) } + +func testAccNutanixVMConfigWithDiskContainer(r int) 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 = "test-dou-vm-%[1]d" + cluster_uuid = local.cluster1 + num_vcpus_per_socket = 1 + num_sockets = 1 + memory_size_mib = 186 + + disk_list { + disk_size_bytes = 68157440 + disk_size_mib = 65 + + storage_config { + storage_container_reference { + kind = "storage_container" + uuid = "2bbe77bc-fd14-4697-8de1-6369757f9219" + } + } + } + } + `, r) +} diff --git a/nutanix/structure.go b/nutanix/structure.go index 6eea9f95a..8e2058a23 100644 --- a/nutanix/structure.go +++ b/nutanix/structure.go @@ -5,6 +5,7 @@ import ( "strconv" "github.com/hashicorp/terraform/helper/schema" + "github.com/spf13/cast" v3 "github.com/terraform-providers/terraform-provider-nutanix/client/v3" "github.com/terraform-providers/terraform-provider-nutanix/utils" ) @@ -104,40 +105,51 @@ func flattenNicList(nics []*v3.VMNic) []map[string]interface{} { func flattenDiskList(disks []*v3.VMDisk) []map[string]interface{} { diskList := make([]map[string]interface{}, 0) - if disks != nil { - diskList = make([]map[string]interface{}, 0) - for _, v := range disks { - disk := make(map[string]interface{}) + for _, v := range disks { + var deviceProps []map[string]interface{} + var storageConfig []map[string]interface{} - disk["uuid"] = utils.StringValue(v.UUID) - disk["disk_size_bytes"] = utils.Int64Value(v.DiskSizeBytes) - disk["disk_size_mib"] = utils.Int64Value(v.DiskSizeMib) + if v.DeviceProperties != nil { + deviceProps = make([]map[string]interface{}, 1) + index := fmt.Sprintf("%d", utils.Int64Value(v.DeviceProperties.DiskAddress.DeviceIndex)) + adapter := v.DeviceProperties.DiskAddress.AdapterType - var deviceProps []map[string]interface{} - if v.DeviceProperties != nil { - deviceProps = make([]map[string]interface{}, 1) - deviceProp := make(map[string]interface{}) - index := fmt.Sprintf("%d", utils.Int64Value(v.DeviceProperties.DiskAddress.DeviceIndex)) - adapter := v.DeviceProperties.DiskAddress.AdapterType - if index == "3" && *adapter == IDE { - continue - } - diskAddress := map[string]interface{}{ + if index == "3" && *adapter == IDE { + continue + } + + deviceProps[0] = map[string]interface{}{ + "device_type": v.DeviceProperties.DeviceType, + "disk_address": map[string]interface{}{ "device_index": index, "adapter_type": adapter, - } - - deviceProp["disk_address"] = diskAddress - deviceProp["device_type"] = v.DeviceProperties.DeviceType - - deviceProps[0] = deviceProp + }, } - disk["device_properties"] = deviceProps - disk["data_source_reference"] = flattenReferenceValues(v.DataSourceReference) - disk["volume_group_reference"] = flattenReferenceValues(v.VolumeGroupReference) + } - diskList = append(diskList, disk) + if v.StorageConfig != nil { + storageConfig = append(storageConfig, map[string]interface{}{ + "flash_mode": cast.ToString(v.StorageConfig.FlashMode), + "storage_container_reference": []map[string]interface{}{ + { + "url": cast.ToString(v.StorageConfig.StorageContainerReference.URL), + "kind": cast.ToString(v.StorageConfig.StorageContainerReference.Kind), + "name": cast.ToString(v.StorageConfig.StorageContainerReference.Name), + "uuid": cast.ToString(v.StorageConfig.StorageContainerReference.UUID), + }, + }, + }) } + + diskList = append(diskList, map[string]interface{}{ + "uuid": utils.StringValue(v.UUID), + "disk_size_bytes": utils.Int64Value(v.DiskSizeBytes), + "disk_size_mib": utils.Int64Value(v.DiskSizeMib), + "device_properties": deviceProps, + "storage_config": storageConfig, + "data_source_reference": flattenReferenceValues(v.DataSourceReference), + "volume_group_reference": flattenReferenceValues(v.VolumeGroupReference), + }) } return diskList } @@ -178,53 +190,6 @@ func flattenGPUList(gpu []*v3.VMGpuOutputStatus) []map[string]interface{} { return gpuList } -func setDiskList(disk []*v3.VMDisk, hasCloudInit *v3.GuestCustomizationStatus) []map[string]interface{} { - var diskList []map[string]interface{} - if len(disk) > 0 { - for _, v1 := range disk { - if hasCloudInit != nil { - if hasCloudInit.CloudInit != nil && utils.StringValue(v1.DeviceProperties.DeviceType) == CDROM { - continue - } - } - - disk := make(map[string]interface{}) - disk["uuid"] = utils.StringValue(v1.UUID) - disk["disk_size_bytes"] = utils.Int64Value(v1.DiskSizeBytes) - disk["disk_size_mib"] = utils.Int64Value(v1.DiskSizeMib) - if v1.DataSourceReference != nil { - disk["data_source_reference"] = flattenReferenceValues(v1.DataSourceReference) - } - - if v1.VolumeGroupReference != nil { - disk["volume_group_reference"] = flattenReferenceValues(v1.VolumeGroupReference) - } - - dp := make([]map[string]interface{}, 1) - deviceProps := make(map[string]interface{}) - deviceProps["device_type"] = utils.StringValue(v1.DeviceProperties.DeviceType) - dp[0] = deviceProps - - diskAddress := make(map[string]interface{}) - if v1.DeviceProperties.DiskAddress != nil { - diskAddress["device_index"] = fmt.Sprintf("%d", utils.Int64Value(v1.DeviceProperties.DiskAddress.DeviceIndex)) - diskAddress["adapter_type"] = utils.StringValue(v1.DeviceProperties.DiskAddress.AdapterType) - } - deviceProps["disk_address"] = diskAddress - - disk["device_properties"] = dp - - diskList = append(diskList, disk) - } - } - - if diskList == nil { - return make([]map[string]interface{}, 0) - } - - return diskList -} - func flattenNutanixGuestTools(d *schema.ResourceData, guest *v3.GuestToolsStatus) error { nutanixGuestTools := make(map[string]interface{}) ngtCredentials := make(map[string]string) diff --git a/website/docs/d/virtual_machine.html.markdown b/website/docs/d/virtual_machine.html.markdown index 8c6acc11f..de9d1564f 100644 --- a/website/docs/d/virtual_machine.html.markdown +++ b/website/docs/d/virtual_machine.html.markdown @@ -109,6 +109,18 @@ The device_properties attribute supports the following. * `device_type`: - A Disk type (default: DISK). * `disk_address`: - Address of disk to boot from. +### Storage Config +User inputs of storage configuration parameters for VMs. + +* `flash_mode`: - State of the storage policy to pin virtual disks to the hot tier. When specified as a VM attribute, the storage policy applies to all virtual disks of the VM unless overridden by the same attribute specified for a virtual disk. + +* `storage_container_reference`: - Reference to a kind. Either one of (kind, uuid) or url needs to be specified. +* `storage_container_reference.#.url`: - GET query on the URL will provide information on the source. +* `storage_container_reference.#.kind`: - kind of the container reference +* `storage_container_reference.#.name`: - name of the container reference +* `storage_container_reference.#.uuid`: - uiid of the container reference + + ### Sysprep The guest_customization_sysprep attribute supports the following: diff --git a/website/docs/r/virtual_machine.html.markdown b/website/docs/r/virtual_machine.html.markdown index d99079f23..1cf8630df 100644 --- a/website/docs/r/virtual_machine.html.markdown +++ b/website/docs/r/virtual_machine.html.markdown @@ -31,6 +31,31 @@ resource "nutanix_virtual_machine" "vm1" { } ``` +## Example Usage with storage config +```hcl +data "nutanix_clusters" "clusters" {} + +resource "nutanix_virtual_machine" "vm" { + name = "myVm" + cluster_uuid = data.nutanix_clusters.clusters.entities.0.metadata.uuid + num_vcpus_per_socket = 1 + num_sockets = 1 + memory_size_mib = 186 + + disk_list { + disk_size_bytes = 68157440 + disk_size_mib = 65 + + storage_config { + storage_container_reference { + kind = "storage_container" + uuid = "2bbe67bc-fd14-4637-8de1-6379257f4219" + } + } + } +} +``` + ## Argument Reference The following arguments are supported: @@ -93,6 +118,17 @@ The device_properties attribute supports the following. * `device_type`: - A Disk type (default: DISK). * `disk_address`: - Address of disk to boot from. +### Storage Config +User inputs of storage configuration parameters for VMs. + +* `flash_mode`: - State of the storage policy to pin virtual disks to the hot tier. When specified as a VM attribute, the storage policy applies to all virtual disks of the VM unless overridden by the same attribute specified for a virtual disk. + +* `storage_container_reference`: - Reference to a kind. Either one of (kind, uuid) or url needs to be specified. +* `storage_container_reference.#.url`: - GET query on the URL will provide information on the source. +* `storage_container_reference.#.kind`: - kind of the container reference +* `storage_container_reference.#.name`: - name of the container reference +* `storage_container_reference.#.uuid`: - uiid of the container reference + ### Sysprep The guest_customization_sysprep attribute supports the following: