Trying to get an example to add an nvdimm device/host PMEM datastore to a virtual machine. I've read the docs, but I'm missing some clarity somewhere, and keep getting errors.
aimers1975 opened this issue · 3 comments
@jrgarcia If it helps at all to getting an answer to this example we are stuck on. Here is what we are currently encountering:
We are using the vmware rbvmomi ruby API version 2.2. [We were previously using RbVmomi 1.12, but were finding some of the objects were not found. So possibly confirm this operation requires the latest rbvmomi?]
We are trying to attach an NVDIMM directly to a VM via this API in Direct-Access mode. The VM version is 14, and the Guest OS version is Centos7 as stated in the requirements.
Manually we are having no trouble, and have turned on verbose logging on our vcenter to view the parameters sent behind the scenes to reconfigure the virtual machine. [I have displayed what I see in vCenter logs, which we believe we are reproducing in our code at the bottom of this issue after the code example.]
Again, as far as I can tell, we have matched these parameters exactly, but unfortunately when we attempt the configuration via the API we get the following error:
Error: com.vmware.vim.vpxd.vmprov.pMemDatastoreSetDirectly
Setting a PMem datastore directly for device configuration is not supported. Please use storage profile instead.
We do believe we are sending the Host local PMEM Storage Profile with the correct ID as follows, within our DefinedProfileSpec.
profile = RbVmomi::VIM.VirtualMachineDefinedProfileSpec(:profileId => "c268da1b-b343-49f7-a468-b1deeb7078e0")
Here is the example code - any guidance is greatly appreciated, if we are doing something wrong... Or if this is a bug?:
#!/opt/puppet/bin/ruby
module Vmware
class Vim
def initialize(ip, host, password)
require 'rbvmomi'
@options = {}
@options[:insecure] = true
@options[:host] = ip
@options[:user] = host
@options[:password] = password
vim
end
def vim
@vim ||= RbVmomi::VIM.connect(@options)
end
def reconnect
@vim = nil
vim
end
end
end
def vim
@v.vim
end
if ARGV.size < 7
raise "\n\nScript input requires: vcenter, username, password, datacenter, cluster, host, vm\n Example: ruby attachpmem.rb 100.68.108.67 administrator@vsphere.local password thisDatacenter cluster1 host1 vm1"
end
@v = Vmware::Vim.new(ARGV[0], ARGV[1], ARGV[2])
def host_nvdimm_datastores
host.datastore.select { |ds| ds.summary.type == "PMEM" }
end
def datacenter
vim.root.children.find { |datacenter| datacenter.name == ARGV[3]}
end
def host
cluster.host.find{|clus| clus.name == ARGV[5]}
end
def cluster
datacenter.hostFolder.children.find{|cluster| cluster.name == ARGV[4]}
end
def findvm_by_name(folder, vm_name)
folder.children.each do |f|
case f
when RbVmomi::VIM::Folder
foundvm = findvm_by_name(f, vm_name)
return foundvm if foundvm
when RbVmomi::VIM::VirtualMachine
return f if f.name == vm_name
when RbVmomi::VIM::VirtualApp
f.vm.each do |v|
return f if v.name == vm_name
end
else
raise(Puppet::Error, "unknown child type found: #{f.class}")
end
end
nil
end
def vm
findvm_by_name(datacenter.vmFolder, ARGV[6])
end
capacity = host_nvdimm_datastores.first.info.freeSpace / (1000 * 1000)
filename = host_nvdimm_datastores.first.info.url
# PMEM DS filename
backing = RbVmomi::VIM.VirtualNVDIMMBackingInfo(:fileName => filename)
# Host-local PMem Default Storage Policy
profile = RbVmomi::VIM.VirtualMachineDefinedProfileSpec(:profileId => "c268da1b-b343-49f7-a468-b1deeb7078e0")
nvdimm_dev = RbVmomi::VIM.VirtualNVDIMM(:key => -103, :deviceInfo => RbVmomi::VIM.Description(:label => "New NVDIMM", :summary => "New NVDIMM"),:backing => backing, :controllerKey => -104, :capacityInMB => capacity)
nvdimm_dev_spec = RbVmomi::VIM.VirtualDeviceConfigSpec(:operation => RbVmomi::VIM.VirtualDeviceConfigSpecOperation('add'), :fileOperation => RbVmomi::VIM.VirtualDeviceConfigSpecFileOperation('create'), :device => nvdimm_dev, :profile => [profile])
control_dev = RbVmomi::VIM.VirtualNVDIMMController(:key => -103, :deviceInfo => RbVmomi::VIM.Description(:label => "New NVDIMM Controller", :summary => "New NVDIMM Controller"), :busNumber => 0)
control_spec = RbVmomi::VIM.VirtualDeviceConfigSpec(:operation => RbVmomi::VIM.VirtualDeviceConfigSpecOperation('add'), :device => control_dev)
spec = RbVmomi::VIM.VirtualMachineConfigSpec(:deviceChange => [control_spec, nvdimm_dev_spec], :memoryReservationLockedToMax => true)
power_state = vm.summary.runtime.powerState
puts "Current power state is: %s" % power_state
power_off_task = vm.ShutdownGuest if power_state != "poweredOff"
power_state = vm.summary.runtime.powerState
puts "Current power state is: %s" % power_state
retries = 0
while power_state != "poweredOff" && retries < 10
puts "Waiting for VM to power off..."
puts "Current power state is %s" % power_state
sleep(10)
retries += 1
power_state = vm.summary.runtime.powerState
end
task = vm.ReconfigVM_Task(:spec => spec)
begin
task.wait_for_completion
rescue
if task.info.state == "error"
puts "VM configuration failed.\n Error: %s\n %s\n\n\n" % [task.info.error.fault.faultMessage[0].key, task.info.error.fault.faultMessage[0].message]
raise
end
end
puts "VM Reconfigure completed successfully"
Here is what we see logged by vcenter both by our code above, as well as when we perform this operation manually:
deviceChange = (vim.vm.device.VirtualDeviceSpec) [
--> (vim.vm.device.VirtualDeviceSpec) {
--> operation = "add",
--> fileOperation = "create",
--> device = (vim.vm.device.VirtualNVDIMM) {
--> key = -103,
--> deviceInfo = (vim.Description) {
--> label = "New NVDIMM device",
--> summary = ""
--> },
--> backing = (vim.vm.device.VirtualNVDIMM.BackingInfo) {
--> fileName = "ds:///vmfs/volumes/pmem:5d2dd5df-0f51180a-72c9-e4434b7ba70c/",
--> datastore = ,
--> backingObjectId = ,
--> parent = (vim.vm.device.VirtualNVDIMM.BackingInfo) null,
--> changeId =
--> },
--> connectable = (vim.vm.device.VirtualDevice.ConnectInfo) null,
--> slotInfo = (vim.vm.device.VirtualDevice.BusSlotInfo) null,
--> controllerKey = -104,
--> unitNumber = ,
--> capacityInMB = 30720
--> },
--> profile = (vim.vm.ProfileSpec) [
--> (vim.vm.DefinedProfileSpec) {
--> profileId = "c268da1b-b343-49f7-a468-b1deeb7078e0",
--> replicationSpec = (vim.vm.replication.ReplicationSpec) null,
--> profileData = (vim.vm.ProfileRawData) null,
--> profileParams =
--> }
--> ],
--> backing = (vim.vm.device.VirtualDeviceSpec.BackingSpec) null
--> },
--> (vim.vm.device.VirtualDeviceSpec) {
--> operation = "add",
--> fileOperation = ,
--> device = (vim.vm.device.VirtualNVDIMMController) {
--> key = -104,
--> deviceInfo = (vim.Description) {
--> label = "New NVDIMM Controller",
--> summary = ""
--> },
--> backing = (vim.vm.device.VirtualDevice.BackingInfo) null,
--> connectable = (vim.vm.device.VirtualDevice.ConnectInfo) null,
--> slotInfo = (vim.vm.device.VirtualDevice.BusSlotInfo) null,
--> controllerKey = ,
--> unitNumber = ,
--> busNumber = 0,
--> device =
--> },
--> profile = ,
--> backing = (vim.vm.device.VirtualDeviceSpec.BackingSpec) null
--> }
--> ],
@jrgarcia Was able to get this to work. The filename needed to be left empty for the NVDIMM device backing. Changing to:
backing = RbVmomi::VIM.VirtualNVDIMMBackingInfo(:fileName => "")
and my code worked... The vCenter logging where the filename string was populated threw me off.
Got some help from another forum, hope this may help someone else trying for the same operation.
@aimers1975 Good to know! Thanks for following up. Is this ok to close?
I'm going to go ahead and close this for now, but feel free to reopen this or file a new issue if something causes a problem again. Thanks!