Top Level Namespace
Defined Under Namespace
Modules: RVC
Constant Summary collapse
- URI_REGEX =
%r{ ^ (?: ([^@:]+) (?:: ([^@]*) )? @ )? ([^@:]+) (?::(.*))? $ }x
- VNC =
Copyright © 2011 VMware, Inc. All Rights Reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
ENV['VNC'] || search_path('vinagre') || search_path('tightvnc')
- VMRC_NAME =
"vmware-vmrc-linux-x86-3.0.0"
- VMRC_PKGVER =
1
- VMRC_BASENAME =
"#{VMRC_NAME}.#{VMRC_PKGVER}.tar.bz2"
- VMRC_URL =
"http://cloud.github.com/downloads/vmware/rvc/#{VMRC_BASENAME}"
- VMRC_SHA256 =
"cda9ba0b0078aee9a7b9704d720ef4c7d74ae2028efb71815d0eb91a5de75921"
- CURL =
ENV['CURL'] || 'curl'
- HELP_ORDER =
%w(basic vm)
Instance Method Summary collapse
- #_add_device(vm, dev) ⇒ Object
- #_add_net_device(vm, klass, network) ⇒ Object
- #_display_snapshot_tree(nodes, indent) ⇒ Object
- #_extraConfig(vm, *regexes) ⇒ Object
- #_setExtraConfig(vm, hash) ⇒ Object
- #add_host(cluster, hostname, opts) ⇒ Object
- #add_net_device(vm, opts) ⇒ Object
- #annotate(vm, str) ⇒ Object
- #answer(vm, str) ⇒ Object
- #cd(obj) ⇒ Object
- #change_device_connectivity(vm, label, connected) ⇒ Object
- #clone(src, dst, opts) ⇒ Object
- #connect(uri, opts) ⇒ Object
- #create(name, parent, opts) ⇒ Object
- #debug ⇒ Object
- #deltaize_disks(vm) ⇒ Object
- #destroy(objs) ⇒ Object
- #devices(vm) ⇒ Object
- #disconnect(connection) ⇒ Object
- #download(datastore_path, local_path) ⇒ Object
- #edit(file) ⇒ Object
- #enter_maintenance_mode(hosts, opts) ⇒ Object
- #evacuate(src, dsts, opts) ⇒ Object
- #exit_maintenance_mode(hosts, opts) ⇒ Object
- #extraConfig(vm, regexes) ⇒ Object
- #find(ds, opts) ⇒ Object
- #find_ancestor(klass) ⇒ Object
- #find_local_vmrc ⇒ Object
- #find_vmrc ⇒ Object
- #find_vmx_files(ds) ⇒ Object
- #help(path) ⇒ Object
- #info(obj) ⇒ Object
- #insert_cdrom(vm, iso) ⇒ Object
- #install ⇒ Object
- #ip(vms) ⇒ Object
- #kill(vms) ⇒ Object
- #layout(vm) ⇒ Object
- #ls(obj) ⇒ Object
- #mark(key, objs) ⇒ Object
- #migrate(vms, opts) ⇒ Object
-
#mkdir(datastore_path) ⇒ Object
TODO dispatch to datastore.mkdir if path is in a datastore.
- #mv(src, dst) ⇒ Object
- #off(vm) ⇒ Object
- #on(vms) ⇒ Object
- #ping(vm) ⇒ Object
- #prompt_cert_insecure ⇒ Object
- #prompt_cert_unknown ⇒ Object
- #prompt_password ⇒ Object
- #quit ⇒ Object
- #reachable_ip(host) ⇒ Object
- #reboot(hosts, opts) ⇒ Object
- #reboot_guest(vms) ⇒ Object
- #reconnect(hosts, opts) ⇒ Object
- #register(vmx_file, opts) ⇒ Object
- #reload ⇒ Object
- #reload_entity(objs) ⇒ Object
- #remove_device(vm, label) ⇒ Object
- #reset(vms) ⇒ Object
- #revert(vm) ⇒ Object
- #rvc(vm) ⇒ Object
- #setExtraConfig(vm, pairs) ⇒ Object
- #shares_from_string(str) ⇒ Object
- #show(objs) ⇒ Object
- #shutdown_guest(vms) ⇒ Object
- #snapshot(vm, name) ⇒ Object
- #snapshots(vm) ⇒ Object
- #ssh(vm, cmd, opts) ⇒ Object
- #standby_guest(vms) ⇒ Object
- #suspend(vms) ⇒ Object
- #type(name) ⇒ Object
- #unregister(vm) ⇒ Object
- #unused_vnc_port(ip) ⇒ Object
- #update(pool, opts) ⇒ Object
- #upload(local_path, datastore_path) ⇒ Object
- #view(vms) ⇒ Object
- #vm_ip(vm) ⇒ Object
-
#vnc_client(ip, port, password) ⇒ Object
Override this to spawn a VNC client differently.
-
#vnc_password ⇒ Object
Override this if you don’t want a random password.
Instance Method Details
#_add_device(vm, dev) ⇒ Object
473 474 475 476 477 478 479 480 |
# File 'lib/rvc/modules/vm.rb', line 473 def _add_device vm, dev spec = { :deviceChange => [ { :operation => :add, :device => dev }, ] } vm.ReconfigVM_Task(:spec => spec).wait_for_completion end |
#_add_net_device(vm, klass, network) ⇒ Object
482 483 484 485 486 487 488 489 490 491 492 493 494 |
# File 'lib/rvc/modules/vm.rb', line 482 def _add_net_device vm, klass, network _add_device vm, klass.new( :key => -1, :deviceInfo => { :summary => network, :label => `uuidgen`.chomp }, :backing => VIM.VirtualEthernetCardNetworkBackingInfo( :deviceName => network ), :addressType => 'generated' ) end |
#_display_snapshot_tree(nodes, indent) ⇒ Object
536 537 538 539 540 541 |
# File 'lib/rvc/modules/vm.rb', line 536 def _display_snapshot_tree nodes, indent nodes.each do |node| puts "#{' '*indent}#{node.name} #{node.createTime}" _display_snapshot_tree node.childSnapshotList, (indent+1) end end |
#_extraConfig(vm, *regexes) ⇒ Object
361 362 363 364 365 366 367 368 |
# File 'lib/rvc/modules/vm.rb', line 361 def _extraConfig vm, *regexes vm.config.extraConfig.each do |h| if regexes.empty? or regexes.any? { |r| h[:key] =~ r } puts "#{h[:key]}: #{h[:value]}" end end nil end |
#_setExtraConfig(vm, hash) ⇒ Object
354 355 356 357 358 359 |
# File 'lib/rvc/modules/vm.rb', line 354 def _setExtraConfig vm, hash cfg = { :extraConfig => hash.map { |k,v| { :key => k, :value => v } }, } vm.ReconfigVM_Task(:spec => cfg).wait_for_completion end |
#add_host(cluster, hostname, opts) ⇒ Object
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
# File 'lib/rvc/modules/cluster.rb', line 40 def add_host cluster, hostname, opts sslThumbprint = nil while true spec = { :force => false, :hostName => hostname, :userName => opts[:username], :password => opts[:password], :sslThumbprint => sslThumbprint, } task = cluster.AddHost_Task :spec => spec, :asConnected => false begin task.wait_for_completion rescue VIM::SSLVerifyFault puts "SSL thumbprint: #{$!.fault.thumbprint}" $stdout.write "Accept this thumbprint? (y/n) " $stdout.flush answer = $stdin.readline.chomp err "Aborted" unless answer == 'y' or answer == 'yes' sslThumbprint = $!.fault.thumbprint end end end |
#add_net_device(vm, opts) ⇒ Object
462 463 464 465 466 467 468 469 470 |
# File 'lib/rvc/modules/vm.rb', line 462 def add_net_device vm, opts case opts[:type] when 'e1000' _add_net_device vm, VIM::VirtualE1000, opts[:network] when 'vmxnet3' _add_net_device vm, VIM::VirtualVmxnet3, opts[:network] else err "unknown device" end end |
#annotate(vm, str) ⇒ Object
631 632 633 |
# File 'lib/rvc/modules/vm.rb', line 631 def annotate vm, str vm.ReconfigVM_Task(:spec => { :annotation => str }).wait_for_completion end |
#answer(vm, str) ⇒ Object
249 250 251 252 253 |
# File 'lib/rvc/modules/vm.rb', line 249 def answer vm, str choice = q.choice.choiceInfo.find { |x| x.label == str } err("invalid answer") unless choice vm.AnswerVM :questionid => q.path, :answerChoice => choice.key end |
#cd(obj) ⇒ Object
121 122 123 124 125 126 |
# File 'lib/rvc/modules/basic.rb', line 121 def cd obj $shell.fs.cd(obj) $shell.fs.mark '', [find_ancestor(RbVmomi::VIM::Datacenter)].compact $shell.fs.mark '@', [find_ancestor(RbVmomi::VIM)].compact $shell.fs.marks.delete_if { |k,v| k =~ /^\d+$/ } end |
#change_device_connectivity(vm, label, connected) ⇒ Object
658 659 660 661 662 663 664 665 666 667 668 |
# File 'lib/rvc/modules/vm.rb', line 658 def change_device_connectivity vm, label, connected dev = vm.config.hardware.device.find { |x| x.deviceInfo.label == label } err "no such device" unless dev dev.connectable.connected = connected spec = { :deviceChange => [ { :operation => :edit, :device => dev }, ] } vm.ReconfigVM_Task(:spec => spec).wait_for_completion end |
#clone(src, dst, opts) ⇒ Object
579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 |
# File 'lib/rvc/modules/vm.rb', line 579 def clone src, dst, opts folder, name = *dst diskMoveType = nil if opts[:linked] deltaize_disks src diskMoveType = :moveChildMostDiskBacking end task = src.CloneVM_Task(:folder => folder, :name => name, :spec => { :location => { :diskMoveType => diskMoveType, :host => opts[:host], :pool => opts[:pool], }, :template => opts[:template], :powerOn => opts[:powerOn], }) progress [task] end |
#connect(uri, opts) ⇒ Object
289 290 291 |
# File 'lib/rvc/modules/vm.rb', line 289 def connect vm, label change_device_connectivity vm, label, true end |
#create(name, parent, opts) ⇒ Object
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 |
# File 'lib/rvc/modules/vm.rb', line 109 def create dest, opts err "must specify resource pool (--pool)" unless opts[:pool] err "must specify datastore (--datastore)" unless opts[:datastore] vmFolder, name = *dest datastore_path = "[#{opts[:datastore].name}]" config = { :name => name, :guestId => 'otherGuest', :files => { :vmPathName => datastore_path }, :numCPUs => 1, :memoryMB => 128, :deviceChange => [ { :operation => :add, :device => VIM.VirtualLsiLogicController( :key => 1000, :busNumber => 0, :sharedBus => :noSharing ) }, { :operation => :add, :fileOperation => :create, :device => VIM.VirtualDisk( :key => -1, :backing => VIM.VirtualDiskFlatVer2BackingInfo( :fileName => datastore_path, :diskMode => :persistent, :thinProvisioned => true ), :controllerKey => 1000, :unitNumber => 0, :capacityInKB => 4000000 ) }, { :operation => :add, :device => VIM.VirtualCdrom( :key => -2, :connectable => { :allowGuestControl => true, :connected => true, :startConnected => true, }, :backing => VIM.VirtualCdromIsoBackingInfo( :fileName => datastore_path ), :controllerKey => 200, :unitNumber => 0 ) }, { :operation => :add, :device => VIM.VirtualE1000( :key => -3, :deviceInfo => { :label => 'Network Adapter 1', :summary => 'VM Network' }, :backing => VIM.VirtualEthernetCardNetworkBackingInfo( :deviceName => 'VM Network' ), :addressType => 'generated' ) } ], } vmFolder.CreateVM_Task(:config => config, :pool => opts[:pool], :host => opts[:host]).wait_for_completion end |
#debug ⇒ Object
82 83 84 85 86 87 |
# File 'lib/rvc/modules/basic.rb', line 82 def debug debug = $shell.debug = !$shell.debug $shell.connections.each do |name,conn| conn.debug = debug end end |
#deltaize_disks(vm) ⇒ Object
603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 |
# File 'lib/rvc/modules/vm.rb', line 603 def deltaize_disks vm real_disks = vm.config.hardware.device.grep(VIM::VirtualDisk).select { |x| x.backing.parent == nil } unless real_disks.empty? puts "Reconfiguring source VM to use delta disks..." deviceChange = [] real_disks.each do |disk| deviceChange << { :operation => :remove, :device => disk } deviceChange << { :operation => :add, :fileOperation => :create, :device => disk.dup.tap { |x| x.backing = x.backing.dup x.backing.fileName = "[#{disk.backing.datastore.name}]" x.backing.parent = disk.backing } } end progress [vm.ReconfigVM_Task(:spec => { :deviceChange => deviceChange })] end end |
#destroy(objs) ⇒ Object
211 212 213 |
# File 'lib/rvc/modules/basic.rb', line 211 def destroy objs tasks objs, :Destroy end |
#devices(vm) ⇒ Object
273 274 275 276 277 278 279 280 |
# File 'lib/rvc/modules/vm.rb', line 273 def devices vm devs = vm.config.hardware.device devs.each do |dev| = [] << (dev.connectable.connected ? :connected : :disconnected) if dev.props.member? :connectable puts "#{dev.deviceInfo.label} (#{dev.class}): #{dev.deviceInfo.summary}; #{ * ' '}" end end |
#disconnect(connection) ⇒ Object
300 301 302 |
# File 'lib/rvc/modules/vm.rb', line 300 def disconnect vm, label change_device_connectivity vm, label, false end |
#download(datastore_path, local_path) ⇒ Object
27 28 29 30 31 |
# File 'lib/rvc/modules/datastore.rb', line 27 def download datastore_path, local_path file = lookup_single(datastore_path) err "not a datastore file" unless file.is_a? RbVmomi::VIM::Datastore::FakeDatastoreFile file.datastore.download file.path, local_path end |
#edit(file) ⇒ Object
43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
# File 'lib/rvc/modules/mark.rb', line 43 def edit key editor = ENV['VISUAL'] || ENV['EDITOR'] || 'vi' objs = $shell.fs.marks[key] or err "no such mark #{key.inspect}" filename = File.join(Dir.tmpdir, "rvc.#{Time.now.to_i}.#{rand(65536)}") File.open(filename, 'w') { |io| objs.each { |obj| io.puts(obj.rvc_path_str) } } begin system("#{editor} #{filename}") new_paths = File.readlines(filename).map(&:chomp) rescue return new_objs = new_paths.map { |path| lookup(path) }.inject([], &:+) mark key, new_objs ensure File.unlink filename end end |
#enter_maintenance_mode(hosts, opts) ⇒ Object
81 82 83 |
# File 'lib/rvc/modules/host.rb', line 81 def enter_maintenance_mode hosts, opts tasks hosts, :EnterMaintenanceMode, :timeout => opts[:timeout] end |
#evacuate(src, dsts, opts) ⇒ Object
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
# File 'lib/rvc/modules/host.rb', line 39 def evacuate src, dsts, opts vim = src._connection vms = src.vm dst_hosts = dsts.map(&:host).flatten checks = ['cpu', 'software'] dst_hosts.reject! { |host| host == src || host.runtime.connectionState != 'connected' || host.runtime.inMaintenanceMode } candidates = {} vms.each do |vm| required_datastores = vm.datastore result = vim.serviceInstance.QueryVMotionCompatibility(:vm => vm, :host => dst_hosts, :compatibility => checks) result.reject! { |x| x.compatibility != checks || x.host.datastore & required_datastores != required_datastores } candidates[vm] = result.map { |x| x.host } end if candidates.any? { |vm,hosts| hosts.empty? } puts "The following VMs have no compatible vMotion destination:" candidates.select { |vm,hosts| hosts.empty? }.each { |vm,hosts| puts " #{vm.name}" } return end tasks = candidates.map do |vm,hosts| host = hosts[rand(hosts.size)] vm.MigrateVM_Task(:host => host, :priority => :defaultPriority) end progress tasks end |
#exit_maintenance_mode(hosts, opts) ⇒ Object
92 93 94 |
# File 'lib/rvc/modules/host.rb', line 92 def exit_maintenance_mode hosts, opts tasks hosts, :ExitMaintenanceMode, :timeout => opts[:timeout] end |
#extraConfig(vm, regexes) ⇒ Object
337 338 339 |
# File 'lib/rvc/modules/vm.rb', line 337 def extraConfig vm, regexes _extraConfig(vm, *regexes.map { |x| /#{x}/ }) end |
#find(ds, opts) ⇒ Object
312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 |
# File 'lib/rvc/modules/vm.rb', line 312 def find ds, opts folder = opts[:folder] rp = opts[:resource_pool] || opts[:folder]._connection.rootFolder.childEntity[0].hostFolder.childEntity[0].resourcePool paths = find_vmx_files(ds) if paths.empty? puts "no VMX files found" return end puts "Select a VMX file" path = (paths) or return folder.RegisterVM_Task(:path => path, :asTemplate => false, :pool => rp).wait_for_completion end |
#find_ancestor(klass) ⇒ Object
128 129 130 |
# File 'lib/rvc/modules/basic.rb', line 128 def find_ancestor klass $shell.fs.cur.rvc_path.map { |k,v| v }.reverse.find { |x| x.is_a? klass } end |
#find_local_vmrc ⇒ Object
31 32 33 34 |
# File 'lib/rvc/modules/vmrc.rb', line 31 def find_local_vmrc path = File.join(Dir.tmpdir, VMRC_NAME, 'plugins', 'vmware-vmrc') File.exists?(path) && path end |
#find_vmrc ⇒ Object
36 37 38 |
# File 'lib/rvc/modules/vmrc.rb', line 36 def find_vmrc find_local_vmrc || search_path('vmrc') end |
#find_vmx_files(ds) ⇒ Object
636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 |
# File 'lib/rvc/modules/vm.rb', line 636 def find_vmx_files ds datastorePath = "[#{ds.name}] /" searchSpec = { :details => { :fileOwner => false, :fileSize => false, :fileType => true, :modification => false }, :query => [ VIM::VmConfigFileQuery() ] } task = ds.browser.SearchDatastoreSubFolders_Task(:datastorePath => datastorePath, :searchSpec => searchSpec) results = task.wait_for_completion files = [] results.each do |result| result.file.each do |file| files << result.folderPath + file.path end end files end |
#help(path) ⇒ Object
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
# File 'lib/rvc/modules/basic.rb', line 44 def help path obj = lookup_single(path) if path if obj puts "Relevant commands for #{obj.class}:" else puts "All commands:" end MODULES.sort_by do |mod_name,mod| HELP_ORDER.index(mod_name) || HELP_ORDER.size end.each do |mod_name,mod| opts = mod.instance_variable_get(:@opts) opts.each do |method_name,method_opts| parser = RVC::OptionParser.new method_name, &method_opts next unless obj.nil? or parser.applicable.any? { |x| obj.is_a? x } aliases = ALIASES.select { |k,v| v == "#{mod_name}.#{method_name}" }.map(&:first) aliases_text = aliases.empty? ? '' : " (#{aliases*', '})" puts "#{mod_name}.#{method_name}#{aliases_text}: #{parser.summary?}" if parser.summary? end end if not obj puts (<<-EOS) To see detailed help for a command, use its --help option. To show only commands relevant to a specific object, use "help /path/to/object". EOS end end |
#info(obj) ⇒ Object
194 195 196 197 198 199 200 201 |
# File 'lib/rvc/modules/basic.rb', line 194 def info obj puts "path: #{obj.rvc_path_str}" if obj.respond_to? :display_info obj.display_info else puts "class: #{obj.class.name}" end end |
#insert_cdrom(vm, iso) ⇒ Object
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 |
# File 'lib/rvc/modules/vm.rb', line 185 def insert_cdrom vm, iso device = vm.config.hardware.device.grep(VIM::VirtualCdrom)[0] err "No virtual CDROM drive found" unless device device.backing = VIM.VirtualCdromIsoBackingInfo(:fileName => iso.datastore_path) spec = { :deviceChange => [ { :operation => :edit, :device => device } ] } vm.ReconfigVM_Task(:spec => spec) end |
#install ⇒ Object
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
# File 'lib/rvc/modules/vmrc.rb', line 75 def install system "which #{CURL} > /dev/null" or err "curl not found" system "which sha256sum > /dev/null" or err "sha256sum not found" puts "Downloading VMRC..." dir = Dir.mktmpdir vmrc_file = "#{dir}/#{VMRC_BASENAME}" checksum_file = "#{dir}/sha256sums" system "#{CURL} -L #{VMRC_URL} -o #{vmrc_file}" or err "download failed" puts "Checking integrity..." File.open(checksum_file, 'w') { |io| io.puts "#{VMRC_SHA256} *#{vmrc_file}" } system "sha256sum -c #{checksum_file}" or err "integrity check failed" puts "Installing VMRC..." system "tar -xj -f #{vmrc_file} -C #{Dir.tmpdir}" or err("VMRC installation failed") puts "VMRC was installed successfully." FileUtils.rm_r dir end |
#ip(vms) ⇒ Object
424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 |
# File 'lib/rvc/modules/vm.rb', line 424 def ip vms props = %w(summary.runtime.powerState summary.guest.ipAddress summary.config.annotation) connection = single_connection vms filters = vms.map do |vm| connection.propertyCollector.CreateFilter :spec => { :propSet => [{ :type => 'VirtualMachine', :all => false, :pathSet => props }], :objectSet => [{ :obj => vm }], }, :partialUpdates => false end ver = '' while not vms.empty? result = connection.propertyCollector.WaitForUpdates(:version => ver) ver = result.version vms.reject! do |vm| begin ip = vm_ip(vm) puts "#{vm.name}: #{ip}" true rescue UserError false end end end ensure filters.each(&:DestroyPropertyFilter) if filters end |
#kill(vms) ⇒ Object
236 237 238 239 240 |
# File 'lib/rvc/modules/vm.rb', line 236 def kill vms on_vms = vms.select { |x| x.summary.runtime.powerState == 'poweredOn' } off on_vms unless on_vms.empty? CMD.basic.destroy vms unless vms.empty? end |
#layout(vm) ⇒ Object
261 262 263 264 265 |
# File 'lib/rvc/modules/vm.rb', line 261 def layout vm vm.layoutEx.file.each do |f| puts "#{f.type}: #{f.name}" end end |
#ls(obj) ⇒ Object
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 |
# File 'lib/rvc/modules/basic.rb', line 141 def ls obj children = obj.children name_map = children.invert children, fake_children = children.partition { |k,v| v.is_a? VIM::ManagedEntity } i = 0 fake_children.each do |name,child| puts "#{i} #{name}#{child.ls_text(nil)}" child.rvc_link obj, name $shell.fs.mark i.to_s, [child] i += 1 end return if children.empty? filterSpec = VIM.PropertyFilterSpec(:objectSet => [], :propSet => []) filteredTypes = Set.new children.each do |name,child| filterSpec.objectSet << { :obj => child } filteredTypes << child.class end filteredTypes.each do |x| filterSpec.propSet << { :type => x.wsdl_name, :pathSet => x.ls_properties+%w(name), } end connection = single_connection(children.map { |k,v| v }) results = connection.propertyCollector.RetrieveProperties(:specSet => [filterSpec]) results.each do |r| name = name_map[r.obj] text = r.obj.ls_text(r) rescue " (error)" realname = r['name'] if name != r['name'] puts "#{i} #{name}#{realname && " [#{realname}]"}#{text}" r.obj.rvc_link obj, name $shell.fs.mark i.to_s, [r.obj] i += 1 end end |
#mark(key, objs) ⇒ Object
30 31 32 33 |
# File 'lib/rvc/modules/mark.rb', line 30 def mark key, objs err "invalid mark name" unless key =~ /^\w+$/ $shell.fs.mark key, objs end |
#migrate(vms, opts) ⇒ Object
561 562 563 564 565 |
# File 'lib/rvc/modules/vm.rb', line 561 def migrate vms, opts tasks vms, :MigrateVM, :pool => opts[:pool], :host => opts[:host], :priority => :defaultPriority end |
#mkdir(datastore_path) ⇒ Object
TODO dispatch to datastore.mkdir if path is in a datastore
281 282 283 284 |
# File 'lib/rvc/modules/basic.rb', line 281 def mkdir path parent = lookup_single! File.dirname(path), RbVmomi::VIM::Folder parent.CreateFolder(:name => File.basename(path)) end |
#mv(src, dst) ⇒ Object
251 252 253 254 255 256 257 258 |
# File 'lib/rvc/modules/basic.rb', line 251 def mv src, dst src_dir = File.dirname(src) dst_dir = File.dirname(dst) err "cross-directory mv not yet supported" unless src_dir == dst_dir dst_name = File.basename(dst) obj = lookup(src) obj.Rename_Task(:newName => dst_name).wait_for_completion end |
#off(vm) ⇒ Object
40 41 42 |
# File 'lib/rvc/modules/vm.rb', line 40 def off vms tasks vms, :PowerOffVM end |
#on(vms) ⇒ Object
28 29 30 |
# File 'lib/rvc/modules/vm.rb', line 28 def on vms tasks vms, :PowerOnVM end |
#ping(vm) ⇒ Object
413 414 415 416 |
# File 'lib/rvc/modules/vm.rb', line 413 def ping vm ip = vm_ip vm system_fg "ping #{Shellwords.escape ip}" end |
#prompt_cert_insecure ⇒ Object
143 144 145 |
# File 'lib/rvc/modules/vim.rb', line 143 def prompt_cert_insecure agree("SSL certificate verification failed. Connect anyway (y/n)? ", true) end |
#prompt_cert_unknown ⇒ Object
147 148 149 |
# File 'lib/rvc/modules/vim.rb', line 147 def prompt_cert_unknown agree("Are you sure you want to continue connecting (y/n)? ", true) end |
#prompt_password ⇒ Object
139 140 141 |
# File 'lib/rvc/modules/vim.rb', line 139 def prompt_password ask("password: ") { |q| q.echo = false } end |
#quit ⇒ Object
98 99 100 |
# File 'lib/rvc/modules/basic.rb', line 98 def quit exit end |
#reachable_ip(host) ⇒ Object
70 71 72 73 74 75 76 77 78 79 |
# File 'lib/rvc/modules/vnc.rb', line 70 def reachable_ip host ips = host.config.network.vnic.map { |x| x.spec.ip.ipAddress } # TODO optimize ips.find do |x| begin Timeout.timeout(1) { TCPSocket.new(x, 443).close; true } rescue false end end or err("could not find IP for server #{host.name}") end |
#reboot(hosts, opts) ⇒ Object
27 28 29 |
# File 'lib/rvc/modules/host.rb', line 27 def reboot hosts, opts tasks hosts, :RebootHost, :force => opts[:force] end |
#reboot_guest(vms) ⇒ Object
96 97 98 |
# File 'lib/rvc/modules/vm.rb', line 96 def reboot_guest vms vms.each(&:RebootGuest) end |
#reconnect(hosts, opts) ⇒ Object
114 115 116 117 118 119 120 121 |
# File 'lib/rvc/modules/host.rb', line 114 def reconnect hosts, opts spec = { :force => false, :userName => opts[:username], :password => opts[:password], } tasks hosts, :ReconnectHost end |
#register(vmx_file, opts) ⇒ Object
210 211 212 213 214 215 |
# File 'lib/rvc/modules/vm.rb', line 210 def register vmx_file, opts rp = opts[:resource_pool] || opts[:folder]._connection.rootFolder.childEntity[0].hostFolder.childEntity[0].resourcePool vm = opts[:folder].RegisterVM_Task(:path => vmx_file.datastore_path, :asTemplate => false, :pool => rp).wait_for_completion end |
#reload ⇒ Object
109 110 111 |
# File 'lib/rvc/modules/basic.rb', line 109 def reload RVC.reload_modules end |
#reload_entity(objs) ⇒ Object
223 224 225 |
# File 'lib/rvc/modules/basic.rb', line 223 def reload_entity objs objs.each(&:Reload) end |
#remove_device(vm, label) ⇒ Object
503 504 505 506 507 508 509 510 511 512 |
# File 'lib/rvc/modules/vm.rb', line 503 def remove_device vm, label dev = vm.config.hardware.device.find { |x| x.deviceInfo.label == label } err "no such device" unless dev spec = { :deviceChange => [ { :operation => :remove, :device => dev }, ] } vm.ReconfigVM_Task(:spec => spec).wait_for_completion end |
#reset(vms) ⇒ Object
53 54 55 |
# File 'lib/rvc/modules/vm.rb', line 53 def reset vms tasks vms, :ResetVM end |
#revert(vm) ⇒ Object
549 550 551 |
# File 'lib/rvc/modules/vm.rb', line 549 def revert vm tasks [vm], :RevertToCurrentSnapshot end |
#rvc(vm) ⇒ Object
395 396 397 398 399 400 401 402 403 |
# File 'lib/rvc/modules/vm.rb', line 395 def rvc vm ip = vm_ip vm env = Hash[%w(RBVMOMI_PASSWORD RBVMOMI_HOST RBVMOMI_USER RBVMOMI_SSL RBVMOMI_PORT RBVMOMI_FOLDER RBVMOMI_DATASTORE RBVMOMI_PATH RBVMOMI_DATACENTER RBVMOMI_COMPUTER).map { |k| [k,nil] }] cmd = "rvc #{Shellwords.escape ip}" system_fg(cmd, env) end |
#setExtraConfig(vm, pairs) ⇒ Object
348 349 350 351 |
# File 'lib/rvc/modules/vm.rb', line 348 def setExtraConfig vm, pairs h = Hash[pairs.map { |x| x.split('=', 2).tap { |a| a << '' if a.size == 1 } }] _setExtraConfig vm, h end |
#shares_from_string(str) ⇒ Object
35 36 37 38 39 40 41 42 43 44 |
# File 'lib/rvc/modules/resource_pool.rb', line 35 def shares_from_string str case str when 'normal', 'low', 'high' { :level => str, :shares => 0 } when /^\d+$/ { :level => 'custom', :shares => str.to_i } else err "Invalid shares argument #{str.inspect}" end end |
#show(objs) ⇒ Object
236 237 238 239 240 |
# File 'lib/rvc/modules/basic.rb', line 236 def show objs objs.each do |obj| puts "#{obj.rvc_path_str}: #{obj.class}" end end |
#shutdown_guest(vms) ⇒ Object
76 77 78 |
# File 'lib/rvc/modules/vm.rb', line 76 def shutdown_guest vms vms.each(&:ShutdownGuest) end |
#snapshot(vm, name) ⇒ Object
521 522 523 |
# File 'lib/rvc/modules/vm.rb', line 521 def snapshot vm, name tasks [vm], :CreateSnapshot, :memory => true, :name => name, :quiesce => false end |
#snapshots(vm) ⇒ Object
532 533 534 |
# File 'lib/rvc/modules/vm.rb', line 532 def snapshots vm _display_snapshot_tree vm.snapshot.rootSnapshotList, 0 end |
#ssh(vm, cmd, opts) ⇒ Object
380 381 382 383 384 385 |
# File 'lib/rvc/modules/vm.rb', line 380 def ssh vm, cmd, opts ip = vm_ip vm cmd_arg = cmd ? Shellwords.escape(cmd) : "" ssh_cmd = "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -l #{Shellwords.escape opts[:login]} #{Shellwords.escape ip} #{cmd_arg}" system_fg(ssh_cmd) end |
#standby_guest(vms) ⇒ Object
86 87 88 |
# File 'lib/rvc/modules/vm.rb', line 86 def standby_guest vms vms.each(&:StandbyGuest) end |
#suspend(vms) ⇒ Object
66 67 68 |
# File 'lib/rvc/modules/vm.rb', line 66 def suspend vms tasks vms, :SuspendVM end |
#type(name) ⇒ Object
28 29 30 31 32 |
# File 'lib/rvc/modules/basic.rb', line 28 def type name klass = RbVmomi::VIM.type(name) rescue err("#{name.inspect} is not a VMODL type.") $shell.introspect_class klass nil end |
#unregister(vm) ⇒ Object
223 224 225 |
# File 'lib/rvc/modules/vm.rb', line 223 def unregister vm vm.UnregisterVM end |
#unused_vnc_port(ip) ⇒ Object
81 82 83 84 85 86 87 88 |
# File 'lib/rvc/modules/vnc.rb', line 81 def unused_vnc_port ip 10.times do port = 5901 + rand(64) unused = (TCPSocket.connect(ip, port).close rescue true) return port if unused end err "no unused port found" end |
#update(pool, opts) ⇒ Object
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
# File 'lib/rvc/modules/resource_pool.rb', line 79 def update pool, opts spec = { :cpuAllocation => { :limit => opts[:cpu_limit], :reservation => opts[:cpu_reservation], :expandableReservation => opts[:cpu_expandable], :shares => shares_from_string(opts[:cpu_shares]), }, :memoryAllocation => { :limit => opts[:mem_limit], :reservation => opts[:mem_reservation], :expandableReservation => opts[:mem_expandable], :shares => shares_from_string(opts[:mem_shares]), }, } pool.UpdateConfig(:name => opts[:name], :spec => spec) end |
#upload(local_path, datastore_path) ⇒ Object
40 41 42 43 44 45 46 47 |
# File 'lib/rvc/modules/datastore.rb', line 40 def upload local_path, datastore_path datastore_dir_path = File.dirname datastore_path dir = lookup_single(datastore_dir_path) err "datastore directory does not exist" unless dir.is_a? RbVmomi::VIM::Datastore::FakeDatastoreFolder err "local file does not exist" unless File.exists? local_path real_datastore_path = "#{dir.path}/#{File.basename(datastore_path)}" dir.datastore.upload real_datastore_path, local_path end |
#view(vms) ⇒ Object
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
# File 'lib/rvc/modules/vnc.rb', line 31 def view vm ip = reachable_ip vm.runtime.host extraConfig = vm.config.extraConfig already_enabled = extraConfig.find { |x| x.key == 'RemoteDisplay.vnc.enabled' && x.value.downcase == 'true' } if already_enabled puts "VNC already enabled" port = extraConfig.find { |x| x.key == 'RemoteDisplay.vnc.port' }.value password = extraConfig.find { |x| x.key == 'RemoteDisplay.vnc.password' }.value else port = unused_vnc_port ip password = vnc_password vm.ReconfigVM_Task(:spec => { :extraConfig => [ { :key => 'RemoteDisplay.vnc.enabled', :value => 'true' }, { :key => 'RemoteDisplay.vnc.password', :value => password }, { :key => 'RemoteDisplay.vnc.port', :value => port.to_s } ] }).wait_for_completion end vnc_client ip, port, password end |
#vm_ip(vm) ⇒ Object
670 671 672 673 674 675 676 677 678 679 680 681 682 |
# File 'lib/rvc/modules/vm.rb', line 670 def vm_ip vm summary = vm.summary err "VM is not powered on" unless summary.runtime.powerState == 'poweredOn' ip = if summary.guest.ipAddress and summary.guest.ipAddress != '127.0.0.1' summary.guest.ipAddress elsif note = YAML.load(summary.config.annotation) and note.is_a? Hash and note.member? 'ip' note['ip'] else err "no IP known for this VM" end end |
#vnc_client(ip, port, password) ⇒ Object
Override this to spawn a VNC client differently
98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
# File 'lib/rvc/modules/vnc.rb', line 98 def vnc_client ip, port, password if VNC fork do $stderr.reopen("#{ENV['HOME']||'.'}/.rvc-vmrc.log", "w") Process.setpgrp exec VNC, "#{ip}:#{port}" end puts "spawning #{VNC}" puts "#{ip}:#{port} password: #{password}" else puts "no VNC client configured" puts "#{ip}:#{port} password: #{password}" end end |
#vnc_password ⇒ Object
Override this if you don’t want a random password
91 92 93 94 95 |
# File 'lib/rvc/modules/vnc.rb', line 91 def vnc_password n = 8 chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890' (0...n).map { chars[rand(chars.length)].chr }.join end |