bin/esx in esx-0.4.1 vs bin/esx in esx-0.4.2

- old
+ new

@@ -3,16 +3,18 @@ require 'esx' require 'terminal-table/import' require 'clamp' require 'net/http' require 'fileutils' +require 'json' class BaseCommand < Clamp::Command parameter "ADDRESS", "ESX host address" option "--user", "USER", "Username", :default => "root" option "--password", "PASSWORD", "Password", :default => "" option "--debug", :flag, "Print debugging info" + option "--free-license", :flag, "If your Hypervisor have a free license", :default => false end class InfoCommand < BaseCommand parameter "ADDRESS", "ESX host address" @@ -20,11 +22,11 @@ option "--password", "PASSWORD", "Password", :default => "" def execute begin - host = ESX::Host.connect(address, user, password) + host = ESX::Host.connect(address, user, password, true, {:free_license=>free_license?}) puts name = host.name.upcase puts "*" * name.size puts name @@ -76,13 +78,13 @@ parameter "ADDRESS", "ESX host address" option "--vm-name", "VM_NAME", "Virtual Machine to destroy" def execute begin - host = ESX::Host.connect address, user, password + host = ESX::Host.connect address, user, password, true, {:free_license=>free_license?} host.virtual_machines.each do |vm| - if vm.name == vm_name + if vm.name == vm_name print "Destroying Virtual Machine '#{vm.name}'..." vm.power_off unless vm.power_state == 'poweredOff' vm.destroy puts "Done." end @@ -103,11 +105,11 @@ parameter "ADDRESS", "ESX host address" option "--vm-name", "VM_NAME", "Virtual Machine to Power Off" def execute begin - host = ESX::Host.connect address, user, password + host = ESX::Host.connect address, user, password, true, {:free_license=>free_license?} host.virtual_machines.each do |vm| if vm.name == vm_name and vm.power_state == 'poweredOn' print "Powering Off VM #{vm_name}... " vm.power_off puts "Done." @@ -129,11 +131,11 @@ parameter "ADDRESS", "ESX host address" option "--vm-name", "VM_NAME", "Virtual Machine to Power On" def execute begin - host = ESX::Host.connect address, user, password + host = ESX::Host.connect address, user, password, true, {:free_license=>free_license?} host.virtual_machines.each do |vm| if vm.name == vm_name and vm.power_state != 'poweredOn' print "Powering On VM #{vm_name}... " vm.power_on puts "Done." @@ -148,11 +150,140 @@ end end end +class DeleteNICCommand < BaseCommand + parameter "ADDRESS", "ESX host address" + option "--vm-name", "VM_NAME", "Virtual Machine" + option "--mac-address", "MAC_ADDRESS", "MAC address to remove" + option "--force", :flag, "Force reboot" + def execute + begin + host = ESX::Host.connect address, user, password, true, {:free_license=>free_license?} + + vm = host.virtual_machines.find{|x| x.name.eql? vm_name} + if vm + hd=vm.vm_object.config.hardware.device.grep(RbVmomi::VIM::VirtualEthernetCard).find{|nic| nic.props[:macAddress].eql?mac_address} + if hd + spec = RbVmomi::VIM.VirtualMachineConfigSpec({:deviceChange => [{:operation => :remove,:device => hd}]}) + unless free_license? + vm.vm_object.ReconfigVM_Task(:spec => spec).wait_for_completion + else + #TODO: This is horrible! Find a way to reconfigure the VM without downtime + key = hd.key + vmx_file = vm.vm_object.config.files.vmPathName.gsub("[","/vmfs/volumes/").gsub(/]\s*/,"/") + puts "VMX file: #{vmx_file}" if debug? + eth_name = host.remote_command("fgrep #{mac_address} #{vmx_file} | cut -d. -f1") + if eth_name + eth_name.strip! + puts "#{eth_name} found!" if debug? + host.remote_command "sed -i -e '/.*#{eth_name}\..*/d' #{vmx_file}" + end + if force? + vm.power_off + host.remote_command "vim-cmd vmsvc/unregister #{vm.vmid}" + id = host.remote_command "vim-cmd solo/registervm #{vmx_file}" + host.remote_command "vim-cmd vmsvc/power.on #{id}" + else + puts "You have to power-off the vm unregister it and register it agin." + end + end + puts "Done." + else + puts "No NIC with #{mac_address} mac address was found!" + end + else + puts "No Virtual Machine found!" + end + rescue Exception => e + $stderr.puts "Can't connect to the host #{address}." + if debug? + $stderr.puts e.message + end + exit 1 + end + end +end + + +class AddNICCommand < BaseCommand + parameter "ADDRESS", "ESX host address" + option "--vm-name", "VM_NAME", "Virtual Machine" + option "--mac-address", "MAC_ADDRESS", "MAC address to add", :default => nil + option "--network", "NETWORK", "Network name for new interface" + option "--force", :flag, "Force reboot" + + def execute + begin + host = ESX::Host.connect address, user, password, true, {:free_license=>free_license?} + vm = host.virtual_machines.find{|x| x.name.eql? vm_name} + if vm + hd = vm.vm_object.config.hardware.device.grep(RbVmomi::VIM::VirtualEthernetCard).find{|nic| nic.props[:macAddress].eql?mac_address} + s = vm.vm_object.config.hardware.device.grep(RbVmomi::VIM::VirtualEthernetCard).size + if hd + puts "NIC with #{mac_address} mac address already exists!" + else + if mac_address + nics = {:macAddress => mac_address, :addressType => 'manual'} + else + nics = {:addressType => 'generated'} + end + spec = RbVmomi::VIM.VirtualMachineConfigSpec({:deviceChange => [{ + :operation => :add, + :device => RbVmomi::VIM.VirtualE1000({ + :key => s, + :deviceInfo => { + :label => "Network Adapter #{s}", + :summary => network || 'VM Network' + }, + :backing => RbVmomi::VIM.VirtualEthernetCardNetworkBackingInfo( + :deviceName => network || 'VM Network' + ) + }.merge(nics)) + }]}) + unless free_license? + vm.vm_object.ReconfigVM_Task(:spec => spec).wait_for_completion + else + #TODO: This is horrible! Find a way to reconfigure the VM without downtime + vmx_file = vm.vm_object.config.files.vmPathName.gsub("[","/vmfs/volumes/").gsub(/]\s*/,"/") + puts "VMX file: #{vmx_file}" if debug? + host.remote_command " echo 'ethernet#{s}.present = \"true\"' >> #{vmx_file}" + host.remote_command " echo 'ethernet#{s}.virtualDev = \"e1000\"' >> #{vmx_file}" + host.remote_command " echo 'ethernet#{s}.wakeOnPcktRcv = \"false\"' >> #{vmx_file}" + host.remote_command " echo 'ethernet#{s}.networkName = \"#{network || 'VM Network'}\"' >> #{vmx_file}" + if mac_address + host.remote_command " echo 'ethernet#{s}.addressType = \"static\"' >> #{vmx_file}" + host.remote_command " echo 'ethernet#{s}.address = \"#{mac_address}\"' >> #{vmx_file}" + else + host.remote_command " echo 'ethernet#{s}.addressType = \"generated\"' >> #{vmx_file}" + end + if force? + vm.power_off + host.remote_command "vim-cmd vmsvc/unregister #{vm.vmid}" + id = host.remote_command "vim-cmd solo/registervm #{vmx_file}" + host.remote_command "vim-cmd vmsvc/power.on #{id}" + else + puts "You have to power-off the vm unregister it and register it agin." + end + end + puts "Done." + end + else + puts "No Virtual Machine found!" + end + rescue Exception => e + $stderr.puts "Can't connect to the host #{address}." + if debug? + $stderr.puts e.message + end + exit 1 + end + end +end + class CreateVMCommand < BaseCommand parameter "ADDRESS", "ESX host address" option "--disk-file", "DISK_FILE", "VMDK file to import", :attribute_name => :disk_file option "--disk-size", "DISK_SIZE", "VM Disk size in MB", :attribute_name => :disk_size, :default => 8192 @@ -165,11 +296,11 @@ option "--datastore", "DATASTORE", "Datastore used to host the disk", :default => "datastore1" option "--poweron", :flag, "Power on the VM after creation" def execute begin - host = ESX::Host.connect address, user, password + host = ESX::Host.connect address, user, password, true, {:free_license=>free_license?} rescue Exception => e $stderr.puts "Can't connect to the host #{address}." if debug? $stderr.puts e.message end @@ -179,11 +310,11 @@ $stderr.puts "Both --disk-file and --disk-size specified. --disk-size will be ignored." end downloaded_file = nil if disk_file.nil? # if --disk-file nil? create the VM without disk - vm = host.create_vm :vm_name => name, + vm = host.create_vm :vm_name => name, :datastore => datastore, :disk_type => :flat, :memory => memory, :disk_size => disk_size, :guest_id => guest_id, :nics => [{:mac_address => mac_address, :network => vm_network}] else df = disk_file.dup @@ -194,11 +325,11 @@ puts "Downloading file... (#{tmpfile})" download! downloaded_file, tmpfile puts df = tmpfile rescue Exception => e - FileUtils.rm_f(tmpfile) + FileUtils.rm_f(tmpfile) $stderr.puts "Error downloading file from #{downloaded_file}." $stderr.puts e.message if debug? exit 1 end end @@ -218,24 +349,24 @@ exit 1 end if not downloaded_file.nil? puts "Deleting tmp file #{df}" if debug? - FileUtils.rm_f(df) + FileUtils.rm_f(df) end - vm = host.create_vm :vm_name => name, - :disk_file => "#{name}/#{name}.vmdk", + vm = host.create_vm :vm_name => name, + :disk_file => "#{name}/#{name}.vmdk", :datastore => datastore, :disk_type => :flat, :memory => memory, :guest_id => guest_id, :nics => [{mac_address => mac_address, :network => vm_network}] end if poweron? vm.power_on end end def report_progress(progress, total, show_parts=true) - line_reset = "\r\e[0K" + line_reset = "\r\e[0K" percent = (progress.to_f / total.to_f) * 100 line = "Progress: #{percent.to_i}%" line << " (#{progress} / #{total})" if show_parts line = "#{line_reset}#{line}" $stdout.sync = true @@ -282,14 +413,17 @@ end end class DefaultCommand < Clamp::Command - default_subcommand "info", "Display host info", InfoCommand + self.default_subcommand="info" + subcommand "info", "Display host info", InfoCommand subcommand "create-vm", "Create a VM", CreateVMCommand subcommand "poweron-vm", "Power On a VM", PowerOnVMCommand subcommand "poweroff-vm", "Power Off a VM", PowerOffVMCommand subcommand "destroy-vm", "Destroy VM", DestroyVMCommand + subcommand "add-nic", "Add NIC to a VM", AddNICCommand + subcommand "delete-nic", "Delete NIC from a VM", DeleteNICCommand end begin DefaultCommand.run rescue Exception => e