Top Level Namespace
- Includes:
- RVC::Util
Defined Under Namespace
Modules: RVC Classes: LazyDVPort, MetricNumber, Numeric, ProgressStream, TimeDiff
Constant Summary collapse
- VIM =
RbVmomi::VIM
- DEFAULT_SERVER_PLACEHOLDER =
Copyright © 2012 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.
'0.0.0.0'
- VNC =
ENV['VNC'] || search_path('tightvnc') || search_path('vncviewer') || search_path('vinagre')
- TIMEFMT =
'%Y-%m-%dT%H:%M:%SZ'
- DISPLAY_TIMEFMT =
{ :realtime => '%H:%M', 1 => '%H:%M', 2 => '%m/%d', 3 => '%m/%d', 4 => '%Y/%m/%d', }
- VMRC_CHECKSUMS =
{ "i686-linux" => "b8f11c92853502c3dd208da79514a66d2dd4734b8564aceb9952333037859d04", "x86_64-linux" => "86ec4bc6f23da0c33045d9bf48d9fe66ab2f426b523d8b37531646819891bf54", "i686-mswin" => "f8455f0df038fbc8e817e4381af44fa2141496cb4e2b61f505f75bc447841949", }
- PACKAGE_VERSION =
'A'
- ARCH =
RbConfig::CONFIG['arch']
- ON_WINDOWS =
(RbConfig::CONFIG['host_os'] =~ /(mswin|mingw)/) != nil
- IGNORE_STATUSES =
%w(green gray)
- HELP_ORDER =
%w(basic vm)
- NET_DEVICE_CLASSES =
{ 'e1000' => VIM::VirtualE1000, 'vmxnet3' => VIM::VirtualVmxnet3, }
- SCSI_CONTROLLER_TYPES =
{ 'pvscsi' => VIM::ParaVirtualSCSIController, 'buslogic' => VIM::VirtualBusLogicController, 'lsilogic' => VIM::VirtualLsiLogicController, 'lsilogic-sas' => VIM::VirtualLsiLogicSASController, }
- SCSI_BUS_NUMBERS =
[0, 1, 2, 3]
- EsxcliCache =
RVC::TTLCache.new 60
Constants included from RVC::Util
RVC::Util::PROGRESS_BAR_LEFT, RVC::Util::PROGRESS_BAR_MIDDLE, RVC::Util::PROGRESS_BAR_RIGHT, RVC::Util::UserError
Instance Method Summary collapse
- #_add_device(vm, fileOp, dev) ⇒ Object
- #_extra_config(vm, *regexes) ⇒ Object
- #_set_extra_config(vm, hash) ⇒ Object
- #_vm_create(clusters, datastore, vm_folder, opts = {}) ⇒ Object
- #abbrev_hostnames(names) ⇒ Object
- #add_cdrom(vm, opts) ⇒ Object
- #add_disk(vm, path, opts) ⇒ Object
- #add_host(cluster, hostnames, opts) ⇒ Object
- #add_hosts(vds, hosts, opts) ⇒ Object
- #add_iscsi_target(hosts, opts) ⇒ Object
- #add_net(vm, network, opts) ⇒ Object
- #add_nfs_datastore(hosts, opts) ⇒ Object
- #add_privilege(name, privileges) ⇒ Object
- #add_scsi_controller(vm, opts) ⇒ Object
- #add_serial(vm) ⇒ Object
- #annotate(vm, str) ⇒ Object
- #answer(str, vms) ⇒ Object
- #apply_recommendations(cluster, opts) ⇒ Object
- #apply_settings(obj, port_spec) ⇒ Object
- #authenticate(vm, opts) ⇒ Object
- #block(obj) ⇒ Object
- #bootconfig(vm, opts) ⇒ Object
- #cd(obj) ⇒ Object
- #change_devices_connectivity(devs, connected) ⇒ Object
- #check_auth(vm, opts) ⇒ Object
- #check_installed ⇒ Object
- #check_known_hosts(host, peer_public_key) ⇒ Object
- #chmod(vm, opts) ⇒ Object
- #choose_vmrc_version(vim_version) ⇒ Object
- #clear_auth(vm, opts) ⇒ Object
- #clone(src, dst, opts) ⇒ Object
- #coerce_str(type, v) ⇒ Object
- #collapse_inheritance(default_spec, port_spec) ⇒ Object
- #configure_ha(cluster, opts) ⇒ Object
- #connect(devs) ⇒ Object
- #connect_serial_uri(dev, uri, opts) ⇒ Object
- #counter(counter_name, obj) ⇒ Object
- #counters(obj) ⇒ Object
- #create(name, parent, opts) ⇒ Object
- #create_portgroup(vds, name, opts) ⇒ Object
- #create_vds(dest, opts) ⇒ Object
- #create_vmknic(portgroup, hosts, opts) ⇒ Object
- #cur_auth_mgr ⇒ Object
- #debug ⇒ Object
- #delete(objs) ⇒ Object
- #deltaize_disks(vm) ⇒ Object
- #describe(snapshot, description) ⇒ Object
- #destroy(objs) ⇒ Object
- #disconnect(devs) ⇒ Object
- #download(file, local_path) ⇒ Object
- #download_file(vm, opts) ⇒ Object
- #edit(file) ⇒ Object
- #enter_maintenance_mode(hosts, opts) ⇒ Object
- #evacuate(src, dsts, opts) ⇒ Object
- #events(obj, opts) ⇒ Object
- #execute(*args) ⇒ Object
- #exit_maintenance_mode(hosts, opts) ⇒ Object
- #extra_config(vm, regexes) ⇒ Object
- #extract(src, dst) ⇒ Object
- #fields(obj) ⇒ Object
- #find(args, opts) ⇒ Object
- #find_ancestor(klass) ⇒ Object
- #find_interval(pm, start) ⇒ Object
- #find_items(terms = nil, roots = nil, types = nil) ⇒ Object
- #find_orphans(ds, opts) ⇒ Object
- #find_vmrc(arch, version) ⇒ Object
- #find_vmx_files(ds) ⇒ Object
- #get(objs) ⇒ Object
- #get_auth(vm, opts) ⇒ Object
- #get_inherited_config(obj) ⇒ Object
- #help(input) ⇒ Object
-
#help_namespace(ns) ⇒ Object
TODO namespace summaries.
- #help_summary(cmd) ⇒ Object
- #http_path(dc_name, ds_name, path) ⇒ Object
- #info(obj) ⇒ Object
- #insert_cdrom(dev, iso) ⇒ Object
- #install ⇒ Object
- #ip(vms) ⇒ Object
- #keychain_password(username, hostname) ⇒ Object
- #kill(vms) ⇒ Object
- #layout(vm) ⇒ Object
- #leaves(roots, types = []) ⇒ Object
- #list ⇒ Object
- #list_auth(vm) ⇒ Object
- #local_vmrc_dir(arch) ⇒ Object
- #logbundles(servers, opts) ⇒ Object
- #lookup_esxcli(host, args) ⇒ Object
- #ls(obj) ⇒ Object
- #ls_guest(vm, opts) ⇒ Object
- #mark(key, objs) ⇒ Object
- #merge_ranges(ranges) ⇒ Object
- #migrate(vms, opts) ⇒ Object
-
#mkdir(datastore_path) ⇒ Object
TODO dispatch to datastore.mkdir if path is in a datastore.
- #mktmpdir(vm, opts) ⇒ Object
- #mktmpfile(vm, opts) ⇒ Object
- #modify_cpu(vm, opts) ⇒ Object
- #modify_memory(vm, opts) ⇒ Object
- #mv(objs) ⇒ Object
- #mvdir(vm, opts) ⇒ Object
- #mvfile(vm, opts) ⇒ Object
- #off(vm) ⇒ Object
- #on(vms) ⇒ Object
- #output_formatted(cmd, result) ⇒ Object
- #output_formatted_none(result, info, hints) ⇒ Object
- #output_formatted_simple(result, info, hints) ⇒ Object
- #output_formatted_table(result, info, hints) ⇒ Object
- #permissions(name) ⇒ Object
- #pick_controller(vm, controller, controller_classes) ⇒ Object
- #ping(vm) ⇒ Object
- #plot(counter_name, objs, opts) ⇒ Object
- #prompt_password ⇒ Object
- #quit ⇒ Object
- #rdp(vms, h) ⇒ Object
- #reachable_ip(host) ⇒ Object
- #reboot(hosts, opts) ⇒ Object
- #reboot_guest(vms) ⇒ Object
- #recommendations(cluster) ⇒ Object
- #reconnect(hosts, opts) ⇒ Object
- #register(vmx_file, opts) ⇒ Object
- #reload(opts) ⇒ Object
- #reload_entity(objs) ⇒ Object
- #remove(objs, opts) ⇒ Object
- #remove_privilege(name, privileges) ⇒ Object
- #rename(snapshot, name) ⇒ Object
- #require_gnuplot ⇒ Object
- #rescan_storage(hosts) ⇒ Object
- #reset(vms) ⇒ Object
- #retrieve_datasets(pm, counter, specs) ⇒ Object
- #revert(arg) ⇒ Object
- #rmdir(vm, opts) ⇒ Object
- #rmfile(vm, opts) ⇒ Object
- #rvc(vm, opts) ⇒ Object
- #save_keychain_password(username, password, hostname) ⇒ Object
- #screenshot(vm, local_path) ⇒ Object
- #security(obj, opts) ⇒ Object
- #set(objs, opts) ⇒ Object
- #set_extra_config(vm, pairs) ⇒ Object
- #set_respool(obj, respool) ⇒ Object
- #shaper(obj, opts) ⇒ Object
- #shares_from_string(str) ⇒ Object
- #show(objs) ⇒ Object
- #show_all_portgroups(path) ⇒ Object
- #show_all_ports(path) ⇒ Object
- #show_all_vds(path) ⇒ Object
- #show_running_config(vds) ⇒ Object
- #shutdown_guest(vms, opts) ⇒ Object
- #spawn_vmrc(vmrc, moref, host, ticket) ⇒ Object
- #ssh(vm, cmd, opts) ⇒ Object
- #standby_guest(vms) ⇒ Object
- #start_program(vm, opts) ⇒ Object
- #stats(metrics, objs, opts) ⇒ Object
-
#stats_time(secs) ⇒ Object
see vSphere Client: Administration -> vCenter Server Settings -> Statistics -> Statistics Intervals.
- #storage(root) ⇒ Object
- #subtract_ranges(ranges, minus_ranges) ⇒ Object
- #summarize(obj) ⇒ Object
- #suspend(vms) ⇒ Object
- #switch(name) ⇒ Object
- #table(objs, opts) ⇒ Object
- #table_key(str) ⇒ Object
- #table_sort_compare(a, b) ⇒ Object
- #tasks ⇒ Object
- #term(x) ⇒ Object
- #translate_respool(vds, pk, show_inheritance = true) ⇒ Object
- #translate_vlan(vlan) ⇒ Object
- #type(name) ⇒ Object
- #unblock(obj) ⇒ Object
- #unregister(vm) ⇒ Object
- #unset_respool(obj) ⇒ Object
- #unused_vnc_port(ip) ⇒ Object
- #update(name, opts) ⇒ Object
- #upload(local_path, dest) ⇒ Object
- #upload_file(vm, opts) ⇒ Object
- #verify(filename, expected_hash) ⇒ Object
- #view(vms, opts) ⇒ Object
- #vlan_switchtag(obj, vlan) ⇒ Object
- #vlan_trunk(obj, vlan, opts) ⇒ Object
- #vm_create(clusters, opts) ⇒ Object
- #vm_ip(vm) ⇒ Object
- #vmrc_url(arch) ⇒ Object
-
#vnc_client(ip, port, password) ⇒ Object
Override this to spawn a VNC client differently.
- #vnc_client_connect(ip, port, password, vnc_opts = nil) ⇒ Object
-
#vnc_password ⇒ Object
Override this if you don’t want a random password.
- #wait_for_multiple_tasks(tasks, timeout) ⇒ Object
- #wait_for_shutdown(vms, opts) ⇒ Object
- #watch(counter_name, objs, opts) ⇒ Object
- #what(objs) ⇒ Object
- #with_gnuplot(persist) ⇒ Object
Methods included from RVC::Util
#collect_children, #display_inventory, #err, #http_clone, #http_download, #http_upload, #interactive?, #menu, #metric, #one_progress, #progress, #retrieve_fields, #search_path, #single_connection, #status_color, #system_fg, #tcsetpgrp, #terminal_columns
Instance Method Details
#_add_device(vm, fileOp, dev) ⇒ Object
262 263 264 265 266 267 268 269 270 271 272 273 274 |
# File 'lib/rvc/modules/device.rb', line 262 def _add_device vm, fileOp, dev spec = { :deviceChange => [ { :operation => :add, :fileOperation => fileOp, :device => dev }, ] } task = vm.ReconfigVM_Task(:spec => spec) result = progress([task])[task] if result == nil new_device = vm.collect('config.hardware.device')[0].grep(dev.class).last puts "Added device #{new_device.name}" end end |
#_extra_config(vm, *regexes) ⇒ Object
374 375 376 377 378 379 380 381 |
# File 'lib/rvc/modules/vm.rb', line 374 def _extra_config 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 |
#_set_extra_config(vm, hash) ⇒ Object
367 368 369 370 371 372 |
# File 'lib/rvc/modules/vm.rb', line 367 def _set_extra_config vm, hash cfg = { :extraConfig => hash.map { |k,v| { :key => k, :value => v } }, } vm.ReconfigVM_Task(:spec => cfg).wait_for_completion end |
#_vm_create(clusters, datastore, vm_folder, opts = {}) ⇒ Object
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 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 |
# File 'lib/rvc/modules/diagnostics.rb', line 78 def _vm_create clusters, datastore, vm_folder, opts = {} pc = datastore._connection.serviceContent.propertyCollector datastore_path = "[#{datastore.name}]" run = Time.now.to_i % 1000 tasks_map = {} cluster_host_map = {} clusters_props = pc.collectMultiple(clusters, 'name', 'resourcePool', 'host') all_hosts = clusters_props.map{|c, p| p['host']}.flatten hosts_props = pc.collectMultiple(all_hosts, 'name') hosts_infos = Hash[all_hosts.map{|host| [host, {}]}] clusters.each do |cluster| cluster_props = clusters_props[cluster] rp = cluster_props['resourcePool'] hosts = cluster_props['host'] hosts.map do |host| cluster_host_map[host] = cluster config = { :name => "VM-on-#{hosts_props[host]['name']}-#{run}", :guestId => 'otherGuest', :files => { :vmPathName => datastore_path }, :numCPUs => 1, :memoryMB => 16, :deviceChange => [ { :operation => :add, :device => VIM.VirtualCdrom( :key => -2, :connectable => { :allowGuestControl => true, :connected => true, :startConnected => true, }, :backing => VIM.VirtualCdromIsoBackingInfo( :fileName => datastore_path ), :controllerKey => 200, :unitNumber => 0 ) } ], } task = vm_folder.CreateVM_Task(:config => config, :pool => rp, :host => host) tasks_map[task] = host hosts_infos[host][:create_task] = task end end create_tasks = tasks_map.keys create_results = wait_for_multiple_tasks create_tasks, opts[:timeout] create_results.each { |t, r| hosts_infos[tasks_map[t]][:create_result] = r } vms = create_results.select{|t, x| x.is_a? VIM::VirtualMachine} destroy_tasks = Hash[vms.map{|t, x| [x.Destroy_Task, t]}] destroy_results = wait_for_multiple_tasks destroy_tasks.keys, opts[:timeout] destroy_results.each do |t, r| create_task = destroy_tasks[t] hosts_infos[tasks_map[create_task]][:destroy_result] = r end out = {} all_hosts.each do |host| host_info = hosts_infos[host] host_props = hosts_props[host] cluster = cluster_host_map[host] cluster_props = clusters_props[cluster] result = host_info[:create_result] result = host_info[:destroy_result] if result.is_a?(VIM::VirtualMachine) if result == nil error_str = nil status = 'green' elsif result.is_a?(String) error_str = result status = 'red' else error_str = "#{result.fault.class.wsdl_name}: #{result.localizedMessage}" status = 'red' end out[host_props['name']] = { 'cluster' => cluster_props['name'], 'status' => status, 'error' => error_str } end out end |
#abbrev_hostnames(names) ⇒ Object
581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 |
# File 'lib/rvc/modules/vds.rb', line 581 def abbrev_hostnames names min_len = 999 split_names = names.map { |name| new_r = name.split('.').reverse min_len = [min_len, new_r.size].min new_r } matches = 0 (0..(min_len-1)).each do |i| if split_names.first[i] == split_names.last[i] matches = i+1 else break end end if matches == min_len matches -= 1 end if matches > 0 names.each { |n| n.replace(n.split('.').reverse.drop(matches).reverse.join('.') + '.~') } end end |
#add_cdrom(vm, opts) ⇒ Object
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 |
# File 'lib/rvc/modules/device.rb', line 148 def add_cdrom vm, opts controller, unit_number = pick_controller vm, opts[:controller], [VIM::VirtualIDEController] id = "cdrom-#{controller.key}-#{unit_number}" _add_device vm, nil, VIM.VirtualCdrom( :controllerKey => controller.key, :key => -1, :unitNumber => unit_number, :backing => VIM.VirtualCdromAtapiBackingInfo( :deviceName => id, :useAutoDetect => false ), :connectable => VIM.VirtualDeviceConnectInfo( :allowGuestControl => true, :connected => true, :startConnected => true ) ) end |
#add_disk(vm, path, opts) ⇒ Object
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 |
# File 'lib/rvc/modules/device.rb', line 115 def add_disk vm, path, opts controller, unit_number = pick_controller vm, opts[:controller], [VIM::VirtualSCSIController, VIM::VirtualIDEController] id = "disk-#{controller.key}-#{unit_number}" if path dir, file = *path filename = "#{dir.datastore_path}/#{file}" else filename = "#{File.dirname(vm.summary.config.vmPathName)}/#{id}.vmdk" end opts[:file_op] = nil if opts[:file_op] == 'reuse' _add_device vm, opts[:file_op], VIM::VirtualDisk( :key => -1, :backing => VIM.VirtualDiskFlatVer2BackingInfo( :fileName => filename, :diskMode => :persistent, :thinProvisioned => true ), :capacityInKB => MetricNumber.parse(opts[:size]).to_i/1000, :controllerKey => controller.key, :unitNumber => unit_number ) end |
#add_host(cluster, hostnames, opts) ⇒ Object
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/cluster.rb', line 45 def add_host cluster, hostnames, opts sslThumbprint = nil hostnames.each do |hostname| while true spec = { :force => opts[:force], :hostName => hostname, :userName => opts[:username], :password => opts[:password], :sslThumbprint => sslThumbprint, } task = cluster.AddHost_Task :spec => spec, :asConnected => true begin one_progress task break rescue VIM::SSLVerifyFault unless opts[:insecure] 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' end sslThumbprint = $!.fault.thumbprint end end end end |
#add_hosts(vds, hosts, opts) ⇒ Object
616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 |
# File 'lib/rvc/modules/vds.rb', line 616 def add_hosts vds, hosts, opts pnicSpec = opts[:vmnic].map do |x| VIM::DistributedVirtualSwitchHostMemberPnicSpec({:pnicDevice => x}) end dvsConfig = VIM::DVSConfigSpec({ :configVersion => vds.config.configVersion, :host => hosts.map do |host| { :operation => :add, :host => host, :backing => VIM::DistributedVirtualSwitchHostMemberPnicBacking({ :pnicSpec => pnicSpec }) } end }) task = vds.ReconfigureDvs_Task(:spec => dvsConfig) progress([task]) end |
#add_iscsi_target(hosts, opts) ⇒ Object
159 160 161 162 163 164 165 166 167 168 169 170 171 |
# File 'lib/rvc/modules/host.rb', line 159 def add_iscsi_target hosts, opts hosts.each do |host| puts "configuring host #{host.name}" storage = host.configManager.storageSystem storage.UpdateSoftwareInternetScsiEnabled(:enabled => true) adapter = storage.storageDeviceInfo.hostBusAdapter.grep(VIM::HostInternetScsiHba)[0] storage.AddInternetScsiStaticTargets( :iScsiHbaDevice => adapter.device, :targets => [ VIM::HostInternetScsiHbaStaticTarget(:address => opts[:address], :iScsiName => opts[:iqn]) ] ) storage.RescanAllHba end end |
#add_net(vm, network, opts) ⇒ Object
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
# File 'lib/rvc/modules/device.rb', line 77 def add_net vm, network, opts klass = NET_DEVICE_CLASSES[opts[:type]] or err "unknown network adapter type #{opts[:type].inspect}" case network when VIM::DistributedVirtualPortgroup switch, pg_key = network.collect 'config.distributedVirtualSwitch', 'key' port = VIM.DistributedVirtualSwitchPortConnection( :switchUuid => switch.uuid, :portgroupKey => pg_key) summary = network.name backing = VIM.VirtualEthernetCardDistributedVirtualPortBackingInfo(:port => port) when VIM::Network summary = network.name backing = VIM.VirtualEthernetCardNetworkBackingInfo(:deviceName => network.name) else fail end _add_device vm, nil, klass.new( :key => -1, :deviceInfo => { :summary => summary, :label => "", }, :backing => backing, :addressType => 'generated' ) end |
#add_nfs_datastore(hosts, opts) ⇒ Object
180 181 182 183 184 185 186 187 188 189 190 191 |
# File 'lib/rvc/modules/host.rb', line 180 def add_nfs_datastore hosts, opts hosts.each do |host| datastoreSystem, = host.collect 'configManager.datastoreSystem' spec = { :accessMode => 'readWrite', :localPath => opts[:name], :remoteHost => opts[:address], :remotePath => opts[:path] } datastoreSystem.CreateNasDatastore :spec => spec end end |
#add_privilege(name, privileges) ⇒ Object
115 116 117 118 119 120 121 122 |
# File 'lib/rvc/modules/role.rb', line 115 def add_privilege name, privileges role = cur_auth_mgr.roleList.find { |x| x.name == name } err "no such role #{name.inspect}" unless role cur_auth_mgr.UpdateAuthorizationRole :roleId => role.roleId, :newName => role.name, :privIds => (role.privilege | privileges) end |
#add_scsi_controller(vm, opts) ⇒ Object
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 |
# File 'lib/rvc/modules/device.rb', line 211 def add_scsi_controller vm, opts klass = SCSI_CONTROLLER_TYPES[opts[:type]] or err "invalid SCSI controller type #{opts[:type].inspect}" err "invalid value for --sharing" unless VIM::VirtualSCSISharing.values.member? opts[:sharing] existing_devices, = vm.collect 'config.hardware.device' used_bus_numbers = existing_devices.grep(VIM::VirtualSCSIController).map(&:busNumber) bus_number = (SCSI_BUS_NUMBERS - used_bus_numbers).min err "unable to allocate a bus number, too many SCSI controllers" unless bus_number controller = klass.new( :key => -1, :busNumber => bus_number, :sharedBus => opts[:sharing], :hotAddRemove => opts[:hot_add] ) _add_device vm, nil, controller end |
#add_serial(vm) ⇒ Object
236 237 238 239 240 |
# File 'lib/rvc/modules/device.rb', line 236 def add_serial vm # create an initial no-op backing backing = VIM::VirtualSerialPortURIBackingInfo(:direction => :client, :serviceURI => 'localhost:0') _add_device vm, nil, VIM::VirtualSerialPort(:yieldOnPoll => true, :key => -1, :backing => backing) end |
#annotate(vm, str) ⇒ Object
573 574 575 |
# File 'lib/rvc/modules/vm.rb', line 573 def annotate vm, str vm.ReconfigVM_Task(:spec => { :annotation => str }).wait_for_completion end |
#answer(str, vms) ⇒ Object
288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 |
# File 'lib/rvc/modules/vm.rb', line 288 def answer str, vms vms.each do |vm| begin if q = vm.runtime.question choices = q.choice.choiceInfo choice = choices.find { |x| x.label == str } if !choice puts "#{vm.name}: #{choice} invalid, choices: #{choices.map{ |x| x.label }}" else vm.AnswerVM :questionId => q.id, :answerChoice => choice.key end end rescue puts "#{vm.name rescue vm}: #{$!.}" end end end |
#apply_recommendations(cluster, opts) ⇒ Object
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 |
# File 'lib/rvc/modules/cluster.rb', line 145 def apply_recommendations cluster, opts pc = cluster._connection.serviceContent.propertyCollector recommendation = cluster.recommendation if opts[:key] && opts[:key].length > 0 recommendation.select! { |x| opts[:key].member?(x.key) } end if opts[:type] && opts[:type].length > 0 recommendation.select! { |x| (opts[:type] & x.action.map { |y| y.class.wsdl_name }).length > 0 } end all_tasks = [] # We do recommendations in chunks, because VC can't process more than a # few migrations anyway and this way we get more fair queuing, less # timeouts of long queued migrations and a better RVC user experience # due to less queued tasks at a time. It would otherwise be easy to # exceed the screensize with queued tasks while recommendation.length > 0 recommendation.pop(20).each do |r| targets = r.action.map { |y| y.target } recent_tasks = pc.collectMultiple(targets, 'recentTask') prev_tasks = targets.map { |x| recent_tasks[x]['recentTask'] } cluster.ApplyRecommendation(:key => r.key) recent_tasks = pc.collectMultiple(targets, 'recentTask') tasks = targets.map { |x| recent_tasks[x]['recentTask'] } all_tasks += (tasks.flatten - prev_tasks.flatten) end progress all_tasks end end |
#apply_settings(obj, port_spec) ⇒ Object
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
# File 'lib/rvc/modules/vds.rb', line 77 def apply_settings obj, port_spec if obj.is_a?(VIM::DistributedVirtualSwitch) tasks [obj], :ReconfigureDvs, :spec =>{:defaultPortConfig => port_spec, :configVersion => obj.config.configVersion} elsif obj.is_a?(VIM::DistributedVirtualPortgroup) vds = obj.config.distributedVirtualSwitch collapse_inheritance vds.config.defaultPortConfig, port_spec tasks [obj], :ReconfigureDVPortgroup, :spec => { :defaultPortConfig => port_spec, :configVersion => obj.config.configVersion} elsif obj.is_a?(VIM::DistributedVirtualPort) config = obj.rvc_parent.config vds = config.distributedVirtualSwitch collapse_inheritance config.defaultPortConfig, port_spec tasks [vds], :ReconfigureDVPort, :port => [{ :key => obj.key, :operation => 'edit', :setting => port_spec }] obj.invalidate vds end end |
#authenticate(vm, opts) ⇒ Object
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
# File 'lib/rvc/modules/vm_guest.rb', line 9 def authenticate vm, opts auth = ((@auths ||= {})[vm] ||= {})[opts[:username]] if opts[:password].nil? or opts[:password].empty? opts[:password] = ask("password: ") { |q| q.echo = false } end auth = VIM.NamePasswordAuthentication( :username => opts[:username], :password => opts[:password], :interactiveSession => opts[:interactive_session] ) @auths[vm][opts[:username]] = auth begin check_auth vm, opts rescue clear_auth vm, opts err "Could not authenticate: #{$!}" end end |
#block(obj) ⇒ Object
189 190 191 |
# File 'lib/rvc/modules/vds.rb', line 189 def block obj apply_settings obj, { :blocked => { :value => true, :inherited => false } } end |
#bootconfig(vm, opts) ⇒ Object
216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 |
# File 'lib/rvc/modules/vm.rb', line 216 def bootconfig vm, opts if opts[:show] pp vm.config.bootOptions return end cur_delay = vm.config.bootOptions.bootDelay cur_retrydelay = vm.config.bootOptions.bootRetryDelay cur_retryenabled = vm.config.bootOptions.bootRetryEnabled if opts[:delay] and opts[:delay] != cur_delay new_delay = opts[:delay] else new_delay = cur_delay end if opts[:retrydelay] and opts[:retrydelay] != cur_retrydelay new_retrydelay = opts[:retrydelay] new_retryenabled = true else new_retrydelay = cur_retrydelay end if opts[:enablebootretry] new_retryenabled = true elsif opts[:disablebootretry] new_retryenabled = false else new_retryenabled = cur_retryenabled end spec = { :bootOptions => { :bootDelay => new_delay, :bootRetryDelay => new_retrydelay, :bootRetryEnabled => new_retryenabled, } } vm.ReconfigVM_Task(:spec => spec).wait_for_completion end |
#cd(obj) ⇒ Object
124 125 126 127 128 129 |
# File 'lib/rvc/modules/basic.rb', line 124 def cd obj shell.fs.cd(obj) shell.fs.marks[''] = [find_ancestor(RbVmomi::VIM::Datacenter)].compact shell.fs.marks['@'] = [find_ancestor(RbVmomi::VIM)].compact shell.fs.delete_numeric_marks end |
#change_devices_connectivity(devs, connected) ⇒ Object
276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 |
# File 'lib/rvc/modules/device.rb', line 276 def change_devices_connectivity devs, connected if dev = devs.find { |dev| dev.connectable.nil? } err "#{dev.name} is not connectable." end vm_devs = devs.group_by(&:rvc_vm) tasks = vm_devs.map do |vm,my_devs| device_changes = my_devs.map do |dev| dev = dev.dup dev.connectable = dev.connectable.dup dev.connectable.connected = connected dev.connectable.startConnected = connected { :operation => :edit, :device => dev } end spec = { :deviceChange => device_changes } vm.ReconfigVM_Task(:spec => spec) end progress tasks end |
#check_auth(vm, opts) ⇒ Object
38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/rvc/modules/vm_guest.rb', line 38 def check_auth vm, opts auth = get_auth vm, opts guestOperationsManager = vm._connection.serviceContent.guestOperationsManager err "This command requires vSphere 5 or greater" unless guestOperationsManager.respond_to? :authManager guestOperationsManager.authManager.ValidateCredentialsInGuest( :vm => vm, :auth => auth ) end |
#check_installed ⇒ Object
46 47 48 |
# File 'lib/rvc/modules/vmrc.rb', line 46 def check_installed File.exists? local_vmrc_dir(ARCH) end |
#check_known_hosts(host, peer_public_key) ⇒ Object
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 |
# File 'lib/rvc/modules/vim.rb', line 184 def check_known_hosts host, peer_public_key known_hosts = RVC::KnownHosts.new result, arg = known_hosts.verify 'vim', host, peer_public_key.to_s if result == :not_found puts "The authenticity of host '#{host}' can't be established." puts "Public key fingerprint is #{arg}." err "Connection failed" unless agree("Are you sure you want to continue connecting (y/n)? ", true) puts "Warning: Permanently added '#{host}' (vim) to the list of known hosts" known_hosts.add 'vim', host, peer_public_key.to_s elsif result == :mismatch err "Public key fingerprint for host '#{host}' does not match #{known_hosts.filename}:#{arg}." elsif result == :ok else err "Unexpected result from known_hosts check" end end |
#chmod(vm, opts) ⇒ Object
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
# File 'lib/rvc/modules/vm_guest.rb', line 115 def chmod vm, opts guestOperationsManager = vm._connection.serviceContent.guestOperationsManager err "This command requires vSphere 5 or greater" unless guestOperationsManager.respond_to? :fileManager fileManager = guestOperationsManager.fileManager opts[:permissions] = opts[:permissions].to_i(8) if opts[:permissions] auth = get_auth vm, opts fileManager. ChangeFileAttributesInGuest( :vm => vm, :auth => auth, :guestFilePath => opts[:guest_path], :fileAttributes => VIM.GuestPosixFileAttributes( :groupId => opts[:group_id], :ownerId => opts[:owner_id], :permissions => opts[:permissions] ) ) end |
#choose_vmrc_version(vim_version) ⇒ Object
61 62 63 64 65 66 67 |
# File 'lib/rvc/modules/vmrc.rb', line 61 def choose_vmrc_version vim_version if vim_version >= '5.1.0' '5.0.0' else '3.0.0' end end |
#clear_auth(vm, opts) ⇒ Object
86 87 88 89 90 91 92 93 94 |
# File 'lib/rvc/modules/vm_guest.rb', line 86 def clear_auth vm, opts unless @auths.nil? or vm.nil? if @auths.member? vm @auths[vm].delete opts[:username] @auths.delete vm if @auths[vm].empty? @auths = nil if @auths.empty? end end end |
#clone(src, dst, opts) ⇒ Object
522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 |
# File 'lib/rvc/modules/vm.rb', line 522 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[:power_on], }) progress [task] end |
#coerce_str(type, v) ⇒ Object
116 117 118 119 120 121 122 123 124 125 126 127 |
# File 'lib/rvc/modules/find.rb', line 116 def coerce_str type, v fail "expected String, got #{v.class}" unless v.is_a? String if type <= Integer then v.to_i elsif type == Float then v.to_f elsif type == TrueClass or type == FalseClass then v == 'true' elsif type == NilClass then v == 'nil' ? nil : !nil elsif v == 'nil' then nil elsif type == String then v elsif type.respond_to? :parse then type.parse(v) else fail "unexpected coercion type #{type}" end end |
#collapse_inheritance(default_spec, port_spec) ⇒ Object
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
# File 'lib/rvc/modules/vds.rb', line 99 def collapse_inheritance default_spec, port_spec inherited = true if port_spec.is_a? Hash port_spec.keys.each do |key| if key == :inherited then next end default_child = default_spec.send key child = port_spec[key] child_inheritance = collapse_inheritance default_child, child inherited = inherited && child_inheritance end if port_spec.has_key?(:inherited) port_spec[:inherited] = inherited end inherited else if default_spec == port_spec true else false end end end |
#configure_ha(cluster, opts) ⇒ Object
82 83 84 85 86 87 88 89 |
# File 'lib/rvc/modules/cluster.rb', line 82 def configure_ha cluster, opts spec = VIM::ClusterConfigSpecEx( :dasConfig => { :enabled => !opts[:disabled], } ) one_progress(cluster.ReconfigureComputeResource_Task :spec => spec, :modify => true) end |
#connect(devs) ⇒ Object
34 35 36 37 38 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 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 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 |
# File 'lib/rvc/modules/vim.rb', line 34 def connect uri, opts uri = RVC::URIParser.parse uri unless uri.is_a? URI username = uri.user || ENV['RBVMOMI_USER'] password = uri.password || ENV['RBVMOMI_PASSWORD'] host = uri.host port = uri.port || 443 certdigest = opts[:certdigest] # TODO put in URI bad_cert = false vim = nil loop do begin vim = RbVmomi::VIM.new :host => host, :port => port, :path => '/sdk', :ns => 'urn:vim25', :rev => (opts[:rev]||'4.0'), :ssl => true, :insecure => bad_cert break rescue OpenSSL::SSL::SSLError # We'll check known_hosts next raise if bad_cert bad_cert = true rescue Errno::EHOSTUNREACH, SocketError err $!. end end if bad_cert peer_public_key = vim.http.peer_cert.public_key # if user specified a hash on the commandline, verify against that if certdigest if certdigest != Digest::SHA2.hexdigest(peer_public_key.to_s()) err "Bad certificate digest specified for #{host}!" end else # Fall back to SSH-style known_hosts check_known_hosts(host, peer_public_key) end end unless opts[:rev] # negotiate API version rev = vim.serviceContent.about.apiVersion env_rev = ENV['RVC_VIMREV'] if env_rev && env_rev.to_f == 0 vim.rev = env_rev else vim.rev = [rev, env_rev || '5.1'].min end end isVC = vim.serviceContent.about.apiType == "VirtualCenter" # authenticate if username == nil if isVC isLinux = vim.serviceContent.about.osType == "linux-x64" username = isLinux ? 'root' : 'Administrator' else username = 'root' end puts "Using default username #{username.inspect}." end # If we already have a password, then don't bother querying if we have an OSX # keychain entry for it. If we have either of them, use it. # So will use command line first, then ENV, then keychain on OSX, then prompt. loaded_from_keychain = nil password = keychain_password( username , host ) if password.nil? if not password.nil? loaded_from_keychain = password end if opts[:cookie] vim. = opts[:cookie] else password_given = password != nil loop do begin password = prompt_password unless password_given vim.serviceContent.sessionManager.Login :userName => username, :password => password break rescue RbVmomi::VIM::InvalidLogin err $!. if password_given end end end Thread.new do while true sleep 600 vim.serviceInstance.CurrentTime end end # if we got to here, save the password, unless we loaded it from keychain save_keychain_password( username , password , host ) unless loaded_from_keychain == password # Stash the address we used to connect so VMRC can use it. vim.define_singleton_method(:_host) { host } conn_name = host.dup conn_name = "#{conn_name}:1" if shell.connections.member? conn_name conn_name.succ! while shell.connections.member? conn_name shell.connections[conn_name] = vim end |
#connect_serial_uri(dev, uri, opts) ⇒ Object
252 253 254 255 256 257 258 259 |
# File 'lib/rvc/modules/device.rb', line 252 def connect_serial_uri dev, uri, opts err "must specify --client or --server" unless opts[:client] || opts[:server] direction = opts[:client] ? 'client' : 'server' dev = dev.dup dev.backing = VIM::VirtualSerialPortURIBackingInfo(:direction => direction, :serviceURI => uri) spec = { :deviceChange => [ { :operation => :edit, :device => dev } ] } progress [dev.rvc_vm.ReconfigVM_Task(:spec => spec)] end |
#counter(counter_name, obj) ⇒ Object
267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 |
# File 'lib/rvc/modules/perf.rb', line 267 def counter counter_name, obj vim = obj ? obj._connection : lookup_single('~@') pm = vim.serviceContent.perfManager counter = pm.perfcounter_hash[counter_name] or err "no such counter #{counter_name.inspect}" active_intervals = pm.active_intervals active_intervals_text = lambda do |level| xs = active_intervals[level] xs.empty? ? 'none' : xs.map(&:name).map(&:inspect) * ', ' end puts "Label: #{counter.nameInfo.label}" puts "Summary: #{counter.nameInfo.summary}" puts "Unit label: #{counter.unitInfo.label}" puts "Unit summary: #{counter.unitInfo.summary}" puts "Rollup type: #{counter.rollupType}" puts "Stats type: #{counter.statsType}" puts "Level: #{counter.level}" puts " Enabled in intervals: #{active_intervals_text[counter.level]}" puts "Per-device level: #{counter.perDeviceLevel}" puts " Enabled in intervals: #{active_intervals_text[counter.perDeviceLevel]}" if obj interval = pm.provider_summary(obj).refreshRate if interval == -1 # Object does not support real time stats interval = nil end puts "Real time interval: #{interval || 'N/A'}" metrics = pm.QueryAvailablePerfMetric(:entity => obj, :intervalId => interval) metrics.select! { |x| x.counterId == counter.key } instances = metrics.map(&:instance).reject(&:empty?) unless instances.empty? puts "Instances:" instances.map do |x| puts " #{x}" end end end end |
#counters(obj) ⇒ Object
222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 |
# File 'lib/rvc/modules/perf.rb', line 222 def counters obj pm = obj._connection.serviceContent.perfManager interval = pm.provider_summary(obj).refreshRate if interval == -1 # Object does not support real time stats interval = nil end active_intervals = pm.active_intervals active_intervals_text = lambda do |level| return '' unless level xs = active_intervals[level] return 'none' if xs.empty? xs.map { |x| x.name.match(/Past (\w+)/)[1] } * ',' end metrics = pm.QueryAvailablePerfMetric( :entity => obj, :intervalId => interval) available_counters = metrics.map(&:counterId).uniq. map { |id| pm.perfcounter_idhash[id] } groups = available_counters.group_by { |counter| counter.groupInfo } table = Terminal::Table.new table.add_row ["Name", "Description", "Unit", "Level", "Active Intervals"] groups.sort_by { |group,counters| group.key }.each do |group,counters| table.add_separator table.add_row [{ :value => group.label, :colspan => 5}] table.add_separator counters.sort_by(&:name).each do |counter| table.add_row [counter.name, counter.nameInfo.label, counter.unitInfo.label, counter.level, active_intervals_text[counter.level]] end end puts(table) end |
#create(name, parent, opts) ⇒ Object
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 184 185 186 187 188 |
# File 'lib/rvc/modules/vm.rb', line 154 def create dest, opts err "must specify resource pool (--pool)" unless opts[:pool] err "must specify datastore (--datastore)" unless opts[:datastore] err "memory must be a multiple of 4MB" unless opts[:memory] % 4 == 0 vmFolder, name = *dest datastore_path = "[#{opts[:datastore].name}]" config = { :name => name, :guestId => opts[:guest_id], :files => { :vmPathName => datastore_path }, :numCPUs => opts[:cpucount], :memoryMB => opts[:memory], :deviceChange => [ { :operation => :add, :device => VIM.VirtualCdrom( :key => -2, :connectable => { :allowGuestControl => true, :connected => true, :startConnected => true, }, :backing => VIM.VirtualCdromIsoBackingInfo( :fileName => datastore_path ), :controllerKey => 200, :unitNumber => 0 ) } ], } vmFolder.CreateVM_Task(:config => config, :pool => opts[:pool], :host => opts[:host]).wait_for_completion end |
#create_portgroup(vds, name, opts) ⇒ Object
47 48 49 50 51 |
# File 'lib/rvc/modules/vds.rb', line 47 def create_portgroup vds, name, opts tasks [vds], :AddDVPortgroup, :spec => [{ :name => name, :type => opts[:type], :numPorts => opts[:num_ports] }] end |
#create_vds(dest, opts) ⇒ Object
60 61 62 63 64 65 |
# File 'lib/rvc/modules/vds.rb', line 60 def create_vds dest, opts folder, name = *dest tasks [folder], :CreateDVS, :spec => { :configSpec => { :name => name }, :productInfo => { :version => opts[:vds_version] } } end |
#create_vmknic(portgroup, hosts, opts) ⇒ Object
642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 |
# File 'lib/rvc/modules/vds.rb', line 642 def create_vmknic portgroup, hosts, opts if !portgroup.is_a?(VIM::DistributedVirtualPortgroup) err "Legacy switches not supported yet" end hosts.each do |host| ns = host.configManager.networkSystem vmknic_name = ns.AddVirtualNic( :portgroup => "", :nic => { :ip => { :dhcp => true }, :distributedVirtualPort => VIM::DistributedVirtualSwitchPortConnection( :portgroupKey => portgroup.key, :switchUuid => portgroup.config.distributedVirtualSwitch.uuid, ) } ) puts "Host #{host.name}: Added vmknic #{vmknic_name}" end end |
#cur_auth_mgr ⇒ Object
23 24 25 26 |
# File 'lib/rvc/modules/role.rb', line 23 def cur_auth_mgr conn = shell.fs.cur._connection conn.serviceContent. end |
#debug ⇒ Object
108 109 110 111 112 113 114 |
# File 'lib/rvc/modules/basic.rb', line 108 def debug debug = shell.debug = !shell.debug shell.connections.each do |name,conn| conn.debug = debug if conn.respond_to? :debug end puts "debug mode #{debug ? 'en' : 'dis'}abled" end |
#delete(objs) ⇒ Object
87 88 89 90 91 |
# File 'lib/rvc/modules/role.rb', line 87 def delete name, opts role = cur_auth_mgr.roleList.find { |x| x.name == name } err "no such role #{name.inspect}" unless role cur_auth_mgr.RemoveAuthorizationRole :roleId => role.roleId, :failIfUsed => opts[:force] end |
#deltaize_disks(vm) ⇒ Object
545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 |
# File 'lib/rvc/modules/vm.rb', line 545 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 |
#describe(snapshot, description) ⇒ Object
71 72 73 |
# File 'lib/rvc/modules/snapshot.rb', line 71 def describe snapshot, description snapshot.find_tree.snapshot.RenameSnapshot :description => description end |
#destroy(objs) ⇒ Object
281 282 283 |
# File 'lib/rvc/modules/basic.rb', line 281 def destroy objs tasks objs, :Destroy end |
#disconnect(devs) ⇒ Object
131 132 133 |
# File 'lib/rvc/modules/host.rb', line 131 def disconnect hosts tasks hosts, :DisconnectHost end |
#download(file, local_path) ⇒ Object
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 |
# File 'lib/rvc/modules/vmrc.rb', line 142 def download url_str, dest puts "Downloading VMRC..." url = URI.parse(url_str) http = if ENV['http_proxy'] proxy_uri = URI.parse(ENV['http_proxy']) proxy_user, proxy_pass = proxy_uri.userinfo.split(/:/) if proxy_uri.userinfo Net::HTTP::Proxy(proxy_uri.host, proxy_uri.port, proxy_user, proxy_pass) else Net::HTTP end begin File.open(dest, 'wb') do |io| res = http.start(url.host, url.port) do |http| http.get(url.path) do |segment| io.write segment end end res.value end rescue Exception err "Error downloading VMRC: #{$!.class}: #{$!.}" end end |
#download_file(vm, opts) ⇒ Object
252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 |
# File 'lib/rvc/modules/vm_guest.rb', line 252 def download_file vm, opts guestOperationsManager = vm._connection.serviceContent.guestOperationsManager err "This command requires vSphere 5 or greater" unless guestOperationsManager.respond_to? :fileManager fileManager = guestOperationsManager.fileManager auth = get_auth vm, opts download_url = fileManager. InitiateFileTransferFromGuest( :vm => vm, :auth => auth, :guestFilePath => opts[:guest_path] ).url download_uri = URI.parse(download_url.gsub /http(s?):\/\/\*:[0-9]*/, "") download_path = "#{download_uri.path}?#{download_uri.query}" http_download vm._connection, download_path, opts[:local_path] end |
#edit(file) ⇒ Object
45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
# File 'lib/rvc/modules/mark.rb', line 45 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
104 105 106 107 108 109 110 111 112 |
# File 'lib/rvc/modules/host.rb', line 104 def enter_maintenance_mode hosts, opts if opts[:no_wait] hosts.each do |host| host.EnterMaintenanceMode_Task(:timeout => opts[:timeout], :evacuatePoweredOffVms => opts[:evacuate_powered_off_vms]) end else tasks hosts, :EnterMaintenanceMode, :timeout => opts[:timeout], :evacuatePoweredOffVms => opts[:evacuate_powered_off_vms] end end |
#evacuate(src, dsts, opts) ⇒ Object
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
# File 'lib/rvc/modules/host.rb', line 60 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 |
#events(obj, opts) ⇒ Object
376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 |
# File 'lib/rvc/modules/basic.rb', line 376 def events obj, opts err "'events' not supported at this level" unless obj.respond_to?(:_connection) manager = obj._connection.serviceContent.eventManager @event_details ||= Hash[manager.collect("description.eventInfo").first.collect { |d| [d.key, d] }] spec = VIM::EventFilterSpec(:entity => VIM::EventFilterSpecByEntity(:entity => obj, :recursion => "all")) collector = manager.CreateCollectorForEvents(:filter => spec) collector.SetCollectorPageSize(:maxCount => opts[:lines]) collector.latestPage.reverse.each do |event| time = event.createdTime.localtime.strftime("%m/%d/%Y %I:%M %p") category = @event_details[event.class.to_s].category puts "[#{time}] [#{category}] #{event.fullFormattedMessage.strip}" end ensure collector.DestroyCollector if collector end |
#execute(*args) ⇒ Object
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
# File 'lib/rvc/modules/esxcli.rb', line 71 def execute *args host_path = args.shift or err "host argument required" host = lookup_single! host_path, VIM::HostSystem o = lookup_esxcli host, args case o when VIM::EsxcliCommand cmd = o parser = cmd.option_parser begin opts = parser.parse args rescue Trollop::CommandlineError err "error: #{$!.}" rescue Trollop::HelpNeeded parser.educate return end begin opts.reject! { |k,v| !opts.member? :"#{k}_given" } result = cmd.call(opts) rescue RbVmomi::Fault puts "#{$!.}" puts "cause: #{$!.faultCause}" if $!.respond_to? :faultCause and $!.faultCause $!.faultMessage.each { |x| puts x } if $!.respond_to? :faultMessage $!.errMsg.each { |x| puts "error: #{x}" } if $!.respond_to? :errMsg end output_formatted cmd, result when VIM::EsxcliNamespace ns = o unless ns.commands.empty? puts "Available commands:" ns.commands.each do |k,v| puts "#{k}: #{v.cli_info.help}" end puts unless ns.namespaces.empty? end unless ns.namespaces.empty? puts "Available namespaces:" ns.namespaces.each do |k,v| puts "#{k}: #{v.cli_info.help}" end end end end |
#exit_maintenance_mode(hosts, opts) ⇒ Object
121 122 123 |
# File 'lib/rvc/modules/host.rb', line 121 def exit_maintenance_mode hosts, opts tasks hosts, :ExitMaintenanceMode, :timeout => opts[:timeout] end |
#extra_config(vm, regexes) ⇒ Object
350 351 352 |
# File 'lib/rvc/modules/vm.rb', line 350 def extra_config vm, regexes _extra_config(vm, *regexes.map { |x| /#{x}/ }) end |
#extract(src, dst) ⇒ Object
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 |
# File 'lib/rvc/modules/vmrc.rb', line 179 def extract src, dst puts "Installing VMRC..." FileUtils.mkdir_p dst Zip::ZipFile.open(src) do |zf| zf.each do |e| dst_filename = File.join(dst, e.name) case e.ftype when :file FileUtils.mkdir_p File.dirname(dst_filename) zf.extract e.name, dst_filename File.chmod(e.unix_perms, dst_filename) if e.unix_perms when :directory FileUtils.mkdir_p dst_filename else $stderr.puts "unknown file type #{e.ftype}" end end end end |
#fields(obj) ⇒ Object
400 401 402 403 404 405 406 407 408 409 |
# File 'lib/rvc/modules/basic.rb', line 400 def fields obj obj.class.ancestors.select { |x| x.respond_to? :fields }.each do |klass| fields = klass.fields false next if fields.empty? puts "Fields on #{klass}:" fields.each do |name,field| puts " #{name}: #{field.summary}" end end end |
#find(args, opts) ⇒ Object
325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 |
# File 'lib/rvc/modules/vm.rb', line 325 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
131 132 133 |
# File 'lib/rvc/modules/basic.rb', line 131 def find_ancestor klass shell.fs.cur.rvc_path.map { |k,v| v }.reverse.find { |x| x.is_a? klass } end |
#find_interval(pm, start) ⇒ Object
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
# File 'lib/rvc/modules/perf.rb', line 46 def find_interval pm, start now = Time.now ago = now - start if ago < 3600 #puts "Using realtime interval, period = 20 seconds." interval_id = 20 display_timefmt = DISPLAY_TIMEFMT[:realtime] else intervals = pm.historicalInterval interval = intervals.find { |x| now - x.length < start } err "start time is too long ago" unless interval #puts "Using historical interval #{interval.name.inspect}, period = #{interval.samplingPeriod} seconds." interval_id = interval.samplingPeriod display_timefmt = DISPLAY_TIMEFMT[interval.key] end return interval_id, display_timefmt end |
#find_items(terms = nil, roots = nil, types = nil) ⇒ Object
54 55 56 57 58 59 60 61 62 63 64 |
# File 'lib/rvc/modules/find.rb', line 54 def find_items terms = nil, roots = nil, types = nil roots ||= ['.'] terms ||= [] types.each { |t| terms << "+type=#{t}" } roots = roots.map { |x| lookup x }.flatten(1) terms = terms.map { |x| term x[1..-1] } candidates = leaves roots, types results = candidates.select { |r| terms.all? { |t| t[r] } } end |
#find_orphans(ds, 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 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 |
# File 'lib/rvc/modules/datastore.rb', line 109 def find_orphans ds, opts pc = ds._connection.serviceContent.propertyCollector vms = ds.vm puts "Collecting file information about #{vms.length} VMs ... (this may take a while)" dsName = ds.name vmFiles = pc.collectMultiple vms, 'layoutEx.file' puts "Collecting file information on datastore '#{dsName}' ..." dsBrowser = ds.browser result = dsBrowser.SearchDatastore_Task( :datastorePath => "[#{dsName}] ", :searchSpec => { :details => { :fileType => true, :fileSize => false, :fileOwner => false, :modification => false } } ).wait_for_completion dsDirectories = result.file.grep(RbVmomi::VIM::FolderFileInfo).map(&:path) puts "Checking for any VMs that got added inbetween ..." addedVms = ds.vm - vms if addedVms.length > 0 puts "Processing #{addedVms.length} new VMs ..." vmFiles.merge!(pc.collectMultiple addedVms, 'layoutEx.file') end begin perDSUsage = pc.collectMultiple vms, 'storage.perDatastoreUsage' rescue RbVmomi::Fault => ex if ex.fault.is_a?(RbVmomi::VIM::ManagedObjectNotFound) vms = vms - [ex.fault.obj] retry end perDSUsage = [] raise end puts "Cross-referencing VM files with files on datastore '#{dsName}' ..." vmFilenameHash = Hash[vmFiles.map do |vm, info| [ vm, info["layoutEx.file"].map{|x| x.name}.select{|x| x =~ /^\[#{dsName}\] /}.map{|x| x.gsub(/^\[#{dsName}\] /, '')} ] end] filenames = vmFilenameHash.values.flatten(1) vmDirectories = filenames.map{ |x| x.split('/').first }.uniq orphanDirectories = (dsDirectories - vmDirectories).reject { |x| x =~ /^\./ } puts "Found #{orphanDirectories.length} potentially orphaned directories" puts "Composing list of potentially orphaned files ... (this may take a while)" data = orphanDirectories.map do |dir| begin result = dsBrowser.SearchDatastoreSubFolders_Task( :datastorePath => "[#{dsName}] #{dir}/", :searchSpec => { :details => { :fileType => false, :fileSize => true, :fileOwner => false, :modification => false } } ).wait_for_completion files = result.map(&:file).flatten dirSize = files.map(&:fileSize).sum $stdout.write "." $stdout.flush [dir, dirSize, files.length] rescue puts "failed to search #{dir.inspect}: #{$!.}" nil end end.compact puts puts if data.empty? puts "No orphans found" else puts(Terminal::Table.new do data.sort_by { |a| a[1] }.each do |x| dir, dirSize, numFiles = x self.headings = 'Directory', 'Space Used', '# Files' add_row [dir, "#{dirSize.metric}B", numFiles] end end) end puts totalSize = data.map{|x| x[1]}.sum dsSummary = ds.summary vmDsUsage = perDSUsage.map{|vm, x| x['storage.perDatastoreUsage'].find{|y| y.datastore == ds}}.reject{|x| x == nil} committed = vmDsUsage.map{|x| x.committed}.sum unshared = vmDsUsage.map{|x| x.unshared}.sum otherSpace = (dsSummary.capacity - dsSummary.freeSpace) - unshared puts "Provisioned on Datastore: #{dsSummary.uncommitted.metric}B" puts "Capacity of Datastore: #{dsSummary.capacity.metric}B" puts "Free Space on Datastore: #{dsSummary.freeSpace.metric}B" puts "VMs Provisioned on Datastore: #{vmDsUsage.map(&:uncommitted).sum.metric}B" puts "VMs Used on Datastore: #{committed.metric}B" puts "VMs Unshared on Datastore: #{vmDsUsage.map(&:unshared).sum.metric}B" puts "Unaccounted space: #{otherSpace.metric}B" puts "Total size of detected potential orphans: #{totalSize.metric}B" puts results = data.map do |dirInfo| RbVmomi::VIM::Datastore::FakeDatastoreFolder.new(ds, "#{dirInfo[0]}") end opts[:mark] ||= "#{dsName}_orphans" shell.cmds.mark.mark opts[:mark], results puts "Saved results to mark '#{opts[:mark]}'" i = 0 results.each do |r| display_path = r.path puts "#{i} #{display_path}" shell.cmds.mark.mark i.to_s, [r] i += 1 end end |
#find_vmrc(arch, version) ⇒ Object
50 51 52 53 54 55 56 57 58 59 |
# File 'lib/rvc/modules/vmrc.rb', line 50 def find_vmrc arch, version path = if version == '3.0.0' basename = ON_WINDOWS ? 'vmware-vmrc.exe' : 'vmware-vmrc' File.join(local_vmrc_dir(arch), version, 'plugins', basename) else fail "VMRC5 not yet supported on win32" if ON_WINDOWS File.join(local_vmrc_dir(arch), version, 'vmware-vmrc-5.0', 'run.sh') end File.exists?(path) && path end |
#find_vmx_files(ds) ⇒ Object
604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 |
# File 'lib/rvc/modules/vm.rb', line 604 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 |
#get(objs) ⇒ Object
44 45 46 47 48 49 50 |
# File 'lib/rvc/modules/role.rb', line 44 def get name role = cur_auth_mgr.roleList.find { |x| x.name == name } err "no such role #{name.inspect}" unless role puts "label: #{role.info.label}" puts "summary: #{role.info.summary}" puts "privileges: #{role.privilege.sort * ' '}" end |
#get_auth(vm, opts) ⇒ Object
97 98 99 100 101 |
# File 'lib/rvc/modules/vm_guest.rb', line 97 def get_auth vm, opts auth = @auths.fetch(vm).fetch(opts[:username]) ensure err "No credentials found. You must authenticate before executing this command." if auth.nil? end |
#get_inherited_config(obj) ⇒ Object
67 68 69 70 71 72 73 74 75 |
# File 'lib/rvc/modules/vds.rb', line 67 def get_inherited_config obj if obj.is_a?(VIM::DistributedVirtualSwitch) nil elsif obj.is_a?(VIM::DistributedVirtualPortgroup) obj.config.distributedVirtualSwitch.config.defaultPortConfig elsif obj.is_a?(VIM::DistributedVirtualPort) obj.rvc_parent.config.defaultPortConfig end end |
#help(input) ⇒ Object
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
# File 'lib/rvc/modules/basic.rb', line 48 def help input if input cmdpath, args = Shell.parse_input input o = shell.cmds.lookup(cmdpath, Namespace) || shell.cmds.lookup(cmdpath) RVC::Util.err "invalid command or namespace" unless o else o = shell.cmds end case o when Command o.parser.educate when Namespace help_namespace o end # TODO apropos puts (<<-EOS) To see commands in a namespace: help namespace_name To see detailed help for a command: help namespace_name.command_name EOS end |
#help_namespace(ns) ⇒ Object
TODO namespace summaries
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
# File 'lib/rvc/modules/basic.rb', line 73 def help_namespace ns unless ns.namespaces.empty? puts "Namespaces:" ns.namespaces.sort_by do |child_name,child| HELP_ORDER.index(child_name.to_s) || HELP_ORDER.size end.each do |child_name,child| puts child_name end end puts unless ns.namespaces.empty? or ns.commands.empty? unless ns.commands.empty? puts "Commands:" ns.commands.sort_by do |cmd_name,cmd| HELP_ORDER.index(cmd_name.to_s) || HELP_ORDER.size end.each do |cmd_name,cmd| help_summary cmd end end end |
#help_summary(cmd) ⇒ Object
95 96 97 98 99 |
# File 'lib/rvc/modules/basic.rb', line 95 def help_summary cmd aliases = shell.cmds.aliases.select { |k,v| shell.cmds.lookup(v) == cmd }.map(&:first) aliases_text = aliases.empty? ? '' : " (#{aliases*', '})" puts "#{cmd.name}#{aliases_text}: #{cmd.summary}" end |
#http_path(dc_name, ds_name, path) ⇒ Object
98 99 100 |
# File 'lib/rvc/modules/datastore.rb', line 98 def http_path dc_name, ds_name, path "/folder/#{URI.escape path}?dcPath=#{URI.escape dc_name}&dsName=#{URI.escape ds_name}" end |
#info(obj) ⇒ Object
264 265 266 267 268 269 270 271 |
# File 'lib/rvc/modules/basic.rb', line 264 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(dev, iso) ⇒ Object
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 |
# File 'lib/rvc/modules/device.rb', line 174 def insert_cdrom dev, iso vm = dev.rvc_vm backing = VIM.VirtualCdromIsoBackingInfo(:fileName => iso.datastore_path) spec = { :deviceChange => [ { :operation => :edit, :device => dev.class.new( :key => dev.key, :controllerKey => dev.controllerKey, :backing => backing) } ] } progress [vm.ReconfigVM_Task(:spec => spec)] end |
#install ⇒ Object
132 133 134 135 136 137 138 139 140 |
# File 'lib/rvc/modules/vmrc.rb', line 132 def install err "No VMRC available for architecture #{ARCH}" unless VMRC_CHECKSUMS.member? ARCH zip_filename = "#{local_vmrc_dir(ARCH)}.zip" url = vmrc_url ARCH download url, zip_filename verify zip_filename, VMRC_CHECKSUMS[ARCH] extract zip_filename, local_vmrc_dir(ARCH) puts "VMRC was installed successfully." end |
#ip(vms) ⇒ Object
466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 |
# File 'lib/rvc/modules/vm.rb', line 466 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 |
#keychain_password(username, hostname) ⇒ Object
150 151 152 153 154 155 156 157 158 159 160 161 162 |
# File 'lib/rvc/modules/vim.rb', line 150 def keychain_password username , hostname return nil unless RbConfig::CONFIG['host_os'] =~ /^darwin1[01]/ begin require 'osx_keychain' rescue LoadError return nil end keychain = OSXKeychain.new return keychain["rvc", "#{username}@#{hostname}" ] end |
#kill(vms) ⇒ Object
276 277 278 279 280 |
# File 'lib/rvc/modules/vm.rb', line 276 def kill vms on_vms = vms.select { |x| x.summary.runtime.powerState == 'poweredOn' } off on_vms unless on_vms.empty? shell.cmds.basic.destroy vms unless vms.empty? end |
#layout(vm) ⇒ Object
311 312 313 314 315 |
# File 'lib/rvc/modules/vm.rb', line 311 def layout vm vm.layoutEx.file.each do |f| puts "#{f.type}: #{f.name}" end end |
#leaves(roots, types = []) ⇒ Object
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
# File 'lib/rvc/modules/find.rb', line 66 def leaves roots, types = [] leaves = Set.new new_nodes = roots while not new_nodes.empty? nodes = new_nodes new_nodes = Set.new nodes.each do |node| if (node.class.traverse? or roots.member? node) and (types & (node.field('type') || [])).empty? node.children.each { |k,v| v.rvc_link(node, k); new_nodes << v } else leaves << node end end end leaves end |
#list ⇒ Object
65 66 67 |
# File 'lib/rvc/modules/mark.rb', line 65 def list shell.fs.marks.each { |k,v| puts k } end |
#list_auth(vm) ⇒ Object
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
# File 'lib/rvc/modules/vm_guest.rb', line 56 def list_auth vm if @auths.nil? puts "No credentials available." return end if vm.nil? auth_list = @auths elsif !@auths.member? vm puts "No credentials available." return else auth_list = { vm => @auths[vm] } end auth_list.each_key do |vmkey| puts vmkey.rvc_path_str auth_list[vmkey].each_key do |userkey| puts " #{userkey}" end end end |
#local_vmrc_dir(arch) ⇒ Object
42 43 44 |
# File 'lib/rvc/modules/vmrc.rb', line 42 def local_vmrc_dir arch File.join(Dir.tmpdir, "vmware-vmrc-#{arch}-#{Process.uid}-#{PACKAGE_VERSION}") end |
#logbundles(servers, opts) ⇒ Object
273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 |
# File 'lib/rvc/modules/vim.rb', line 273 def logbundles servers, opts vim = single_connection servers diagMgr = vim.serviceContent.diagnosticManager name = vim.host FileUtils.mkdir_p opts[:dest] hosts = servers.grep VIM::HostSystem include_default = servers.member? vim puts "#{Time.now}: Generating log bundles..." bundles = begin diagMgr.GenerateLogBundles_Task( :includeDefault => include_default, :host => hosts ).wait_for_completion rescue VIM::TaskInProgress $!.task.wait_for_completion end dest_path = nil bundles.each do |b| uri = URI.parse(b.url.sub('*', DEFAULT_SERVER_PLACEHOLDER)) bundle_name = b.system ? b.system.name : name dest_path = File.join(opts[:dest], "#{bundle_name}-" + File.basename(uri.path)) puts "#{Time.now}: Downloading bundle #{b.url} to #{dest_path}" uri.host = vim.http.address if uri.host == DEFAULT_SERVER_PLACEHOLDER Net::HTTP.get_response uri do |res| File.open dest_path, 'w' do |io| res.read_body do |data| io.write data if $stdout.tty? $stdout.write '.' $stdout.flush end end end puts if $stdout.tty? end end dest_path end |
#lookup_esxcli(host, args) ⇒ Object
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
# File 'lib/rvc/modules/esxcli.rb', line 29 def lookup_esxcli host, args cur = EsxcliCache[host, :esxcli] i = 0 while i < args.length k = args[i] if cur.namespaces.member? k cur = cur.namespaces[k] elsif cur.commands.member? k cur = cur.commands[k] break else err "nonexistent esxcli namespace or command #{k.inspect}" end i += 1 end return cur end |
#ls(obj) ⇒ Object
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 184 185 186 187 188 189 190 191 |
# File 'lib/rvc/modules/basic.rb', line 144 def ls obj if obj.respond_to?(:rvc_ls) return obj.rvc_ls end 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.cmds.mark.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 overallStatus), } 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'] colored_name = status_color name, r['overallStatus'] puts "#{i} #{colored_name}#{realname && " [#{realname}]"}#{text}" r.obj.rvc_link obj, name shell.cmds.mark.mark i.to_s, [r.obj] i += 1 end end |
#ls_guest(vm, opts) ⇒ Object
327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 |
# File 'lib/rvc/modules/vm_guest.rb', line 327 def ls_guest vm, opts guestOperationsManager = vm._connection.serviceContent.guestOperationsManager err "This command requires vSphere 5 or greater" unless guestOperationsManager.respond_to? :fileManager fileManager = guestOperationsManager.fileManager auth = get_auth vm, opts files = fileManager. ListFilesInGuest( :vm => vm, :auth => auth, :filePath => opts[:guest_path], :index => opts[:index], :maxResults => opts[:max_results], :matchPattern => opts[:match_pattern] ) files.files.each do |file| puts file.path end puts "Remaining: #{files.remaining}" unless files.remaining.zero? return files end |
#mark(key, objs) ⇒ Object
32 33 34 35 |
# File 'lib/rvc/modules/mark.rb', line 32 def mark key, objs err "invalid mark name" unless key =~ /^\w+$/ shell.fs.marks[key] = objs end |
#merge_ranges(ranges) ⇒ Object
307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 |
# File 'lib/rvc/modules/vds.rb', line 307 def merge_ranges(ranges) ranges = ranges.sort_by {|r| r.first } if !ranges.empty? *outages = ranges.shift else outages = [] end ranges.each do |r| lastr = outages[-1] if lastr.last >= r.first - 1 outages[-1] = lastr.first..[r.last, lastr.last].max else outages.push(r) end end outages end |
#migrate(vms, opts) ⇒ Object
504 505 506 507 508 |
# File 'lib/rvc/modules/vm.rb', line 504 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
362 363 364 365 |
# File 'lib/rvc/modules/basic.rb', line 362 def mkdir path parent = lookup_single! File.dirname(path), RbVmomi::VIM::Folder parent.CreateFolder(:name => File.basename(path)) end |
#mktmpdir(vm, opts) ⇒ Object
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 |
# File 'lib/rvc/modules/vm_guest.rb', line 147 def mktmpdir vm, opts guestOperationsManager = vm._connection.serviceContent.guestOperationsManager err "This command requires vSphere 5 or greater" unless guestOperationsManager.respond_to? :fileManager fileManager = guestOperationsManager.fileManager auth = get_auth vm, opts dirname = fileManager. CreateTemporaryDirectoryInGuest( :vm => vm, :auth => auth, :prefix => opts[:prefix], :suffix => opts[:suffix], :directoryPath => opts[:guest_path] ) puts dirname return dirname end |
#mktmpfile(vm, opts) ⇒ Object
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 |
# File 'lib/rvc/modules/vm_guest.rb', line 176 def mktmpfile vm, opts guestOperationsManager = vm._connection.serviceContent.guestOperationsManager err "This command requires vSphere 5 or greater" unless guestOperationsManager.respond_to? :fileManager fileManager = guestOperationsManager.fileManager auth = get_auth vm, opts filename = fileManager. CreateTemporaryFileInGuest( :vm => vm, :auth => auth, :prefix => opts[:prefix], :suffix => opts[:suffix], :directoryPath => opts[:guest_path] ) puts filename return filename end |
#modify_cpu(vm, opts) ⇒ Object
584 585 586 587 |
# File 'lib/rvc/modules/vm.rb', line 584 def modify_cpu vm, opts spec = { :numCPUs => opts[:num] } tasks [vm], :ReconfigVM, :spec => spec end |
#modify_memory(vm, opts) ⇒ Object
596 597 598 599 600 601 |
# File 'lib/rvc/modules/vm.rb', line 596 def modify_memory vm, opts err "VM needs to be off" unless vm.summary.runtime.powerState == 'poweredOff' err "memory must be a multiple of 4MB" unless ( opts[:size] % 4 ) == 0 spec = { :memoryMB => opts[:size] } tasks [vm], :ReconfigVM, :spec => spec end |
#mv(objs) ⇒ Object
321 322 323 324 325 |
# File 'lib/rvc/modules/basic.rb', line 321 def mv objs err "Destination entity missing" unless objs.size > 1 dst = objs.pop progress [dst.MoveIntoFolder_Task(:list => objs)] end |
#mvdir(vm, opts) ⇒ Object
387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 |
# File 'lib/rvc/modules/vm_guest.rb', line 387 def mvdir vm, opts guestOperationsManager = vm._connection.serviceContent.guestOperationsManager err "This command requires vSphere 5 or greater" unless guestOperationsManager.respond_to? :fileManager fileManager = guestOperationsManager.fileManager auth = get_auth vm, opts fileManager. MoveDirectoryInGuest( :vm => vm, :auth => auth, :srcDirectoryPath => opts[:src_guest_path], :dstDirectoryPath => opts[:dst_guest_path] ) end |
#mvfile(vm, opts) ⇒ Object
413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 |
# File 'lib/rvc/modules/vm_guest.rb', line 413 def mvfile vm, opts guestOperationsManager = vm._connection.serviceContent.guestOperationsManager err "This command requires vSphere 5 or greater" unless guestOperationsManager.respond_to? :fileManager fileManager = guestOperationsManager.fileManager auth = get_auth vm, opts fileManager. MoveFileInGuest( :vm => vm, :auth => auth, :srcFilePath => opts[:src_guest_path], :dstFilePath => opts[:dst_guest_path], :overwrite => opts[:overwrite] ) end |
#off(vm) ⇒ Object
43 44 45 |
# File 'lib/rvc/modules/vm.rb', line 43 def off vms tasks vms, :PowerOffVM end |
#on(vms) ⇒ Object
31 32 33 |
# File 'lib/rvc/modules/vm.rb', line 31 def on vms tasks vms, :PowerOnVM end |
#output_formatted(cmd, result) ⇒ Object
119 120 121 122 123 124 125 126 127 128 129 130 |
# File 'lib/rvc/modules/esxcli.rb', line 119 def output_formatted cmd, result hints = Hash[cmd.cli_info.hints] formatter = hints['formatter'] formatter = "none" if formatter == "" sym = :"output_formatted_#{formatter}" if respond_to? sym send sym, result, cmd.cli_info, hints else puts "Unknown formatter #{formatter.inspect}" pp result end end |
#output_formatted_none(result, info, hints) ⇒ Object
132 133 134 |
# File 'lib/rvc/modules/esxcli.rb', line 132 def output_formatted_none result, info, hints pp result if result != true end |
#output_formatted_simple(result, info, hints) ⇒ Object
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
# File 'lib/rvc/modules/esxcli.rb', line 136 def output_formatted_simple result, info, hints case result when Array result.each do |r| output_formatted_simple r, info, hints puts end when RbVmomi::BasicTypes::DataObject prop_descs = result.class.ancestors. take_while { |x| x != RbVmomi::BasicTypes::DataObject && x != VIM::DynamicData }. map(&:props_desc).flatten(1) prop_descs.each do |desc| print "#{desc['name']}: " pp result.send desc['name'] end else pp result end end |
#output_formatted_table(result, info, hints) ⇒ Object
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 |
# File 'lib/rvc/modules/esxcli.rb', line 161 def output_formatted_table result, info, hints if result.empty? puts "Empty result" return end columns = if hints.member? 'table-columns' hints['table-columns'].split ',' elsif k = hints.keys.find { |k| k =~ /^fields:/ } hints[k].split ',' else [] end ordering = columns.map { |x| table_key x } units = Hash[hints.select { |k,v| k =~ /^units:/ }.map { |k,v| [table_key(k.match(/[^.]+$/).to_s), v] }] table = Terminal::Table.new :headings => columns result.each do |r| row = [] r.class.full_props_desc.each do |desc| name = desc['name'] key = table_key name next unless idx = ordering.index(key) val = r.send name unit = units[key] row[idx] = case unit when nil then val when '%' then "#{val}#{unit}" else "#{val} #{unit}" end end table.add_row row end puts table end |
#permissions(name) ⇒ Object
58 59 60 61 62 63 64 65 66 67 |
# File 'lib/rvc/modules/role.rb', line 58 def name role = cur_auth_mgr.roleList.find { |x| x.name == name } err "no such role #{name.inspect}" unless role cur_auth_mgr.RetrieveRolePermissions(:roleId => role.roleId).each do |perm| flags = [] flags << 'group' if perm[:group] flags << 'propagate' if perm[:propagate] puts " #{perm[:principal]}#{flags.empty? ? '' : " (#{flags * ', '})"}: #{perm.entity.name}" end end |
#pick_controller(vm, controller, controller_classes) ⇒ Object
297 298 299 300 301 302 303 304 305 306 307 308 309 310 |
# File 'lib/rvc/modules/device.rb', line 297 def pick_controller vm, controller, controller_classes existing_devices, = vm.collect 'config.hardware.device' controller ||= existing_devices.find do |dev| controller_classes.any? { |klass| dev.is_a? klass } && dev.device.length < 2 end err "no suitable controller found" unless controller used_unit_numbers = existing_devices.select { |dev| dev.controllerKey == controller.key }.map(&:unitNumber) unit_number = (used_unit_numbers.max||-1) + 1 [controller, unit_number] end |
#ping(vm) ⇒ Object
455 456 457 458 |
# File 'lib/rvc/modules/vm.rb', line 455 def ping vm ip = vm_ip vm system_fg "ping #{Shellwords.escape ip}" end |
#plot(counter_name, objs, opts) ⇒ Object
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 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 |
# File 'lib/rvc/modules/perf.rb', line 82 def plot counter_name, objs, opts require_gnuplot vim = single_connection objs pm = vim.serviceContent.perfManager group_key, counter_key, rollup_type = counter_name.split('.', 3) now = Time.now opts[:end] ||= now opts[:start] ||= opts[:end] - 1800 err "end time is in the future" unless opts[:end] <= Time.now interval_id, display_timefmt = find_interval pm, opts[:start] all_counters = Hash[pm.perfCounter.map { |x| [x.key, x] }] metrics = pm.QueryAvailablePerfMetric( :entity => objs.first, :interval => interval_id) metric = metrics.find do |metric| counter = all_counters[metric.counterId] counter.groupInfo.key == group_key && counter.nameInfo.key == counter_key end or err "counter #{group_key}.#{counter_key} was not found in the #{interval_id}s interval" counter = all_counters[metric.counterId] specs = objs.map do |obj| { :entity => obj, :metricId => [metric], :intervalId => interval_id, :startTime => opts[:start], :endTime => opts[:end], :format => 'csv', } end with_gnuplot(true) do |gp| plot = Gnuplot::Plot.new(gp) do |plot| if objs.size == 1 plot.title "#{counter_name} on #{objs[0].name}" else plot.title counter_name end plot.ylabel counter.unitInfo.label plot.xlabel "Time" plot.terminal 'dumb' if opts[:terminal] plot.set 'xdata', 'time' plot.set 'format', "x '#{display_timefmt}'" plot.set 'timefmt', TIMEFMT.inspect if counter.unitInfo.key == 'percent' plot.set 'yrange', '[0:100]' end plot.data = retrieve_datasets pm, counter, specs end gp.puts end end |
#prompt_password ⇒ Object
146 147 148 |
# File 'lib/rvc/modules/vim.rb', line 146 def prompt_password ask("password: ") { |q| q.echo = false } end |
#quit ⇒ Object
31 32 33 |
# File 'lib/rvc/modules/core.rb', line 31 def quit exit end |
#rdp(vms, h) ⇒ Object
429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 |
# File 'lib/rvc/modules/vm.rb', line 429 def rdp vms, h resolution = h[:resolution] if !resolution resolution = $rdpResolution ? $rdpResolution : '1024x768' end vms.each do |vm| ip = vm_ip vm begin timeout(1) { TCPSocket.new ip, 3389; up = true } rescue puts "#{vm.name}: Warning: Looks like the RDP port is not responding" end cmd = "rdesktop -u '#{h[:username]}' -p '#{h[:password]}' -g#{resolution} #{ip} >/dev/null 2>&1 &" system(cmd) end end |
#reachable_ip(host) ⇒ Object
72 73 74 75 76 77 78 79 80 81 |
# File 'lib/rvc/modules/vnc.rb', line 72 def reachable_ip host ips = host.collect('config.network.vnic')[0].map { |x| x.spec.ip.ipAddress } 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
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
# File 'lib/rvc/modules/host.rb', line 30 def reboot hosts, opts tasks hosts, :RebootHost, :force => opts[:force] if opts[:wait] puts "Waiting for hosts to reboot ..." # There is no proper way to wait for a host to reboot, so we # implement a heuristic that is close enough: # First we wait for a moment to give the host time to actually # disconnect. Then we just wait for it to be responding again. sleep 3 * 60 hosts.each do |host| # We could use the property collector here to wait for an # update instead of polling. while !(host.runtime.connectionState == "connected" && host.runtime.powerState == "poweredOn") sleep 10 end puts "Host #{host.name} is back up" end end end |
#reboot_guest(vms) ⇒ Object
126 127 128 |
# File 'lib/rvc/modules/vm.rb', line 126 def reboot_guest vms vms.each(&:RebootGuest) end |
#recommendations(cluster) ⇒ Object
96 97 98 99 100 101 102 103 104 105 106 107 108 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 |
# File 'lib/rvc/modules/cluster.rb', line 96 def recommendations cluster # Collect everything we need from VC with as few calls as possible pc = cluster._connection.serviceContent.propertyCollector recommendation, hosts, datastores = cluster.collect 'recommendation', 'host', 'datastore' if recommendation.length == 0 puts "None" return end targets = recommendation.map { |x| x.target } recommendation.each { |x| targets += x.action.map { |y| y.target } } targets += hosts targets += datastores targets.compact! name_map = pc.collectMultiple(targets, 'name') # Compose the output (tries to avoid making any API calls) out = Terminal::Table.new(['Key', 'Reason', 'Target', 'Actions']) do recommendation.each do |r| target_name = r.target ? name_map[r.target]['name'] : "" actions = r.action.map do |a| action = "#{a.class.wsdl_name}: #{name_map[a.target]['name']}" dst = nil if a.is_a?(RbVmomi::VIM::ClusterMigrationAction) dst = a.drsMigration.destination end if a.is_a?(RbVmomi::VIM::StorageMigrationAction) dst = a.destination end if dst if !name_map[dst] name_map[dst] = {'name' => dst.name} end action += " (to #{name_map[dst]['name']})" end action end add_row [r.key, r.reasonText, target_name, actions.join("\n")] end end puts out end |
#reconnect(hosts, opts) ⇒ Object
143 144 145 146 147 148 149 150 |
# File 'lib/rvc/modules/host.rb', line 143 def reconnect hosts, opts spec = { :force => false, :userName => opts[:username], :password => opts[:password], } tasks hosts, :ReconnectHost end |
#register(vmx_file, opts) ⇒ Object
198 199 200 201 202 203 |
# File 'lib/rvc/modules/vm.rb', line 198 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(opts) ⇒ Object
43 44 45 46 47 48 49 50 51 |
# File 'lib/rvc/modules/core.rb', line 43 def reload opts old_verbose = $VERBOSE $VERBOSE = nil unless opts[:verbose] shell.reload_modules opts[:verbose] RbVmomi::VIM.reload_extensions ensure $VERBOSE = old_verbose end |
#reload_entity(objs) ⇒ Object
293 294 295 |
# File 'lib/rvc/modules/basic.rb', line 293 def reload_entity objs objs.each(&:Reload) end |
#remove(objs, opts) ⇒ Object
50 51 52 53 54 55 56 57 58 59 60 61 62 |
# File 'lib/rvc/modules/device.rb', line 50 def remove devs, opts vm_devs = devs.group_by(&:rvc_vm) tasks = vm_devs.map do |vm,my_devs| device_changes = my_devs.map do |dev| fileOp = (dev.backing.is_a?(VIM::VirtualDeviceFileBackingInfo) && !opts[:no_destroy]) ? 'destroy' : nil { :operation => :remove, :fileOperation => fileOp, :device => dev } end spec = { :deviceChange => device_changes } vm.ReconfigVM_Task(:spec => spec) end progress tasks end |
#remove_privilege(name, privileges) ⇒ Object
131 132 133 134 135 136 137 138 |
# File 'lib/rvc/modules/role.rb', line 131 def remove_privilege name, privileges role = cur_auth_mgr.roleList.find { |x| x.name == name } err "no such role #{name.inspect}" unless role cur_auth_mgr.UpdateAuthorizationRole :roleId => role.roleId, :newName => role.name, :privIds => (role.privilege - privileges) end |
#rename(snapshot, name) ⇒ Object
100 101 102 103 104 105 106 |
# File 'lib/rvc/modules/role.rb', line 100 def rename old, new role = cur_auth_mgr.roleList.find { |x| x.name == old } err "no such role #{old.inspect}" unless role cur_auth_mgr.UpdateAuthorizationRole :roleId => role.roleId, :newName => new, :privIds => role.privilege end |
#require_gnuplot ⇒ Object
33 34 35 36 37 38 39 40 41 42 43 44 |
# File 'lib/rvc/modules/perf.rb', line 33 def require_gnuplot begin require 'gnuplot' rescue LoadError Gem::Specification.reset begin require 'gnuplot' rescue LoadError err "The gnuplot gem is not installed" end end end |
#rescan_storage(hosts) ⇒ Object
199 200 201 202 203 204 205 |
# File 'lib/rvc/modules/host.rb', line 199 def rescan_storage hosts hosts.each do |host| storageSystem = host.configManager.storageSystem storageSystem.RescanAllHba storageSystem.RescanVmfs end end |
#reset(vms) ⇒ Object
56 57 58 |
# File 'lib/rvc/modules/vm.rb', line 56 def reset vms tasks vms, :ResetVM end |
#retrieve_datasets(pm, counter, specs) ⇒ Object
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 |
# File 'lib/rvc/modules/perf.rb', line 146 def retrieve_datasets pm, counter, specs results = pm.QueryPerf(:querySpec => specs) datasets = results.map do |result| times = result.sampleInfoCSV.split(',').select { |x| x['T'] } if result.value.empty? puts "No data for #{result.entity.name} #{counter.name}" next end data = result.value[0].value.split(',').map(&:to_i) if counter.unitInfo.key == 'percent' times.length.times do |i| times[i] = data[i] = nil if data[i] < 0 end times.compact! data.compact! data.map! { |x| x/100.0 } end Gnuplot::DataSet.new([times, data]) do |ds| ds.notitle if specs.size == 1 ds.with = "lines" ds.using = '1:2' ds.title = result.entity.name end end.compact end |
#revert(arg) ⇒ Object
45 46 47 48 49 50 51 |
# File 'lib/rvc/modules/snapshot.rb', line 45 def revert arg if arg.is_a? VIM::VirtualMachine tasks [arg], :RevertToCurrentSnapshot else tasks [arg.find_tree.snapshot], :RevertToSnapshot end end |
#rmdir(vm, opts) ⇒ Object
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 |
# File 'lib/rvc/modules/vm_guest.rb', line 204 def rmdir vm, opts guestOperationsManager = vm._connection.serviceContent.guestOperationsManager err "This command requires vSphere 5 or greater" unless guestOperationsManager.respond_to? :fileManager fileManager = guestOperationsManager.fileManager auth = get_auth vm, opts fileManager. DeleteDirectoryInGuest( :vm => vm, :auth => auth, :directoryPath => opts[:guest_path], :recursive => opts[:recursive] ) end |
#rmfile(vm, opts) ⇒ Object
228 229 230 231 232 233 234 235 236 237 238 239 240 241 |
# File 'lib/rvc/modules/vm_guest.rb', line 228 def rmfile vm, opts guestOperationsManager = vm._connection.serviceContent.guestOperationsManager err "This command requires vSphere 5 or greater" unless guestOperationsManager.respond_to? :fileManager fileManager = guestOperationsManager.fileManager auth = get_auth vm, opts fileManager. DeleteFileInGuest( :vm => vm, :auth => auth, :filePath => opts[:guest_path] ) end |
#rvc(vm, opts) ⇒ Object
409 410 411 412 413 414 415 416 417 |
# File 'lib/rvc/modules/vm.rb', line 409 def rvc vm, opts 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 #{opts[:user] && Shellwords.escape("#{opts[:user]}@")}#{Shellwords.escape ip}" system_fg(cmd, env) end |
#save_keychain_password(username, password, hostname) ⇒ Object
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 |
# File 'lib/rvc/modules/vim.rb', line 164 def save_keychain_password username , password , hostname # only works for OSX at the minute. return false unless RbConfig::CONFIG['host_os'] =~ /^darwin10/ # check we already managed to load that gem. if defined? OSXKeychain::VERSION if agree("Save password for connection (y/n)? ", true) keychain = OSXKeychain.new # update the keychain, unless it's already set to that. keychain.set("rvc", "#{username}@#{hostname}" , password ) unless keychain["rvc", "#{username}@#{hostname}" ] == password end else return false end end |
#screenshot(vm, local_path) ⇒ Object
649 650 651 |
# File 'lib/rvc/modules/vm.rb', line 649 def screenshot vm, local_path http_download vm._connection, "/screen?id=#{vm._ref}", local_path end |
#security(obj, opts) ⇒ Object
376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 |
# File 'lib/rvc/modules/vds.rb', line 376 def security obj, opts if (opts[:allow_promisc] and opts[:deny_promisc]) or (opts[:allow_mac_changes] and opts[:deny_mac_changes]) or (opts[:allow_forged] and opts[:deny_forged]) puts "Can't both allow and deny!" return end policy = { :inherited => false } if opts[:allow_promisc] policy[:allowPromiscuous] = { :inherited => false, :value => true } elsif opts[:deny_promisc] policy[:allowPromiscuous] = { :inherited => false, :value => false } end if opts[:allow_mac_changes] policy[:macChanges] = { :inherited => false, :value => true } elsif opts[:deny_mac_changes] policy[:macChanges] = { :inherited => false, :value => false } end if opts[:allow_forged] policy[:forgedTransmits] = { :inherited => false, :value => true } elsif opts[:deny_forged] policy[:forgedTransmits] = { :inherited => false, :value => false } end inherited_spec = get_inherited_config(obj) if inherited_spec != nil collapse_inheritance inherited_spec.securityPolicy, policy end spec = VIM::VMwareDVSPortSetting.new() spec.securityPolicy = policy apply_settings obj, spec end |
#set(objs, opts) ⇒ Object
54 55 56 57 58 59 60 61 62 63 64 65 66 |
# File 'lib/rvc/modules/permissions.rb', line 54 def set objs, opts conn = single_connection objs authMgr = conn.serviceContent. role = authMgr.roleList.find { |x| x.name == opts[:role] } err "no such role #{role.inspect}" unless role perm = { :roleId => role.roleId, :principal => opts[:principal], :group => opts[:group], :propagate => opts[:propagate] } objs.each do |obj| authMgr.SetEntityPermissions(:entity => obj, :permission => [perm]) end end |
#set_extra_config(vm, pairs) ⇒ Object
361 362 363 364 |
# File 'lib/rvc/modules/vm.rb', line 361 def set_extra_config vm, pairs h = Hash[pairs.map { |x| x.split('=', 2).tap { |a| a << '' if a.size == 1 } }] _set_extra_config vm, h end |
#set_respool(obj, respool) ⇒ Object
434 435 436 437 |
# File 'lib/rvc/modules/vds.rb', line 434 def set_respool obj, respool apply_settings obj, {:networkResourcePoolKey => {:inherited => false, :value => respool.key} } end |
#shaper(obj, opts) ⇒ Object
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 177 178 179 |
# File 'lib/rvc/modules/vds.rb', line 138 def shaper obj, opts if !(opts[:tx] or opts[:rx]) or (opts[:tx] and opts[:rx]) puts "Need to configure either Rx or Tx Shaping!" return end if opts[:enable] and opts[:disable] puts "Can't both enable and disable traffic shaping!" return end shaper_spec = { :inherited => false} if opts[:enable] shaper_spec[:enabled] = { :value => true, :inherited => false } end if opts[:disable] shaper_spec[:enabled] = { :value => false, :inherited => false } end if opts[:average_bw] shaper_spec[:averageBandwidth] = { :value => (opts[:average_bw] * 1000), :inherited => false } end if opts[:burst_size] shaper_spec[:burstSize] = { :value => (opts[:burst_size] * 1000), :inherited => false } end if opts[:peak_bw] shaper_spec[:peakBandwidth] = { :value => (opts[:peak_bw] * 1000), :inherited => false } end if opts[:rx] port_spec = { :inShapingPolicy => shaper_spec } else port_spec = { :outShapingPolicy => shaper_spec } end apply_settings obj, port_spec end |
#shares_from_string(str) ⇒ Object
37 38 39 40 41 42 43 44 45 46 |
# File 'lib/rvc/modules/resource_pool.rb', line 37 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
30 31 32 33 34 35 36 37 |
# File 'lib/rvc/modules/alarm.rb', line 30 def show objs alarm_states = objs.map(&:triggeredAlarmState).flatten.uniq alarm_states.each do |alarm_state| info = alarm_state.alarm.info colored_alarm_status = status_color alarm_state.overallStatus, alarm_state.overallStatus puts "#{alarm_state.entity.name}: #{info.name} (#{colored_alarm_status}): #{info.description}" end end |
#show_all_portgroups(path) ⇒ Object
460 461 462 463 464 465 466 467 468 469 470 471 472 473 |
# File 'lib/rvc/modules/vds.rb', line 460 def show_all_portgroups path paths = path.map { |p| p.rvc_path_str } if paths.empty? paths = nil end vds = shell.cmds.find.find_items nil, paths, ['vds'] pgs = [] vds.each do |v| v.portgroup.each { |pg| pgs << pg} end shell.cmds.basic.table pgs, { :field => ["vds_name", "name", "vlan"], :field_given => true } end |
#show_all_ports(path) ⇒ Object
498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 |
# File 'lib/rvc/modules/vds.rb', line 498 def show_all_ports path rows = [] num_vds = 0 num_pgs = 0 path.each do |obj| if obj.class < VIM::DistributedVirtualSwitch num_vds += 1 vds = obj ports = vds.FetchDVPorts(:criteria => { :active => true }) else #obj.class < VIM::DistributedVirtualPortgroup num_pgs += 1 vds = obj.config.distributedVirtualSwitch ports = vds.FetchDVPorts(:criteria => { :portgroupKey => [obj.key], :inside => true, :active => true}) end pc = vds._connection.propertyCollector # fetch names of VMs, portgroups, vDS objects = [] ports.each do |port| objects << port.proxyHost if port.connectee objects << port.connectee.connectedEntity end end vds.portgroup.each { |pg| objects << pg } objects << vds spec = { :objectSet => objects.map { |obj| { :obj => obj } }, :propSet => [{:type => "ManagedEntity", :pathSet => %w(name) }, {:type => "DistributedVirtualPortgroup", :pathSet => %w(name key)}] } props = pc.RetrieveProperties(:specSet => [spec]) names = {} props.each do |prop| names[prop.obj] = prop['name'] if prop['key'] names[prop['key']] = prop['name'] end end vds_name = names[vds] # put each port as a row in the table ports.each do |port| port_key = begin port.key.to_i; rescue port.key; end connectee = nil hostname = names[port.proxyHost].dup if port.connectee and port.connectee.type == "vmVnic" connectee = names[port.connectee.connectedEntity] elsif port.connectee connectee = port.connectee.nicKey end rows << [port_key, port.config.name, vds_name, names[port.portgroupKey], translate_vlan(port.config.setting.vlan), port.state.runtimeInfo.blocked, hostname, connectee] end end abbrev_hostnames(rows.map { |r| r[6] }) columns = ['key', 'name', 'vds', 'portgroup', 'vlan', 'blocked', 'host', 'connectee'] # if we're just querying against a single vDS, skip the vds name column if num_vds <= 1 columns.delete_at(2) rows.each { |r| r.delete_at(2) } end # if we're just querying against one portgroup, skip portgroup name column if num_pgs <= 1 and num_vds < 1 columns.delete_at(2) rows.each { |r| r.delete_at(2) } end t = Terminal::Table.new(columns) rows.sort_by { |o| o[0] }.each { |o| t << o } puts t end |
#show_all_vds(path) ⇒ Object
480 481 482 483 484 485 486 487 488 489 |
# File 'lib/rvc/modules/vds.rb', line 480 def show_all_vds path paths = path.map { |p| p.rvc_path_str } if paths.empty? paths = nil end vds = shell.cmds.find.find_items nil, paths, ['vds'] shell.cmds.basic.table vds, { :field => ['name', 'vlans', 'hosts'], :field_given => true } end |
#show_running_config(vds) ⇒ Object
444 445 446 447 448 449 450 451 452 453 |
# File 'lib/rvc/modules/vds.rb', line 444 def show_running_config vds shell.cmds.basic.info vds portgroups = vds.children['portgroups'] portgroups.rvc_link vds, 'portgroups' vds.children['portgroups'].children.each do |name, pg| pg.rvc_link portgroups, name puts '---' shell.cmds.basic.info pg end end |
#shutdown_guest(vms, opts) ⇒ Object
105 106 107 108 |
# File 'lib/rvc/modules/vm.rb', line 105 def shutdown_guest vms, opts vms.each(&:ShutdownGuest) wait_for_shutdown vms, opts unless opts[:timeout].nil? end |
#spawn_vmrc(vmrc, moref, host, ticket) ⇒ Object
108 109 110 111 112 |
# File 'lib/rvc/modules/vmrc.rb', line 108 def spawn_vmrc vmrc, moref, host, ticket err "Ruby 1.9 required" unless Process.respond_to? :spawn Process.spawn vmrc, '-h', host, '-p', ticket, '-M', moref, :err => "#{ENV['HOME']||'.'}/.rvc-vmrc.log" end |
#ssh(vm, cmd, opts) ⇒ Object
393 394 395 396 397 398 |
# File 'lib/rvc/modules/vm.rb', line 393 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
116 117 118 |
# File 'lib/rvc/modules/vm.rb', line 116 def standby_guest vms vms.each(&:StandbyGuest) end |
#start_program(vm, opts) ⇒ Object
447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 |
# File 'lib/rvc/modules/vm_guest.rb', line 447 def start_program vm, opts guestOperationsManager = vm._connection.serviceContent.guestOperationsManager err "This command requires vSphere 5 or greater" unless guestOperationsManager.respond_to? :processManager processManager = guestOperationsManager.processManager auth = get_auth vm, opts pid = processManager. StartProgramInGuest( :vm => vm, :auth => auth, :spec => VIM.GuestProgramSpec( :arguments => opts[:arguments], :programPath => opts[:program_path], :envVariables => opts[:env], :workingDirectory => opts[:working_directory] ) ) Timeout.timeout opts[:timeout] do while true processes = processManager. ListProcessesInGuest( :vm => vm, :auth => auth, :pids => [pid] ) process = processes.first if !process.endTime.nil? if process.exitCode != 0 err "Process failed with exit code #{process.exitCode}" end break elsif opts[:background] break end sleep opts[:delay] end end rescue Timeout::Error err "Timed out waiting for process to finish." end |
#stats(metrics, objs, opts) ⇒ Object
315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 |
# File 'lib/rvc/modules/perf.rb', line 315 def stats metrics, objs, opts metrics = metrics.split(",") vim = single_connection objs pm = vim.serviceContent.perfManager metrics.each do |x| err "no such metric #{x}" unless pm.perfcounter_hash.member? x end interval = pm.provider_summary(objs.first).refreshRate start_time = nil if interval == -1 # Object does not support real time stats interval = 300 start_time = Time.now - 300 * 5 end stat_opts = { :interval => interval, :startTime => start_time, } stat_opts[:max_samples] = opts[:samples] if opts[:samples] res = pm.retrieve_stats objs, metrics, stat_opts table = Terminal::Table.new table.add_row ['Object', 'Metric', 'Values', 'Unit'] table.add_separator objs.each do |obj| metrics.each do |metric| stat = res[obj][:metrics][metric] metric_info = pm.perfcounter_hash[metric] table.add_row([obj.name, metric, stat.join(','), metric_info.unitInfo.label]) end end puts table end |
#stats_time(secs) ⇒ Object
see vSphere Client: Administration -> vCenter Server Settings -> Statistics -> Statistics Intervals
25 26 27 28 29 30 31 32 33 34 35 36 |
# File 'lib/rvc/modules/statsinterval.rb', line 25 def stats_time secs length = secs / 60 [[60, "Minutes"], [24, "Hours"], [7, "Days"], [4, "Weeks"], [12, "Months"]].each do |div, name| if length < div return "#{length} #{name}" end length = length / div end return "#{length} Years" end |
#storage(root) ⇒ Object
105 106 107 108 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 |
# File 'lib/rvc/modules/resource_pool.rb', line 105 def storage root propSet = [ { :type => 'ResourcePool', :pathSet => ['name', 'parent'] }, { :type => 'VirtualMachine', :pathSet => ['name', 'parent', 'storage', 'resourcePool'] } ] filterSpec = RbVmomi::VIM.PropertyFilterSpec( :objectSet => [ :obj => root, :selectSet => [ RbVmomi::VIM.TraversalSpec( :name => 'tsResourcePool1', :type => 'ResourcePool', :path => 'resourcePool', :skip => false, :selectSet => [ RbVmomi::VIM.SelectionSpec(:name => 'tsResourcePool1'), RbVmomi::VIM.SelectionSpec(:name => 'tsResourcePool2') ] ), RbVmomi::VIM.TraversalSpec( :name => 'tsResourcePool2', :type => 'ResourcePool', :path => 'vm', :skip => false, :selectSet => [ RbVmomi::VIM.SelectionSpec(:name => 'tsResourcePool1'), RbVmomi::VIM.SelectionSpec(:name => 'tsResourcePool2') ] ) ] ], :propSet => propSet ) result = root._connection.propertyCollector.RetrieveProperties(:specSet => [filterSpec]) objs = Hash[result.map { |r| [r.obj, r] }] usages = Hash.new { |h,k| h[k] = 0 } objs.each do |obj,r| next unless obj.is_a? VIM::VirtualMachine cur = r['resourcePool'] usage = r['storage'].perDatastoreUsage.map(&:unshared).sum while cur usages[cur] += usage cur = cur == root ? nil : objs[cur]['parent'] end end children = Hash.new { |h,k| h[k] = [] } objs.each { |obj,r| children[r['parent']] << obj } display = lambda do |level,obj| puts "#{' '*level}#{objs[obj]['name']}: #{usages[obj].metric}B" children[obj].each do |child| display[level+1, child] end end display[0, root] end |
#subtract_ranges(ranges, minus_ranges) ⇒ Object
326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 |
# File 'lib/rvc/modules/vds.rb', line 326 def subtract_ranges(ranges, minus_ranges) outages = [] minus_range = minus_ranges.shift ranges.each do |r| while true if minus_range == nil or (minus_range.first > r.last) break elsif minus_range.first < r.first and minus_range.last < r.first next elsif minus_range.first <= r.first and minus_range.last < r.last r = ((minus_range.last+1)..r.last) minus_range = minus_ranges.shift next elsif minus_range.first > r.first and minus_range.last >= r.last r = (r.first..(minus_range.first-1)) break elsif minus_range.first > r.first and minus_range.last < r.last outages << (r.first..(minus_range.first-1)) r = ((minus_range.last+1)..r.last) minus_range = minus_ranges.shift break elsif minus_range.first <= r.first and minus_range.last >= r.last if minus_range.last == r.last minus_range = minus_ranges.shift end r = nil break end end if r != nil outages << r end end outages end |
#summarize(obj) ⇒ Object
30 31 32 33 34 35 36 |
# File 'lib/rvc/modules/vds.rb', line 30 def summarize obj if !obj.respond_to?(:summarize) puts "not a vds or portgroup!" return end obj.summarize end |
#suspend(vms) ⇒ Object
69 70 71 |
# File 'lib/rvc/modules/vm.rb', line 69 def suspend vms tasks vms, :SuspendVM end |
#switch(name) ⇒ Object
26 27 28 |
# File 'lib/rvc/modules/connection.rb', line 26 def switch name shell.switch_connection name end |
#table(objs, opts) ⇒ Object
439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 |
# File 'lib/rvc/modules/basic.rb', line 439 def table objs, opts if opts[:field_given] fields = opts[:field].map { |x| x.split ':' }.flatten(1) else fields = objs.map(&:class).uniq. map { |x| x.fields.select { |k,v| v.default? } }. map(&:keys).flatten(1).uniq end data = retrieve_fields(objs, fields).values if f = opts[:sort] data.sort! { |a,b| table_sort_compare a[f], b[f] } data.reverse! if opts[:reverse] end # Invert field components to get an array of header rows field_components = fields.map { |x| x.split '.' } header_rows = [] field_components.each_with_index do |cs,i| cs.each_with_index do |c,j| header_rows[j] ||= [nil]*field_components.length header_rows[j][i] = c end end table = Terminal::Table.new header_rows.each { |row| table.add_row row } table.add_separator data.each do |h| table.add_row(fields.map { |f| h[f] == nil ? 'N/A' : h[f] }) end puts table end |
#table_key(str) ⇒ Object
157 158 159 |
# File 'lib/rvc/modules/esxcli.rb', line 157 def table_key str str.downcase.gsub(/[^\w\d_]/, '') end |
#table_sort_compare(a, b) ⇒ Object
474 475 476 477 478 479 480 |
# File 'lib/rvc/modules/basic.rb', line 474 def table_sort_compare a, b return a <=> b if a != nil and b != nil return 0 if a == nil and b == nil return -1 if a == nil return 1 if b == nil fail end |
#tasks ⇒ Object
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 |
# File 'lib/rvc/modules/vim.rb', line 207 def tasks conn = single_connection [shell.fs.cur] begin view = conn.serviceContent.viewManager.CreateListView collector = conn.serviceContent.taskManager.CreateCollectorForTasks(:filter => { :time => { :beginTime => conn.serviceInstance.CurrentTime.to_datetime, # XXX :timeType => :queuedTime } }) collector.SetCollectorPageSize :maxCount => 1 filter_spec = { :objectSet => [ { :obj => view, :skip => true, :selectSet => [ VIM::TraversalSpec(:path => 'view', :type => view.class.wsdl_name) ] }, { :obj => collector }, ], :propSet => [ { :type => 'Task', :pathSet => %w(info.state) }, { :type => 'TaskHistoryCollector', :pathSet => %w(latestPage) }, ] } filter = conn.propertyCollector.CreateFilter(:partialUpdates => false, :spec => filter_spec) ver = '' loop do result = conn.propertyCollector.WaitForUpdates(:version => ver) ver = result.version result.filterSet[0].objectSet.each do |r| remove = [] case r.obj when VIM::TaskHistoryCollector infos = collector.ReadNextTasks :maxCount => 100 view.ModifyListView :add => infos.map(&:task) when VIM::Task puts "#{Time.now} #{r.obj.info.name} #{r.obj.info.entityName} #{r['info.state']}" unless r['info.state'] == nil remove << r.obj if %w(error success).member? r['info.state'] end view.ModifyListView :remove => remove unless remove.empty? end end rescue Interrupt ensure filter.DestroyPropertyFilter if filter collector.DestroyCollector if collector view.DestroyView if view end end |
#term(x) ⇒ Object
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
# File 'lib/rvc/modules/find.rb', line 84 def term x case x when /^([\w.]+)(!)?(>=|<=|=|>|<|~)/ lhs = $1 negate = $2 != nil op = $3 rhs = $' lambda do |o| a = o.field(lhs) a = [a].compact unless a.is_a? Enumerable return negate if a.empty? type = a.first.class fail "all objects in field #{lhs.inspect} must have the same type" unless a.all? { |x| x.is_a? type } b = coerce_str type, rhs a.any? do |x| case op when '=' then x == b when '>' then x > b when '>=' then x >= b when '<' then x < b when '<=' then x <= b when '~' then x =~ Regexp.new(b) end end ^ negate end when /^\w+$/ lambda { |o| o.field(x) } else err "failed to parse expression #{x.inspect}" end end |
#translate_respool(vds, pk, show_inheritance = true) ⇒ Object
289 290 291 292 293 294 295 296 297 298 299 300 301 302 |
# File 'lib/rvc/extensions/DistributedVirtualPortgroup.rb', line 289 def translate_respool vds, pk, show_inheritance = true if pk.value == '-1' poolName = "-" else poolName = vds.networkResourcePool.find_all { |pool| pk.value == pool.key }[0].name end if show_inheritance and !pk.inherited poolName += "*" end poolName end |
#translate_vlan(vlan) ⇒ Object
256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 |
# File 'lib/rvc/extensions/DistributedVirtualPortgroup.rb', line 256 def translate_vlan vlan case "#{vlan.class}" when "VmwareDistributedVirtualSwitchVlanIdSpec" config = vlan.vlanId == 0 ? "-" : vlan.vlanId.to_s + " (tagging)" when "VmwareDistributedVirtualSwitchTrunkVlanSpec" config = vlan.vlanId.map { |r| if r.start != r.end "#{r.start}-#{r.end}" else "#{r.start}" end }.join(',') + " (trunked)" when "Array" config = vlan.map { |r| if r.start != r.end "#{r.start}-#{r.end}" else "#{r.start}" end }.join(',') if config == "0" config = "-" else config += " (trunked)" end when "VmwareDistributedVirtualSwitchPvlanSpec" # XXX needs to be mapped config = vlan.pvlanId.to_s + " (pvlan?)" end config end |
#type(name) ⇒ Object
32 33 34 35 36 |
# File 'lib/rvc/modules/basic.rb', line 32 def type name klass = RbVmomi::VIM.type(name) rescue err("#{name.inspect} is not a VMODL type.") shell.introspect_class klass nil end |
#unblock(obj) ⇒ Object
203 204 205 |
# File 'lib/rvc/modules/vds.rb', line 203 def unblock obj apply_settings obj, { :blocked => { :value => false, :inherited => false } } end |
#unregister(vm) ⇒ Object
263 264 265 |
# File 'lib/rvc/modules/vm.rb', line 263 def unregister vm vm.UnregisterVM end |
#unset_respool(obj) ⇒ Object
421 422 423 424 |
# File 'lib/rvc/modules/vds.rb', line 421 def unset_respool obj apply_settings obj, {:networkResourcePoolKey => {:inherited => false, :value => nil} } end |
#unused_vnc_port(ip) ⇒ Object
83 84 85 86 87 88 89 90 |
# File 'lib/rvc/modules/vnc.rb', line 83 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(name, opts) ⇒ Object
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
# File 'lib/rvc/modules/resource_pool.rb', line 81 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, dest) ⇒ Object
45 46 47 48 49 50 51 52 53 |
# File 'lib/rvc/modules/datastore.rb', line 45 def upload local_path, dest dir, datastore_filename = *dest err "local file does not exist" unless File.exists? local_path real_datastore_path = "#{dir.path}/#{datastore_filename}" upload_path = http_path dir.datastore.send(:datacenter).name, dir.datastore.name, real_datastore_path http_upload dir.datastore._connection, local_path, upload_path end |
#upload_file(vm, opts) ⇒ Object
285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 |
# File 'lib/rvc/modules/vm_guest.rb', line 285 def upload_file vm, opts guestOperationsManager = vm._connection.serviceContent.guestOperationsManager err "This command requires vSphere 5 or greater" unless guestOperationsManager.respond_to? :fileManager fileManager = guestOperationsManager.fileManager opts[:permissions] = opts[:permissions].to_i(8) if opts[:permissions] auth = get_auth vm, opts file = File.new(opts[:local_path], 'rb') upload_url = fileManager. InitiateFileTransferToGuest( :vm => vm, :auth => auth, :guestFilePath => opts[:guest_path], :fileAttributes => VIM.GuestPosixFileAttributes( :groupId => opts[:group_id], :ownerId => opts[:owner_id], :permissions => opts[:permissions] ), :fileSize => file.size, :overwrite => opts[:overwrite] ) upload_uri = URI.parse(upload_url.gsub /http(s?):\/\/\*:[0-9]*/, "") upload_path = "#{upload_uri.path}?#{upload_uri.query}" http_upload vm._connection, opts[:local_path], upload_path end |
#verify(filename, expected_hash) ⇒ Object
169 170 171 172 173 174 175 176 177 |
# File 'lib/rvc/modules/vmrc.rb', line 169 def verify filename, expected_hash if expected_hash == :nocheck puts "WARNING: skipping hash check" else puts "Checking integrity..." hexdigest = Digest::SHA256.file(filename).hexdigest err "Hash mismatch: expected #{expected_hash}, found #{hexdigest}" if hexdigest != expected_hash end end |
#view(vms, opts) ⇒ Object
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
# File 'lib/rvc/modules/vnc.rb', line 33 def view vm ip = reachable_ip vm.collect('runtime.host')[0] extraConfig, = vm.collect('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 |
#vlan_switchtag(obj, vlan) ⇒ Object
288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 |
# File 'lib/rvc/modules/vds.rb', line 288 def vlan_switchtag obj, vlan # if it matches, inherit settings from switch or portgroup inherited = false inherited_spec = get_inherited_config(obj) if inherited_spec != nil then inherited_spec = inherited_spec.vlan end if inherited_spec.class == VIM::VmwareDistributedVirtualSwitchVlanIdSpec if inherited_spec.vlanId.to_s == vlan.to_s inherited = true end end spec = VIM::VMwareDVSPortSetting.new() spec.vlan = VIM::VmwareDistributedVirtualSwitchVlanIdSpec.new() spec.vlan.vlanId = vlan spec.vlan.inherited = inherited apply_settings obj, spec end |
#vlan_trunk(obj, vlan, opts) ⇒ Object
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 |
# File 'lib/rvc/modules/vds.rb', line 221 def vlan_trunk obj, vlan, opts ranges = [] vlan.sub(' ', '').split(',').each do |range_str| range_val = range_str.split('-') ranges << Range.new(range_val[0].to_i, if range_val.length > 1 range_val[1].to_i else range_val[0].to_i end) end if opts[:append] or opts[:exclude] old_vlan = obj.config.defaultPortConfig.vlan if old_vlan.class == VIM::VmwareDistributedVirtualSwitchVlanIdSpec puts "Can't append/exclude trunk range to switch tagging configuration!" return elsif old_vlan.class == VIM::VmwareDistributedVirtualSwitchTrunkVlanSpec old_vlan = old_vlan.vlanId.map { |r| r.start..r.end } end old_vlan = merge_ranges(old_vlan) end if opts[:append] ranges = ranges + old_vlan end ranges = merge_ranges(ranges) if opts[:exclude] ranges = subtract_ranges(old_vlan, ranges) ranges = merge_ranges(ranges) end spec = VIM::VMwareDVSPortSetting.new() spec.vlan = VIM::VmwareDistributedVirtualSwitchTrunkVlanSpec.new() spec.vlan.vlanId = ranges.map { |r| { :start => r.first, :end => r.last } } spec.vlan.inherited = false if ranges.empty? # if we excluded all ranges, just allow everything vlan_switchtag obj, 0 return end inherited_spec = get_inherited_config(obj) if inherited_spec != nil then inherited_spec = inherited_spec.vlan end if inherited_spec.class == VIM::VmwareDistributedVirtualSwitchTrunkVlanSpec inherited_ranges = inherited.vlanId.map { |range| range.start..range.end } if (merge_ranges(inherited_ranges) - ranges) == [] spec.vlan.inherited = true end end apply_settings obj, spec end |
#vm_create(clusters, opts) ⇒ Object
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
# File 'lib/rvc/modules/diagnostics.rb', line 60 def vm_create clusters, opts datastore = opts[:datastore] vm_folder = opts[:vm_folder] err "datastore is a required parameter" unless datastore err "vm_folder is a required parameter" unless vm_folder puts "Creating one VM per host ... (timeout = #{opts[:timeout]} sec)" result = _vm_create clusters, datastore, vm_folder, opts errors = result.select{|h, x| x['status'] != 'green'} errors.each do |host, info| puts "Failed to create VM on host #{host} (in cluster #{info['cluster']}): #{info['error']}" end if errors.length == 0 puts "Success" end end |
#vm_ip(vm) ⇒ Object
626 627 628 629 630 631 632 633 634 635 636 637 638 |
# File 'lib/rvc/modules/vm.rb', line 626 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 |
#vmrc_url(arch) ⇒ Object
38 39 40 |
# File 'lib/rvc/modules/vmrc.rb', line 38 def vmrc_url arch "http://cloud.github.com/downloads/vmware/rvc/vmware-vmrc-public-#{arch}-#{PACKAGE_VERSION}.zip" end |
#vnc_client(ip, port, password) ⇒ Object
Override this to spawn a VNC client differently
We can save the vnc pasword out to a file, then call vncviewer with it directly so we don’t need to “password” auth.
103 104 105 106 107 108 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 |
# File 'lib/rvc/modules/vnc.rb', line 103 def vnc_client ip, port, password unless VNC puts "no VNC client configured" puts "#{ip}:#{port} password: #{password}" return false end if File.basename(VNC) == 'vncviewer' # or other vnc clients that support the same -passwd tightvnc = %x(#{VNC} --version 2>&1).lines.first['TightVNC'] != nil file = Tempfile.new('rvcvncpass') filename = file.path begin if tightvnc IO.popen("vncpasswd -f > #{filename}", 'w+') do |vncpass| vncpass.puts password vncpass.puts password end else IO.popen("vncpasswd #{filename}", 'w+') do |vncpass| vncpass.puts password vncpass.puts password end end vnc_client_connect ip, port, password, "-passwd #{filename}" ensure sleep 3 # we have to do this, as the vncviewer forks, and we've no simple way of working out if that thread has read the file yet. file.close file.unlink end else vnc_client_connect ip, port, password end end |
#vnc_client_connect(ip, port, password, vnc_opts = nil) ⇒ Object
138 139 140 141 142 143 144 145 146 147 148 149 |
# File 'lib/rvc/modules/vnc.rb', line 138 def vnc_client_connect ip, port, password, vnc_opts=nil fork do $stdout.reopen("#{ENV['HOME']||'.'}/.rvc-vnc.log", "w") $stderr.reopen("#{ENV['HOME']||'.'}/.rvc-vnc.err", "w") Process.setpgrp exec [ VNC, vnc_opts, "#{ip}:#{port}" ].join ' ' end puts "spawning #{VNC}" print "#{ip}:#{port} password: #{password}" print " options: #{vnc_opts}" unless vnc_opts.nil? puts end |
#vnc_password ⇒ Object
Override this if you don’t want a random password
93 94 95 96 97 |
# File 'lib/rvc/modules/vnc.rb', line 93 def vnc_password n = 8 chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890' (0...n).map { chars[rand(chars.length)].chr }.join end |
#wait_for_multiple_tasks(tasks, timeout) ⇒ Object
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
# File 'lib/rvc/modules/diagnostics.rb', line 23 def wait_for_multiple_tasks tasks, timeout if tasks == [] return [] end pc = tasks.first._connection.serviceContent.propertyCollector done = false t1 = Time.now while !done && (Time.now - t1) < timeout tasks_props = pc.collectMultiple(tasks, 'info.state') if tasks_props.reject{|t,f| ['success', 'error'].member?(f['info.state'])}.empty? done = true end sleep 2 end tasks_props = pc.collectMultiple(tasks, 'info.state', 'info.error') results = Hash[tasks_props.map do |task, props| result = if props['info.state'] == 'success' task.info.result elsif props['info.state'] == 'error' props['info.error'] else "Timed out" end [task, result] end] results end |
#wait_for_shutdown(vms, opts) ⇒ Object
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
# File 'lib/rvc/modules/vm.rb', line 81 def wait_for_shutdown vms, opts finish_time = Time.now + opts[:timeout] while Time.now < finish_time all_off = true vms.each do |vm| if vm.summary.runtime.powerState == 'poweredOn' all_off = false end end return if all_off sleep_time = [opts[:delay], finish_time - Time.now].min sleep sleep_time if sleep_time > 0 end err "At least one VM did not shut down!" end |
#watch(counter_name, objs, opts) ⇒ Object
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 |
# File 'lib/rvc/modules/perf.rb', line 200 def watch counter_name, objs, opts require_gnuplot with_gnuplot false do |gp| puts "Press Ctrl-C to stop." while true plot counter_name, objs, :terminal => opts[:terminal] sleep opts[:interval] if opts[:terminal] $stdout.write "\e[25A" $stdout.flush end end end rescue Interrupt end |
#what(objs) ⇒ Object
306 307 308 309 310 |
# File 'lib/rvc/modules/basic.rb', line 306 def what objs objs.each do |obj| puts "#{obj.rvc_path_str}: #{obj.class}" end end |
#with_gnuplot(persist) ⇒ Object
175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 |
# File 'lib/rvc/modules/perf.rb', line 175 def with_gnuplot persist if $rvc_gnuplot yield $rvc_gnuplot else cmd = Gnuplot.gnuplot(persist) or err 'gnuplot not found' $rvc_gnuplot = IO::popen(cmd, "w") begin yield $rvc_gnuplot ensure gp = $rvc_gnuplot $rvc_gnuplot = nil gp.close end end end |