Skip to content

Commit ed77105

Browse files
dkallegstack72
authored andcommitted
Improved SCSI controller handling (hashicorp#7908)
Govmomi tries to use the 7th slot in a scsi controller, which is not allowed. This patch will appropriately select the slot to attach a disk to as well as determine if a scsi controller is full.
1 parent f140724 commit ed77105

2 files changed

Lines changed: 126 additions & 0 deletions

File tree

builtin/providers/vsphere/resource_vsphere_virtual_machine.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1198,6 +1198,12 @@ func addHardDisk(vm *object.VirtualMachine, size, iops int64, diskType string, d
11981198
}
11991199

12001200
if err != nil || controller == nil {
1201+
// Check if max number of scsi controller are already used
1202+
diskControllers := getSCSIControllers(devices)
1203+
if len(diskControllers) >= 4 {
1204+
return fmt.Errorf("[ERROR] Maximum number of SCSI controllers created")
1205+
}
1206+
12011207
log.Printf("[DEBUG] Couldn't find a %v controller. Creating one..", controller_type)
12021208

12031209
var c types.BaseVirtualDevice
@@ -1268,6 +1274,14 @@ func addHardDisk(vm *object.VirtualMachine, size, iops int64, diskType string, d
12681274
log.Printf("[DEBUG] addHardDisk - diskPath: %v", diskPath)
12691275
disk := devices.CreateDisk(controller, datastore.Reference(), diskPath)
12701276

1277+
if strings.Contains(controller_type, "scsi") {
1278+
unitNumber, err := getNextUnitNumber(devices, controller)
1279+
if err != nil {
1280+
return err
1281+
}
1282+
*disk.UnitNumber = unitNumber
1283+
}
1284+
12711285
existing := devices.SelectByBackingInfo(disk.Backing)
12721286
log.Printf("[DEBUG] disk: %#v\n", disk)
12731287

@@ -1300,6 +1314,44 @@ func addHardDisk(vm *object.VirtualMachine, size, iops int64, diskType string, d
13001314
}
13011315
}
13021316

1317+
func getSCSIControllers(vmDevices object.VirtualDeviceList) []*types.VirtualController {
1318+
// get virtual scsi controllers of all supported types
1319+
var scsiControllers []*types.VirtualController
1320+
for _, device := range vmDevices {
1321+
devType := vmDevices.Type(device)
1322+
switch devType {
1323+
case "scsi", "lsilogic", "buslogic", "pvscsi", "lsilogic-sas":
1324+
if c, ok := device.(types.BaseVirtualController); ok {
1325+
scsiControllers = append(scsiControllers, c.GetVirtualController())
1326+
}
1327+
}
1328+
}
1329+
return scsiControllers
1330+
}
1331+
1332+
func getNextUnitNumber(devices object.VirtualDeviceList, c types.BaseVirtualController) (int32, error) {
1333+
key := c.GetVirtualController().Key
1334+
1335+
var unitNumbers [16]bool
1336+
unitNumbers[7] = true
1337+
1338+
for _, device := range devices {
1339+
d := device.GetVirtualDevice()
1340+
1341+
if d.ControllerKey == key {
1342+
if d.UnitNumber != nil {
1343+
unitNumbers[*d.UnitNumber] = true
1344+
}
1345+
}
1346+
}
1347+
for i, taken := range unitNumbers {
1348+
if !taken {
1349+
return int32(i), nil
1350+
}
1351+
}
1352+
return -1, fmt.Errorf("[ERROR] getNextUnitNumber - controller is full")
1353+
}
1354+
13031355
// addCdrom adds a new virtual cdrom drive to the VirtualMachine and attaches an image (ISO) to it from a datastore path.
13041356
func addCdrom(vm *object.VirtualMachine, datastore, path string) error {
13051357
devices, err := vm.Device(context.TODO())
@@ -1902,6 +1954,10 @@ func (vm *virtualMachine) setupVirtualMachine(c *govmomi.Client) error {
19021954

19031955
err = addHardDisk(newVM, vm.hardDisks[i].size, vm.hardDisks[i].iops, vm.hardDisks[i].initType, datastore, diskPath, vm.hardDisks[i].controller)
19041956
if err != nil {
1957+
err2 := addHardDisk(newVM, vm.hardDisks[i].size, vm.hardDisks[i].iops, vm.hardDisks[i].initType, datastore, diskPath, vm.hardDisks[i].controller)
1958+
if err2 != nil {
1959+
return err2
1960+
}
19051961
return err
19061962
}
19071963
}

builtin/providers/vsphere/resource_vsphere_virtual_machine_test.go

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,76 @@ func TestAccVSphereVirtualMachine_client_debug(t *testing.T) {
328328
})
329329
}
330330

331+
const testAccCheckVSphereVirtualMachineConfig_diskSCSICapacity = `
332+
resource "vsphere_virtual_machine" "scsiCapacity" {
333+
name = "terraform-test"
334+
` + testAccTemplateBasicBody + `
335+
disk {
336+
size = 1
337+
controller_type = "scsi-paravirtual"
338+
name = "one"
339+
}
340+
disk {
341+
size = 1
342+
controller_type = "scsi-paravirtual"
343+
name = "two"
344+
}
345+
disk {
346+
size = 1
347+
controller_type = "scsi-paravirtual"
348+
name = "three"
349+
}
350+
disk {
351+
size = 1
352+
controller_type = "scsi-paravirtual"
353+
name = "four"
354+
}
355+
disk {
356+
size = 1
357+
controller_type = "scsi-paravirtual"
358+
name = "five"
359+
}
360+
disk {
361+
size = 1
362+
controller_type = "scsi-paravirtual"
363+
name = "six"
364+
}
365+
disk {
366+
size = 1
367+
controller_type = "scsi-paravirtual"
368+
name = "seven"
369+
}
370+
}
371+
`
372+
373+
func TestAccVSphereVirtualMachine_diskSCSICapacity(t *testing.T) {
374+
var vm virtualMachine
375+
basic_vars := setupTemplateBasicBodyVars()
376+
config := basic_vars.testSprintfTemplateBody(testAccCheckVSphereVirtualMachineConfig_diskSCSICapacity)
377+
378+
vmName := "vsphere_virtual_machine.scsiCapacity"
379+
380+
test_exists, test_name, test_cpu, test_uuid, test_mem, test_num_disk, test_num_of_nic, test_nic_label :=
381+
TestFuncData{vm: vm, label: basic_vars.label, vmName: vmName, numDisks: "8"}.testCheckFuncBasic()
382+
383+
log.Printf("[DEBUG] template= %s", testAccCheckVSphereVirtualMachineConfig_diskSCSICapacity)
384+
log.Printf("[DEBUG] template config= %s", config)
385+
386+
resource.Test(t, resource.TestCase{
387+
PreCheck: func() { testAccPreCheck(t) },
388+
Providers: testAccProviders,
389+
CheckDestroy: testAccCheckVSphereVirtualMachineDestroy,
390+
Steps: []resource.TestStep{
391+
resource.TestStep{
392+
Config: config,
393+
Check: resource.ComposeTestCheckFunc(
394+
test_exists, test_name, test_cpu, test_uuid, test_mem, test_num_disk, test_num_of_nic, test_nic_label,
395+
),
396+
},
397+
},
398+
})
399+
}
400+
331401
const testAccCheckVSphereVirtualMachineConfig_initType = `
332402
resource "vsphere_virtual_machine" "thin" {
333403
name = "terraform-test"

0 commit comments

Comments
 (0)