From 52eeaf2ebb6974d262e529b4687d5ec6bf0ddb43 Mon Sep 17 00:00:00 2001 From: Vasil Atanasov Date: Mon, 22 Jan 2024 16:09:21 +0200 Subject: [PATCH] Add folder field for `d/vsphere_virtual_machine` Added `folder` field to `d/vsphere_virtual_machine` to mitigate the 80 characters limitation of the `name` field. Added e2e test Updated documentation Fixes #1262 Signed-off-by: Vasil Atanasov --- .../data_source_vsphere_virtual_machine.go | 17 +++- ...ata_source_vsphere_virtual_machine_test.go | 88 +++++++++++++++++++ website/docs/d/virtual_machine.html.markdown | 1 + 3 files changed, 105 insertions(+), 1 deletion(-) diff --git a/vsphere/data_source_vsphere_virtual_machine.go b/vsphere/data_source_vsphere_virtual_machine.go index 5be33c986..5be753b71 100644 --- a/vsphere/data_source_vsphere_virtual_machine.go +++ b/vsphere/data_source_vsphere_virtual_machine.go @@ -5,7 +5,9 @@ package vsphere import ( "fmt" + "github.com/hashicorp/terraform-provider-vsphere/vsphere/internal/helper/folder" "log" + "path" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" @@ -23,6 +25,13 @@ func dataSourceVSphereVirtualMachine() *schema.Resource { Description: "The managed object ID of the datacenter the virtual machine is in. This is not required when using ESXi directly, or if there is only one datacenter in your infrastructure.", Optional: true, }, + "folder": { + Type: schema.TypeString, + Optional: true, + Description: "The name of the folder the virtual machine is in. Allows distinguishing virtual machines with the same name in different folder paths", + StateFunc: folder.NormalizePath, + ConflictsWith: []string{"uuid", "moid"}, + }, "scsi_controller_scan_count": { Type: schema.TypeInt, Description: "The number of SCSI controllers to scan for disk sizes and controller types on.", @@ -183,6 +192,7 @@ func dataSourceVSphereVirtualMachineRead(d *schema.ResourceData, meta interface{ uuid := d.Get("uuid").(string) moid := d.Get("moid").(string) name := d.Get("name").(string) + folderName := d.Get("folder").(string) var vm *object.VirtualMachine var err error @@ -202,7 +212,12 @@ func dataSourceVSphereVirtualMachineRead(d *schema.ResourceData, meta interface{ } log.Printf("[DEBUG] Datacenter for VM/template search: %s", dc.InventoryPath) } - vm, err = virtualmachine.FromPath(client, name, dc) + + searchPath := name + if len(folderName) > 0 { + searchPath = path.Join(folderName, name) + } + vm, err = virtualmachine.FromPath(client, searchPath, dc) } if err != nil { diff --git a/vsphere/data_source_vsphere_virtual_machine_test.go b/vsphere/data_source_vsphere_virtual_machine_test.go index 4915c14c8..c2c89e311 100644 --- a/vsphere/data_source_vsphere_virtual_machine_test.go +++ b/vsphere/data_source_vsphere_virtual_machine_test.go @@ -197,6 +197,48 @@ func TestAccDataSourceVSphereVirtualMachine_moid(t *testing.T) { }) } +func TestAccDataSourceVSphereVirtualMachine_nameAndFolder(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { + RunSweepers() + testAccPreCheck(t) + testAccDataSourceVSphereVirtualMachinePreCheck(t) + }, + Providers: testAccProviders, + Steps: []resource.TestStep{{ + Config: testAccDataSourceVirtualMachineFolder(), + Check: resource.ComposeTestCheckFunc( + resource.TestMatchResourceAttr( + "data.vsphere_virtual_machine.vm1", + "id", + regexp.MustCompile("^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$")), + resource.TestCheckResourceAttrSet("data.vsphere_virtual_machine.vm1", "guest_id"), + resource.TestCheckResourceAttrSet("data.vsphere_virtual_machine.vm1", "scsi_type"), + resource.TestCheckResourceAttrSet("data.vsphere_virtual_machine.vm1", "memory"), + resource.TestCheckResourceAttrSet("data.vsphere_virtual_machine.vm1", "num_cpus"), + resource.TestCheckResourceAttrSet("data.vsphere_virtual_machine.vm1", "num_cores_per_socket"), + resource.TestCheckResourceAttrSet("data.vsphere_virtual_machine.vm1", "firmware"), + resource.TestCheckResourceAttrSet("data.vsphere_virtual_machine.vm1", "hardware_version"), + resource.TestCheckResourceAttrSet("data.vsphere_virtual_machine.vm1", "disks.#"), + resource.TestCheckResourceAttrSet("data.vsphere_virtual_machine.vm1", "disks.0.size"), + resource.TestCheckResourceAttrSet("data.vsphere_virtual_machine.vm1", "disks.0.eagerly_scrub"), + resource.TestCheckResourceAttrSet("data.vsphere_virtual_machine.vm1", "disks.0.thin_provisioned"), + resource.TestCheckResourceAttrSet("data.vsphere_virtual_machine.vm1", "disks.0.unit_number"), + resource.TestCheckResourceAttrSet("data.vsphere_virtual_machine.vm1", "disks.0.label"), + resource.TestCheckResourceAttrSet("data.vsphere_virtual_machine.vm1", "network_interface_types.#"), + resource.TestCheckResourceAttrSet("data.vsphere_virtual_machine.vm1", "network_interfaces.#"), + resource.TestCheckResourceAttrSet("data.vsphere_virtual_machine.vm1", "network_interfaces.0.adapter_type"), + resource.TestCheckResourceAttrSet("data.vsphere_virtual_machine.vm1", "network_interfaces.0.bandwidth_limit"), + resource.TestCheckResourceAttrSet("data.vsphere_virtual_machine.vm1", "network_interfaces.0.bandwidth_reservation"), + resource.TestCheckResourceAttrSet("data.vsphere_virtual_machine.vm1", "network_interfaces.0.bandwidth_share_level"), + resource.TestCheckResourceAttrSet("data.vsphere_virtual_machine.vm1", "network_interfaces.0.bandwidth_share_count"), + resource.TestCheckResourceAttrSet("data.vsphere_virtual_machine.vm1", "network_interfaces.0.mac_address"), + resource.TestCheckResourceAttrSet("data.vsphere_virtual_machine.vm1", "network_interfaces.0.network_id"), + resource.TestCheckResourceAttrSet("data.vsphere_virtual_machine.vm1", "firmware")), + }}, + }) +} + func testAccDataSourceVSphereVirtualMachinePreCheck(t *testing.T) { if os.Getenv("TF_VAR_VSPHERE_DATACENTER") == "" { t.Skip("set TF_VAR_VSPHERE_DATACENTER to run vsphere_virtual_machine data source acceptance tests") @@ -284,3 +326,49 @@ data "vsphere_virtual_machine" "template" { os.Getenv("TF_VAR_VSPHERE_TEMPLATE"), ) } + +func testAccDataSourceVirtualMachineFolder() string { + return fmt.Sprintf(` + %s + + resource "vsphere_folder" "new_vm_folder" { + path = "new-vm-folder" + datacenter_id = data.vsphere_datacenter.rootdc1.id + type = "vm" + + } + + resource "vsphere_virtual_machine" "vm" { + name = "foo" + resource_pool_id = data.vsphere_compute_cluster.rootcompute_cluster1.resource_pool_id + folder = vsphere_folder.new_vm_folder.path + datastore_id = data.vsphere_datastore.rootds1.id + num_cpus = 1 + memory = 1024 + guest_id = "other3xLinux64Guest" + network_interface { + network_id = data.vsphere_network.network1.id + } + disk { + label = "disk0" + size = 10 + } + wait_for_guest_ip_timeout = 0 + wait_for_guest_net_timeout = 0 + } + + data vsphere_virtual_machine "vm1" { + name = vsphere_virtual_machine.vm.name + datacenter_id = data.vsphere_datacenter.rootdc1.id + folder = vsphere_folder.new_vm_folder.path + } + + +`, testhelper.CombineConfigs( + testhelper.ConfigDataRootDC1(), + testhelper.ConfigDataRootPortGroup1(), + testhelper.ConfigDataRootComputeCluster1(), + testhelper.ConfigDataRootDS1(), + )) + +} diff --git a/website/docs/d/virtual_machine.html.markdown b/website/docs/d/virtual_machine.html.markdown index 58af05bb8..6936ef0aa 100644 --- a/website/docs/d/virtual_machine.html.markdown +++ b/website/docs/d/virtual_machine.html.markdown @@ -60,6 +60,7 @@ The following arguments are supported: is not performed. * `uuid` - (Optional) Specify this field for a UUID lookup, `name` and `datacenter_id` are not required if this is specified. +* `folder` - (Optional) The name of the virtual machine folder where the virtual machine is located. The `name` argument is limited to 80 characters. If the `name` argument includes the full path to the virtual machine and exceeds the 80 characters limit, the `folder` folder argument can be used. * `datacenter_id` - (Optional) The [managed object reference ID][docs-about-morefs] of the datacenter the virtual machine is located in. This can be omitted if the search path used in `name` is an absolute path.