I understand this is 6 years old, and I was unable to find an answer for RDM using any language/API - and came across this post.
I figured it out, so thought I'd post here in case anyone else has the same issue.
There are two strands to achieving this.
1) Create the VirtualDisk VMDK file with backing for the RDM mapping
2) Attach the VirtualDisk to the VM
I'm using pyVmomi, so the breakdown in these strands are:
Preparation) Collect the data you will need.
a) Using your scsiLun object, retrieve the scsiLun.capacity.block and scsiLun.capacity.blockSize attributes.
calculte the capacityInKB value with scsiLun.capacity.block * scsiLun.capacity.blockSize / 1024
b) You need to find the controllerKey from the VirtualMachine object.
Iterate virtualMachine.config.hardware.device looking for each device being an instance of:
vim.vm.device.ParaVirtualSCSIController
vim.vm.device.VirtualLsiLogicController
vim.vm.device.VirtualLsiLogicSASController
vim.vm.device.VirtualBusLogicController
You need to store these somewhere - these are your scsi controller devices in the VM, they will have a .key value that you need.
Next (or at the same time as above - I separated them out) you need to iterate virtualMachine.config.hardware.device looking for
vim.vm.device.VirtualDisk instances
Each of these devices will have two attributes .controllerKey and .unitNumber
The controllerKey will correspond to the .key values discovered when looking for the scsiControllers. This tells you which controller "connects" this VirtualDisk.
The unitNumber is the controller scsiid - every disk needs a unique number between 0-15 (but don't use 7 as that is for the controller itself).
Using the above information you can calculate the controllerKey and unitNumber value for your new disk. My method is to walk the controllers, and walk each disk on that specific controller. I remove the unitNumber from a prepopulated array/list of 0..6,8..15. If by the end of the walk, the array size is > 0 then I choose that controllerKey and the first element in the list (will be the first unused unitNumber).
c) Find the Datacenter used by your VirtualMachine (needed for the CreateVirtualDisk method)
To do this I take the virtualMachine object and if it has an attribute .parent then I recursively follow the .parent objects until I find one of the instance type vim.Datacenter
d) Figure out where to store the .vmdk - If you want, like me, to put it with the VM files:
rdmFilename = os.path.dirname(virtualMachine.config.files.vmPathName) + "/" + scsiLun.canonicalName + ".vmdk"
1) Create the RDM VirtualDisk device
#Create the devicespec
newVirtualDiskSpec = vim.VirtualDiskManager.DeviceBackedVirtualDiskSpec(diskType="rdm",
adapterType="lsiLogic",
device=scsiLun.deviceName)
#And create the disk with a task
createDiskTask = self.vmContent.virtualDiskManager.CreateVirtualDisk(name=rdmFilename,
datacenter=vmDatacenter,
spec=newVirtualDiskSpec)
Like all tasks, you need to wait for it to complete (or error)
2) Attach the VirtualDisk for the VM
It might appear that most of this information should be above in the VMDK, but really we're now just describing the above VMDK RDM container to to the VM.
deviceBlockCount = scsiLun.capacity.block
deviceBlockSize = scsiLun.capacity.blockSize
deviceSizeInKB = (deviceBlockSize * deviceBlockCount) / 1024
newdisk = vim.vm.device.VirtualDisk()
newdisk.deviceInfo = vim.Description()
newdisk.deviceInfo.label = scsiLun.deviceName
newdisk.deviceInfo.summary = str(deviceSizeInKB/1024/1024) + " GB"
newdisk.backing = vim.vm.device.VirtualDisk.RawDiskMappingVer1BackingInfo()
newdisk.backing.compatibilityMode = vim.vm.device.VirtualDiskOption.CompatibilityMode.physicalMode
newdisk.backing.diskMode = vim.vm.device.VirtualDiskOption.DiskMode.independent_persistent
newdisk.backing.fileName = rdmFilename # same as above in step 1
newdisk.backing.deviceName = scsiLun.deviceName
newdisk.backing.lunUuid = scsiLun.uuid
newdisk.capacityInKB = deviceSizeInKB # calculated from lun attributes
newdisk.controllerKey = scsiControllerKey # one we discovered in this VM
newdisk.unitNumber = unitNumber # calculated unused scsiid
# Create the new DiskDevice object
newdiskDevice = vim.vm.device.VirtualDeviceSpec()
newdiskDevice.device = newdisk
newdiskDevice.operation = vim.vm.device.VirtualDeviceSpec.Operation.add
# And attach it to the VM via a ReconfigVM_Task
configSpec = vim.vm.ConfigSpec(deviceChange=[newdiskDevice])
reconfigTask = virtualMachine.ReconfigVM_Task(configSpec)
And again wait for the task to complete/
Tearing it down involves finding the VirtualDisk object (I'm searching vmdisk.backing.lunUuid for the WWN I'm interested in) and
# Create a config to remove the virtualdisk
diskDevice = vim.vm.device.VirtualDeviceSpec()
diskDevice.device = vDisk
diskDevice.operation = vim.vm.device.VirtualDeviceSpec.Operation.remove
# And remove it from the VM
configSpec = vim.vm.ConfigSpec(deviceChange=[diskDevice])
reconfigTask = testVm.ReconfigVM_Task(configSpec)
Note we still have the VMDK for the RDM lying in the VM's datastore directory, so we remove that with
# Finally, delete the vmdk from the datastore
deleteDiskTask = self.vmContent.virtualDiskManager.DeleteVirtualDisk(
name=vDisk.backing.fileName,
datacenter=vmDatacenter)
#Wait for the DeleteVirtualDisk task to complete
Hope this helps.