Change:
vSphere cloud provider volume plugin attach disk limits the number of volumes because of two issues: new SCSI controller is only created when one does not exist. A new controller should be when required and limit not reached. disk will fail when attaching disk to slot 7 on controller. Slot 7 on SCSI controller is reserved and therefore should be skipped. This issue has been brought up in Govmomi library .

Discussion:
"k8s.io/kubernetes/pkg/util/runtime" ) <del> const ProviderName = "vsphere" const ActivePowerState = "poweredOn" const DefaultDiskController = "scsi" const DefaultSCSIControllerType = "lsilogic-sas" </del> <ins> const ( ProviderName              = "vsphere" ActivePowerState          = "poweredOn" SCSIControllerType        = "scsi" LSILogicControllerType    = "lsilogic" BusLogicControllerType    = "buslogic" PVSCSIControllerType      = "pvscsi" LSILogicSASControllerType = "lsilogic-sas" SCSIControllerLimit       = 4 SCSIControllerDeviceLimit = 15 SCSIDeviceSlots           = 16 SCSIReservedSlot          = 7 ) </ins> // Controller types that are currently supported for hot attach of disks // lsilogic driver type is currently not supported because,when a device gets detached

} if cfg.Disk.SCSIControllerType == "" { <del> cfg.Disk.SCSIControllerType = DefaultSCSIControllerType </del> <ins> cfg.Disk.SCSIControllerType = LSILogicSASControllerType </ins> } else if !checkControllerSupported(cfg.Disk.SCSIControllerType) { glog.Errorf("%v is not a supported SCSI Controller type. Please configure 'lsilogic-sas' OR 'pvscsi'", cfg.Disk.SCSIControllerType) return nil, errors.New("Controller type not supported. Please configure 'lsilogic-sas' OR 'pvscsi'")

var diskControllerType = vs.cfg.Disk.SCSIControllerType // find SCSI controller of particular type from VM devices <del> var diskController = getSCSIController(vmDevices, diskControllerType) </del> <ins> allSCSIControllers := getSCSIControllers(vmDevices) scsiControllersOfRequiredType := getSCSIControllersOfType(vmDevices, diskControllerType) scsiController := getAvailableSCSIController(scsiControllersOfRequiredType) </ins> var newSCSICreated = false var newSCSIController types.BaseVirtualDevice // creating a scsi controller as there is none found of controller type defined <del> if diskController == nil { </del> <ins> if scsiController == nil { if len(allSCSIControllers) >= SCSIControllerLimit { // we reached the maximum number of controllers we can attach return "", "", fmt.Errorf("SCSI Controller Limit of %d has been reached, cannot create another SCSI controller", SCSIControllerLimit) } </ins> glog.V(4).Infof("Creating a SCSI controller of %v type", diskControllerType) newSCSIController, err := vmDevices.CreateSCSIController(diskControllerType) if err != nil {

return "", "", err } <del> diskController = getSCSIController(vmDevices, vs.cfg.Disk.SCSIControllerType) if diskController == nil { </del> <ins> scsiController = getSCSIController(vmDevices, vs.cfg.Disk.SCSIControllerType) if scsiController == nil { </ins> glog.Errorf("cannot find SCSI controller in VM - %v", err) // attempt clean up of scsi controller cleanUpController(newSCSIController, vmDevices, vm, ctx)

newSCSICreated = true } <del> disk := vmDevices.CreateDisk(diskController, ds.Reference(), vmDiskPath) </del> <ins> disk := vmDevices.CreateDisk(scsiController, ds.Reference(), vmDiskPath) unitNumber, err := getNextUnitNumber(vmDevices, scsiController) if err != nil { glog.Errorf("cannot attach disk to VM, limit reached - %v.", err) return "", "", err } *disk.UnitNumber = unitNumber </ins> backing := disk.Backing.(*types.VirtualDiskFlatVer2BackingInfo) backing.DiskMode = string(types.VirtualDiskModeIndependent_persistent)

return deviceName, diskUUID, nil } <ins> func getNextUnitNumber(devices object.VirtualDeviceList, c types.BaseVirtualController) (int32, error) { // get next available SCSI controller unit number var takenUnitNumbers [SCSIDeviceSlots]bool takenUnitNumbers[SCSIReservedSlot] = true key := c.GetVirtualController().Key for _, device := range devices { d := device.GetVirtualDevice() if d.ControllerKey == key { if d.UnitNumber != nil { takenUnitNumbers[*d.UnitNumber] = true } } } for unitNumber, takenUnitNumber := range takenUnitNumbers { if !takenUnitNumber { return int32(unitNumber), nil } } return -1, fmt.Errorf("SCSI Controller with key=%d does not have any avaiable slots (LUN).", key) } </ins> func getSCSIController(vmDevices object.VirtualDeviceList, scsiType string) *types.VirtualController { // get virtual scsi controller of passed argument type for _, device := range vmDevices {

return nil } <ins> func getSCSIControllersOfType(vmDevices object.VirtualDeviceList, scsiType string) []*types.VirtualController { // get virtual scsi controllers of passed argument type var scsiControllers []*types.VirtualController for _, device := range vmDevices { devType := vmDevices.Type(device) if devType == scsiType { if c, ok := device.(types.BaseVirtualController); ok { scsiControllers = append(scsiControllers, c.GetVirtualController()) } } } return scsiControllers } func getSCSIControllers(vmDevices object.VirtualDeviceList) []*types.VirtualController { // get all virtual scsi controllers var scsiControllers []*types.VirtualController for _, device := range vmDevices { devType := vmDevices.Type(device) switch devType { case SCSIControllerType, LSILogicControllerType, BusLogicControllerType, PVSCSIControllerType, LSILogicSASControllerType: if c, ok := device.(types.BaseVirtualController); ok { scsiControllers = append(scsiControllers, c.GetVirtualController()) } } } return scsiControllers } func getAvailableSCSIController(scsiControllers []*types.VirtualController) *types.VirtualController { // get SCSI controller which has space for adding more devices for _, controller := range scsiControllers { if len(controller.Device) < SCSIControllerDeviceLimit { return controller } } return nil } </ins> func getVirtualDiskUUID(newDevice types.BaseVirtualDevice) (string, error) { vd := newDevice.GetVirtualDevice()