class Chef::Knife::VsphereVmVmdkAdd
Add a new disk to a virtual machine VsphereVmvmdkadd extends the BaseVspherecommand
Public Instance Methods
run()
click to toggle source
The main run method for vm_vmdk_add
# File lib/chef/knife/vsphere_vm_vmdk_add.rb, line 33 def run $stdout.sync = true vmname = @name_args[0] if vmname.nil? show_usage ui.fatal("You must specify a virtual machine name") exit 1 end size = @name_args[1] if size.nil? ui.fatal "You need a VMDK size!" show_usage exit 1 end vim = vim_connection vdm = vim.serviceContent.virtualDiskManager vm = get_vm_by_name(vmname, get_config(:folder)) || fatal_exit("Could not find #{vmname}") fatal_exit "Could not find #{vmname}" unless vm target_lun = get_config(:target_lun) unless get_config(:target_lun).nil? vmdk_size_kb = size.to_i * 1024 * 1024 if target_lun.nil? vmdk_datastore = choose_datastore(vm.datastore, size) exit(-1) if vmdk_datastore.nil? else vmdk_datastores = find_datastores_regex(target_lun) vmdk_datastore = choose_datastore(vmdk_datastores, size) exit(-1) if vmdk_datastore.nil? vmdk_dir = "[#{vmdk_datastore.name}] #{vmname}" # create the vm folder on the LUN or subsequent operations will fail. unless vmdk_datastore.exists? vmname dc = datacenter begin dc._connection.serviceContent.fileManager.MakeDirectory name: vmdk_dir, datacenter: dc, createParentDirectories: false rescue RbVmomi::Fault => e ui.warn "Ignoring a fault when trying to create #{vmdk_dir}. This may be related to issue #213." if log_verbose? puts "Chose #{vmdk_datastore.name} out of #{vmdk_datastores.map(&:name).join(", ")}" puts e end end end end puts "Choosing: #{vmdk_datastore.name}" # now we need to inspect the files in this datastore to get our next file name next_vmdk = 1 pc = vmdk_datastore._connection.serviceContent.propertyCollector vms = vmdk_datastore.vm vm_files = pc.collectMultiple vms, "layoutEx.file" vm_files.keys.each do |vmFile| vm_files[vmFile]["layoutEx.file"].each do |layout| if layout.name =~ %r{^\[#{vmdk_datastore.name}\] #{vmname}/#{vmname}_([0-9]+).vmdk} num = Regexp.last_match(1) next_vmdk = num.to_i + 1 if next_vmdk <= num.to_i end end end vmdk_file_name = "#{vmname}/#{vmname}_#{next_vmdk}.vmdk" vmdk_name = "[#{vmdk_datastore.name}] #{vmdk_file_name}" vmdk_type = get_config(:vmdk_type) vmdk_type = "preallocated" if vmdk_type == "thick" puts "Next vmdk name is => #{vmdk_name}" # create the disk unless vmdk_datastore.exists? vmdk_file_name vmdk_spec = RbVmomi::VIM::FileBackedVirtualDiskSpec( adapterType: "lsiLogic", capacityKb: vmdk_size_kb, diskType: vmdk_type ) ui.info "Creating VMDK" ui.info "#{ui.color "Capacity:", :cyan} #{size} GB" ui.info "#{ui.color "Disk:", :cyan} #{vmdk_name}" if get_config(:noop) ui.info "#{ui.color "Skipping disk creation process because --noop specified.", :red}" else vdm.CreateVirtualDisk_Task( datacenter: datacenter, name: vmdk_name, spec: vmdk_spec ).wait_for_completion end end ui.info "Attaching VMDK to #{vmname}" # now we run through the SCSI controllers to see if there's an available one available_controllers = [] use_controller = nil scsi_tree = {} vm.config.hardware.device.each do |device| if device.is_a? RbVmomi::VIM::VirtualSCSIController if scsi_tree[device.controllerKey].nil? scsi_tree[device.key] = {} scsi_tree[device.key]["children"] = [] end scsi_tree[device.key]["device"] = device end next unless device.class == RbVmomi::VIM::VirtualDisk if scsi_tree[device.controllerKey].nil? scsi_tree[device.controllerKey] = {} scsi_tree[device.controllerKey]["children"] = [] end scsi_tree[device.controllerKey]["children"].push(device) end scsi_tree.keys.sort.each do |controller| if scsi_tree[controller]["children"].length < 15 available_controllers.push(scsi_tree[controller]["device"].deviceInfo.label) end end if available_controllers.length > 0 use_controller = available_controllers[0] puts "using #{use_controller}" else if scsi_tree.keys.length < 4 # Add a controller if none are available puts "no controllers available. Will attempt to create" new_scsi_key = scsi_tree.keys.sort[scsi_tree.length - 1] + 1 new_scsi_bus_number = scsi_tree[scsi_tree.keys.sort[scsi_tree.length - 1]]["device"].busNumber + 1 controller_device = RbVmomi::VIM::VirtualLsiLogicController( key: new_scsi_key, busNumber: new_scsi_bus_number, sharedBus: :noSharing ) device_config_spec = RbVmomi::VIM::VirtualDeviceConfigSpec( device: controller_device, operation: RbVmomi::VIM::VirtualDeviceConfigSpecOperation("add") ) vm_config_spec = RbVmomi::VIM::VirtualMachineConfigSpec( deviceChange: [device_config_spec] ) if get_config(:noop) ui.info "#{ui.color "Skipping controller creation process because --noop specified.", :red}" else vm.ReconfigVM_Task(spec: vm_config_spec).wait_for_completion end else ui.info "Controllers maxed out at 4." exit(-1) end end # now go back and get the new device's name vm.config.hardware.device.each do |device| if device.class == RbVmomi::VIM::VirtualLsiLogicController use_controller = device.deviceInfo.label if device.key == new_scsi_key end end # add the disk controller = find_device(vm, use_controller) used_unit_numbers = [] scsi_tree.keys.sort.each do |c| next unless controller.key == scsi_tree[c]["device"].key used_unit_numbers.push(scsi_tree[c]["device"].scsiCtlrUnitNumber) scsi_tree[c]["children"].each do |disk| used_unit_numbers.push(disk.unitNumber) end end available_unit_numbers = [] (0..15).each do |scsi_id| if used_unit_numbers.grep(scsi_id).length > 0 else available_unit_numbers.push(scsi_id) end end # ensure we don't try to add the controllers SCSI ID new_unit_number = available_unit_numbers.min puts "using SCSI ID #{new_unit_number}" vmdk_backing = RbVmomi::VIM::VirtualDiskFlatVer2BackingInfo( datastore: vmdk_datastore, diskMode: "persistent", fileName: vmdk_name ) device = RbVmomi::VIM::VirtualDisk( backing: vmdk_backing, capacityInKB: vmdk_size_kb, controllerKey: controller.key, key: -1, unitNumber: new_unit_number ) device_config_spec = RbVmomi::VIM::VirtualDeviceConfigSpec( device: device, operation: RbVmomi::VIM::VirtualDeviceConfigSpecOperation("add") ) vm_config_spec = RbVmomi::VIM::VirtualMachineConfigSpec( deviceChange: [device_config_spec] ) if get_config(:noop) ui.info "#{ui.color "Skipping disk attaching process because --noop specified.", :red}" else vm.ReconfigVM_Task(spec: vm_config_spec).wait_for_completion end end