Top Level Namespace
- Includes:
- RVC::Util
Defined Under Namespace
Modules: PbmHelperModule, RVC Classes: LazyDVPort, MetricNumber, Numeric, ProgressStream, SimpleGetForm, TimeDiff, VsanObserver
Constant Summary collapse
- VIM =
RbVmomi::VIM
- DEFAULT_SERVER_PLACEHOLDER =
'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', }
- PBM =
RbVmomi::PBM
- 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::TCSETPGRP, RVC::Util::UserError
Instance Method Summary collapse
- #_add_device(vm, fileOp, dev) ⇒ Object
- #_assessAvailabilityByStatus(state) ⇒ Object
- #_catch_spbm_resets(conn) ⇒ Object
- #_components_in_dom_config(dom_config) ⇒ Object
- #_extra_config(vm, *regexes) ⇒ Object
- #_fetch_disk_stats(obj, metrics, instances, opts = {}) ⇒ Object
- #_filtered_cluster_recommendations(cluster, key, type) ⇒ Object
- #_get_vm_obj_uuids(vm, vmsProps) ⇒ Object
- #_host_info(host, prefix = '') ⇒ Object
- #_normalize_uuid(uuid) ⇒ Object
- #_object_info(obj_uuids, opts) ⇒ Object
- #_observe_snapshot(conn, host, hosts, vmView, pc, hosts_props, vsanIntSys) ⇒ Object
- #_parseJson(json) ⇒ Object
- #_print_dom_config_tree(dom_obj_uuid, obj_infos, indent = 0, opts = {}) ⇒ Object
- #_print_dom_config_tree_int(dom_config, dom_components_str, indent = 0) ⇒ Object
- #_run_with_rev(conn, rev) ⇒ Object
- #_set_extra_config(vm, hash) ⇒ Object
- #_vm_create(clusters, datastore, vm_folder, opts = {}) ⇒ Object
- #_vsan_cluster_disks_info(cluster, opts = {}) ⇒ Object
-
#_vsan_host_disks_info(hosts) ⇒ Object
hosts is a hash: host => hostname.
- #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_license_to_cluster(cluster, opts) ⇒ Object
- #apply_recommendations(cluster, opts) ⇒ Object
- #apply_settings(obj, port_spec) ⇒ Object
- #authenticate(vms, opts) ⇒ Object
- #block(obj) ⇒ Object
- #bootconfig(vm, opts) ⇒ Object
- #cd(obj) ⇒ Object
- #change_devices_connectivity(devs, connected) ⇒ Object
- #check_auth(vm, opts) ⇒ Object
- #check_compliance(vms) ⇒ Object
- #check_installed ⇒ Object
- #check_known_hosts(host, peer_public_key) ⇒ Object
- #check_limits(hosts_and_clusters, opts = {}) ⇒ Object
- #check_state(cluster_or_host, opts) ⇒ Object
- #chmod(vm, opts) ⇒ Object
- #choose_vmrc_version(vim_version) ⇒ Object
- #clear_auth(vm, opts) ⇒ Object
- #clone(src, dst, opts) ⇒ Object
- #cluster_info(cluster) ⇒ Object
- #cluster_set_default_policy(cluster, policy) ⇒ Object
- #cmmds_find(cluster_or_host, opts) ⇒ Object
- #coerce_str(type, v) ⇒ Object
- #collapse_inheritance(default_spec, port_spec) ⇒ Object
- #config_syslog(entity, ip, opts) ⇒ Object
- #configure_drs(clusters, opts) ⇒ Object
- #configure_ha(clusters, opts) ⇒ Object
- #configure_swap(clusters, opts) ⇒ Object
- #connect(devs) ⇒ Object
- #connect_serial_uri(dev, uri, opts) ⇒ Object
- #convert_uuids(uuids) ⇒ 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) ⇒ Object
- #cur_auth_mgr ⇒ Object
- #debug ⇒ Object
- #delete(objs) ⇒ Object
- #deltaize_disks(vm) ⇒ Object
- #describe(snapshot, description) ⇒ Object
- #deselect_vmknic_for_service(vmknic, service, hosts) ⇒ Object
- #destroy(objs) ⇒ Object
- #device_add_disk(vm, path, opts) ⇒ Object
- #device_change_storage_profile(devs, opts) ⇒ Object
- #disable_vsan_on_cluster(cluster) ⇒ Object
- #disconnect(devs) ⇒ Object
- #disk_object_info(cluster_or_host, disk_uuids, opts = {}) ⇒ Object
- #disks_info(hosts) ⇒ Object
- #disks_stats(hosts_and_clusters, opts = {}) ⇒ Object
- #download(file, local_path) ⇒ Object
- #download_file(vm, opts) ⇒ Object
- #edit(file) ⇒ Object
- #enable_vsan_on_cluster(cluster, opts) ⇒ 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_inconsistent_vms(cluster_or_host) ⇒ Object
It is possible for the management stack (hostd and vc) to lose the handle of a VM which is powered on (has a running vmx instance).
- #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
- #fix_inconsistent_vms(vms) ⇒ Object
- #fix_renamed_vms(vms) ⇒ Object
- #generic_http_download(uri, local_path) ⇒ Object
- #generic_http_upload(local_path, uri, size = nil) ⇒ 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
- #host_consume_disks(hosts_or_clusters, opts) ⇒ Object
- #host_info(host) ⇒ Object
- #host_wipe_vsan_disks(hosts, opts) ⇒ Object
- #http_path(dc_name, ds_name, path) ⇒ Object
- #info(obj) ⇒ Object
- #insert_cdrom(dev, iso) ⇒ Object
- #install ⇒ Object
- #ip(vms) ⇒ Object
- #is_uuid(str) ⇒ Object
- #keychain_password(username, hostname) ⇒ Object
- #kill(vms) ⇒ Object
- #layout(vm) ⇒ Object
- #leaves(roots, types = []) ⇒ Object
- #list ⇒ Object
- #list_auth(vm) ⇒ Object
- #lldpnetmap(hosts_and_clusters, opts = {}) ⇒ 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
- #migrate_vmknic(host, vmknic, portgroup) ⇒ 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_counters(counter_names, opts) ⇒ Object
- #modify_cpu(vm, opts) ⇒ Object
- #modify_memory(vm, opts) ⇒ Object
- #mv(objs) ⇒ Object
- #mvdir(vm, opts) ⇒ Object
- #mvfile(vm, opts) ⇒ Object
- #namespace_change_storage_profile(vms, opts) ⇒ Object
- #obj_status_report(cluster_or_host, opts) ⇒ Object
- #object_info(cluster, obj_uuids, opts = {}) ⇒ Object
- #object_reconfigure(cluster_or_host, obj_uuids, opts) ⇒ Object
- #observer(cluster_or_host, 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
- #profile_apply(profiles) ⇒ Object
- #profile_create(profile_name, opts) ⇒ Object
- #profile_delete(profiles) ⇒ Object
- #prompt_password ⇒ Object
- #quit ⇒ Object
- #rdp(vms, h) ⇒ Object
- #reachable_ip(host) ⇒ Object
- #reapply_vsan_vmknic_config(hosts, opts) ⇒ Object
- #reboot(hosts, opts) ⇒ Object
- #reboot_guest(vms) ⇒ Object
- #recommendations(cluster) ⇒ Object
- #reconfig_net(devs, opts) ⇒ Object
- #reconnect(hosts, opts) ⇒ Object
- #recover_spbm(cluster_or_host, 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
- #restart_services(clusters, opts) ⇒ Object
- #resync_dashboard(cluster_or_host, opts) ⇒ 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
- #select_vmknic_for_service(vmknic, service, hosts) ⇒ 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
- #ssh_exec!(ssh, command) ⇒ Object
- #standby_guest(vms) ⇒ Object
- #start_program(vms, 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(vms, opts) ⇒ Object
- #verify(filename, expected_hash) ⇒ Object
- #view(vms, opts) ⇒ Object
- #vlan_switchtag(obj, vlan) ⇒ Object
- #vlan_trunk(obj, vlan, opts) ⇒ Object
- #vm_change_storage_profile(vms, opts) ⇒ Object
- #vm_create(clusters, opts) ⇒ Object
- #vm_ip(vm) ⇒ Object
- #vm_object_info(vms, opts) ⇒ Object
- #vm_perf_stats(vms, opts) ⇒ 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
- #whatif_host_failures(hosts_and_clusters, opts = {}) ⇒ 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
298 299 300 301 302 303 304 305 306 307 308 309 310 |
# File 'lib/rvc/modules/device.rb', line 298 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 |
#_assessAvailabilityByStatus(state) ⇒ Object
2988 2989 2990 2991 2992 2993 2994 2995 2996 |
# File 'lib/rvc/modules/vsan.rb', line 2988 def _assessAvailabilityByStatus state mask = { 'DATA_AVAILABLE' => (1 << 0), 'QUORUM' => (1 << 1), 'PERF_COMPLIANT' => (1 << 2), 'INCOMPLETE' => (1 << 3), } Hash[mask.map{|k,v| [k, (state & v) != 0]}] end |
#_catch_spbm_resets(conn) ⇒ Object
719 720 721 722 723 724 725 726 727 728 |
# File 'lib/rvc/modules/spbm.rb', line 719 def _catch_spbm_resets(conn) begin yield rescue EOFError if conn conn.pbm = nil end err "Connection to SPBM timed out, try again" end end |
#_components_in_dom_config(dom_config) ⇒ Object
464 465 466 467 468 469 470 471 472 473 474 |
# File 'lib/rvc/modules/vsan.rb', line 464 def _components_in_dom_config dom_config out = [] if ['Component', 'Witness'].member?(dom_config['type']) out << dom_config else dom_config.select{|k,v| k =~ /child-\d+/}.each do |k, v| out += _components_in_dom_config v end end out end |
#_extra_config(vm, *regexes) ⇒ Object
401 402 403 404 405 406 407 408 |
# File 'lib/rvc/modules/vm.rb', line 401 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 |
#_fetch_disk_stats(obj, metrics, instances, opts = {}) ⇒ Object
1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 |
# File 'lib/rvc/modules/vsan.rb', line 1344 def _fetch_disk_stats obj, metrics, instances, opts = {} conn = obj._connection pm = conn.serviceContent.perfManager metrics.each do |x| err "no such metric #{x}" unless pm.perfcounter_hash.member? x end interval = pm.provider_summary(obj).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, :instance => instances, :multi_instance => true, } stat_opts[:max_samples] = opts[:samples] if opts[:samples] res = pm.retrieve_stats [obj], metrics, stat_opts out = {} if res && res[obj] res[obj][:metrics].each do |key, values| metric, device = key out[device] ||= {} out[device][metric] = values end end out end |
#_filtered_cluster_recommendations(cluster, key, type) ⇒ Object
182 183 184 185 186 187 188 189 190 191 |
# File 'lib/rvc/modules/cluster.rb', line 182 def _filtered_cluster_recommendations cluster, key, type recommendation = cluster.recommendation if key && key.length > 0 recommendation.select! { |x| key.member?(x.key) } end if type && type.length > 0 recommendation.select! { |x| (type & x.action.map { |y| y.class.wsdl_name }).length > 0 } end recommendation end |
#_get_vm_obj_uuids(vm, vmsProps) ⇒ Object
942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 |
# File 'lib/rvc/modules/vsan.rb', line 942 def _get_vm_obj_uuids vm, vmsProps obj_uuids = {} disks = vmsProps[vm]['disks'] = vmsProps[vm]['config.hardware.device'].select{|x| x.is_a?(VIM::VirtualDisk)} pathName = vmsProps[vm]['summary.config'].vmPathName namespaceUuid = vmsProps[vm]['namespaceUuid'] = pathName.split("] ")[1].split("/")[0] obj_uuids[namespaceUuid] = pathName disks.each do |disk| backing = disk.backing while backing obj_uuids[backing.backingObjectId] = backing.fileName backing = backing.parent end end obj_uuids end |
#_host_info(host, prefix = '') ⇒ Object
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 413 414 415 416 417 418 419 420 421 422 423 424 |
# File 'lib/rvc/modules/vsan.rb', line 377 def _host_info host, prefix = '' configManager = host.configManager netSys = configManager.networkSystem vsan = configManager.vsanSystem config = vsan.config enabled = config.enabled line = lambda{|x| puts "#{prefix}#{x}" } line.call "VSAN enabled: %s" % (enabled ? "yes" : "no") if !enabled return end status = vsan.QueryHostStatus() line.call "Cluster info:" line.call " Cluster role: #{status.nodeState.state}" line.call " Cluster UUID: #{config.clusterInfo.uuid}" line.call " Node UUID: #{config.clusterInfo.nodeUuid}" line.call " Member UUIDs: #{status.memberUuid} (#{status.memberUuid.length})" line.call "Storage info:" line.call " Auto claim: %s" % (config.storageInfo.autoClaimStorage ? "yes" : "no") line.call " Disk Mappings:" if config.storageInfo.diskMapping.length == 0 line.call " None" end config.storageInfo.diskMapping.each do |mapping| capacity = mapping.ssd.capacity size = capacity.block * capacity.blockSize line.call " SSD: #{mapping.ssd.displayName} - #{size / 1024**3} GB" mapping.nonSsd.map do |md| capacity = md.capacity size = capacity.block * capacity.blockSize line.call " MD: #{md.displayName} - #{size / 1024**3} GB" end end line.call "NetworkInfo:" if config.networkInfo.port.length == 0 line.call " Not configured" end vmknics, = netSys.collect 'networkConfig.vnic' config.networkInfo.port.each do |port| dev = port.device vmknic = vmknics.find{|x| x.device == dev} ip = "IP unknown" if vmknic ip = vmknic.spec.ip.ipAddress end line.call " Adapter: #{dev} (#{ip})" end end |
#_normalize_uuid(uuid) ⇒ Object
476 477 478 479 480 481 482 483 |
# File 'lib/rvc/modules/vsan.rb', line 476 def _normalize_uuid uuid uuid = uuid.gsub("-", "") uuid = "%s-%s-%s-%s-%s" % [ uuid[0..7], uuid[8..11], uuid[12..15], uuid[16..19], uuid[20..31] ] uuid end |
#_object_info(obj_uuids, opts) ⇒ Object
1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 |
# File 'lib/rvc/modules/vsan.rb', line 1191 def _object_info obj_uuids, opts if !opts[:cluster] err "Must specify a VSAN Cluster" end host = opts[:host] if opts[:cluster].is_a?(VIM::HostSystem) host = opts[:cluster] end # XXX: Verify VSAN is enabled on the cluster if host hosts = [host] conn = host._connection else hosts = opts[:cluster].host conn = opts[:cluster]._connection end _run_with_rev(conn, "dev") do pc = conn.propertyCollector hosts_props = pc.collectMultiple(hosts, 'name', 'runtime.connectionState', 'configManager.vsanSystem', 'configManager.vsanInternalSystem' ) connected_hosts = hosts_props.select do |k,v| v['runtime.connectionState'] == 'connected' end.keys hosts = connected_hosts if hosts.length == 0 err "Couldn't find any connected hosts" end if opts[:perspective_from_host] if !connected_hosts.member?(opts[:perspective_from_host]) err "Perspective-Host not connected, or not in considered group of hosts" end end # Detect partitions: # We need to ask every host which other hosts it believes to share a # VSAN cluster (partition) with. This is a call down to ESX, so we spawn # one connection and one thread per host to parallelize. We detect # partitions by grouping VMs based on quoting the same cluster members. hosts_props.map do |host, props| if !connected_hosts.member?(host) next end Thread.new do begin vsanSys = props['configManager.vsanSystem'] c1 = conn.spawn_additional_connection vsanSys = vsanSys.dup_on_conn(c1) res = vsanSys.QueryHostStatus() hosts_props[host]['vsanCluster'] = res rescue Exception => ex puts "Failed to gather host status from #{props['name']}: #{ex.class}: #{ex.}" end end end.compact.each{|t| t.join} partitions = hosts_props.select do |h, p| connected_hosts.member?(h) end.group_by{|h, p| p['vsanCluster'].memberUuid} partition_exists = (partitions.length > 1) if partition_exists puts "#{Time.now}: WARNING: VSAN Cluster network partition detected." puts "#{Time.now}: The individual partitions of the cluster will have " puts "#{Time.now}: different views on object/component availablity. An " puts "#{Time.now}: attempt is made to show VM object accessibility from the " puts "#{Time.now}: perspective of the host on which a VM is registered. " puts "#{Time.now}: Please fix the network partition as soon as possible " puts "#{Time.now}: as it will seriously impact the availability of your " puts "#{Time.now}: VMs in your VSAN cluster. Check vsan.cluster_info for" puts "#{Time.now}: more details." puts "#{Time.now}: " puts "#{Time.now}: The following partitions were detected:" i = 1 partitions.values.map do |part| part_hosts = part.map{|x| hosts_props[x[0]]}.compact.map{|x| x['name']} puts "#{Time.now}: #{i}) #{part_hosts.join(", ")}" i += 1 end puts "" if opts[:perspective_from_host] name = hosts_props[opts[:perspective_from_host]]['name'] puts "Showing data from perspective of host #{name} as requested" puts "" end end host_vsan_uuids, host_props, vsan_disk_uuids = _vsan_cluster_disks_info( opts[:cluster], :hosts_props => hosts_props ) extra_info = { 'host_vsan_uuids' => host_vsan_uuids, 'host_props' => host_props, 'vsan_disk_uuids' => vsan_disk_uuids, } obj_uuids = obj_uuids.compact.map{|x| _normalize_uuid(x)} obj_uuids = obj_uuids.select{|x| is_uuid(x)} objs = {'obj_uuid_from_host' => {}} objs['has_partitions'] = partition_exists # Dealing with partitions: # In the non-partitioned case we can just select any host and ask it # for the object info, given that CMMDS is (eventual) consistent # across the cluster. But during a network partition it is most logical # to ask the host on which a VM is registered about what it thinks about # the objects in question. So in case of a network partition we fall # back to a slower code path that asks each host individually about # the objects it (hopefully) knows best about. # Note: Upon power on DRS will pick a host to power the VM on. That other # host may not be in the same partition and DRS doesn't know about it, # so although we tried to show the object from the "right" hosts perspective # it may still not be the right host when debugging a power on failure. if opts[:objToHostMap] && partition_exists && !opts[:perspective_from_host] obj_uuids_groups = obj_uuids.group_by{|x| opts[:objToHostMap][x]} obj_uuids_groups.each do |host, group| vsanIntSys = hosts_props[host]['configManager.vsanInternalSystem'] group_objs = vsanIntSys.query_vsan_objects(:uuids => group) # Here we are merging and overriding potentially conflicting # information about LSOM_OBJECT and DISK entries. No smarts are # applied, as I am not aware of issues arising from those # possible inconsistencies. group_objs.each do |k,v| objs[k] ||= {} objs[k].merge!(v) end group.each do |uuid| objs['obj_uuid_from_host'][uuid] = host end end else if opts[:perspective_from_host] host = opts[:perspective_from_host] else host = hosts.first end vsanIntSys = hosts_props[host]['configManager.vsanInternalSystem'] objs = vsanIntSys.query_vsan_objects(:uuids => obj_uuids) end objs.merge!(extra_info) objs end end |
#_observe_snapshot(conn, host, hosts, vmView, pc, hosts_props, vsanIntSys) ⇒ Object
1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 |
# File 'lib/rvc/modules/vsan.rb', line 1810 def _observe_snapshot conn, host, hosts, vmView, pc, hosts_props, vsanIntSys startTime = Time.now observation = { 'cmmds' => { 'clusterInfos' => {}, 'clusterDirs' => {}, }, 'vsi' => {}, 'inventory' => {}, } exceptions = [] threads = [] begin threads << Thread.new do begin t1 = Time.now vms = vmView.view vmProperties = [ 'name', 'runtime.powerState', 'datastore', 'config.annotation', 'parent', 'resourcePool', 'storage.perDatastoreUsage', 'summary.config.memorySizeMB', 'summary.config.numCpu', 'summary.config.vmPathName', 'config.hardware.device', 'runtime.connectionState', ] vmsProps = pc.collectMultiple(vms, *vmProperties) t2 = Time.now puts "Query VM properties: %.2f sec" % (t2 - t1) observation['inventory']['vms'] = {} vmsProps.each do |vm, vmProps| vmProps['vsan-obj-uuids'] = {} devices = vmProps['config.hardware.device'] || [] disks = devices.select{|x| x.is_a?(VIM::VirtualDisk)} disks.each do |disk| newBacking = {} newDisk = { 'unitNumber' => disk.unitNumber, 'controllerKey' => disk.controllerKey, 'backing' => newBacking, } backing = disk.backing if !backing.is_a?(VIM::VirtualDiskFlatVer2BackingInfo) next end while backing uuid = backing.backingObjectId if uuid vmProps['vsan-obj-uuids'][uuid] = backing.fileName newBacking['uuid'] = uuid end newBacking['fileName'] = backing.fileName backing = backing.parent if backing newBacking['parent'] = {} newBacking = newBacking['parent'] end end vmProps['disks'] ||= [] vmProps['disks'] << newDisk end # Do not add devices to the snapshot as they are too big vmProps.delete('config.hardware.device') begin vmPathName = vmProps['summary.config.vmPathName'] uuid = vmPathName.split("] ")[1].split("/")[0] vmProps['vsan-obj-uuids'][uuid] = vmPathName rescue end observation['inventory']['vms'][vm._ref] = vmProps end rescue Exception => ex exceptions << ex end end threads << Thread.new do begin sleep(20) hostname = hosts_props[host]['name'] # XXX: Should pick one host per partition c1 = conn.spawn_additional_connection vsanIntSys1 = vsanIntSys.dup_on_conn(c1) t1 = Time.now res = vsanIntSys1.query_cmmds( (1..30).map{|x| {:type => x}} ) t2 = Time.now puts "Query CMMDS from #{hostname}: %.2f sec (json size: %dKB)" % [ (t2 - t1), JSON.dump(res).length / 1024 ] observation['cmmds']['clusterDirs'][hostname] = res rescue Exception => ex exceptions << ex end end hosts.each do |host| threads << Thread.new do begin hostname = hosts_props[host]['name'] vsanIntSys1 = hosts_props[host]['configManager.vsanInternalSystem'] c1 = conn.spawn_additional_connection vsanIntSys1 = vsanIntSys1.dup_on_conn(c1) t1 = Time.now res = vsanIntSys1.QueryVsanStatistics(:labels => [ 'dom', 'lsom', 'worldlets', 'plog', 'dom-objects', 'mem', 'cpus', 'slabs', 'vscsi', 'cbrc', 'disks', #'rdtassocsets', 'system-mem', 'pnics', ] ) t2 = Time.now res = JSON.load(res) puts "Query Stats on #{host.name}: %.2f sec (on ESX: %.2f, json size: %dKB)" % [ (t2 - t1), res['on-esx-collect-duration'], JSON.dump(res).length / 1024 ] observation['vsi'][hostname] = res rescue Exception => ex exceptions << ex end end end threads.each{|x| x.join} if exceptions.length > 0 raise exceptions.first end rescue Interrupt threads.each{|t| t.terminate} end { 'type' => 'inventory-snapshot', 'snapshot' => observation, 'starttime' => startTime.to_f, 'endtime' => Time.now.to_f, } end |
#_parseJson(json) ⇒ Object
2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 |
# File 'lib/rvc/modules/vsan.rb', line 2977 def _parseJson json if json == "BAD" return nil end begin json = JSON.load(json) rescue nil end end |
#_print_dom_config_tree(dom_obj_uuid, obj_infos, indent = 0, opts = {}) ⇒ Object
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 580 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 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 |
# File 'lib/rvc/modules/vsan.rb', line 512 def _print_dom_config_tree dom_obj_uuid, obj_infos, indent = 0, opts = {} pre = " " * indent dom_obj_infos = obj_infos['dom_objects'][dom_obj_uuid] if !dom_obj_infos puts "#{pre}Couldn't find info about DOM object '#{dom_obj_uuid}'" return end dom_obj = dom_obj_infos['config'] policy = dom_obj_infos['policy'] dom_components = _components_in_dom_config(dom_obj['content']) csn = nil begin csn = dom_obj['content']['attributes']['CSN'] rescue end dom_components_str = Hash[dom_components.map do |dom_comp| attr = dom_comp['attributes'] state = attr['componentState'] comp_uuid = dom_comp['componentUuid'] state_names = { '0' => 'FIRST', '1' => 'NONE', '2' => 'NEED_CONFIG', '3' => 'INITIALIZE', '4' => 'INITIALIZED', '5' => 'ACTIVE', '6' => 'ABSENT', '7' => 'STALE', '8' => 'RESYNCHING', '9' => 'DEGRADED', '10' => 'RECONFIGURING', '11' => 'CLEANUP', '12' => 'TRANSIENT', '13' => 'LAST', } state_name = state.to_s if state_names[state.to_s] state_name = "#{state_names[state.to_s]} (#{state})" end props = { 'state' => state_name, } if state.to_s.to_i == 6 && attr['staleCsn'] if attr['staleCsn'] != csn props['csn'] = "STALE (#{attr['staleCsn']}!=#{csn})" end end comp_policy = {} ['readOPS', 'writeOPS'].select{|x| attr[x]}.each do |x| comp_policy[x] = attr[x] end if attr['readCacheReservation'] && attr['readCacheHitRate'] comp_policy['rc size/hitrate'] = "%.2fGB/%d%%" % [ attr['readCacheReservation'].to_f / 1024**3, attr['readCacheHitRate'], ] end if attr['bytesToSync'] comp_policy['dataToSync'] = "%.2f GB" % [ attr['bytesToSync'].to_f / 1024**3 ] end lsom_object = obj_infos['lsom_objects'][comp_uuid] if lsom_object host = obj_infos['host_vsan_uuids'][lsom_object['owner']] if host hostName = obj_infos['host_props'][host]['name'] else hostName = "unknown" end md_uuid = dom_comp['diskUuid'] md = obj_infos['vsan_disk_uuids'][md_uuid] ssd_uuid = obj_infos['disk_objects'][md_uuid]['content']['ssdUuid'] #pp ssd_uuid ssd = obj_infos['vsan_disk_uuids'][ssd_uuid] #pp ssd props.merge!({ 'host' => hostName, 'md' => md ? md.DisplayName : "unknown", 'ssd' => ssd ? ssd.DisplayName : "unknown", }) if opts[:highlight_disk] && md_uuid == opts[:highlight_disk] props['md'] = "**#{props['md']}**" elsif opts[:highlight_disk] && ssd_uuid == opts[:highlight_disk] props['ssd'] = "**#{props['ssd']}**" end else props.merge!({ 'host' => "LSOM object not found" }) end propsStr = props.map{|k,v| "#{k}: #{v}"}.join(", ") comp_policy_str = comp_policy.map{|k,v| "#{k}: #{v}"}.join(", ") [comp_uuid, [comp_uuid, propsStr, comp_policy_str]] end] if policy policy = policy.map{|k,v| "#{k} = #{v}"}.join(", ") else policy = "No POLICY entry found in CMMDS" end owner = obj_infos['host_vsan_uuids'][dom_obj['owner']] if owner owner = obj_infos['host_props'][owner]['name'] else owner = "unknown" end puts "#{pre}DOM Object: #{dom_obj['uuid']} (owner: #{owner}, policy: #{policy})" if opts[:context] puts "#{pre} Context: #{opts[:context]}" end _print_dom_config_tree_int dom_obj['content'], dom_components_str, indent end |
#_print_dom_config_tree_int(dom_config, dom_components_str, indent = 0) ⇒ Object
485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 |
# File 'lib/rvc/modules/vsan.rb', line 485 def _print_dom_config_tree_int dom_config, dom_components_str, indent = 0 pre = " " * indent type = dom_config['type'] children = dom_config.select{|k,v| k =~ /child-\d+/}.values if ['RAID_0', 'RAID_1', 'Concatenation'].member?(type) puts "#{pre}#{type}" children.each do |child| _print_dom_config_tree_int child, dom_components_str, indent + 1 end elsif ['Configuration'].member?(type) # puts "#{pre}#{type}" children.each do |child| _print_dom_config_tree_int child, dom_components_str, indent + 1 end elsif ['Witness', 'Component'].member?(type) comp_uuid = dom_config['componentUuid'] info = dom_components_str[comp_uuid] line = "#{pre}#{type}: #{info[0]}" if info[2].length > 0 puts "#{line} (#{info[1]}," puts "#{' ' * line.length} #{info[2]})" else puts "#{line} (#{info[1]})" end end end |
#_run_with_rev(conn, rev) ⇒ Object
426 427 428 429 430 431 432 433 434 |
# File 'lib/rvc/modules/vsan.rb', line 426 def _run_with_rev conn, rev old_rev = conn.rev begin conn.rev = rev yield ensure conn.rev = old_rev end end |
#_set_extra_config(vm, hash) ⇒ Object
394 395 396 397 398 399 |
# File 'lib/rvc/modules/vm.rb', line 394 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
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 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/diagnostics.rb', line 175 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, :annotation => YAML.dump({'lease' => Time.now + 2 * opts[:timeout] + 60}), :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 ) } ], } begin task = vm_folder.CreateVM_Task(:config => config, :pool => rp, :host => host) tasks_map[task] = host hosts_infos[host][:create_task] = task rescue puts "Failed to create task for host #{host.name}" end 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) error_detail = nil 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' begin error_detail = result.fault.faultMessage rescue end end out[host_props['name']] = { 'cluster' => cluster_props['name'], 'status' => status, 'error' => error_str, 'error_detail' => error_detail, } end out end |
#_vsan_cluster_disks_info(cluster, opts = {}) ⇒ Object
681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 |
# File 'lib/rvc/modules/vsan.rb', line 681 def _vsan_cluster_disks_info cluster, opts = {} pc = cluster._connection.propertyCollector if cluster.is_a?(VIM::HostSystem) hosts = [cluster] else hosts = cluster.host end if opts[:hosts_props] hosts_props = opts[:hosts_props] else hosts_props = pc.collectMultiple(hosts, 'name', 'runtime.connectionState', 'configManager.vsanSystem', 'configManager.vsanInternalSystem', ) end hosts_props = hosts_props.select do |k,v| v['runtime.connectionState'] == 'connected' end vsan_systems = hosts_props.map{|h,p| p['configManager.vsanSystem']} vsan_props = pc.collectMultiple(vsan_systems, 'config.clusterInfo') host_vsan_uuids = Hash[hosts_props.map do |host, props| vsan_system = props['configManager.vsanSystem'] vsan_info = vsan_props[vsan_system]['config.clusterInfo'] [vsan_info.nodeUuid, host] end] vsan_disk_uuids = {} vsan_disk_uuids.merge!( _vsan_host_disks_info(Hash[hosts_props.map{|h, p| [h, p['name']]}]) ) [host_vsan_uuids, hosts_props, vsan_disk_uuids] end |
#_vsan_host_disks_info(hosts) ⇒ Object
hosts is a hash: host => hostname
633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 |
# File 'lib/rvc/modules/vsan.rb', line 633 def _vsan_host_disks_info hosts hosts.each do |k,v| if !v hosts[k] = k.name end end conn = hosts.keys.first._connection vsanDiskUuids = {} $disksCache ||= {} if !hosts.keys.all?{|x| $disksCache[x]} lock = Mutex.new hosts.map do |host, hostname| Thread.new do if !$disksCache[host] c1 = conn.spawn_additional_connection host2 = host.dup_on_conn(c1) $disksCache[host] = [] lock.synchronize do puts "#{Time.now}: Fetching VSAN disk info from #{hostname} (may take a moment) ..." end begin timeout(45) do list = host2.esxcli.vsan.storage.list list.each{|x| x._set_property :host, host} $disksCache[host] = list end rescue Exception => ex lock.synchronize do puts "#{Time.now}: Failed to gather from #{hostname}: #{ex.class}: #{ex.}" end end end end end.each{|t| t.join} puts "#{Time.now}: Done fetching VSAN disk infos" end hosts.map do |host, hostname| disks = $disksCache[host] disks.each do |disk| vsanDiskUuids[disk.VSANUUID] = disk end end vsanDiskUuids 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
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 |
# File 'lib/rvc/modules/device.rb', line 184 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
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 |
# File 'lib/rvc/modules/device.rb', line 151 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 => !(opts[:thick] == 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
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 |
# File 'lib/rvc/modules/host.rb', line 195 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] if opts[:dynamic_target] storage.UpdateInternetScsiName( :iScsiHbaDevice => adapter.device, :iScsiName => opts[:iqn] ) storage.AddInternetScsiSendTargets( :iScsiHbaDevice => adapter.device, :targets => [ VIM::HostInternetScsiHbaSendTarget(:address => opts[:address]) ] ) else storage.AddInternetScsiStaticTargets( :iScsiHbaDevice => adapter.device, :targets => [ VIM::HostInternetScsiHbaStaticTarget( :address => opts[:address], :iScsiName => opts[:iqn]) ] ) end 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
233 234 235 236 237 238 239 240 241 242 243 244 |
# File 'lib/rvc/modules/host.rb', line 233 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
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 |
# File 'lib/rvc/modules/device.rb', line 247 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
272 273 274 275 276 |
# File 'lib/rvc/modules/device.rb', line 272 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
611 612 613 |
# File 'lib/rvc/modules/vm.rb', line 611 def annotate vm, str vm.ReconfigVM_Task(:spec => { :annotation => str }).wait_for_completion end |
#answer(str, vms) ⇒ Object
315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 |
# File 'lib/rvc/modules/vm.rb', line 315 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_license_to_cluster(cluster, opts) ⇒ Object
3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 |
# File 'lib/rvc/modules/vsan.rb', line 3574 def apply_license_to_cluster cluster, opts conn = cluster._connection puts "#{cluster.name}: Applying VSAN License on the cluster..." licenseManager = conn.serviceContent.licenseManager licenseAssignmentManager = licenseManager.licenseAssignmentManager assignment = licenseAssignmentManager.UpdateAssignedLicense( :entity => cluster._ref, :licenseKey => opts[:license_key] ) if opts[:null_reconfigure] # Due to races in the cluster assignment mechanism in vSphere 5.5 GA a # disks may or may not be auto-claimed as would normally be expected. Doing # a Null-Reconfigure causes the license state to be synchronized correctly and # allows auto-claim to work as expected. puts "#{cluster.name}: Null-Reconfigure to force auto-claim..." spec = VIM::ClusterConfigSpecEx() task = cluster.ReconfigureComputeResource_Task(:spec => spec, :modify => true) progress([task]) childtasks = task.child_tasks if childtasks && childtasks.length > 0 progress(childtasks) end end end |
#apply_recommendations(cluster, opts) ⇒ Object
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 234 235 |
# File 'lib/rvc/modules/cluster.rb', line 200 def apply_recommendations cluster, opts pc = cluster._connection.serviceContent.propertyCollector recommendation = _filtered_cluster_recommendations( cluster, opts[:key], opts[:type] ) 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| begin 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) rescue VIM::InvalidArgument end end if all_tasks.length > 0 progress all_tasks all_tasks = [] end recommendation = _filtered_cluster_recommendations( cluster, opts[:key], opts[:type] ) 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(vms, opts) ⇒ Object
31 32 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/vm_guest.rb', line 31 def authenticate vms, opts vms.each do |vm| 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 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
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 |
# File 'lib/rvc/modules/vm.rb', line 234 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
312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 |
# File 'lib/rvc/modules/device.rb', line 312 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
62 63 64 65 66 67 68 69 70 71 72 |
# File 'lib/rvc/modules/vm_guest.rb', line 62 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_compliance(vms) ⇒ Object
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 |
# File 'lib/rvc/modules/spbm.rb', line 500 def check_compliance vms dc, = lookup '~' conn = dc._connection _catch_spbm_resets(conn) do pbm = conn.pbm pm = pbm.serviceContent.profileManager cm = pbm.serviceContent.complianceManager compliance = cm.PbmCheckCompliance(:entities => vms.map do |vm| vm.all_pbmobjref end.flatten) profile_ids = Hash[compliance.map{|x| [x.entity.key, x.profile.uniqueId]}] compliances = Hash[compliance.map{|x| [x.entity.key, x.complianceStatus]}] profiles = nil begin profileIds = profile_ids.values.uniq.compact.map do |x| PBM::PbmProfileId(:uniqueId => x) end if profileIds.length > 0 profiles = pm.PbmRetrieveContent( :profileIds => profileIds ) else profiles = [] end rescue Exception => ex pp "#{ex.class}: #{ex.}" pp profile_ids raise ex end profiles = Hash[profiles.map{|x| [x.profileId.uniqueId, x.name]}] profiles = Hash[profile_ids.map{|k,v| [k, profiles[v] || v]}] t = Terminal::Table.new() t << ['VM/Virtual Disk', 'Profile', 'Compliance'] t.add_separator vms.each do |vm| t << [ vm.name, profiles[vm._ref] || "unknown", compliances[vm._ref] || "unknown", ] vm.disks.each do |disk| id = "#{vm._ref}:#{disk.key}" t << [ " #{disk.deviceInfo.label}", profiles[id] || "unknown", compliances[id] || "unknown", ] end end puts t puts "" stats = Hash[compliances.values.group_by{|x| x}.map{|k,v| [k, v.length]}] stats.sort_by{|k,v| k}.each do |type, count| puts "Number of '#{type}' entities: #{count}" end end 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 |
#check_limits(hosts_and_clusters, opts = {}) ⇒ Object
3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 |
# File 'lib/rvc/modules/vsan.rb', line 3069 def check_limits hosts_and_clusters, opts = {} conn = hosts_and_clusters.first._connection hosts = hosts_and_clusters.select{|x| x.is_a?(VIM::HostSystem)} clusters = hosts_and_clusters.select{|x| x.is_a?(VIM::ClusterComputeResource)} pc = conn.propertyCollector cluster_hosts = pc.collectMultiple(clusters, 'host') cluster_hosts.each do |cluster, props| hosts += props['host'] end hosts = hosts.uniq _run_with_rev(conn, "dev") do hosts_props = pc.collectMultiple(hosts, 'name', 'runtime.connectionState', 'configManager.vsanSystem', 'configManager.vsanInternalSystem' ) hosts = hosts_props.select do |k,v| v['runtime.connectionState'] == 'connected' end.keys if hosts.length == 0 err "Couldn't find any connected hosts" end lock = Mutex.new all_disks = {} puts "#{Time.now}: Gathering stats from all hosts ..." hosts_props.map do |host, props| if props['runtime.connectionState'] != 'connected' next end hosts_props[host]['profiling'] = {} Thread.new do vsanIntSys = props['configManager.vsanInternalSystem'] c1 = conn.spawn_additional_connection vsanIntSys2 = vsanIntSys.dup_on_conn(c1) begin timeout(45) do t1 = Time.now res = vsanIntSys2.query_vsan_statistics( :labels => ['rdtglobal', 'lsom-node'] ) t2 = Time.now hosts_props[host]['profiling']['rdtglobal'] = t2 - t1 hosts_props[host]['rdtglobal'] = res['rdt.globalinfo'] hosts_props[host]['lsom.node'] = res['lsom.node'] end rescue Exception => ex puts "Failed to gather RDT info from #{props['name']}: #{ex.class}: #{ex.}" end begin timeout(60) do t1 = Time.now res = vsanIntSys2.QueryVsanStatistics( :labels => ['dom', 'dom-objects-counts'] ) res = JSON.parse(res) if res && !res['dom.owners.count'] # XXX: Remove me later # This code is a fall back path in case we are dealing # with an old ESX host (before Nov13 2013). As we only # need to be compatible with VSAN GA, we can remove this # code once everyone is upgraded. res = vsanIntSys2.QueryVsanStatistics( :labels => ['dom', 'dom-objects'] ) res = JSON.parse(res) numOwners = res['dom.owners.stats'].keys.length else numOwners = res['dom.owners.count'].keys.length end t2 = Time.now hosts_props[host]['profiling']['domstats'] = t2 - t1 hosts_props[host]['dom'] = { 'numClients'=> res['dom.clients'].keys.length, 'numOwners'=> numOwners, } end rescue Exception => ex puts "Failed to gather DOM info from #{props['name']}: #{ex.class}: #{ex.}" end begin timeout(45) do t1 = Time.now disks = vsanIntSys2.QueryPhysicalVsanDisks(:props => [ 'lsom_objects_count', 'uuid', 'isSsd', 'capacity', 'capacityUsed', ]) t2 = Time.now hosts_props[host]['profiling']['physdisk'] = t2 - t1 disks = JSON.load(disks) # Getting the data from all hosts is kind of overkill, but # this way we deal with partitions and get info on all disks # everywhere. But we have duplicates, so need to merge. lock.synchronize do all_disks.merge!(disks) end end rescue Exception => ex puts "Failed to gather disks info from #{props['name']}: #{ex.class}: #{ex.}" end end end.compact.each{|t| t.join} # hosts_props.each do |host, props| # puts "#{Time.now}: Host #{props['name']}: #{props['profiling']}" # end puts "#{Time.now}: Gathering disks info ..." disks = all_disks vsan_disks_info = {} vsan_disks_info.merge!( _vsan_host_disks_info(Hash[hosts.map{|h| [h, hosts_props[h]['name']]}]) ) disks.each do |k, v| v['esxcli'] = vsan_disks_info[v['uuid']] if v['esxcli'] v['host'] = v['esxcli']._get_property :host hosts_props[v['host']]['components'] ||= 0 hosts_props[v['host']]['components'] += v['lsom_objects_count'] hosts_props[v['host']]['disks'] ||= [] hosts_props[v['host']]['disks'] << v end end t = Terminal::Table.new() t << ['Host', 'RDT', 'Disks'] t.add_separator hosts_props.each do |host, props| rdt = props['rdtglobal'] || {} lsomnode = props['lsom.node'] || {} dom = props['dom'] || {} t << [ props['name'], [ "Assocs: #{rdt['assocCount']}/#{rdt['maxAssocCount']}", "Sockets: #{rdt['socketCount']}/#{rdt['maxSocketCount']}", "Clients: #{dom['numClients'] || 'N/A'}", "Owners: #{dom['numOwners'] || 'N/A'}", ].join("\n"), ([ "Components: #{props['components']}/%s" % [ lsomnode['numMaxComponents'] || 'N/A' ], ] + (props['disks'] || []).map do |disk| if disk['capacity'] > 0 usage = disk['capacityUsed'] * 100 / disk['capacity'] usage = "#{usage}%" else usage = "N/A" end "#{disk['esxcli'].DisplayName}: #{usage}" end).join("\n"), ] end puts t end end |
#check_state(cluster_or_host, opts) ⇒ Object
3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 |
# File 'lib/rvc/modules/vsan.rb', line 3610 def check_state cluster_or_host, opts conn = cluster_or_host._connection pc = conn.propertyCollector if cluster_or_host.is_a?(VIM::ClusterComputeResource) cluster = cluster_or_host hosts = cluster.host else hosts = [host] end _run_with_rev(conn, "dev") do hosts_props = pc.collectMultiple(hosts, 'name', 'runtime.connectionState', 'configManager.vsanSystem', 'configManager.vsanInternalSystem' ) connected_hosts = hosts_props.select do |k,v| v['runtime.connectionState'] == 'connected' end.keys host = connected_hosts.first if !host err "Couldn't find any connected hosts" end vsanIntSys = hosts_props[host]['configManager.vsanInternalSystem'] vsanSysList = Hash[hosts_props.map do |host, props| [props['name'], props['configManager.vsanSystem']] end] clusterInfos = pc.collectMultiple(vsanSysList.values, 'config.clusterInfo') hostUuidMap = Hash[vsanSysList.map do |hostname, sys| [clusterInfos[sys]['config.clusterInfo'].nodeUuid, hostname] end] entries = nil ds_list = host.datastore ds_props = pc.collectMultiple(ds_list, 'name', 'summary.type') ds = ds_props.select{|k, x| x['summary.type'] == "vsan"}.keys.first ds_name = ds_props[ds]['name'] vms = ds.vm vms_props = pc.collectMultiple(vms, 'name', 'runtime.connectionState') puts "#{Time.now}: Step 1: Check for inaccessible VSAN objects" statusses = vsanIntSys.query_cmmds([{:type => 'CONFIG_STATUS'}]) bad = statusses.select do |x| state = _assessAvailabilityByStatus(x['content']['state']) !state['DATA_AVAILABLE'] || !state['QUORUM'] end if !opts[:refresh_state] puts "Detected #{bad.length} objects to not be inaccessible" bad.each do |x| uuid = x['uuid'] hostname = hostUuidMap[x['owner']] puts "Detected #{uuid} on #{hostname} to be inaccessible" end else bad.group_by{|x| hostUuidMap[x['owner']]}.each do |hostname, badOnHost| owner = hosts_props.select{|k,v| v['name'] == hostname}.keys.first owner_props = hosts_props[owner] owner_vsanIntSys = owner_props['configManager.vsanInternalSystem'] badOnHost.each do |x| uuid = x['uuid'] puts "Detected #{uuid} to not be inaccessible, refreshing state" end if badOnHost.length > 0 badUuids = badOnHost.map{|x| x['uuid']} owner_vsanIntSys.AbdicateDomOwnership(:uuids => badUuids) end end puts "" puts "#{Time.now}: Step 1b: Check for inaccessible VSAN objects, again" statusses = vsanIntSys.query_cmmds([{:type => 'CONFIG_STATUS'}]) bad = statusses.select do |x| state = _assessAvailabilityByStatus(x['content']['state']) !state['DATA_AVAILABLE'] || !state['QUORUM'] end bad.each do |x| puts "Detected #{x['uuid']} is still inaccessible" end end puts "" puts "#{Time.now}: Step 2: Check for invalid/inaccessible VMs" invalid_vms = vms_props.select do |k,v| ['invalid', 'inaccessible', 'orphaned'].member?(v['runtime.connectionState']) end.keys tasks = [] invalid_vms.each do |vm| vm_props = vms_props[vm] vm_state = vm_props['runtime.connectionState'] if !opts[:refresh_state] puts "Detected VM '#{vm_props['name']}' as being '#{vm_state}'" else puts "Detected VM '#{vm_props['name']}' as being '#{vm_state}', reloading ..." begin if vm_state == 'orphaned' path = vm.summary.config.vmPathName tasks << vm.reloadVirtualMachineFromPath_Task( :configurationPath => path ) else vm.Reload vm.Reload end rescue Exception => ex puts "#{ex.class}: #{ex.}" end end end tasks = tasks.compact if tasks.length > 0 progress(tasks) end puts "" if opts[:refresh_state] puts "#{Time.now}: Step 2b: Check for invalid/inaccessible VMs again" vms_props = pc.collectMultiple(vms, 'name', 'runtime.connectionState') invalid_vms = vms_props.select do |k,v| ['invalid', 'inaccessible', 'orphaned'].member?(v['runtime.connectionState']) end.keys invalid_vms.each do |vm| vm_props = vms_props[vm] vm_state = vm_props['runtime.connectionState'] puts "Detected VM '#{vm_props['name']}' as still '#{vm_state}'" end puts "" end puts "#{Time.now}: Step 3: Check for VMs for which VC/hostd/vmx" \ " are out of sync" inconsistent_vms = find_inconsistent_vms(cluster_or_host) if opts[:reregister_vms] and not inconsistent_vms.empty? puts "You have chosen to fix these VMs. This involves re-registering" \ " the VM which will cause loss of some of the management state of"\ " this VM (for eg. storage policy, permissions, tags," \ " scheduled tasks, etc. but NO data loss). Do you want to" \ " continue [y/N] ?" opt = $stdin.gets.chomp if opt == 'y' || opt == 'Y' puts "Attempting to fix these vms..." fix_inconsistent_vms(inconsistent_vms) end end puts "" end end |
#chmod(vm, opts) ⇒ Object
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
# File 'lib/rvc/modules/vm_guest.rb', line 139 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
110 111 112 113 114 115 116 117 118 |
# File 'lib/rvc/modules/vm_guest.rb', line 110 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
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 580 581 |
# File 'lib/rvc/modules/vm.rb', line 550 def clone src, dst, opts folder, name = *dst diskMoveType = nil if opts[:linked] deltaize_disks src diskMoveType = :moveChildMostDiskBacking end if opts[:customizationspecname] begin spec = src._connection.serviceContent.customizationSpecManager.GetCustomizationSpec(:name => opts[:customizationspecname]).spec rescue print "Customization Spec '#{opts[:customizationspecname]}' not found\n" return end end task = src.CloneVM_Task(:folder => folder, :name => name, :spec => { :customization => spec, :location => { :diskMoveType => diskMoveType, :host => opts[:host], :pool => opts[:pool], }, :template => opts[:template], :powerOn => opts[:power_on], }) progress [task] end |
#cluster_info(cluster) ⇒ Object
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 |
# File 'lib/rvc/modules/vsan.rb', line 255 def cluster_info cluster conn = cluster._connection pc = conn.propertyCollector hosts = cluster.host hosts_props = pc.collectMultiple(hosts, 'name', 'runtime.connectionState') connected_hosts = hosts_props.select do |k,v| v['runtime.connectionState'] == 'connected' end.keys hosts = connected_hosts _run_with_rev(conn, "dev") do hosts.each do |host| begin puts "Host: #{hosts_props[host]['name']}" _host_info host, " " rescue Exception => ex puts "#{Time.now}: Got exception: #{ex.class}: #{ex.}" end puts "" end end end |
#cluster_set_default_policy(cluster, policy) ⇒ Object
443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 |
# File 'lib/rvc/modules/vsan.rb', line 443 def cluster_set_default_policy cluster, policy hosts = cluster.host conn = cluster._connection pc = conn.propertyCollector _run_with_rev(conn, "dev") do vsan, = hosts.first.collect 'configManager.vsanSystem' cluster_uuid, = vsan.collect 'config.clusterInfo.uuid' hosts.each do |host| policy_node = host.esxcli.vsan.policy ['cluster', 'vdisk', 'vmnamespace', 'vmswap'].each do |policy_class| policy_node.setdefault( :clusteruuid => cluster_uuid, :policy => policy, :policyclass => policy_class, ) end end end end |
#cmmds_find(cluster_or_host, opts) ⇒ Object
881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 |
# File 'lib/rvc/modules/vsan.rb', line 881 def cmmds_find cluster_or_host, opts conn = cluster_or_host._connection pc = conn.propertyCollector host = cluster_or_host entries = [] hostUuidMap = {} _run_with_rev(conn, "dev") do vsanIntSys = nil if cluster_or_host.is_a?(VIM::ClusterComputeResource) cluster = cluster_or_host hosts = cluster.host else hosts = [host] end hosts_props = pc.collectMultiple(hosts, 'name', 'runtime.connectionState', 'configManager.vsanSystem', 'configManager.vsanInternalSystem' ) connected_hosts = hosts_props.select do |k,v| v['runtime.connectionState'] == 'connected' end.keys host = connected_hosts.first if !host err "Couldn't find any connected hosts" end vsanIntSys = hosts_props[host]['configManager.vsanInternalSystem'] vsanSysList = Hash[hosts_props.map do |host, props| [props['name'], props['configManager.vsanSystem']] end] clusterInfos = pc.collectMultiple(vsanSysList.values, 'config.clusterInfo') hostUuidMap = Hash[vsanSysList.map do |hostname, sys| [clusterInfos[sys]['config.clusterInfo'].nodeUuid, hostname] end] entries = vsanIntSys.query_cmmds([{ :owner => opts[:owner], :uuid => opts[:uuid], :type => opts[:type], }], :gzip => true) end t = Terminal::Table.new() t << ['#', 'Type', 'UUID', 'Owner', 'Health', 'Content'] t.add_separator entries.each_with_index do |entry, i| t << [ i + 1, entry['type'], entry['uuid'], hostUuidMap[entry['owner']] || entry['owner'], entry['health'], PP.pp(entry['content'], ''), ] end puts t 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 |
#config_syslog(entity, ip, opts) ⇒ Object
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 |
# File 'lib/rvc/modules/syslog.rb', line 35 def config_syslog entity, ip, opts if entity.is_a?(VIM) puts "#{Time.now}: Finding all Hosts inside VC" $shell.fs.marks['vcrvc'] = entity hosts = [] hosts += $shell.fs.lookup("~vcrvc/*/computers/*/host") hosts += $shell.fs.lookup("~vcrvc/*/computers/*/hosts/*") elsif entity.is_a?(VIM::ComputeResource) hosts = entity.host else hosts = [entity] end if hosts.length == 0 err "No hosts found" end conn = hosts.first._connection pc = conn.propertyCollector lock = Mutex.new hosts_props = pc.collectMultiple(hosts, 'name', 'runtime.connectionState', ) connected_hosts = hosts_props.select do |k,v| v['runtime.connectionState'] == 'connected' end.keys host = connected_hosts.first if !connected_hosts.first err "Couldn't find any connected hosts" end puts "#{Time.now}: Configuring all ESX hosts ..." loghost = "udp://#{ip}:514" hosts.map do |host| Thread.new do begin c1 = conn.spawn_additional_connection host = host.dup_on_conn(c1) hostName = host.name lock.synchronize do puts "#{Time.now}: Configuring syslog on #{hostName}" end syslog = host.esxcli.system.syslog syslog.config.set(:loghost => loghost) syslog.reload rescue Exception => ex puts "#{Time.now}: #{host.name}: Got exception: #{ex.class}: #{ex.}" end end end.each{|t| t.join} puts "#{Time.now}: Done configuring syslog on all hosts" local = "#{File.dirname(__FILE__)}/configurevCloudSuiteSyslog.sh" osType = conn.serviceContent.about.osType if File.exists?(local) && osType == "linux-x64" puts "#{Time.now}: Configuring VCVA ..." Net::SSH.start(conn.host, "root", :password => opts[:vc_root_pwd], :paranoid => false) do |ssh| ssh.scp.upload!(local, "/tmp/configurevCloudSuiteSyslog.sh") cmd = "sh /tmp/configurevCloudSuiteSyslog.sh vcsa #{ip}" puts "#{Time.now}: Running '#{cmd}' on VCVA" puts ssh.exec!(cmd) end puts "#{Time.now}: Done with VC" else puts "#{Time.now}: VC isn't Linux, skipping ..." end puts "#{Time.now}: Done" end |
#configure_drs(clusters, opts) ⇒ Object
106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'lib/rvc/modules/cluster.rb', line 106 def configure_drs clusters, opts clusterSpec = VIM::ClusterConfigSpecEx( :drsConfig => { :defaultVmBehavior => opts[:mode] ? opts[:mode].to_sym : nil, :enabled => !opts[:disabled] } ) tasks = clusters.map do |cluster| cluster.ReconfigureComputeResource_Task(:modify => true, :spec => clusterSpec) end progress(tasks) end |
#configure_ha(clusters, opts) ⇒ Object
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
# File 'lib/rvc/modules/cluster.rb', line 82 def configure_ha clusters, opts spec = VIM::ClusterConfigSpecEx( :dasConfig => { :enabled => !opts[:disabled], } ) tasks = clusters.map do |cluster| cluster.ReconfigureComputeResource_Task(:spec => spec, :modify => true) end progress(tasks) childtasks = tasks.map{|t| t.child_tasks}.flatten.compact if childtasks && childtasks.length > 0 progress(childtasks) end end |
#configure_swap(clusters, opts) ⇒ Object
125 126 127 128 129 130 131 132 133 |
# File 'lib/rvc/modules/cluster.rb', line 125 def configure_swap clusters, opts clusterSpec = VIM::ClusterConfigSpecEx( :vmSwapPlacement => opts[:mode] ) tasks = clusters.map do |cluster| cluster.ReconfigureComputeResource_Task(:modify => true, :spec => clusterSpec) end progress(tasks) 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.5'].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
288 289 290 291 292 293 294 295 |
# File 'lib/rvc/modules/device.rb', line 288 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 |
#convert_uuids(uuids) ⇒ Object
960 961 962 963 964 965 966 967 968 969 970 971 972 973 |
# File 'lib/rvc/modules/vsan.rb', line 960 def convert_uuids uuids nUuids = {} uuids.each do |uuid| begin oUuid = uuid.split(' ').join() nUuids[oUuid[0..7] + '-' + oUuid[8..11] + '-' + oUuid[12..20] + '-' + oUuid[21..-1]] = true rescue Exception => ex puts "Ignoring malformed uuid #{uuid}: #{ex.class}: #{ex.}" end end return nUuids end |
#counter(counter_name, obj) ⇒ Object
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 307 308 |
# File 'lib/rvc/modules/perf.rb', line 269 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 259 260 |
# 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", "Per-Dev", "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| pp counter table.add_row [counter.name, counter.nameInfo.label, counter.unitInfo.label, counter.level, counter.perDeviceLevel, active_intervals_text[counter.level]] end end puts(table) end |
#create(name, parent, opts) ⇒ Object
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 |
# File 'lib/rvc/modules/vm.rb', line 172 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) ⇒ 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 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
583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 |
# File 'lib/rvc/modules/vm.rb', line 583 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 |
#deselect_vmknic_for_service(vmknic, service, hosts) ⇒ Object
283 284 285 286 287 288 |
# File 'lib/rvc/modules/host.rb', line 283 def deselect_vmknic_for_service vmknic, service, hosts hosts.each do |host| vnicSys = host.configManager.virtualNicManager vnicSys.DeselectVnicForNicType(:nicType => service, :device => vmknic) end end |
#destroy(objs) ⇒ Object
284 285 286 |
# File 'lib/rvc/modules/basic.rb', line 284 def destroy objs tasks objs, :Destroy end |
#device_add_disk(vm, path, opts) ⇒ Object
642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 |
# File 'lib/rvc/modules/spbm.rb', line 642 def device_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' conn = vm._connection _run_with_rev(conn, "dev") do profile = nil if opts[:profile] profile = [VIM::VirtualMachineDefinedProfileSpec( :profileId => opts[:profile].profileId.uniqueId )] end spec = { :deviceChange => [ { :operation => :add, :fileOperation => opts[:file_op], :device => 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 ), :profile => profile, }, ] } task = vm.ReconfigVM_Task(:spec => spec) result = progress([task])[task] if result == nil new_device = vm.collect('config.hardware.device')[0].grep(VIM::VirtualDisk).last puts "Added device #{new_device.name}" end end end |
#device_change_storage_profile(devs, opts) ⇒ Object
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 491 492 493 |
# File 'lib/rvc/modules/spbm.rb', line 463 def device_change_storage_profile devs, opts if !opts[:profile] err "Must specify a storage profile" end vm_devs = devs.group_by(&:rvc_vm) conn = vm_devs.keys.first._connection _catch_spbm_resets(conn) do _run_with_rev(conn, "dev") do profile = nil if opts[:profile] profile = [VIM::VirtualMachineDefinedProfileSpec( :profileId => opts[:profile].profileId.uniqueId )] end tasks = vm_devs.map do |vm, my_devs| spec = { :deviceChange => my_devs.map do |dev| { :operation => :edit, :device => dev, :profile => profile, } end } vm.ReconfigVM_Task(:spec => spec) end progress(tasks) end end end |
#disable_vsan_on_cluster(cluster) ⇒ Object
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 |
# File 'lib/rvc/modules/vsan.rb', line 97 def disable_vsan_on_cluster cluster conn = cluster._connection _run_with_rev(conn, "dev") do spec = VIM::ClusterConfigSpecEx( :vsanConfig => { :enabled => false, } ) task = cluster.ReconfigureComputeResource_Task(:spec => spec, :modify => true) progress([task]) childtasks = task.child_tasks if childtasks && childtasks.length > 0 progress(childtasks) end end end |
#disconnect(devs) ⇒ Object
166 167 168 |
# File 'lib/rvc/modules/host.rb', line 166 def disconnect hosts tasks hosts, :DisconnectHost end |
#disk_object_info(cluster_or_host, disk_uuids, opts = {}) ⇒ Object
738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 |
# File 'lib/rvc/modules/vsan.rb', line 738 def disk_object_info cluster_or_host, disk_uuids, opts = {} conn = cluster_or_host._connection pc = conn.propertyCollector if cluster_or_host.is_a?(VIM::ClusterComputeResource) cluster = cluster_or_host hosts = cluster.host else hosts = [cluster_or_host] end _run_with_rev(conn, "dev") do # XXX: This doesn't yet work when no cluster is given host_vsan_uuids, hosts_props, vsan_disk_uuids = _vsan_cluster_disks_info(cluster) input_disk_uuids = [] m_disk_uuids = [] disk_uuids.each do |disk_uuid| disk = vsan_disk_uuids.find {|k,v| v.DisplayName == disk_uuid} if disk input_disk_uuids << disk if disk[1].IsSSD disks = vsan_disk_uuids.find_all do |k,v| v.VSANDiskGroupName == disk_uuid unless v.IsSSD end m_disk_uuids += disks else m_disk_uuids << disk end else input_disk_uuids << [disk_uuid] m_disk_uuids << [disk_uuid] end end input_disk_uuids.map! {|x| x[0]} m_disk_uuids.map! {|x| x[0]} connected_hosts = hosts_props.select do |k,v| v['runtime.connectionState'] == 'connected' end.keys hosts = connected_hosts if hosts.length == 0 err "Couldn't find any connected hosts" end dslist = hosts.first.datastore dslist_props = pc.collectMultiple(dslist, 'name', 'summary.type') vsandslist = dslist_props.select{|k, v| v['summary.type'] == 'vsan'}.keys vsands = vsandslist.first if !vsands err "Couldn't find VSAN datastore" end vms = vsands.vm vms_props = pc.collectMultiple(vms, 'name', 'config.hardware.device', 'summary.config' ) objects = {} vms.each do |vm| disks = vms_props[vm]['disks'] = vms_props[vm]['config.hardware.device'].select{|x| x.is_a?(VIM::VirtualDisk)} namespaceUuid = vms_props[vm]['namespaceUuid'] = vms_props[vm]['summary.config'].vmPathName.split("] ")[1].split("/")[0] objects[namespaceUuid] = [vm, :namespace] disks.each do |disk| backing = disk.backing while backing objects[backing.backingObjectId] = [vm, backing.fileName] backing = backing.parent end end end vsanIntSys = hosts_props[hosts.first]['configManager.vsanInternalSystem'] json = vsanIntSys.QueryObjectsOnPhysicalVsanDisk(:disks => m_disk_uuids) if json == "BAD" err "Server rejected VSAN object-on-disk query" end result = nil begin result = JSON.load(json) rescue err "Server failed to query VSAN objects-on-disk: #{json}" end result.merge!({ 'host_vsan_uuids' => host_vsan_uuids, 'host_props' => hosts_props, 'vsan_disk_uuids' => vsan_disk_uuids, }) input_disk_uuids.each do |disk_uuid| dom_obj_uuids = [] disk_info = vsan_disk_uuids[disk_uuid] if disk_info name = "#{disk_info.DisplayName} (#{disk_uuid})" if disk_info.IsSSD m_disks = vsan_disk_uuids.find_all do |k, v| v.VSANDiskGroupUUID == disk_uuid unless v.IsSSD end m_disks ? m_disks.map!{|x| x[0]} : disk_uuid m_disks.each {|m_disk| dom_obj_uuids += result['objects_on_disks'][m_disk]} else dom_obj_uuids = result['objects_on_disks'][disk_uuid] end else name = disk_uuid end puts "Physical disk #{name}:" indent = 1 dom_obj_uuids.each do |obj_uuid| object = objects[obj_uuid] if object && object[1] == :namespace vm_name = vms_props[object[0]]['name'] context = "Part of VM #{vm_name}: Namespace directory" elsif object vm_name = vms_props[object[0]]['name'] context = "Part of VM #{vm_name}: Disk: #{object[1]}" else context = "Can't attribute object to any VM, may be swap?" end _print_dom_config_tree( obj_uuid, result, indent, :highlight_disk => disk_uuid, :context => context ) end puts "" end end end |
#disks_info(hosts) ⇒ 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 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 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 |
# File 'lib/rvc/modules/vsan.rb', line 285 def disks_info hosts conn = hosts.first._connection pc = conn.propertyCollector _run_with_rev(conn, "dev") do hosts.each do |host| if hosts.length > 0 puts "Disks on host #{host.name}:" end dsList = host.datastore dsListProps = pc.collectMultiple(dsList, 'summary', 'name', 'info') vmfsDsList = dsListProps.select do |ds, props| props['summary'].type == "VMFS" end.keys vsan = host.configManager.vsanSystem disks = vsan.QueryDisksForVsan() partitions = host.esxcli.storage.core.device.partition.list t = Terminal::Table.new() t << ['DisplayName', 'isSSD', 'Size', 'State'] needSep = true disks.each do |disk| capacity = disk.disk.capacity size = capacity.block * capacity.blockSize sizeStr = "#{size / 1024**3} GB" state = disk.state # if needSep t.add_separator needSep = false # end if state != 'eligible' && disk.error state += " (#{disk.error.localizedMessage})" if disk.error.fault.is_a?(VIM::DiskHasPartitions) state += "\n" state += "\n" state += "Partition table:\n" partitions.select do |x| x.Device == disk.disk.canonicalName && x.Type != 0 end.each do |x| partSize = x.Size.to_f / 1024**3 types = { 0xfb => 'vmfs', 0xfc => 'coredump', 0xfa => 'vsan', 0x0 => 'unused', 0x6 => 'vfat', } type = types[x.Type] || x.Type state += "#{x.Partition}: %.2f GB, type = #{type}" % partSize if type == "vmfs" vmfsStr = vmfsDsList.select do |vmfsDs| props = dsListProps[vmfsDs] props['info'].vmfs.extent.any? do |ext| ext.diskName == x.Device && x.Partition == ext.partition end end.map do |vmfsDs| "'#{dsListProps[vmfsDs]['name']}'" end.join(", ") if vmfsStr state += " (#{vmfsStr})" end end state += "\n" end needSep = true end end t << [ [ disk.disk.displayName, [ disk.disk.vendor, disk.disk.model ].compact.map{|x| x.strip}.join(" ") ].join("\n"), disk.disk.ssd ? "SSD" : "MD", sizeStr, state ] end puts t if hosts.length > 0 puts "" end end end end |
#disks_stats(hosts_and_clusters, opts = {}) ⇒ Object
1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 |
# File 'lib/rvc/modules/vsan.rb', line 1386 def disks_stats hosts_and_clusters, opts = {} opts[:compute_number_of_components] = true conn = hosts_and_clusters.first._connection hosts = hosts_and_clusters.select{|x| x.is_a?(VIM::HostSystem)} clusters = hosts_and_clusters.select{|x| x.is_a?(VIM::ClusterComputeResource)} pc = conn.propertyCollector cluster_hosts = pc.collectMultiple(clusters, 'host') cluster_hosts.each do |cluster, props| hosts += props['host'] end hosts = hosts.uniq _run_with_rev(conn, "dev") do hosts_props = pc.collectMultiple(hosts, 'name', 'runtime.connectionState', 'configManager.vsanSystem', 'configManager.vsanInternalSystem' ) hosts = hosts_props.select do |k,v| v['runtime.connectionState'] == 'connected' end.keys if hosts.length == 0 err "Couldn't find any connected hosts" end hosts_vsansys = Hash[hosts_props.map{|k,v| [v['configManager.vsanSystem'], k]}] node_uuids = pc.collectMultiple(hosts_vsansys.keys, 'config.clusterInfo.nodeUuid') node_uuids = Hash[node_uuids.map do |k, v| [v['config.clusterInfo.nodeUuid'], hosts_vsansys[k]] end] lock = Mutex.new disks = {} vsanIntSys = hosts_props[hosts.first]['configManager.vsanInternalSystem'] disks = vsanIntSys.QueryPhysicalVsanDisks(:props => [ 'lsom_objects_count', 'uuid', 'isSsd', 'capacity', 'capacityUsed', 'capacityReserved', 'iops', 'iopsReserved', 'disk_health', ]) if disks == "BAD" err "Server failed to gather VSAN disk info" end begin disks = JSON.load(disks) rescue err "Server didn't provide VSAN disk info: #{disks}" end #pp disks vsan_disks_info = {} vsan_disks_info.merge!( _vsan_host_disks_info(Hash[hosts.map{|h| [h, hosts_props[h]['name']]}]) ) disks.each do |k, v| v['esxcli'] = vsan_disks_info[v['uuid']] if v['esxcli'] v['host'] = v['esxcli']._get_property :host end end #pp vsan_disks_info #pp disks.values.map{|x| [x['host'], x['esxcli']]} #pp disks.values.group_by{|x| x['host']}.keys disks = disks.values.sort_by do |x| host_props = hosts_props[x['host']] host_props ? host_props['name'] : '' end # Stats are now better handled by observer # disks.group_by{|x| x['host']}.each do |host, host_disks| # next if !host # devices = host_disks.map{|x| x['esxcli'].Device} # metrics = [ # 'disk.numberReadAveraged', 'disk.numberWriteAveraged', # 'disk.deviceLatency', 'disk.maxTotalLatency', # 'disk.queueLatency', 'disk.kernelLatency' # ] # stats = _fetch_disk_stats host, metrics, devices # disks.each do |v| # if v['esxcli'] && stats[v['esxcli'].Device] # v['stats'] = stats[v['esxcli'].Device] # else # v['stats'] ||= {} # metrics.each{|m| v['stats'][m] ||= [-1] } # end # end # end t = Terminal::Table.new() if opts[:show_iops] t << [nil, nil, nil, 'Num', 'Capacity', nil, nil, 'Iops', nil, nil, ] t << ['DisplayName', 'Host', 'isSSD', 'Comp', 'Total', 'Used', 'Reserved', 'Total', 'Reserved', ] else t << [nil, nil, nil, 'Num', 'Capacity', nil, nil, 'Status'] t << ['DisplayName', 'Host', 'isSSD', 'Comp', 'Total', 'Used', 'Reserved', 'Health'] end t.add_separator # XXX: Would be nice to show displayName and host groups = disks.group_by{|x| x['esxcli'] ? x['esxcli'].VSANDiskGroupUUID : nil} groups.each do |group, disks| disks.sort_by{|x| -x['isSsd']}.each do |x| info = x['esxcli'] host_props = hosts_props[x['host']] cols = [ info ? info.DisplayName : 'N/A', host_props ? host_props['name'] : 'N/A', #x['uuid'], (x['isSsd'] == 1) ? 'SSD' : 'MD', x['lsom_objects_count'] || 'N/A', "%.2f GB" % [x['capacity'].to_f / 1024**3], "%.0f %%" % [x['capacityUsed'].to_f * 100 / x['capacity'].to_f], "%.0f %%" % [x['capacityReserved'].to_f * 100 / x['capacity'].to_f], ] if opts[:show_iops] cols += [ "%d" % [x['iops']], "%.0f %%" % [ x['iopsReserved'].to_f * 100 / x['iops'].to_f], ] end # cols += [ # "%dr/%dw" % [x['stats']['disk.numberReadAveraged'].first, # x['stats']['disk.numberWriteAveraged'].first], # "%dd/%dq/%dk" % [x['stats']['disk.deviceLatency'].first, # x['stats']['disk.queueLatency'].first, # x['stats']['disk.kernelLatency'].first,], # ] health = "N/A" if x['disk_health'] && x['disk_health']['healthFlags'] flags = x['disk_health']['healthFlags'] health = [] { 4 => "FAILED", 5 => "OFFLINE", 6 => "DECOMMISSIONED", }.each do |k, v| if flags & (1 << k) != 0 health << v end end if health.length == 0 health = "OK" else health = health.join(", ") end end cols += [ health ] t << cols end if group != groups.keys.last t.add_separator end end puts t end 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
337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 |
# File 'lib/rvc/modules/vm_guest.rb', line 337 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}" generic_http_download download_uri, 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 |
#enable_vsan_on_cluster(cluster, opts) ⇒ Object
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
# File 'lib/rvc/modules/vsan.rb', line 68 def enable_vsan_on_cluster cluster, opts conn = cluster._connection _run_with_rev(conn, "dev") do spec = VIM::ClusterConfigSpecEx( :vsanConfig => { :enabled => true, :defaultConfig => { :autoClaimStorage => (!(opts[:disable_storage_auto_claim] || false)), } } ) task = cluster.ReconfigureComputeResource_Task(:spec => spec, :modify => true) progress([task]) childtasks = task.child_tasks if childtasks && childtasks.length > 0 progress(childtasks) end childtasks = task.child_tasks if childtasks && childtasks.length > 0 progress(childtasks) end end end |
#enter_maintenance_mode(hosts, opts) ⇒ Object
139 140 141 142 143 144 145 146 147 |
# File 'lib/rvc/modules/host.rb', line 139 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
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 |
# File 'lib/rvc/modules/host.rb', line 95 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
379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 |
# File 'lib/rvc/modules/basic.rb', line 379 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
156 157 158 |
# File 'lib/rvc/modules/host.rb', line 156 def exit_maintenance_mode hosts, opts tasks hosts, :ExitMaintenanceMode, :timeout => opts[:timeout] end |
#extra_config(vm, regexes) ⇒ Object
377 378 379 |
# File 'lib/rvc/modules/vm.rb', line 377 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
403 404 405 406 407 408 409 410 411 412 |
# File 'lib/rvc/modules/basic.rb', line 403 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
352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 |
# File 'lib/rvc/modules/vm.rb', line 352 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_inconsistent_vms(cluster_or_host) ⇒ Object
It is possible for the management stack (hostd and vc) to lose the handle of a VM which is powered on (has a running vmx instance). No further operations can be performed on the VM because the running vmx holds locks on the VM. This API is intended to find such VMs. We look for VMs who’s power state is not poweredOn (poweredOff, unknown, etc) for which there is a running vmx instance on any host in the cluster.
982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 |
# File 'lib/rvc/modules/vsan.rb', line 982 def find_inconsistent_vms cluster_or_host if cluster_or_host.is_a?(VIM::ClusterComputeResource) hosts = cluster_or_host.host else hosts = [host] end # Find all non-poweredon vms. conn = hosts.first._connection pc = conn.propertyCollector vms = pc.collectMultiple(hosts, 'vm').values.map{|x| x['vm']}.flatten vmProps = pc.collectMultiple(vms, 'name', 'runtime.powerState', 'summary.config.uuid') notOnVMs = vmProps.select{|vm, p| p['runtime.powerState'] != 'poweredOn'}.keys # Get list of all running vms on all hosts in parallel. threads = [] processList = {} hosts.each do |host| threads << Thread.new do begin processList[host] = host.esxcli.vm.process.list rescue Exception => ex puts "Error getting vm process list on #{host.name}: " \ "#{ex.class}: #{ex.}" end end end threads.each{|t| t.join} uuids = convert_uuids(processList.values.flatten.map{|x| x.UUID}) inconsistentVMs = notOnVMs.select{|vm| uuids.has_key?(vmProps[vm]['summary.config.uuid'])} if not inconsistentVMs.empty? puts "Found VMs for which VC/hostd/vmx are out of sync:" inconsistentVMs.each do |vm| puts "#{vmProps[vm]['name']}" end else puts "Did not find VMs for which VC/hostd/vmx are out of sync" end return inconsistentVMs 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
667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 |
# File 'lib/rvc/modules/vm.rb', line 667 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 |
#fix_inconsistent_vms(vms) ⇒ Object
1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 |
# File 'lib/rvc/modules/vsan.rb', line 1028 def fix_inconsistent_vms vms begin tasks = [] vms.each do |vm| begin path = vm.summary.config.vmPathName rp = vm.resourcePool folder = vm.parent name = vm.name host = vm.summary.runtime.host puts("Unregistering VM #{name}") vm.UnregisterVM() puts("Registering VM #{name}") tasks << folder.RegisterVM_Task(:path => path, :name => name, :asTemplate => false, :pool => rp, :host => host) rescue Exception => ex puts "Skipping VM #{name} due to exception: " \ "#{ex.class}: #{ex.}" end end progress(tasks) end end |
#fix_renamed_vms(vms) ⇒ Object
1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 |
# File 'lib/rvc/modules/vsan.rb', line 1068 def fix_renamed_vms vms begin conn = vms.first._connection pc = conn.propertyCollector vmProps = pc.collectMultiple(vms, 'name', 'summary.config.vmPathName') rename = {} puts "Continuing this command will rename the following VMs:" begin vmProps.each do |k,v| name = v['name'] cfgPath = v['summary.config.vmPathName'] if /.*vmfs.*volumes.*/.match(name) m = /.+\/(.+)\.vmx/.match(cfgPath) if name != m[1] # Save it in a hash so we don't have to do it again if # user choses Y. rename[k] = m[1] puts "#{name} -> #{m[1]}" end end end rescue Exception => ex # Swallow the exception. No need to stop other vms. puts "Skipping VM due to exception: #{ex.class}: #{ex.}" end if rename.length == 0 puts "Nothing to do" return end puts "Do you want to continue [y/N]?" opt = $stdin.gets.chomp if opt == 'y' || opt == 'Y' puts "Renaming..." tasks = rename.keys.map do |vm| vm.Rename_Task(:newName => rename[vm]) end progress(tasks) end end end |
#generic_http_download(uri, local_path) ⇒ 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 |
# File 'lib/rvc/modules/vm_guest.rb', line 267 def generic_http_download uri, local_path http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true http.verify_mode = OpenSSL::SSL::VERIFY_NONE #http.set_debug_output $stderr http.start # headers = { 'cookie' => connection.cookie } headers = {} http_path = "#{uri.path}?#{uri.query}" http.request_get(http_path, headers) do |res| case res when Net::HTTPOK len = res.content_length count = 0 File.open(local_path, 'wb') do |io| res.read_body do |segment| count += segment.length io.write segment $stdout.write "\e[0G\e[Kdownloading #{count}/#{len} bytes (#{(count*100)/len}%)" $stdout.flush end end $stdout.puts else err "download failed: #{res.}" end end end |
#generic_http_upload(local_path, uri, size = nil) ⇒ Object
297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 |
# File 'lib/rvc/modules/vm_guest.rb', line 297 def generic_http_upload local_path, uri, size = nil http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true http.verify_mode = OpenSSL::SSL::VERIFY_NONE #http.set_debug_output $stderr http.start open(local_path, 'rb') do |io| stream = ProgressStream.new(io, size || io.stat.size) do |s| $stdout.write "\e[0G\e[Kuploading #{s.count}/#{s.len} bytes (#{(s.count*100)/s.len}%)" $stdout.flush end headers = { 'content-length' => (size || io.stat.size).to_s, 'Content-Type' => 'application/octet-stream', } http_path = "#{uri.path}?#{uri.query}" request = Net::HTTP::Put.new http_path, headers request.body_stream = stream res = http.request(request) $stdout.puts case res when Net::HTTPOK else err "upload failed: #{res.}" end end 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
121 122 123 124 125 |
# File 'lib/rvc/modules/vm_guest.rb', line 121 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 |
#host_consume_disks(hosts_or_clusters, opts) ⇒ Object
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 |
# File 'lib/rvc/modules/vsan.rb', line 159 def host_consume_disks hosts_or_clusters, opts conn = hosts_or_clusters.first._connection hosts = [] hosts_or_clusters.each do |host_or_cluster| if host_or_cluster.is_a?(VIM::HostSystem) hosts << host_or_cluster else hosts += host_or_cluster.host end end if opts[:filter_ssd_by_model] opts[:filter_ssd_by_model] = /#{opts[:filter_ssd_by_model]}/ end tasks = [] results = {} _run_with_rev(conn, "dev") do tasks = hosts.map do |host| host.consume_disks_for_vsan(opts) end.compact if tasks.length > 0 results = progress(tasks) pp results.values.flatten.map{|x| x.error}.compact else puts "No disks were consumed." end $claimResults = results end $disksCache = {} end |
#host_info(host) ⇒ Object
243 244 245 246 247 248 |
# File 'lib/rvc/modules/vsan.rb', line 243 def host_info host conn = host._connection _run_with_rev(conn, "dev") do _host_info host end end |
#host_wipe_vsan_disks(hosts, opts) ⇒ Object
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 234 235 236 |
# File 'lib/rvc/modules/vsan.rb', line 195 def host_wipe_vsan_disks hosts, opts conn = hosts.first._connection tasks = [] _run_with_rev(conn, "dev") do tasks = hosts.map do |host| hostname = host.name disks = host.filtered_disks_for_vsan(:state_filter => /^inUse$/) if disks.length == 0 next end if !opts[:force] # Don't actually wipe, but show a warning. disks.each do |disk| model = [ disk.vendor, disk.model ].compact.map{|x| x.strip}.join(" ") puts "Would wipe disk #{disk.displayName} (#{model}, ssd = #{disk.ssd})" end end if opts[:force] #disks = disks.select{|x| x.ssd} #host.configManager.vsanSystem.RemoveDisk_Task(:disk => disks) # See PR 1077658 vsan = host.configManager.vsanSystem vsan.RemoveDiskMapping_Task(:mapping => vsan.config.storageInfo.diskMapping) end end.compact if tasks.length > 0 results = progress(tasks) pp results.values.flatten.map{|x| x.error}.compact $wipeResults = results end end if !opts[:force] puts "" puts "NO ACTION WAS TAKEN. Use --force to actually wipe." puts "CAUTION: Wiping disks means all user data will be destroyed!" end $disksCache = {} 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 272 273 274 |
# 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 obj.methods.grep(/rvc_display_info_/).sort.each do |method| obj.send(method) end else puts "class: #{obj.class.name}" end end |
#insert_cdrom(dev, iso) ⇒ Object
210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 |
# File 'lib/rvc/modules/device.rb', line 210 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
493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 |
# File 'lib/rvc/modules/vm.rb', line 493 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 |
#is_uuid(str) ⇒ Object
58 59 60 |
# File 'lib/rvc/modules/vsan.rb', line 58 def is_uuid str str =~ /[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}/ 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
294 295 296 297 298 299 300 301 302 303 304 305 306 307 |
# File 'lib/rvc/modules/vm.rb', line 294 def kill vms on_vms = [] vms.each do |vm| begin if vm.summary.runtime.powerState == 'poweredOn' on_vms.push(vm) end rescue Exception => ex puts "vm.rb:kill: Skipping current object #{vm} due to Exception: #{ex.}" end end off on_vms unless on_vms.empty? shell.cmds.basic.destroy vms unless vms.empty? end |
#layout(vm) ⇒ Object
338 339 340 341 342 |
# File 'lib/rvc/modules/vm.rb', line 338 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.rvc_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
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
# File 'lib/rvc/modules/vm_guest.rb', line 80 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 |
#lldpnetmap(hosts_and_clusters, opts = {}) ⇒ Object
3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 |
# File 'lib/rvc/modules/vsan.rb', line 3003 def lldpnetmap hosts_and_clusters, opts = {} conn = hosts_and_clusters.first._connection hosts = hosts_and_clusters.select{|x| x.is_a?(VIM::HostSystem)} clusters = hosts_and_clusters.select{|x| x.is_a?(VIM::ClusterComputeResource)} pc = conn.propertyCollector cluster_hosts = pc.collectMultiple(clusters, 'host') cluster_hosts.each do |cluster, props| hosts += props['host'] end hosts = hosts.uniq _run_with_rev(conn, "dev") do hosts_props = pc.collectMultiple(hosts, 'name', 'runtime.connectionState', 'configManager.vsanSystem', 'configManager.vsanInternalSystem' ) hosts = hosts_props.select do |k,v| v['runtime.connectionState'] == 'connected' end.keys if hosts.length == 0 err "Couldn't find any connected hosts" end hosts_vsansys = Hash[hosts_props.map{|k,v| [v['configManager.vsanSystem'], k]}] node_uuids = pc.collectMultiple(hosts_vsansys.keys, 'config.clusterInfo.nodeUuid') node_uuids = Hash[node_uuids.map do |k, v| [v['config.clusterInfo.nodeUuid'], hosts_vsansys[k]] end] puts "#{Time.now}: This operation will take 30-60 seconds ..." hosts_props.map do |host, props| Thread.new do begin vsanIntSys = props['configManager.vsanInternalSystem'] c1 = conn.spawn_additional_connection vsanIntSys = vsanIntSys.dup_on_conn(c1) res = vsanIntSys.QueryVsanStatistics(:labels => ['lldpnetmap']) hosts_props[host]['lldpnetmap'] = JSON.parse(res)['lldpnetmap'] rescue Exception => ex puts "Failed to gather lldpnetmap from #{props['name']}: #{ex.class}: #{ex.}" end end end.each{|t| t.join} t = Terminal::Table.new() t << ['Host', 'LLDP info'] t.add_separator hosts_props.each do |host, props| t << [ props['name'], props['lldpnetmap'].map do |switch, pnics| "#{switch}: #{pnics.join(',')}" end.join("\n") ] end puts t 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.rvc_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
422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 |
# File 'lib/rvc/modules/vm_guest.rb', line 422 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
531 532 533 534 535 |
# File 'lib/rvc/modules/vm.rb', line 531 def migrate vms, opts tasks vms, :MigrateVM, :pool => opts[:pool], :host => opts[:host], :priority => :defaultPriority end |
#migrate_vmknic(host, vmknic, portgroup) ⇒ Object
671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 |
# File 'lib/rvc/modules/vds.rb', line 671 def migrate_vmknic host, vmknic, portgroup if !portgroup.is_a?(VIM::DistributedVirtualPortgroup) err "Only migration from standard to a distributed vSwitch is supported for now." end ns = host.configManager.networkSystem # Find the VMkernel interface. vmk_dev = nil ns.networkInfo.vnic.each do |vnic| if vnic.device == vmknic vmk_dev = vnic break end end # Find the source portgroup. src_pg = nil ns.networkInfo.portgroup.each do |pg| if pg.spec.name == vmk_dev.portgroup src_pg = pg break end end ns.UpdateNetworkConfig( changeMode: 'modify', config: VIM::HostNetworkConfig( portgroup: [ VIM::HostPortGroupConfig( changeOperation: 'remove', spec: src_pg.spec ) ], vnic: [ VIM::HostVirtualNicConfig( changeOperation: 'edit', device: vmknic, portgroup: src_pg.spec.name, spec: VIM::HostVirtualNicSpec( distributedVirtualPort: VIM::DistributedVirtualSwitchPortConnection( portgroupKey: portgroup.key, switchUuid: portgroup.config.distributedVirtualSwitch.uuid ) ) ) ] ) ) end |
#mkdir(datastore_path) ⇒ Object
TODO dispatch to datastore.mkdir if path is in a datastore
365 366 367 368 |
# File 'lib/rvc/modules/basic.rb', line 365 def mkdir path parent = lookup_single! File.dirname(path), RbVmomi::VIM::Folder parent.CreateFolder(:name => File.basename(path)) end |
#mktmpdir(vm, opts) ⇒ Object
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 |
# File 'lib/rvc/modules/vm_guest.rb', line 171 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
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 |
# File 'lib/rvc/modules/vm_guest.rb', line 200 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_counters(counter_names, opts) ⇒ Object
318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 |
# File 'lib/rvc/modules/perf.rb', line 318 def modify_counters counter_names, opts vim = lookup_single('~@') pm = vim.serviceContent.perfManager pm.UpdateCounterLevelMapping( :counterLevelMap => counter_names.map do |counter_name| counter = pm.perfcounter_hash[counter_name] if !counter err "no such counter #{counter_name.inspect}" end aggregateLevel = opts[:aggregate_level] || counter.level perDeviceLevel = opts[:per_device_level] || counter.perDeviceLevel { :counterId => counter.key, :aggregateLevel => aggregateLevel, :perDeviceLevel => perDeviceLevel, } end ) end |
#modify_cpu(vm, opts) ⇒ Object
623 624 625 626 627 628 629 630 631 632 633 634 635 636 |
# File 'lib/rvc/modules/vm.rb', line 623 def modify_cpu vm, opts alloc, = vm.collect 'config.cpuAllocation' if opts[:reservation] alloc.reservation = opts[:reservation] end if opts[:limit] alloc.limit = opts[:limit] end spec = { :numCPUs => opts[:num], :cpuAllocation => alloc, } tasks [vm], :ReconfigVM, :spec => spec end |
#modify_memory(vm, opts) ⇒ Object
647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 |
# File 'lib/rvc/modules/vm.rb', line 647 def modify_memory vm, opts err "memory must be a multiple of 4MB" unless ( opts[:size] % 4 ) == 0 #alloc, = vm.collect 'config.memoryAllocation' alloc = VIM::ResourceAllocationInfo() if opts[:reservation] alloc.reservation = opts[:reservation] end if opts[:limit] alloc.limit = opts[:limit] end spec = { :memoryMB => opts[:size], :memoryAllocation => alloc, } tasks [vm], :ReconfigVM, :spec => spec end |
#mv(objs) ⇒ Object
324 325 326 327 328 |
# File 'lib/rvc/modules/basic.rb', line 324 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
482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 |
# File 'lib/rvc/modules/vm_guest.rb', line 482 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
508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 |
# File 'lib/rvc/modules/vm_guest.rb', line 508 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 |
#namespace_change_storage_profile(vms, opts) ⇒ Object
568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 |
# File 'lib/rvc/modules/spbm.rb', line 568 def namespace_change_storage_profile vms, opts if !opts[:profile] err "Must specify a storage profile" end conn = vms.first._connection _catch_spbm_resets(conn) do _run_with_rev(conn, "dev") do profile = nil if opts[:profile] profile = [VIM::VirtualMachineDefinedProfileSpec( :profileId => opts[:profile].profileId.uniqueId )] end tasks = vms.map do |vm| spec = { :vmProfile => profile, } vm.ReconfigVM_Task(:spec => spec) end progress(tasks) end end end |
#obj_status_report(cluster_or_host, opts) ⇒ Object
3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 |
# File 'lib/rvc/modules/vsan.rb', line 3294 def obj_status_report cluster_or_host, opts conn = cluster_or_host._connection pc = conn.propertyCollector if cluster_or_host.is_a?(VIM::ClusterComputeResource) cluster = cluster_or_host hosts = cluster.host else hosts = [host] end _run_with_rev(conn, "dev") do hosts_props = pc.collectMultiple(hosts, 'name', 'runtime.connectionState', 'configManager.vsanSystem', 'configManager.vsanInternalSystem' ) connected_hosts = hosts_props.select do |k,v| v['runtime.connectionState'] == 'connected' end.keys host = connected_hosts.first if !host err "Couldn't find any connected hosts" end vsanIntSys = hosts_props[host]['configManager.vsanInternalSystem'] vsanSysList = Hash[hosts_props.map do |host, props| [props['name'], props['configManager.vsanSystem']] end] clusterInfos = pc.collectMultiple(vsanSysList.values, 'config.clusterInfo') hostUuidMap = Hash[vsanSysList.map do |hostname, sys| [clusterInfos[sys]['config.clusterInfo'].nodeUuid, hostname] end] entries = nil puts "#{Time.now}: Querying all VMs on VSAN ..." ds_list = host.datastore ds_props = pc.collectMultiple(ds_list, 'name', 'summary.type') ds = ds_props.select{|k, x| x['summary.type'] == "vsan"}.keys.first ds_name = ds_props[ds]['name'] vms = ds.vm vmsProps = pc.collectMultiple(vms, 'name', 'runtime.connectionState', 'config.hardware.device', 'summary.config' ) hostname = hosts_props[host]['name'] puts "#{Time.now}: Querying all objects in the system from #{hostname} ..." objects = vsanIntSys.query_cmmds([ {:type => 'DOM_OBJECT'} ], :gzip => true) if !objects err "Server failed to gather DOM_OBJECT entries" end puts "#{Time.now}: Querying all disks in the system ..." # Need a list of live disk uuids to see if components are orphaned. liveDisks = vsanIntSys.query_cmmds([{:type => 'DISK'}]) liveDisks = liveDisks.select do |disk| disk['health'] == "Healthy" end.map do |disk| disk['uuid'] end puts "#{Time.now}: Querying all components in the system ..." # Need a list of live comp uuids to see if components are orphaned. liveComps = vsanIntSys.query_cmmds( [{:type => 'LSOM_OBJECT'}], :gzip => true ) liveComps = liveComps.select do |comp| comp['health'] == "Healthy" end liveComps = liveComps.map do |comp| comp['uuid'] end #pp liveDisks #puts "%d comps total" % liveComps.length puts "#{Time.now}: Got all the info, computing table ..." results = {} orphanRes = {} totalObjects = objects.length totalOrphans = 0 objects = objects.select do |obj| comps = _components_in_dom_config(obj['content']) numHealthy = 0 numDeletedComps = 0 comps.each do |comp| state = comp['attributes']['componentState'] bytesToSync = comp['attributes']['bytesToSync'] || 0 resync = [10, 6].member?(state) && bytesToSync != 0 # Should we count resyncing as healthy? For now, lets do that. if resync || state == 5 || (opts[:ignore_node_uuid] && comp['attributes']['ownerId'] == opts[:ignore_node_uuid]) numHealthy += 1 elsif liveDisks.member?(comp['diskUuid']) && !liveComps.member?(comp['componentUuid']) # A component is considered deleted if it's disk is present # and the component is not present in CMMDS. numDeletedComps += 1 end end obj['numHealthy'] = numHealthy obj['numComps'] = comps.length status = [numHealthy, comps.length] # An object can be orphaned if it is deleted while a minority of # components are absent. To consider this an orphan, the total # number of provably deleted components must be a quorum. # If we have some deleted comps, but not a quorum, then mark it # as an orphanCandidate instead of a full orphan. Orphan candidates # still go into the normal results table. isOrphan = numDeletedComps > 0 && numDeletedComps > comps.length / 2 if isOrphan obj['isOrphan'] = true elsif numDeletedComps > 0 obj['isOrphanCandidate'] = true end if isOrphan # All absent components are orphaned. Consider the object orphaned. totalOrphans += 1 orphanRes[status] ||= 0 orphanRes[status] += 1 else results[status] ||= 0 results[status] += 1 end if opts[:filter_table] ("%d/%d" % [numHealthy, comps.length]) == opts[:filter_table] else true end end obj_uuids = objects.map{|x| x['uuid']} objectUuidMap = Hash[objects.map{|x| [x['uuid'], x]}] all_obj_uuids = [] vmToObjMap = {} vms.each do |vm| vm_obj_uuids = _get_vm_obj_uuids(vm, vmsProps) vm_obj_uuids = vm_obj_uuids.select{|x, v| obj_uuids.member?(x)} vm_obj_uuids = vm_obj_uuids.reject{|x, v| all_obj_uuids.member?(x)} all_obj_uuids += vm_obj_uuids.keys if vm_obj_uuids.length > 0 vmToObjMap[vm] = vm_obj_uuids end end def printObjStatusHist results t = Terminal::Table.new() t << [ 'Num Healthy Comps / Total Num Comps', 'Num objects with such status', ] t.add_separator results.each do |key,val| t << [ "%d/%d" % [key[0], key[1]], " %d" % val, ] end puts t end puts "" puts "Histogram of component health for non-orphaned objects" puts "" printObjStatusHist(results) puts "Total non-orphans: %d" % (totalObjects - totalOrphans) puts "" puts "" puts "Histogram of component health for possibly orphaned objects" puts "" printObjStatusHist(orphanRes) puts "Total orphans: %d" % totalOrphans puts "" if opts[:print_table] || opts[:filter_table] t = Terminal::Table.new() t << [ 'VM/Object', 'objects', 'num healthy / total comps', ] t.add_separator bytesToSyncGrandTotal = 0 objGrandTotal = 0 vmToObjMap.each do |vm, vm_obj_uuids| vmProps = vmsProps[vm] objs = vm_obj_uuids.keys.map{|x| objectUuidMap[x]} t << [ vmProps['name'], objs.length, "", ] objs.each do |obj| if opts[:print_uuids] objName = obj['uuid'] else objName = (vm_obj_uuids[obj['uuid']] || obj['uuid']) end if obj['isOrphan'] orphanStr = "*" elsif obj['isOrphanCandidate'] orphanStr = "-" else orphanStr = "" end t << [ " %s" % objName, '', "%d/%d%s" % [obj['numHealthy'], obj['numComps'], orphanStr], ] objects.delete(obj) end end # Okay, now print the remaining UUIDs which didn't map to any VM. if objects.length > 0 if vmToObjMap.length > 0 t.add_separator end t << [ "Unassociated objects", '', '', ] end objects.each do |obj| if obj['isOrphan'] orphanStr = "*" elsif obj['isOrphanCandidate'] orphanStr = "-" else orphanStr = "" end t << [ " %s" % obj['uuid'], '', "%d/%d%s" % [obj['numHealthy'], obj['numComps'], orphanStr], ] end puts t puts "" puts "+------------------------------------------------------------------+" puts "| Legend: * = all unhealthy comps were deleted (disks present) |" puts "| - = some unhealthy comps deleted, some not or can't tell |" puts "| no symbol = We cannot conclude any comps were deleted |" puts "+------------------------------------------------------------------+" puts "" end end end |
#object_info(cluster, obj_uuids, opts = {}) ⇒ Object
722 723 724 725 726 727 728 729 730 |
# File 'lib/rvc/modules/vsan.rb', line 722 def object_info cluster, obj_uuids, opts = {} opts[:cluster] = cluster objs = _object_info obj_uuids, opts indent = 0 obj_uuids.each do |obj_uuid| _print_dom_config_tree(obj_uuid, objs, indent) puts "" end end |
#object_reconfigure(cluster_or_host, obj_uuids, opts) ⇒ Object
3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 |
# File 'lib/rvc/modules/vsan.rb', line 3243 def object_reconfigure cluster_or_host, obj_uuids, opts conn = cluster_or_host._connection pc = conn.propertyCollector if cluster_or_host.is_a?(VIM::ClusterComputeResource) cluster = cluster_or_host hosts = cluster.host else hosts = [host] end _run_with_rev(conn, "dev") do hosts_props = pc.collectMultiple(hosts, 'name', 'runtime.connectionState', 'configManager.vsanSystem', 'configManager.vsanInternalSystem' ) connected_hosts = hosts_props.select do |k,v| v['runtime.connectionState'] == 'connected' end.keys host = connected_hosts.first if !host err "Couldn't find any connected hosts" end vsanIntSys = hosts_props[host]['configManager.vsanInternalSystem'] obj_uuids.each do |uuid| puts "Reconfiguring '#{uuid}' to #{opts[:policy]}" puts vsanIntSys.ReconfigureDomObject( :uuid => uuid, :policy => opts[:policy] ) end end puts "All reconfigs initiated. Synching operation may be happening in the background" end |
#observer(cluster_or_host, opts) ⇒ Object
2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 |
# File 'lib/rvc/modules/vsan.rb', line 2251 def observer cluster_or_host, opts conn = cluster_or_host._connection pc = conn.propertyCollector host = cluster_or_host entries = [] hostUuidMap = {} vcAbout = conn.serviceContent.about vcInfo = { 'hostname' => conn.host, 'about' => { 'fullName' => vcAbout.fullName, 'osType' => vcAbout.osType, 'apiVersion' => vcAbout.apiVersion, 'apiType' => vcAbout.apiType, 'build' => vcAbout.build, 'instanceUuid' => vcAbout.instanceUuid, 'version' => vcAbout.version, }, } if opts[:run_webserver] && !opts[:force] puts "Running a webserver with unencrypted HTTP on the vCenter machine " puts "could pose a security risk. This tool is an experimenal debugging " puts "tool, which has not been audited or tested for its security." puts "If in doubt, you may want to create a dummy vCenter machine to run" puts "just this tool, instead of running the tool on your production " puts "vCenter machine." puts "In order to run the webserver, please pass --force" err "Force needs to be applied to run the webserver" end require 'rvc/observer/analyzer-lib' require 'rvc/observer/tasks-analyzer' require 'rvc/observer/inventory-analyzer' inventoryAnalyzer = $inventoryAnalyzer tasksAnalyzer = $tasksAnalyzer inventoryAnalyzer ||= InventoryAnalyzer.new tasksAnalyzer ||= TasksAnalyzer.new({}) file = nil if opts[:filename] file = open(opts[:filename], 'a') end server = nil webrickThread = nil hosts_props = nil _run_with_rev(conn, "dev") do vsanIntSys = nil if cluster_or_host.is_a?(VIM::ClusterComputeResource) cluster = cluster_or_host hosts = cluster.host else hosts = [host] end hosts_props = pc.collectMultiple(hosts, 'name', 'runtime.connectionState', 'configManager.vsanSystem', 'configManager.vsanInternalSystem', 'summary.config.product', 'summary.hardware' ) connected_hosts = hosts_props.select do |k,v| v['runtime.connectionState'] == 'connected' end.keys host = connected_hosts.first if !host err "Couldn't find any connected hosts" end vsanIntSys = hosts_props[host]['configManager.vsanInternalSystem'] vsanSysList = Hash[hosts_props.map do |host, props| [props['name'], props['configManager.vsanSystem']] end] clusterInfos = pc.collectMultiple(vsanSysList.values, 'config.clusterInfo') hostUuidMap = Hash[vsanSysList.map do |hostname, sys| [clusterInfos[sys]['config.clusterInfo'].nodeUuid, hostname] end] viewMgr = conn.serviceContent.viewManager rootFolder = conn.serviceContent.rootFolder vmView = viewMgr.CreateContainerView( :container => rootFolder, :type => ['VirtualMachine'], :recursive => true ) if opts[:run_webserver] erbFilename = "#{analyser_lib_dirname}/stats.erb.html" erbFileContent = open(erbFilename, 'r').read server = WEBrick::HTTPServer.new(:Port => opts[:port]) server.mount( "/", SimpleGetForm, tasksAnalyzer, inventoryAnalyzer, erbFileContent, vcInfo, JSON.load(JSON.dump(hosts_props)) ) webrickThread = Thread.new do server.start end end puts "Press <Ctrl>+<C> to stop observing at any point ..." puts startTime = Time.now begin while (Time.now - startTime) < opts[:max_runtime] * 3600 puts "#{Time.now}: Collect one inventory snapshot" t1 = Time.now begin observation = _observe_snapshot( conn, host, connected_hosts, vmView, pc, hosts_props, vsanIntSys ) observation['snapshot']['vcinfo'] = vcInfo observation['timestamp'] = Time.now.to_f if file file.write(JSON.dump(observation) + "\n") file.flush() else puts "#{Time.now}: Live-Processing inventory snapshot" tasksAnalyzer.processTrace(observation) inventoryAnalyzer.processInventorySnapshot(observation) end rescue Interrupt raise rescue Exception => ex puts "#{Time.now}: Got exception: #{ex.class}: #{ex.}" end t2 = Time.now intervalTime = opts[:interval] time = t2 - t1 sleepTime = intervalTime - time if sleepTime <= 0.0 puts "#{Time.now}: Collection took %.2fs (> %.2fs), no sleep ..." % [ time, intervalTime ] else puts "#{Time.now}: Collection took %.2fs, sleeping for %.2fs" % [ time, sleepTime ] puts "#{Time.now}: Press <Ctrl>+<C> to stop observing" sleep(sleepTime) end end rescue Interrupt puts "#{Time.now}: Execution interrupted, wrapping up ..." end #pp res vmView.DestroyView() end if file file.close() end if server server.shutdown webrickThread.join end if opts[:generate_html_bundle] begin VsanObserver.new.generate_observer_bundle( opts[:generate_html_bundle], tasksAnalyzer, inventoryAnalyzer, vcInfo, hosts_props ) rescue Exception => ex puts "#{Time.now}: Failed to generate HTML bundle: #{ex.class}: #{ex.}" end end if opts[:keep_observation_in_memory] $inventoryAnalyzer = inventoryAnalyzer $tasksAnalyzer = tasksAnalyzer else $inventoryAnalyzer = nil $tasksAnalyzer = nil end 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
333 334 335 336 337 338 339 340 341 342 343 344 345 346 |
# File 'lib/rvc/modules/device.rb', line 333 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
482 483 484 485 |
# File 'lib/rvc/modules/vm.rb', line 482 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 |
#profile_apply(profiles) ⇒ Object
353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 |
# File 'lib/rvc/modules/spbm.rb', line 353 def profile_apply profiles if profiles.length == 0 return end pbm = profiles.first.instance_variable_get(:@connection) dc = profiles.first.instance_variable_get(:@dc) vim = dc._connection _catch_spbm_resets(vim) do pm = pbm.serviceContent.profileManager results = pm.applyProfile(:profiles => profiles.map{|x| x.profileId}) tasks = results.map{|x| x.reconfigOutcome.map{|y| y.taskMoid}}.flatten tasks = tasks.map{|x| VIM::Task(vim, x)} progress(tasks) end end |
#profile_create(profile_name, opts) ⇒ Object
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 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 |
# File 'lib/rvc/modules/spbm.rb', line 377 def profile_create profile_name, opts dc, = lookup '~' conn = dc._connection _catch_spbm_resets(conn) do pbm = conn.pbm pm = pbm.serviceContent.profileManager rules = opts[:rule] || [] resType = {:resourceType => "STORAGE"} # Need to support other vendors too cm = pm.PbmFetchCapabilityMetadata( :resourceType => resType, :vendorUuid => "com.vmware.storage.vsan" ) capabilities = cm.map{|x| x.capabilityMetadata}.flatten constraints = rules.map do |rule_str| name, values_str = rule_str.split("=", 2) if !values_str err "Rule is malformed: #{rule_str}, should be <provider>.<capability>=<value>" end ns, id = name.split('.', 2) if !id err "Rule is malformed: #{rule_str}, should be <provider>.<capability>=<value>" end capability = capabilities.find{|x| x.name == name} if !capability err "Capability #{name} unknown" end type = capability.propertyMetadata[0].type values = values_str.split(',') if type.typeName == "XSD_INT" values = values.map{|x| RbVmomi::BasicTypes::Int.new(x.to_i)} end if type.typeName == "XSD_BOOLEAN" values = values.map{|x| (x =~ /(true|True|1|yes|Yes)/) != nil} end if type.is_a?(PBM::PbmCapabilityGenericTypeInfo) && type.genericTypeName == "VMW_RANGE" if values.length != 2 err "#{name} is a range, need to specify 2 values" end value = PBM::PbmCapabilityTypesRange(:min => values[0], :max => values[1]) elsif values.length == 1 value = values.first else err "Value malformed: #{value_str}" end { :id => { :namespace => ns, :id => id }, :constraint => [{ :propertyInstance => [{ :id => id, :value => value }] }] } end pm.PbmCreate( :createSpec => { :name => profile_name, :description => opts[:description], :resourceType => resType, :constraints => PBM::PbmCapabilitySubProfileConstraints( :subProfiles => [ PBM::PbmCapabilitySubProfile( :name => "Object", :capability => constraints ) ] ) } ) end end |
#profile_delete(profiles) ⇒ Object
336 337 338 339 340 341 342 343 344 345 |
# File 'lib/rvc/modules/spbm.rb', line 336 def profile_delete profiles if profiles.length == 0 return end _catch_spbm_resets(nil) do pbm = profiles.first.instance_variable_get(:@connection) pm = pbm.serviceContent.profileManager pm.PbmDelete(:profileId => profiles.map{|x| x.profileId}) 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
456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 |
# File 'lib/rvc/modules/vm.rb', line 456 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
96 97 98 99 100 101 102 103 104 105 |
# File 'lib/rvc/modules/vnc.rb', line 96 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 |
#reapply_vsan_vmknic_config(hosts, opts) ⇒ Object
3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 |
# File 'lib/rvc/modules/vsan.rb', line 3773 def reapply_vsan_vmknic_config hosts, opts hosts.each do |host| hostname = host.name net = host.esxcli.vsan.network nics = net.list() if opts[:vmknic] nics = nics.select{|x| x.VmkNicName == opts[:vmknic]} end keys = { :AgentGroupMulticastAddress => :agentmcaddr, :AgentGroupMulticastPort => :agentmcport, :IPProtocol => nil, :InterfaceUUID => nil, :MasterGroupMulticastAddress => :mastermcaddr, :MasterGroupMulticastPort => :mastermcport, :MulticastTTL => :multicastttl, } puts "Host: #{hostname}" if opts[:dry_run] nics.each do |nic| puts " Would reapply config of vmknic #{nic.VmkNicName}:" keys.keys.each do |key| puts " #{key.to_s}: #{nic.send(key)}" end end else nics.each do |nic| puts " Reapplying config of #{nic.VmkNicName}:" keys.keys.each do |key| puts " #{key.to_s}: #{nic.send(key)}" end puts " Unbinding VSAN from vmknic #{nic.VmkNicName} ..." net.ipv4.remove(:interfacename => nic.VmkNicName) puts " Rebinding VSAN to vmknic #{nic.VmkNicName} ..." params = { :agentmcaddr => nic.AgentGroupMulticastAddress, :agentmcport => nic.AgentGroupMulticastPort, :interfacename => nic.VmkNicName, :mastermcaddr => nic.MasterGroupMulticastAddress, :mastermcport => nic.MasterGroupMulticastPort, :multicastttl => nic.MulticastTTL, } #pp params net.ipv4.add(params) end end end end |
#reboot(hosts, opts) ⇒ Object
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
# File 'lib/rvc/modules/host.rb', line 34 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
144 145 146 |
# File 'lib/rvc/modules/vm.rb', line 144 def reboot_guest vms vms.each(&:RebootGuest) end |
#recommendations(cluster) ⇒ Object
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 |
# File 'lib/rvc/modules/cluster.rb', line 140 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) t = Terminal::Table.new() t << ['Key', 'Reason', 'Target', 'Actions'] 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 t << [r.key, r.reasonText, target_name, actions.join("\n")] end puts t end |
#reconfig_net(devs, opts) ⇒ Object
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 |
# File 'lib/rvc/modules/device.rb', line 112 def reconfig_net devs, opts network = opts[:network] 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 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.backing = backing { :operation => :edit, :device => dev } end spec = { :deviceChange => device_changes } vm.ReconfigVM_Task(:spec => spec) end progress(tasks) end |
#reconnect(hosts, opts) ⇒ Object
178 179 180 181 182 183 184 185 |
# File 'lib/rvc/modules/host.rb', line 178 def reconnect hosts, opts spec = { :force => false, :userName => opts[:username], :password => opts[:password], } tasks hosts, :ReconnectHost end |
#recover_spbm(cluster_or_host, opts) ⇒ Object
3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 |
# File 'lib/rvc/modules/vsan.rb', line 3829 def recover_spbm cluster_or_host, opts conn = cluster_or_host._connection pc = conn.propertyCollector host = cluster_or_host entries = [] hostUuidMap = {} startTime = Time.now _run_with_rev(conn, "dev") do vsanIntSys = nil puts "#{Time.now}: Fetching Host info" if cluster_or_host.is_a?(VIM::ClusterComputeResource) cluster = cluster_or_host hosts = cluster.host else hosts = [host] end hosts_props = pc.collectMultiple(hosts, 'name', 'runtime.connectionState', 'configManager.vsanSystem', 'configManager.vsanInternalSystem', 'datastore' ) connected_hosts = hosts_props.select do |k,v| v['runtime.connectionState'] == 'connected' end.keys host = connected_hosts.first if !host err "Couldn't find any connected hosts" end vsanIntSys = hosts_props[host]['configManager.vsanInternalSystem'] vsanSysList = Hash[hosts_props.map do |host, props| [props['name'], props['configManager.vsanSystem']] end] clusterInfos = pc.collectMultiple(vsanSysList.values, 'config.clusterInfo') hostUuidMap = Hash[vsanSysList.map do |hostname, sys| [clusterInfos[sys]['config.clusterInfo'].nodeUuid, hostname] end] puts "#{Time.now}: Fetching Datastore info" datastores = hosts_props.values.map{|x| x['datastore']}.flatten datastores_props = pc.collectMultiple(datastores, 'name', 'summary.type') vsanDsList = datastores_props.select do |ds, props| props['summary.type'] == "vsan" end.keys if vsanDsList.length > 1 err "Two VSAN datastores found, can't handle that" end vsanDs = vsanDsList[0] puts "#{Time.now}: Fetching VM properties" vms = vsanDs.vm vms_props = pc.collectMultiple(vms, 'name', 'config.hardware.device') puts "#{Time.now}: Fetching policies used on VSAN from CMMDS" entries = vsanIntSys.query_cmmds([{ :type => "POLICY", }], :gzip => true) policies = entries.map{|x| x['content']}.uniq puts "#{Time.now}: Fetching SPBM profiles" pbm = conn.pbm pm = pbm.serviceContent.profileManager profileIds = pm.PbmQueryProfile( :resourceType => {:resourceType => "STORAGE"}, :profileCategory => "REQUIREMENT" ) if profileIds.length > 0 profiles = pm.PbmRetrieveContent(:profileIds => profileIds) else profiles = [] end profilesMap = Hash[profiles.map do |x| ["#{x.profileId.uniqueId}-gen#{x.generationId}", x] end] puts "#{Time.now}: Fetching VM <-> SPBM profile association" vms_entities = vms.map do |vm| vm.all_pbmobjref(:vms_props => vms_props) end.flatten.map{|x| x.dynamicProperty = []; x} associatedProfiles = pm.PbmQueryAssociatedProfiles( :entities => vms_entities ) associatedEntities = associatedProfiles.map{|x| x.object}.uniq puts "#{Time.now}: Computing which VMs do not have a SPBM Profile ..." nonAssociatedEntities = vms_entities - associatedEntities vmsMap = Hash[vms.map{|x| [x._ref, x]}] nonAssociatedVms = {} nonAssociatedEntities.map do |entity| vm = vmsMap[entity.key.split(":").first] nonAssociatedVms[vm] ||= [] nonAssociatedVms[vm] << [entity.objectType, entity.key] end puts "#{Time.now}: Fetching additional info about some VMs" vms_props2 = pc.collectMultiple(vms, 'summary.config.vmPathName') puts "#{Time.now}: Got all info, computing after %.2f sec" % [ Time.now - startTime ] policies.each do |policy| policy['spbmRecoveryCandidate'] = false policy['spbmProfile'] = nil if policy['spbmProfileId'] name = "%s-gen%s" % [ policy['spbmProfileId'], policy['spbmProfileGenerationNumber'], ] policy['spbmName'] = name policy['spbmProfile'] = profilesMap[name] if policy['spbmProfile'] name = policy['spbmProfile'].name policy['spbmName'] = name name = "Existing SPBM Profile:\n#{name}" else policy['spbmRecoveryCandidate'] = true profile = profiles.find do |profile| profile.profileId.uniqueId == policy['spbmProfileId'] && profile.generationId > policy['spbmProfileGenerationNumber'] end # XXX: We should check if there is a profile that matches # one we recovered if profile name = policy['spbmProfile'].name name = "Old generation of SPBM Profile:\n#{name}" else name = "Unknown SPBM Profile. UUID:\n#{name}" end end else name = "Not managed by SPBM" policy['spbmName'] = name end propCap = policy['proportionalCapacity'] if propCap && propCap.is_a?(Array) && propCap.length == 2 policy['proportionalCapacity'] = policy['proportionalCapacity'][0] end policy['spbmDescr'] = name end entriesMap = Hash[entries.map{|x| [x['uuid'], x]}] nonAssociatedEntities = [] nonAssociatedVms.each do |vm, entities| if entities.any?{|x| x == ["virtualMachine", vm._ref]} vmxPath = vms_props2[vm]['summary.config.vmPathName'] if vmxPath =~ /^\[([^\]]*)\] ([^\/])\// nsUuid = $2 entry = entriesMap[nsUuid] if entry && entry['content']['spbmProfileId'] # This is a candidate nonAssociatedEntities << { :objUuid => nsUuid, :type => "virtualMachine", :key => vm._ref, :entry => entry, :vm => vm, :label => "VM Home", } end end end devices = vms_props[vm]['config.hardware.device'] disks = devices.select{|x| x.is_a?(VIM::VirtualDisk)} disks.each do |disk| key = "#{vm._ref}:#{disk.key}" if entities.any?{|x| x == ["virtualDiskId", key]} objUuid = disk.backing.backingObjectId if objUuid entry = entriesMap[objUuid] if entry && entry['content']['spbmProfileId'] # This is a candidate nonAssociatedEntities << { :objUuid => objUuid, :type => "virtualDiskId", :key => key, :entry => entry, :vm => vm, :label => disk.deviceInfo.label, } end end end end end nonAssociatedEntities.each do |entity| policy = policies.find do |policy| match = true ['spbmProfileId', 'spbmProfileGenerationNumber'].each do |k| match = match && policy[k] == entity[:entry]['content'][k] end match end entity[:policy] = policy end candidates = policies.select{|p| p['spbmRecoveryCandidate'] == true} puts "#{Time.now}: Done computing" if !opts[:show_details] puts "" puts "Found %d missing SPBM Profiles." % candidates.length puts "Found %d entities not associated with their SPBM Profiles." % nonAssociatedEntities.length puts "" puts "You have a number of options (can be combined):" puts "1) Run command with --show-details to see a full report about missing" puts "SPBM Profiles and missing VM <-> SPBM Profile associations." puts "2) Run command with --create-missing-profiles to automatically create" puts "all missing SPBM profiles." puts "3)Run command with --create-missing-associations to automatically" puts "create all missing VM <-> SPBM Profile associations." end if opts[:show_details] puts "SPBM Profiles used by VSAN:" t = Terminal::Table.new() t << ['SPBM ID', 'policy'] policies.each do |policy| t.add_separator t << [ policy['spbmDescr'], policy.select{|k,v| k !~ /spbm/}.map{|k,v| "#{k}: #{v}"}.join("\n") ] end puts t puts "" if candidates.length > 0 puts "Recreate missing SPBM Profiles using following RVC commands:" candidates.each do |policy| rules = policy.select{|k,v| k !~ /spbm/} s = rules.map{|k,v| "--rule VSAN.#{k}=#{v}"}.join(" ") puts "spbm.profile_create #{s} #{policy['spbmName']}" end puts "" end end if opts[:show_details] && nonAssociatedEntities.length > 0 puts "Following missing VM <-> SPBM Profile associations were found:" t = Terminal::Table.new() t << ['Entity', 'VM', 'Profile'] t.add_separator nonAssociatedEntities.each do |entity| #puts "'%s' of VM '%s' should be associated with profile '%s' but isn't." % [ t << [ entity[:label], vms_props[entity[:vm]]['name'], entity[:policy]['spbmName'], ] # Fix up the associations. Disabled for now until I can check # with Sudarsan # profile = entity[:policy]['spbmProfile'] # if profile # pm.PbmAssociate( # :entity => PBM::PbmServerObjectRef( # :objectType => entity[:type], # :key => entity[:key], # :serverUuid => conn.serviceContent.about.instanceUuid # ), # :profile => profile.profileId # ) # end end puts t end end end |
#register(vmx_file, opts) ⇒ Object
216 217 218 219 220 221 |
# File 'lib/rvc/modules/vm.rb', line 216 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
296 297 298 |
# File 'lib/rvc/modules/basic.rb', line 296 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
252 253 254 255 256 257 258 |
# File 'lib/rvc/modules/host.rb', line 252 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 |
#restart_services(clusters, opts) ⇒ Object
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
# File 'lib/rvc/modules/host.rb', line 62 def restart_services hosts, opts hosts.each do |host| Net::SSH.start(host.name, "root", :password => opts[:password], :paranoid => false) do |ssh| cmd = "/sbin/chkconfig usbarbitrator off" puts "Running #{cmd}" out = ssh_exec!(ssh,cmd) if out[2] != 0 puts "Failed to execute #{cmd} on host #{host.name}" puts out[1] end cmd = "/sbin/services.sh restart > /tmp/restart_services.log 2>&1" puts "Running #{cmd}" out = ssh_exec!(ssh,cmd) if out[2] != 0 puts "Failed to restart all services on host #{host.name}" puts out[1] else puts "Host #{host.name} restarted all services" end end end end |
#resync_dashboard(cluster_or_host, opts) ⇒ Object
2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 |
# File 'lib/rvc/modules/vsan.rb', line 2465 def resync_dashboard cluster_or_host, opts conn = cluster_or_host._connection pc = conn.propertyCollector if cluster_or_host.is_a?(VIM::ClusterComputeResource) cluster = cluster_or_host hosts = cluster.host else hosts = [host] end _run_with_rev(conn, "dev") do hosts_props = pc.collectMultiple(hosts, 'name', 'runtime.connectionState', 'configManager.vsanSystem', 'configManager.vsanInternalSystem' ) connected_hosts = hosts_props.select do |k,v| v['runtime.connectionState'] == 'connected' end.keys host = connected_hosts.first if !host err "Couldn't find any connected hosts" end hostname = hosts_props[host]['name'] vsanIntSys = hosts_props[host]['configManager.vsanInternalSystem'] vsanSysList = Hash[hosts_props.map do |host, props| [props['name'], props['configManager.vsanSystem']] end] clusterInfos = pc.collectMultiple(vsanSysList.values, 'config.clusterInfo') hostUuidMap = Hash[vsanSysList.map do |hostname, sys| [clusterInfos[sys]['config.clusterInfo'].nodeUuid, hostname] end] entries = nil puts "#{Time.now}: Querying all VMs on VSAN ..." ds_list = host.datastore ds_props = pc.collectMultiple(ds_list, 'name', 'summary.type') ds = ds_props.select{|k, x| x['summary.type'] == "vsan"}.keys.first ds_name = ds_props[ds]['name'] vms = ds.vm vmsProps = pc.collectMultiple(vms, 'name', 'runtime.connectionState', 'config.hardware.device', 'summary.config' ) iter = 0 while (iter == 0) || opts[:refresh_rate] puts "#{Time.now}: Querying all objects in the system from #{hostname} ..." result = vsanIntSys.query_syncing_vsan_objects({}) if !result err "Server failed to gather syncing objects" end objects = result['dom_objects'] puts "#{Time.now}: Got all the info, computing table ..." objects = objects.map do |uuid, objInfo| obj = objInfo['config'] comps = _components_in_dom_config(obj['content']) bytesToSyncTotal = 0 recoveryETATotal = 0 comps = comps.select do |comp| state = comp['attributes']['componentState'] bytesToSync = comp['attributes']['bytesToSync'] || 0 recoveryETA = comp['attributes']['recoveryETA'] || 0 resync = [10, 6].member?(state) && bytesToSync != 0 if resync bytesToSyncTotal += bytesToSync recoveryETATotal = [recoveryETA, recoveryETATotal].max end resync end obj['bytesToSync'] = bytesToSyncTotal obj['recoveryETA'] = recoveryETATotal if comps.length > 0 obj end end.compact obj_uuids = objects.map{|x| x['uuid']} objects = Hash[objects.map{|x| [x['uuid'], x]}] all_obj_uuids = [] vmToObjMap = {} vms.each do |vm| vm_obj_uuids = _get_vm_obj_uuids(vm, vmsProps) vm_obj_uuids = vm_obj_uuids.select{|x, v| obj_uuids.member?(x)} vm_obj_uuids = vm_obj_uuids.reject{|x, v| all_obj_uuids.member?(x)} all_obj_uuids += vm_obj_uuids.keys if vm_obj_uuids.length > 0 vmToObjMap[vm] = vm_obj_uuids end end t = Terminal::Table.new() t << [ 'VM/Object', 'Syncing objects', 'Bytes to sync', #'ETA', ] t.add_separator bytesToSyncGrandTotal = 0 objGrandTotal = 0 vmToObjMap.each do |vm, vm_obj_uuids| vmProps = vmsProps[vm] objs = vm_obj_uuids.keys.map{|x| objects[x]} bytesToSyncTotal = objs.map{|obj| obj['bytesToSync']}.sum recoveryETATotal = objs.map{|obj| obj['recoveryETA']}.max t << [ vmProps['name'], objs.length, "", #"%.2f GB" % (bytesToSyncTotal.to_f / 1024**3), #"%.2f min" % (recoveryETATotal.to_f / 60), ] objs.each do |obj| t << [ " %s" % (vm_obj_uuids[obj['uuid']] || obj['uuid']), '', "%.2f GB" % (obj['bytesToSync'].to_f / 1024**3), #"%.2f min" % (obj['recoveryETA'].to_f / 60), ] end bytesToSyncGrandTotal += bytesToSyncTotal objGrandTotal += objs.length end t.add_separator t << [ 'Total', objGrandTotal, "%.2f GB" % (bytesToSyncGrandTotal.to_f / 1024**3), #"%.2f min" % (recoveryETATotal.to_f / 60), ] puts t iter += 1 if opts[:refresh_rate] sleep opts[:refresh_rate] end end end 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
228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 |
# File 'lib/rvc/modules/vm_guest.rb', line 228 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
252 253 254 255 256 257 258 259 260 261 262 263 264 265 |
# File 'lib/rvc/modules/vm_guest.rb', line 252 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
436 437 438 439 440 441 442 443 444 |
# File 'lib/rvc/modules/vm.rb', line 436 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
712 713 714 |
# File 'lib/rvc/modules/vm.rb', line 712 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 |
#select_vmknic_for_service(vmknic, service, hosts) ⇒ Object
268 269 270 271 272 273 |
# File 'lib/rvc/modules/host.rb', line 268 def select_vmknic_for_service vmknic, service, hosts hosts.each do |host| vnicSys = host.configManager.virtualNicManager vnicSys.SelectVnicForNicType(:nicType => service, :device => vmknic) end 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
388 389 390 391 |
# File 'lib/rvc/modules/vm.rb', line 388 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 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
# File 'lib/rvc/modules/vm.rb', line 105 def shutdown_guest vms, opts conn = vms.first._connection pc = conn.propertyCollector vmsProps = pc.collectMultiple(vms, 'runtime.powerState', 'guest.toolsRunningStatus', 'name') vms.each do |vm| if vmsProps[vm]['runtime.powerState'] != 'poweredOn' puts "VM #{vmsProps[vm]['name']} not powered on, skipping" next end if vmsProps[vm]['guest.toolsRunningStatus'] != 'guestToolsRunning' puts "VM #{vmsProps[vm]['name']} doesn't have tools running, skipping" next end begin vm.ShutdownGuest rescue Exception => ex puts "VM #{vmsProps[vm]['name']}: #{ex.class}: #{ex.}" end end 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
420 421 422 423 424 425 |
# File 'lib/rvc/modules/vm.rb', line 420 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 |
#ssh_exec!(ssh, command) ⇒ Object
291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 |
# File 'lib/rvc/modules/host.rb', line 291 def ssh_exec!(ssh, command) stdout_data = "" stderr_data = "" exit_code = nil exit_signal = nil ssh.open_channel do |channel| channel.exec(command) do |ch, success| unless success abort "FAILED: couldn't execute command (ssh.channel.exec)" end channel.on_data do |ch,data| stdout_data+=data end channel.on_extended_data do |ch,type,data| stderr_data+=data end channel.on_request("exit-status") do |ch,data| exit_code = data.read_long end end end ssh.loop [stdout_data, stderr_data, exit_code] end |
#standby_guest(vms) ⇒ Object
134 135 136 |
# File 'lib/rvc/modules/vm.rb', line 134 def standby_guest vms vms.each(&:StandbyGuest) end |
#start_program(vms, opts) ⇒ Object
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 580 581 582 583 584 585 586 587 588 589 |
# File 'lib/rvc/modules/vm_guest.rb', line 542 def start_program vms, opts vms.each do |vm| 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] ) ) begin 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 end end |
#stats(metrics, objs, opts) ⇒ Object
347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 |
# File 'lib/rvc/modules/perf.rb', line 347 def stats metrics, objs, opts metrics = metrics.split(",") vim = single_connection objs pm = vim.serviceContent.perfManager pc = vim.propertyCollector 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 instances = opts[:instance] || ['*'] if instances.length == 0 instances << '*' end stat_opts = { :interval => interval, :startTime => start_time, :instance => instances, :multi_instance => true, } 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', 'Instance', 'Metric', 'Values', 'Unit'] table.add_separator objs_props = pc.collectMultiple(objs, 'name') objs.sort_by{|obj| objs_props[obj]['name']}.each do |obj| if !res[obj] next end metrics.each do |metric| matches = res[obj][:metrics].select{|k, v| k[0] == metric} matches.each do |key, stat| key, instance = key metric_info = pm.perfcounter_hash[metric] table.add_row([objs_props[obj]['name'], instance, metric, stat.join(','), metric_info.unitInfo.label]) end 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
28 29 30 |
# File 'lib/rvc/modules/connection.rb', line 28 def switch name shell.switch_connection name end |
#table(objs, opts) ⇒ Object
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 473 474 475 |
# File 'lib/rvc/modules/basic.rb', line 442 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
477 478 479 480 481 482 483 |
# File 'lib/rvc/modules/basic.rb', line 477 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
281 282 283 |
# File 'lib/rvc/modules/vm.rb', line 281 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
107 108 109 110 111 112 113 114 |
# File 'lib/rvc/modules/vnc.rb', line 107 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(vms, opts) ⇒ Object
370 371 372 373 374 375 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 |
# File 'lib/rvc/modules/vm_guest.rb', line 370 def upload_file vms, opts vms.each do |vm| 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_size = nil if opts[:local_path] =~ /^http:/ # XXX: Not acceptable for big files file_size = open(opts[:local_path], 'rb').read.length else err "local file does not exist" unless File.exists? local_path file = File.new(opts[:local_path], 'rb') file_size = file.size end 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}" generic_http_upload opts[:local_path], upload_uri, file_size end 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
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 |
# File 'lib/rvc/modules/vnc.rb', line 34 def view vm, opts 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 opts[:ws] opt = extraConfig.find { |x| x.key == 'RemoteDisplay.vnc.webSocket.port' } if opt.nil? ws_port = unused_vnc_port ip vm.ReconfigVM_Task(:spec => { :extraConfig => [ { :key => 'RemoteDisplay.vnc.webSocket.port', :value => ws_port.to_s } ] }).wait_for_completion else ws_port = opt.value end end if already_enabled puts "VNC already enabled" port = extraConfig.find { |x| x.key == 'RemoteDisplay.vnc.port' } if !port err "VNC enabled but no port assigned. Use vnc.off to reset config" end password = extraConfig.find { |x| x.key == 'RemoteDisplay.vnc.password' } password = password ? 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 if opts[:ws] puts "open http://novnc.com?host=#{ip}&port=#{ws_port}&password=#{password}" else vnc_client ip, port, password end 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_change_storage_profile(vms, opts) ⇒ Object
599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 |
# File 'lib/rvc/modules/spbm.rb', line 599 def vm_change_storage_profile vms, opts if !opts[:profile] err "Must specify a storage profile" end conn = vms.first._connection _catch_spbm_resets(conn) do _run_with_rev(conn, "dev") do profile = nil if opts[:profile] profile = [VIM::VirtualMachineDefinedProfileSpec( :profileId => opts[:profile].profileId.uniqueId )] end tasks = vms.map do |vm| disks = vm.disks spec = { :vmProfile => profile, :deviceChange => disks.map do |dev| { :operation => :edit, :device => dev, :profile => profile, } end } vm.ReconfigVM_Task(:spec => spec) end progress(tasks) end end end |
#vm_create(clusters, 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 |
# File 'lib/rvc/modules/diagnostics.rb', line 138 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)" errors = [] failed_hosts = [] begin 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']}" err_msgs = ["Timed out", "InvalidState", "InvalidHostState", "InvalidHostConnectionState", "HostCommunication"] err_msgs.each do |msg| if info['error'].include? msg failed_hosts << host break end end end rescue Exception => e puts "An error occurred:\n" puts "e.message:", e. puts "e.backtrace:", e.backtrace.join("\n") errors = [e] end if errors.length == 0 puts "Success" end if opts[:fix] && failed_hosts != [] opts[:host] = failed_hosts restart_services(clusters, opts) end end |
#vm_ip(vm) ⇒ Object
689 690 691 692 693 694 695 696 697 698 699 700 701 |
# File 'lib/rvc/modules/vm.rb', line 689 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['ip'] note['ip'] else err "no IP known for this VM" end end |
#vm_object_info(vms, opts) ⇒ Object
1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 |
# File 'lib/rvc/modules/vsan.rb', line 1119 def vm_object_info vms, opts begin conn = vms.first._connection pc = conn.propertyCollector firstVm = vms.first host = firstVm.runtime.host if !host err "VM #{firstVm.name} doesn't have an assigned host (yet?)" end opts[:cluster] ||= host.parent _run_with_rev(conn, "dev") do vmsProps = pc.collectMultiple(vms, 'name', 'config.hardware.device', 'summary.config', 'runtime.host', ) obj_uuids = [] objToHostMap = {} vms.each do |vm| vm_obj_uuids = _get_vm_obj_uuids(vm, vmsProps).keys vm_obj_uuids.each{|x| objToHostMap[x] = vmsProps[vm]['runtime.host']} obj_uuids += vm_obj_uuids end opts[:objToHostMap] = objToHostMap objs = _object_info(obj_uuids, opts) hosts_props = objs['host_props'] vms.each do |vm| vmProps = vmsProps[vm] disks = vmProps['disks'] puts "VM #{vmProps['name']}:" if objs['has_partitions'] vmHost = vmProps['runtime.host'] puts " VM registered on host: #{hosts_props[vmHost]['name']}" end indent = 1 pre = " " * indent puts "#{pre}Namespace directory" obj_uuid = vmsProps[vm]['namespaceUuid'] if objs['has_partitions'] && objs['obj_uuid_from_host'][obj_uuid] objHost = objs['obj_uuid_from_host'][obj_uuid] puts "#{pre} Shown from perspective of host #{hosts_props[objHost]['name']}" end _print_dom_config_tree(obj_uuid, objs, indent + 1) disks.each do |disk| indent = 1 backing = disk.backing while backing pre = " " * indent puts "#{pre}Disk backing: #{backing.fileName}" obj_uuid = backing.backingObjectId if objs['has_partitions'] && objs['obj_uuid_from_host'][obj_uuid] objHost = objs['obj_uuid_from_host'][obj_uuid] puts "#{pre} Shown from perspective of host #{hosts_props[objHost]['name']}" end _print_dom_config_tree(obj_uuid, objs, indent + 1) backing = backing.parent indent += 1 end end end end rescue Exception => ex puts ex. puts ex.backtrace raise end end |
#vm_perf_stats(vms, opts) ⇒ Object
2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 |
# File 'lib/rvc/modules/vsan.rb', line 2619 def vm_perf_stats vms, opts conn = vms.first._connection pc = conn.propertyCollector cluster = vms.first.runtime.host.parent hosts = cluster.host _run_with_rev(conn, "dev") do hosts_props = pc.collectMultiple(hosts, 'name', 'runtime.connectionState', 'configManager.vsanSystem', 'configManager.vsanInternalSystem' ) connected_hosts = hosts_props.select do |k,v| v['runtime.connectionState'] == 'connected' end.keys host = connected_hosts.first if !host err "Couldn't find any connected hosts" end vsanIntSys = hosts_props[host]['configManager.vsanInternalSystem'] vsanSysList = Hash[hosts_props.map do |host, props| [props['name'], props['configManager.vsanSystem']] end] clusterInfos = pc.collectMultiple(vsanSysList.values, 'config.clusterInfo') hostUuidMap = Hash[vsanSysList.map do |hostname, sys| [clusterInfos[sys]['config.clusterInfo'].nodeUuid, hostname] end] hostNameToMoMap = Hash[hosts_props.map do |host, props| [props['name'], host] end] entries = nil puts "#{Time.now}: Querying info about VMs ..." vmsProps = pc.collectMultiple(vms, 'name', 'runtime.connectionState', 'config.hardware.device', 'summary.config' ) obj_uuids = [] vms.each do |vm| obj_uuids += _get_vm_obj_uuids(vm, vmsProps).keys end puts "#{Time.now}: Querying VSAN objects used by the VMs ..." objects = vsanIntSys.query_cmmds(obj_uuids.map do |uuid| {:type => 'CONFIG_STATUS', :uuid => uuid} end) if !objects err "Server failed to gather CONFIG_STATUS entries" end objByHost = {} objects.each do |entry| host = hostUuidMap[entry['owner']] if !host next end host = hostNameToMoMap[host] if !host next end objByHost[host] ||= [] objByHost[host] << entry['uuid'] end def fetchStats(objByHost, hosts_props) stats = {} objByHost.each do |host, obj_uuids| vsanIntSys = hosts_props[host]['configManager.vsanInternalSystem'] res = vsanIntSys.QueryVsanStatistics(:labels => obj_uuids.map do |uuid| "dom-object:#{uuid}" end) res = JSON.load(res) obj_uuids.each do |uuid| stats[uuid] = res['dom.owners.selected.stats'][uuid] if stats[uuid] stats[uuid]['ts'] = res['dom.owners.selected.stats-taken'] end end end stats end puts "#{Time.now}: Fetching stats counters once ..." stats1 = fetchStats(objByHost, hosts_props) sleepTime = opts[:interval] puts "#{Time.now}: Sleeping for #{sleepTime} seconds ..." sleep(sleepTime) puts "#{Time.now}: Fetching stats counters again to compute averages ..." stats2 = fetchStats(objByHost, hosts_props) puts "#{Time.now}: Got all data, computing table" stats = {} objects.each do |entry| uuid = entry['uuid'] deltas = Hash[stats2[uuid].keys.map do |key| [key, stats2[uuid][key] - stats1[uuid][key]] end] deltaT = deltas['ts'] stats[uuid] = deltas.merge({ :readIops => deltas['readCount'] / deltaT, :writeIops => deltas['writeCount'] / deltaT, :readTput => deltas['readBytes'] / deltaT, :writeTput => deltas['writeBytes'] / deltaT, :readLatency => 0, :writeLatency => 0, }) if deltas['readCount'] > 0 stats[uuid][:readLatency] = deltas['readLatencySumUs'] / deltas['readCount'] end if deltas['writeCount'] > 0 stats[uuid][:writeLatency] = deltas['writeLatencySumUs'] / deltas['writeCount'] end end t = Terminal::Table.new() t << [ 'VM/Object', 'IOPS', 'Tput (KB/s)', 'Latency (ms)' ] t.add_separator vms.each do |vm| vmProps = vmsProps[vm] vm_obj_uuids = _get_vm_obj_uuids(vm, vmsProps) if !opts[:show_objects] vmStats = {} vmStats[:readLatency] ||= [] vmStats[:writeLatency] ||= [] [:readIops, :writeIops, :readTput, :writeTput].each do |key| vmStats[key] ||= 0.0 end vm_obj_uuids.each do |uuid, path| path = path.gsub(/^\[([^\]]*)\] /, "") objStats = stats[uuid] if !objStats next end [:readIops, :writeIops, :readTput, :writeTput].each do |key| vmStats[key] += (objStats[key] || 0.0) end vmStats[:readLatency] << (objStats[:readLatency] * objStats[:readIops]) vmStats[:writeLatency] << (objStats[:writeLatency] * objStats[:writeIops]) end if vmStats[:readLatency].length > 0 && vmStats[:readIops] > 0.0 vmStats[:readLatency] = vmStats[:readLatency].sum / vmStats[:readIops] else vmStats[:readLatency] = 0.0 end if vmStats[:writeLatency].length > 0 && vmStats[:writeIops] > 0.0 vmStats[:writeLatency] = vmStats[:writeLatency].sum / vmStats[:writeIops] else vmStats[:writeLatency] = 0.0 end t << [ vmProps['name'], [ "%.1fr" % [vmStats[:readIops]], "%.1fw" % [vmStats[:writeIops]], ].join("/"), [ "%.1fr" % [vmStats[:readTput] / 1024.0], "%.1fw" % [vmStats[:writeTput] / 1024.0], ].join("/"), [ "%.1fr" % [vmStats[:readLatency] / 1000.0], "%.1fw" % [vmStats[:writeLatency] / 1000.0], ].join("/"), ] else t << [ vmProps['name'], "", "", "", ] vm_obj_uuids.each do |uuid, path| path = path.gsub(/^\[([^\]]*)\] /, "") objStats = stats[uuid] if !objStats t << [ " %s" % (path || uuid), "N/A","N/A","N/A", ] next end t << [ " %s" % (path || uuid), [ "%.1fr" % [objStats[:readIops]], "%.1fw" % [objStats[:writeIops]], ].join("/"), [ "%.1fr" % [objStats[:readTput] / 1024.0], "%.1fw" % [objStats[:writeTput] / 1024.0], ].join("/"), [ "%.1fr" % [objStats[:readLatency] / 1000.0], "%.1fw" % [objStats[:writeLatency] / 1000.0], ].join("/"), ] end end end # t.add_separator # t << [ # 'Total', # objGrandTotal, # "%.2f GB" % (bytesToSyncGrandTotal.to_f / 1024**3), # #"%.2f min" % (recoveryETATotal.to_f / 60), # ] puts t 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.
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 |
# File 'lib/rvc/modules/vnc.rb', line 127 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
162 163 164 165 166 167 168 169 170 171 172 173 |
# File 'lib/rvc/modules/vnc.rb', line 162 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
117 118 119 120 121 |
# File 'lib/rvc/modules/vnc.rb', line 117 def vnc_password n = 8 chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890' (0...n).map { chars[rand(chars.length)].chr }.join end |
#wait_for_multiple_tasks(tasks, timeout) ⇒ Object
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 50 51 |
# File 'lib/rvc/modules/diagnostics.rb', line 25 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
309 310 311 312 313 |
# File 'lib/rvc/modules/basic.rb', line 309 def what objs objs.each do |obj| puts "#{obj.rvc_path_str}: #{obj.class}" end end |
#whatif_host_failures(hosts_and_clusters, opts = {}) ⇒ Object
1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 |
# File 'lib/rvc/modules/vsan.rb', line 1579 def whatif_host_failures hosts_and_clusters, opts = {} opts[:compute_number_of_components] = true conn = hosts_and_clusters.first._connection hosts = hosts_and_clusters.select{|x| x.is_a?(VIM::HostSystem)} clusters = hosts_and_clusters.select{|x| x.is_a?(VIM::ClusterComputeResource)} pc = conn.propertyCollector cluster_hosts = pc.collectMultiple(clusters, 'host') cluster_hosts.each do |cluster, props| hosts += props['host'] end hosts = hosts.uniq if opts[:num_host_failures_to_simulate] != 1 err "Only simulation of 1 host failure has been implemented" end _run_with_rev(conn, "dev") do hosts_props = pc.collectMultiple(hosts, 'name', 'runtime.connectionState', 'configManager.vsanSystem', 'configManager.vsanInternalSystem' ) hosts = hosts_props.select do |k,v| v['runtime.connectionState'] == 'connected' end.keys if hosts.length == 0 err "Couldn't find any connected hosts" end hosts_vsansys = Hash[hosts_props.map{|k,v| [v['configManager.vsanSystem'], k]}] node_uuids = pc.collectMultiple(hosts_vsansys.keys, 'config.clusterInfo.nodeUuid') node_uuids = Hash[node_uuids.map do |k, v| [v['config.clusterInfo.nodeUuid'], hosts_vsansys[k]] end] lock = Mutex.new disks = {} vsanIntSys = hosts_props[hosts.first]['configManager.vsanInternalSystem'] disks = vsanIntSys.QueryPhysicalVsanDisks(:props => [ 'lsom_objects_count', 'uuid', 'isSsd', 'capacity', 'capacityUsed', 'capacityReserved', 'iops', 'iopsReserved', 'owner', ]) if disks == "BAD" err "Server failed to gather VSAN disk info" end begin disks = JSON.load(disks) rescue err "Server didn't provide VSAN disk info: #{objs}" end # XXX: Do this in threads hosts.map do |host| Thread.new do c1 = conn.spawn_additional_connection props = hosts_props[host] vsanIntSys2 = props['configManager.vsanInternalSystem'] vsanIntSys3 = vsanIntSys2.dup_on_conn(c1) res = vsanIntSys3.query_vsan_statistics(:labels => ['lsom-node']) hosts_props[host]['lsom.node'] = res['lsom.node'] end end.each{|t| t.join} hosts_disks = Hash[disks.values.group_by{|x| x['owner']}.map do |owner, hostDisks| props = {} hdds = hostDisks.select{|disk| disk['isSsd'] == 0} ssds = hostDisks.select{|disk| disk['isSsd'] == 1} hdds.each do |disk| [ 'capacityUsed', 'capacityReserved', 'capacity', 'lsom_objects_count' ].each do |x| props[x] ||= 0 props[x] += disk[x] end end ssds.each do |disk| [ 'capacityReserved', 'capacity', ].each do |x| props["ssd_#{x}"] ||= 0 props["ssd_#{x}"] += disk[x] end end h = node_uuids[owner] props['host'] = h props['hostname'] = h ? hosts_props[h]['name'] : owner props['numHDDs'] = hdds.length props['maxComponents'] = 3000 if hosts_props[h]['lsom.node'] props['maxComponents'] = hosts_props[h]['lsom.node']['numMaxComponents'] end [owner, props] end] sorted_hosts = hosts_disks.values.sort_by{|x| -x['capacityUsed']} if opts[:show_current_usage_per_host] puts "Current utilization of hosts:" t = Terminal::Table.new() t << [nil, nil, 'HDD Capacity', nil, nil, 'Components', 'SSD Capacity'] t << ['Host', 'NumHDDs', 'Total', 'Used', 'Reserved', 'Used', 'Reserved'] t.add_separator hosts_disks.each do |owner, x| cols = [ x['hostname'], x['numHDDs'], "%.2f GB" % [x['capacity'].to_f / 1024**3], "%.0f %%" % [x['capacityUsed'].to_f * 100 / x['capacity'].to_f], "%.0f %%" % [x['capacityReserved'].to_f * 100 / x['capacity'].to_f], "%4u/%u (%.0f %%)" % [ x['lsom_objects_count'], x['maxComponents'], x['lsom_objects_count'].to_f * 100 / x['maxComponents'].to_f ], "%.0f %%" % [x['ssd_capacityReserved'].to_f * 100 / x['ssd_capacity'].to_f], ] t << cols end puts t puts "" end puts "Simulating #{opts[:num_host_failures_to_simulate]} host failures:" puts "" worst_host = sorted_hosts[0] if sorted_hosts.length < 3 puts "Cluster unable to regain full policy compliance after host failure, " puts "not enough hosts remaining." return end t = Terminal::Table.new() t << ["Resource", "Usage right now", "Usage after failure/re-protection"] t.add_separator capacityRow = ["HDD capacity"] # Capacity before failure used = sorted_hosts.map{|x| x['capacityUsed']}.sum total = sorted_hosts.map{|x| x['capacity']}.sum free = total - used usedPctOriginal = 100.0 - (free.to_f * 100 / total.to_f) capacityRow << "%3.0f%% used (%.2f GB free)" % [ usedPctOriginal, free.to_f / 1024**3, ] # Capacity after rebuild used = sorted_hosts[1..-1].map{|x| x['capacityUsed']}.sum total = sorted_hosts[1..-1].map{|x| x['capacity']}.sum additional = worst_host['capacityUsed'] free = total - used usedPctBeforeReMirror = 100.0 - (free.to_f * 100 / total.to_f) usedPctAfterReMirror = 100.0 - ((free - additional).to_f * 100 / total.to_f) usedPctIncrease = usedPctAfterReMirror - usedPctOriginal capacityRow << "%3.0f%% used (%.2f GB free)" % [ usedPctAfterReMirror, (free - additional).to_f / 1024**3, ] t << capacityRow # Components before failure sorted_hosts = hosts_disks.values.sort_by{|x| -x['lsom_objects_count']} worst_host = sorted_hosts[0] used = sorted_hosts.map{|x| x['lsom_objects_count']}.sum total = sorted_hosts.map{|x| x['maxComponents']}.sum free = total - used usedPctOriginal = 100.0 - (free.to_f * 100 / total.to_f) componentsRow = ["Components"] componentsRow << "%3.0f%% used (%u available)" % [ usedPctOriginal, free, ] # Components after rebuild used = sorted_hosts[1..-1].map{|x| x['lsom_objects_count']}.sum total = sorted_hosts[1..-1].map{|x| x['maxComponents']}.sum additional = worst_host['lsom_objects_count'] free = total - used usedPctBeforeReMirror = 100.0 - (free.to_f * 100 / total.to_f) usedPctAfterReMirror = 100.0 - ((free - additional).to_f * 100 / total.to_f) usedPctIncrease = usedPctAfterReMirror - usedPctOriginal componentsRow << "%3.0f%% used (%u available)" % [ usedPctAfterReMirror, (free - additional), ] t << componentsRow # RC reservations before failure sorted_hosts = hosts_disks.values.sort_by{|x| -x['ssd_capacityReserved']} worst_host = sorted_hosts[0] used = sorted_hosts.map{|x| x['ssd_capacityReserved']}.sum total = sorted_hosts.map{|x| x['ssd_capacity']}.sum free = total - used usedPctOriginal = 100.0 - (free.to_f * 100 / total.to_f) rcReservationsRow = ["RC reservations"] rcReservationsRow << "%3.0f%% used (%.2f GB free)" % [ usedPctOriginal, free.to_f / 1024**3, ] # RC reservations after rebuild used = sorted_hosts[1..-1].map{|x| x['ssd_capacityReserved']}.sum total = sorted_hosts[1..-1].map{|x| x['ssd_capacity']}.sum additional = worst_host['ssd_capacityReserved'] free = total - used usedPctBeforeReMirror = 100.0 - (free.to_f * 100 / total.to_f) usedPctAfterReMirror = 100.0 - ((free - additional).to_f * 100 / total.to_f) usedPctIncrease = usedPctAfterReMirror - usedPctOriginal rcReservationsRow << "%3.0f%% used (%.2f GB free)" % [ usedPctAfterReMirror, (free - additional).to_f / 1024**3, ] t << rcReservationsRow puts t 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 |