mirror of
https://github.com/opentofu/opentofu.git
synced 2025-02-25 18:45:20 -06:00
Merge pull request #4243 from kristinn/vsphere-cdrom-support
vSphere: Support mounting ISO images to virtual cdrom drives.
This commit is contained in:
commit
5b1b49e2b7
@ -53,6 +53,11 @@ type windowsOptConfig struct {
|
|||||||
domainUserPassword string
|
domainUserPassword string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type cdrom struct {
|
||||||
|
datastore string
|
||||||
|
path string
|
||||||
|
}
|
||||||
|
|
||||||
type virtualMachine struct {
|
type virtualMachine struct {
|
||||||
name string
|
name string
|
||||||
folder string
|
folder string
|
||||||
@ -65,6 +70,7 @@ type virtualMachine struct {
|
|||||||
template string
|
template string
|
||||||
networkInterfaces []networkInterface
|
networkInterfaces []networkInterface
|
||||||
hardDisks []hardDisk
|
hardDisks []hardDisk
|
||||||
|
cdroms []cdrom
|
||||||
gateway string
|
gateway string
|
||||||
domain string
|
domain string
|
||||||
timeZone string
|
timeZone string
|
||||||
@ -328,6 +334,27 @@ func resourceVSphereVirtualMachine() *schema.Resource {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"cdrom": &schema.Schema{
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"datastore": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"path": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
"boot_delay": &schema.Schema{
|
"boot_delay": &schema.Schema{
|
||||||
Type: schema.TypeInt,
|
Type: schema.TypeInt,
|
||||||
Optional: true,
|
Optional: true,
|
||||||
@ -492,6 +519,25 @@ func resourceVSphereVirtualMachineCreate(d *schema.ResourceData, meta interface{
|
|||||||
log.Printf("[DEBUG] disk init: %v", disks)
|
log.Printf("[DEBUG] disk init: %v", disks)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if vL, ok := d.GetOk("cdrom"); ok {
|
||||||
|
cdroms := make([]cdrom, len(vL.([]interface{})))
|
||||||
|
for i, v := range vL.([]interface{}) {
|
||||||
|
c := v.(map[string]interface{})
|
||||||
|
if v, ok := c["datastore"].(string); ok && v != "" {
|
||||||
|
cdroms[i].datastore = v
|
||||||
|
} else {
|
||||||
|
return fmt.Errorf("Datastore argument must be specified when attaching a cdrom image.")
|
||||||
|
}
|
||||||
|
if v, ok := c["path"].(string); ok && v != "" {
|
||||||
|
cdroms[i].path = v
|
||||||
|
} else {
|
||||||
|
return fmt.Errorf("Path argument must be specified when attaching a cdrom image.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vm.cdroms = cdroms
|
||||||
|
log.Printf("[DEBUG] cdrom init: %v", cdroms)
|
||||||
|
}
|
||||||
|
|
||||||
if vm.template != "" {
|
if vm.template != "" {
|
||||||
err := vm.deployVirtualMachine(client)
|
err := vm.deployVirtualMachine(client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -749,6 +795,31 @@ func addHardDisk(vm *object.VirtualMachine, size, iops int64, diskType string) e
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// addCdrom adds a new virtual cdrom drive to the VirtualMachine and attaches an image (ISO) to it from a datastore path.
|
||||||
|
func addCdrom(vm *object.VirtualMachine, datastore, path string) error {
|
||||||
|
devices, err := vm.Device(context.TODO())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
log.Printf("[DEBUG] vm devices: %#v", devices)
|
||||||
|
|
||||||
|
controller, err := devices.FindIDEController("")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
log.Printf("[DEBUG] ide controller: %#v", controller)
|
||||||
|
|
||||||
|
c, err := devices.CreateCdrom(controller)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
c = devices.InsertIso(c, fmt.Sprintf("[%s] %s", datastore, path))
|
||||||
|
log.Printf("[DEBUG] addCdrom: %#v", c)
|
||||||
|
|
||||||
|
return vm.AddDevice(context.TODO(), c)
|
||||||
|
}
|
||||||
|
|
||||||
// buildNetworkDevice builds VirtualDeviceConfigSpec for Network Device.
|
// buildNetworkDevice builds VirtualDeviceConfigSpec for Network Device.
|
||||||
func buildNetworkDevice(f *find.Finder, label, adapterType string) (*types.VirtualDeviceConfigSpec, error) {
|
func buildNetworkDevice(f *find.Finder, label, adapterType string) (*types.VirtualDeviceConfigSpec, error) {
|
||||||
network, err := f.Network(context.TODO(), "*"+label)
|
network, err := f.Network(context.TODO(), "*"+label)
|
||||||
@ -940,6 +1011,21 @@ func findDatastore(c *govmomi.Client, sps types.StoragePlacementSpec) (*object.D
|
|||||||
return datastore, nil
|
return datastore, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// createCdroms is a helper function to attach virtual cdrom devices (and their attached disk images) to a virtual IDE controller.
|
||||||
|
func createCdroms(vm *object.VirtualMachine, cdroms []cdrom) error {
|
||||||
|
log.Printf("[DEBUG] add cdroms: %v", cdroms)
|
||||||
|
for _, cd := range cdroms {
|
||||||
|
log.Printf("[DEBUG] add cdrom (datastore): %v", cd.datastore)
|
||||||
|
log.Printf("[DEBUG] add cdrom (cd path): %v", cd.path)
|
||||||
|
err := addCdrom(vm, cd.datastore, cd.path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// createVirtualMachine creates a new VirtualMachine.
|
// createVirtualMachine creates a new VirtualMachine.
|
||||||
func (vm *virtualMachine) createVirtualMachine(c *govmomi.Client) error {
|
func (vm *virtualMachine) createVirtualMachine(c *govmomi.Client) error {
|
||||||
dc, err := getDatacenter(c, vm.datacenter)
|
dc, err := getDatacenter(c, vm.datacenter)
|
||||||
@ -1077,6 +1163,7 @@ func (vm *virtualMachine) createVirtualMachine(c *govmomi.Client) error {
|
|||||||
Operation: types.VirtualDeviceConfigSpecOperationAdd,
|
Operation: types.VirtualDeviceConfigSpecOperationAdd,
|
||||||
Device: scsi,
|
Device: scsi,
|
||||||
})
|
})
|
||||||
|
|
||||||
configSpec.Files = &types.VirtualMachineFileInfo{VmPathName: fmt.Sprintf("[%s]", mds.Name)}
|
configSpec.Files = &types.VirtualMachineFileInfo{VmPathName: fmt.Sprintf("[%s]", mds.Name)}
|
||||||
|
|
||||||
task, err := folder.CreateVM(context.TODO(), configSpec, resourcePool, nil)
|
task, err := folder.CreateVM(context.TODO(), configSpec, resourcePool, nil)
|
||||||
@ -1104,6 +1191,12 @@ func (vm *virtualMachine) createVirtualMachine(c *govmomi.Client) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create the cdroms if needed.
|
||||||
|
if err := createCdroms(newVM, vm.cdroms); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1255,6 +1348,7 @@ func (vm *virtualMachine) deployVirtualMachine(c *govmomi.Client) error {
|
|||||||
NumCoresPerSocket: 1,
|
NumCoresPerSocket: 1,
|
||||||
MemoryMB: vm.memoryMb,
|
MemoryMB: vm.memoryMb,
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("[DEBUG] virtual machine config spec: %v", configSpec)
|
log.Printf("[DEBUG] virtual machine config spec: %v", configSpec)
|
||||||
|
|
||||||
log.Printf("[DEBUG] starting extra custom config spec: %v", vm.customConfigurations)
|
log.Printf("[DEBUG] starting extra custom config spec: %v", vm.customConfigurations)
|
||||||
@ -1407,6 +1501,11 @@ func (vm *virtualMachine) deployVirtualMachine(c *govmomi.Client) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create the cdroms if needed.
|
||||||
|
if err := createCdroms(newVM, vm.cdroms); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
taskb, err := newVM.Customize(context.TODO(), customSpec)
|
taskb, err := newVM.Customize(context.TODO(), customSpec)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -1416,7 +1515,7 @@ func (vm *virtualMachine) deployVirtualMachine(c *govmomi.Client) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
log.Printf("[DEBUG]VM customization finished")
|
log.Printf("[DEBUG] VM customization finished")
|
||||||
|
|
||||||
for i := 1; i < len(vm.hardDisks); i++ {
|
for i := 1; i < len(vm.hardDisks); i++ {
|
||||||
err = addHardDisk(newVM, vm.hardDisks[i].size, vm.hardDisks[i].iops, vm.hardDisks[i].initType)
|
err = addHardDisk(newVM, vm.hardDisks[i].size, vm.hardDisks[i].iops, vm.hardDisks[i].initType)
|
||||||
@ -1424,6 +1523,7 @@ func (vm *virtualMachine) deployVirtualMachine(c *govmomi.Client) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("[DEBUG] virtual machine config spec: %v", configSpec)
|
log.Printf("[DEBUG] virtual machine config spec: %v", configSpec)
|
||||||
|
|
||||||
newVM.PowerOn(context.TODO())
|
newVM.PowerOn(context.TODO())
|
||||||
|
@ -388,6 +388,71 @@ func TestAccVSphereVirtualMachine_createWithFolder(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAccVSphereVirtualMachine_createWithCdrom(t *testing.T) {
|
||||||
|
var vm virtualMachine
|
||||||
|
var locationOpt string
|
||||||
|
var datastoreOpt string
|
||||||
|
|
||||||
|
if v := os.Getenv("VSPHERE_DATACENTER"); v != "" {
|
||||||
|
locationOpt += fmt.Sprintf(" datacenter = \"%s\"\n", v)
|
||||||
|
}
|
||||||
|
if v := os.Getenv("VSPHERE_CLUSTER"); v != "" {
|
||||||
|
locationOpt += fmt.Sprintf(" cluster = \"%s\"\n", v)
|
||||||
|
}
|
||||||
|
if v := os.Getenv("VSPHERE_RESOURCE_POOL"); v != "" {
|
||||||
|
locationOpt += fmt.Sprintf(" resource_pool = \"%s\"\n", v)
|
||||||
|
}
|
||||||
|
if v := os.Getenv("VSPHERE_DATASTORE"); v != "" {
|
||||||
|
datastoreOpt = fmt.Sprintf(" datastore = \"%s\"\n", v)
|
||||||
|
}
|
||||||
|
template := os.Getenv("VSPHERE_TEMPLATE")
|
||||||
|
label := os.Getenv("VSPHERE_NETWORK_LABEL_DHCP")
|
||||||
|
cdromDatastore := os.Getenv("VSPHERE_CDROM_DATASTORE")
|
||||||
|
cdromPath := os.Getenv("VSPHERE_CDROM_PATH")
|
||||||
|
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
Providers: testAccProviders,
|
||||||
|
CheckDestroy: testAccCheckVSphereVirtualMachineDestroy,
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
resource.TestStep{
|
||||||
|
Config: fmt.Sprintf(
|
||||||
|
testAccCheckVsphereVirtualMachineConfig_cdrom,
|
||||||
|
locationOpt,
|
||||||
|
label,
|
||||||
|
datastoreOpt,
|
||||||
|
template,
|
||||||
|
cdromDatastore,
|
||||||
|
cdromPath,
|
||||||
|
),
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCheckVSphereVirtualMachineExists("vsphere_virtual_machine.with_cdrom", &vm),
|
||||||
|
resource.TestCheckResourceAttr(
|
||||||
|
"vsphere_virtual_machine.with_cdrom", "name", "terraform-test-with-cdrom"),
|
||||||
|
resource.TestCheckResourceAttr(
|
||||||
|
"vsphere_virtual_machine.with_cdrom", "vcpu", "2"),
|
||||||
|
resource.TestCheckResourceAttr(
|
||||||
|
"vsphere_virtual_machine.with_cdrom", "memory", "4096"),
|
||||||
|
resource.TestCheckResourceAttr(
|
||||||
|
"vsphere_virtual_machine.with_cdrom", "disk.#", "1"),
|
||||||
|
resource.TestCheckResourceAttr(
|
||||||
|
"vsphere_virtual_machine.with_cdrom", "disk.0.template", template),
|
||||||
|
resource.TestCheckResourceAttr(
|
||||||
|
"vsphere_virtual_machine.with_cdrom", "cdrom.#", "1"),
|
||||||
|
resource.TestCheckResourceAttr(
|
||||||
|
"vsphere_virtual_machine.with_cdrom", "cdrom.0.datastore", cdromDatastore),
|
||||||
|
resource.TestCheckResourceAttr(
|
||||||
|
"vsphere_virtual_machine.with_cdrom", "cdrom.0.path", cdromPath),
|
||||||
|
resource.TestCheckResourceAttr(
|
||||||
|
"vsphere_virtual_machine.with_cdrom", "network_interface.#", "1"),
|
||||||
|
resource.TestCheckResourceAttr(
|
||||||
|
"vsphere_virtual_machine.with_cdrom", "network_interface.0.label", label),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func testAccCheckVSphereVirtualMachineDestroy(s *terraform.State) error {
|
func testAccCheckVSphereVirtualMachineDestroy(s *terraform.State) error {
|
||||||
client := testAccProvider.Meta().(*govmomi.Client)
|
client := testAccProvider.Meta().(*govmomi.Client)
|
||||||
finder := find.NewFinder(client.Client, true)
|
finder := find.NewFinder(client.Client, true)
|
||||||
@ -682,3 +747,24 @@ resource "vsphere_virtual_machine" "with_folder" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
const testAccCheckVsphereVirtualMachineConfig_cdrom = `
|
||||||
|
resource "vsphere_virtual_machine" "with_cdrom" {
|
||||||
|
name = "terraform-test-with-cdrom"
|
||||||
|
%s
|
||||||
|
vcpu = 2
|
||||||
|
memory = 4096
|
||||||
|
network_interface {
|
||||||
|
label = "%s"
|
||||||
|
}
|
||||||
|
disk {
|
||||||
|
%s
|
||||||
|
template = "%s"
|
||||||
|
}
|
||||||
|
|
||||||
|
cdrom {
|
||||||
|
datastore = "%s"
|
||||||
|
path = "%s"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
@ -89,6 +89,11 @@ The following environment variables depend on your vSphere environment:
|
|||||||
* VSPHERE\_RESOURCE\_POOL
|
* VSPHERE\_RESOURCE\_POOL
|
||||||
* VSPHERE\_DATASTORE
|
* VSPHERE\_DATASTORE
|
||||||
|
|
||||||
|
The following additional environment variables are needed for running the "Mount ISO as CDROM media" acceptance tests.
|
||||||
|
|
||||||
|
* VSPHERE\_CDROM\_DATASTORE
|
||||||
|
* VSPHERE\_CDROM\_PATH
|
||||||
|
|
||||||
|
|
||||||
These are used to set and verify attributes on the `vsphere_virtual_machine`
|
These are used to set and verify attributes on the `vsphere_virtual_machine`
|
||||||
resource in tests.
|
resource in tests.
|
||||||
|
@ -46,6 +46,7 @@ The following arguments are supported:
|
|||||||
* `dns_servers` - (Optional) List of DNS servers for the virtual network adapter; defaults to 8.8.8.8, 8.8.4.4
|
* `dns_servers` - (Optional) List of DNS servers for the virtual network adapter; defaults to 8.8.8.8, 8.8.4.4
|
||||||
* `network_interface` - (Required) Configures virtual network interfaces; see [Network Interfaces](#network-interfaces) below for details.
|
* `network_interface` - (Required) Configures virtual network interfaces; see [Network Interfaces](#network-interfaces) below for details.
|
||||||
* `disk` - (Required) Configures virtual disks; see [Disks](#disks) below for details
|
* `disk` - (Required) Configures virtual disks; see [Disks](#disks) below for details
|
||||||
|
* `cdrom` - (Optional) Configures a CDROM device and mounts an image as its media; see [CDROM](#cdrom) below for more details.
|
||||||
* `boot_delay` - (Optional) Time in seconds to wait for machine network to be ready.
|
* `boot_delay` - (Optional) Time in seconds to wait for machine network to be ready.
|
||||||
* `windows_opt_config` - (Optional) Extra options for clones of Windows machines.
|
* `windows_opt_config` - (Optional) Extra options for clones of Windows machines.
|
||||||
* `linked_clone` - (Optional) Specifies if the new machine is a [linked clone](https://www.vmware.com/support/ws5/doc/ws_clone_overview.html#wp1036396) of another machine or not.
|
* `linked_clone` - (Optional) Specifies if the new machine is a [linked clone](https://www.vmware.com/support/ws5/doc/ws_clone_overview.html#wp1036396) of another machine or not.
|
||||||
@ -71,6 +72,9 @@ The `windows_opt_config` block supports:
|
|||||||
* `domain_user` - (Optional) User that is a member of the specified domain.
|
* `domain_user` - (Optional) User that is a member of the specified domain.
|
||||||
* `domain_user_password` - (Optional) Password for domain user, in plain text.
|
* `domain_user_password` - (Optional) Password for domain user, in plain text.
|
||||||
|
|
||||||
|
<a id="disks"></a>
|
||||||
|
## Disks
|
||||||
|
|
||||||
The `disk` block supports:
|
The `disk` block supports:
|
||||||
|
|
||||||
* `template` - (Required if size not provided) Template for this disk.
|
* `template` - (Required if size not provided) Template for this disk.
|
||||||
@ -79,6 +83,14 @@ The `disk` block supports:
|
|||||||
* `iops` - (Optional) Number of virtual iops to allocate for this disk.
|
* `iops` - (Optional) Number of virtual iops to allocate for this disk.
|
||||||
* `type` - (Optional) 'eager_zeroed' (the default), or 'thin' are supported options.
|
* `type` - (Optional) 'eager_zeroed' (the default), or 'thin' are supported options.
|
||||||
|
|
||||||
|
<a id="cdrom"></a>
|
||||||
|
## CDROM
|
||||||
|
|
||||||
|
The `cdrom` block supports:
|
||||||
|
|
||||||
|
* `datastore` - (Required) The name of the datastore where the disk image is stored.
|
||||||
|
* `path` - (Required) The absolute path to the image within the datastore.
|
||||||
|
|
||||||
## Attributes Reference
|
## Attributes Reference
|
||||||
|
|
||||||
The following attributes are exported:
|
The following attributes are exported:
|
||||||
|
Loading…
Reference in New Issue
Block a user