rvc 1.5.0 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. data/README.rdoc +1 -1
  2. data/Rakefile +2 -1
  3. data/VERSION +1 -1
  4. data/bin/rvc +53 -9
  5. data/lib/rvc/completion.rb +57 -19
  6. data/lib/rvc/extensions/ComputeResource.rb +2 -2
  7. data/lib/rvc/extensions/DVPortSetting.rb +108 -0
  8. data/lib/rvc/extensions/Datacenter.rb +19 -4
  9. data/lib/rvc/extensions/Datastore.rb +6 -1
  10. data/lib/rvc/extensions/DistributedVirtualPort.rb +146 -0
  11. data/lib/rvc/extensions/DistributedVirtualPortgroup.rb +274 -10
  12. data/lib/rvc/extensions/DistributedVirtualSwitch.rb +124 -3
  13. data/lib/rvc/extensions/Folder.rb +9 -2
  14. data/lib/rvc/extensions/HostSystem.rb +60 -0
  15. data/lib/rvc/extensions/ManagedEntity.rb +19 -0
  16. data/lib/rvc/extensions/ParaVirtualSCSIController.rb +25 -0
  17. data/lib/rvc/extensions/PerfCounterInfo.rb +26 -0
  18. data/lib/rvc/extensions/PerformanceManager.rb +83 -0
  19. data/lib/rvc/extensions/ResourcePool.rb +21 -0
  20. data/lib/rvc/extensions/VirtualDevice.rb +59 -0
  21. data/lib/rvc/extensions/VirtualDisk.rb +25 -0
  22. data/lib/rvc/extensions/VirtualEthernetCard.rb +32 -0
  23. data/lib/rvc/extensions/VirtualMachine.rb +112 -1
  24. data/lib/rvc/field.rb +122 -0
  25. data/lib/rvc/filesystem_session.rb +20 -0
  26. data/lib/rvc/inventory.rb +35 -12
  27. data/lib/rvc/known_hosts.rb +20 -0
  28. data/lib/rvc/memory_session.rb +20 -0
  29. data/lib/rvc/modules.rb +67 -7
  30. data/lib/rvc/modules/alarm.rb +37 -0
  31. data/lib/rvc/modules/basic.rb +172 -41
  32. data/lib/rvc/modules/cluster.rb +18 -2
  33. data/lib/rvc/modules/core.rb +63 -0
  34. data/lib/rvc/modules/datastore.rb +158 -0
  35. data/lib/rvc/modules/device.rb +275 -0
  36. data/lib/rvc/modules/esxcli.rb +193 -0
  37. data/lib/rvc/modules/find.rb +125 -0
  38. data/lib/rvc/modules/issue.rb +33 -0
  39. data/lib/rvc/modules/perf.rb +284 -0
  40. data/lib/rvc/modules/permissions.rb +20 -0
  41. data/lib/rvc/modules/resource_pool.rb +69 -0
  42. data/lib/rvc/modules/role.rb +23 -3
  43. data/lib/rvc/modules/snapshot.rb +20 -0
  44. data/lib/rvc/modules/vds.rb +605 -0
  45. data/lib/rvc/modules/vim.rb +103 -26
  46. data/lib/rvc/modules/vm.rb +93 -220
  47. data/lib/rvc/modules/vnc.rb +50 -13
  48. data/lib/rvc/option_parser.rb +50 -2
  49. data/lib/rvc/readline-ffi.rb +2 -1
  50. data/lib/rvc/shell.rb +34 -33
  51. data/lib/rvc/util.rb +120 -2
  52. data/test/test_fs.rb +9 -5
  53. data/test/test_metric.rb +79 -0
  54. metadata +33 -3
@@ -31,10 +31,34 @@ class RbVmomi::VIM::HostSystem
31
31
  " (host): cpu #{numCpuPkgs}*#{numCpuCores}*#{"%.2f" % (cpuMhz.to_f/1000)} GHz, memory #{"%.2f" % (memorySize/10**9)} GB"
32
32
  end
33
33
 
34
+ def display_info
35
+ summary = self.summary
36
+ runtime = summary.runtime
37
+ stats = summary.quickStats
38
+ hw = summary.hardware
39
+ puts "connection state: #{runtime.connectionState}"
40
+ puts "power state: #{runtime.powerState}"
41
+ puts "uptime: #{"%0.2f" % ((Time.now - runtime.bootTime)/(24*3600))} days" if runtime.bootTime
42
+ puts "in maintenance mode: #{runtime.inMaintenanceMode}"
43
+ puts "standby mode: #{runtime.standbyMode}" if runtime.standbyMode
44
+ if about = summary.config.product
45
+ puts "product: #{about.fullName}"
46
+ puts "license: #{about.licenseProductName} #{about.licenseProductVersion}" if about.licenseProductName
47
+ end
48
+ if runtime.connectionState == 'connected' and runtime.powerState == 'poweredOn'
49
+ overallCpu = hw.numCpuPkgs * hw.numCpuCores * hw.cpuMhz
50
+ puts "cpu: %d*%d*%.2f GHz = %.2f GHz" % [hw.numCpuPkgs, hw.numCpuCores, hw.cpuMhz/1e3, overallCpu/1e3]
51
+ puts "cpu usage: %.2f GHz (%.1f%%)" % [stats.overallCpuUsage/1e3, 100*stats.overallCpuUsage/overallCpu]
52
+ puts "memory: %.2f GB" % [hw.memorySize/1e9]
53
+ puts "memory usage: %.2f GB (%.1f%%)" % [stats.overallMemoryUsage/1e3, 100*1e6*stats.overallMemoryUsage/hw.memorySize]
54
+ end
55
+ end
56
+
34
57
  def children
35
58
  {
36
59
  'vms' => RVC::FakeFolder.new(self, :ls_vms),
37
60
  'datastores' => RVC::FakeFolder.new(self, :ls_datastores),
61
+ 'networks' => RVC::FakeFolder.new(self, :ls_networks),
38
62
  }
39
63
  end
40
64
 
@@ -45,4 +69,40 @@ class RbVmomi::VIM::HostSystem
45
69
  def ls_datastores
46
70
  RVC::Util.collect_children self, :datastore
47
71
  end
72
+
73
+ def ls_networks
74
+ RVC::Util.collect_children self, :network
75
+ end
76
+ end
77
+
78
+ class VIM::EsxcliCommand
79
+ def option_parser
80
+ parser = Trollop::Parser.new
81
+ parser.text cli_info.help
82
+ cli_info.param.each do |cli_param|
83
+ vmodl_param = type_info.paramTypeInfo.find { |x| x.name == cli_param.name }
84
+ opts = trollop_type(vmodl_param.type)
85
+ opts[:required] = vmodl_param.annotation.find { |a| a.name == "optional"} ? false : true
86
+ opts[:long] = cli_param.displayName
87
+ #pp opts.merge(:name => cli_param.name)
88
+ # XXX correct short options
89
+ parser.opt cli_param.name, cli_param.help, opts
90
+ end
91
+ parser
92
+ end
93
+
94
+ def trollop_type t
95
+ if t[-2..-1] == '[]'
96
+ multi = true
97
+ t = t[0...-2]
98
+ else
99
+ multi = false
100
+ end
101
+ type = case t
102
+ when 'string', 'boolean' then t.to_sym
103
+ when 'long' then :int
104
+ else fail "unexpected esxcli type #{t.inspect}"
105
+ end
106
+ { :type => type, :multi => multi }
107
+ end
48
108
  end
@@ -21,6 +21,25 @@
21
21
  class RbVmomi::VIM::ManagedEntity
22
22
  include RVC::InventoryObject
23
23
 
24
+ field 'name' do
25
+ summary "Name"
26
+ property 'name'
27
+ default
28
+ end
29
+
30
+ field 'status' do
31
+ summary 'Status (green/yellow/red/gray)'
32
+ property 'overallStatus'
33
+ default
34
+ end
35
+
36
+ STATUS_COLORS = {
37
+ 'gray' => [],
38
+ 'red' => [:red],
39
+ 'green' => [],
40
+ 'yellow' => [:yellow],
41
+ }
42
+
24
43
  def display_info
25
44
  puts "name: #{name}"
26
45
  puts "type: #{self.class.name}"
@@ -0,0 +1,25 @@
1
+ # Copyright (c) 2011 VMware, Inc. All Rights Reserved.
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ class RbVmomi::VIM::ParaVirtualSCSIController
22
+ def name
23
+ "pvscsi-#{key}"
24
+ end
25
+ end
@@ -0,0 +1,26 @@
1
+ # Copyright (c) 2011 VMware, Inc. All Rights Reserved.
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ class RbVmomi::VIM::PerfCounterInfo
22
+ def name
23
+ "#{groupInfo.key}.#{nameInfo.key}.#{rollupType}"
24
+ end
25
+ end
26
+
@@ -0,0 +1,83 @@
1
+ require 'date'
2
+
3
+ class Time
4
+ def to_datetime
5
+ # Convert seconds + microseconds into a fractional number of seconds
6
+ seconds = sec + Rational(usec, 10**6)
7
+
8
+ # Convert a UTC offset measured in minutes to one measured in a
9
+ # fraction of a day.
10
+ offset = Rational(utc_offset, 60 * 60 * 24)
11
+ DateTime.new(year, month, day, hour, min, seconds, offset)
12
+ end
13
+ end
14
+
15
+ RbVmomi::VIM::PerfCounterInfo
16
+ class RbVmomi::VIM::PerfCounterInfo
17
+ def pretty_name
18
+ @pretty_name ||= "#{self.groupInfo.key}.#{self.nameInfo.key}.#{self.rollupType}"
19
+ end
20
+ end
21
+
22
+ RbVmomi::VIM::PerformanceManager
23
+ class RbVmomi::VIM::PerformanceManager
24
+ def perfcounter_cached
25
+ @perfcounter ||= perfCounter
26
+ end
27
+
28
+ def perfcounter_hash
29
+ @perfcounter_hash ||= Hash[perfcounter_cached.map{|x| [x.pretty_name, x]}]
30
+ end
31
+
32
+ def perfcounter_idhash
33
+ @perfcounter_idhash ||= Hash[perfcounter_cached.map{|x| [x.key, x]}]
34
+ end
35
+
36
+ def provider_summary obj
37
+ @provider_summary ||= {}
38
+ @provider_summary[obj.class] ||= QueryPerfProviderSummary(:entity => obj)
39
+ end
40
+
41
+ def retrieve_stats objects, metrics, opts = {}
42
+ opts = opts.dup
43
+ max_samples = opts[:max_samples] || 1
44
+ realtime = false
45
+ if not opts[:interval]
46
+ provider = provider_summary objects.first
47
+ opts[:interval] = provider.refreshRate
48
+ realtime = true
49
+ else
50
+ provider = provider_summary objects.first
51
+ if opts[:interval] == provider.refreshRate
52
+ realtime = true
53
+ end
54
+ end
55
+
56
+ metric_ids = metrics.map do |x|
57
+ RbVmomi::VIM::PerfMetricId(:counterId => perfcounter_hash[x].key, :instance => '*')
58
+ end
59
+ query_specs = objects.map do |obj|
60
+ RbVmomi::VIM::PerfQuerySpec({
61
+ :maxSample => max_samples,
62
+ :entity => obj,
63
+ :metricId => metric_ids,
64
+ :intervalId => opts[:interval],
65
+ :startTime => (realtime == false ? opts[:start_time].to_datetime : nil),
66
+ })
67
+ end
68
+ stats = QueryPerf(:querySpec => query_specs)
69
+
70
+ Hash[stats.map do |res|
71
+ [
72
+ res.entity,
73
+ {
74
+ :sampleInfo => res.sampleInfo,
75
+ :metrics => Hash[res.value.map do |metric|
76
+ [perfcounter_idhash[metric.id.counterId].pretty_name, metric.value]
77
+ end]
78
+ }
79
+ ]
80
+ end]
81
+ end
82
+
83
+ end
@@ -35,6 +35,27 @@ class RbVmomi::VIM::ResourcePool
35
35
  ]
36
36
  end
37
37
 
38
+ def display_info
39
+ cfg = config
40
+ rt = runtime
41
+ cpuAlloc, memAlloc = cfg.cpuAllocation, cfg.memoryAllocation
42
+
43
+
44
+ cpu_shares_text = cpuAlloc.shares.level == 'custom' ? cpuAlloc.shares.shares.to_s : cpuAlloc.shares.level
45
+ mem_shares_text = memAlloc.shares.level == 'custom' ? memAlloc.shares.shares.to_s : memAlloc.shares.level
46
+
47
+ puts "cpu:"
48
+ puts " reservation: %0.2f GHz" % [cpuAlloc.reservation/1e3]
49
+ puts " limit: %0.2f GHz" % [cpuAlloc.limit/1e3]
50
+ puts " shares: #{cpu_shares_text}"
51
+ puts " usage: %0.2f Ghz (%0.1f)%%" % [rt.cpu.overallUsage/1e3, 100.0*rt.cpu.overallUsage/rt.cpu.maxUsage]
52
+ puts "memory:"
53
+ puts " reservation: %0.2f GB" % [memAlloc.reservation/1e3]
54
+ puts " limit: %0.2f GB" % [memAlloc.limit/1e3]
55
+ puts " shares: #{mem_shares_text}"
56
+ puts " usage: %0.2f GB (%0.1f)%%" % [rt.memory.overallUsage/1e9, 100.0*rt.memory.overallUsage/rt.memory.maxUsage]
57
+ end
58
+
38
59
  def children
39
60
  {
40
61
  'vms' => RVC::FakeFolder.new(self, :children_vms),
@@ -0,0 +1,59 @@
1
+ # Copyright (c) 2011 VMware, Inc. All Rights Reserved.
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ class RbVmomi::VIM::VirtualDevice
22
+ include RVC::InventoryObject
23
+ attr_accessor :rvc_vm
24
+
25
+ # Stable name based on the device key, unit number, etc.
26
+ # May be overridden in subclasses.
27
+ def name
28
+ self.class.to_s =~ /^(?:Virtual)?(?:Machine)?(\w+?)(?:Card|Device|Controller)?$/
29
+ type = $1 ? $1.downcase : 'device'
30
+ "#{type}-#{key}"
31
+ end
32
+
33
+ def ls_text r
34
+ tags = []
35
+ tags << (connectable.connected ? :connected : :disconnected) if props.member? :connectable
36
+ " (#{self.class}): #{deviceInfo.summary}; #{tags * ' '}"
37
+ end
38
+
39
+ def display_info
40
+ super
41
+ devices, = rvc_vm.collect 'config.hardware.device'
42
+ puts "label: #{deviceInfo.label}"
43
+ puts "summary: #{deviceInfo.summary}"
44
+ puts "key: #{key}"
45
+ if controllerKey
46
+ controller = devices.find { |x| x.key == controllerKey }
47
+ puts "controller: #{controller.name}" if controller
48
+ end
49
+ puts "unit number: #{unitNumber}" if unitNumber
50
+ if connectable
51
+ puts "connectivity:"
52
+ puts " connected: #{connectable.connected}"
53
+ puts " start connected: #{connectable.startConnected}"
54
+ puts " guest control: #{connectable.allowGuestControl}"
55
+ puts " status: #{connectable.status}"
56
+ end
57
+ end
58
+ end
59
+
@@ -0,0 +1,25 @@
1
+ # Copyright (c) 2011 VMware, Inc. All Rights Reserved.
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ class RbVmomi::VIM::VirtualDisk
22
+ def name
23
+ "disk-#{controllerKey}-#{unitNumber}"
24
+ end
25
+ end
@@ -0,0 +1,32 @@
1
+ # Copyright (c) 2011 VMware, Inc. All Rights Reserved.
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ class RbVmomi::VIM::VirtualEthernetCard
22
+ def display_info
23
+ super
24
+ puts "address type: #{addressType}"
25
+ puts "MAC address: #{macAddress}"
26
+ puts "Wake on LAN enabled: #{wakeOnLanEnabled}"
27
+ end
28
+
29
+ def name
30
+ "ethernet-#{unitNumber-7}"
31
+ end
32
+ end
@@ -19,6 +19,105 @@
19
19
  # THE SOFTWARE.
20
20
 
21
21
  class RbVmomi::VIM::VirtualMachine
22
+ field 'on' do
23
+ summary "Is the VM powered on?"
24
+ properties %w(runtime.powerState)
25
+ block { |powerState| powerState == 'poweredOn' }
26
+ default
27
+ end
28
+
29
+ field 'storagebw' do
30
+ summary "Storage Bandwidth"
31
+ perfmetrics %w(disk.read.average disk.write.average)
32
+ block do |read, write|
33
+ if read && write
34
+ io = (read.sum.to_f / read.length) + (write.sum.to_f / write.length)
35
+ MetricNumber.new(io * 1024, 'B/s')
36
+ else
37
+ nil
38
+ end
39
+ end
40
+ end
41
+
42
+ [['', 5], ['.realtime', 1], ['.5min', 5 * 3], ['.10min', 10 * 3]].each do |label, max_samples|
43
+ field "storageiops#{label}" do
44
+ summary "Storage IOPS"
45
+ perfmetrics %w(disk.numberReadAveraged.average disk.numberWriteAveraged.average)
46
+ perfmetric_settings :max_samples => max_samples
47
+ block do |read, write|
48
+ if read && write
49
+ io = (read.sum.to_f / read.length) + (write.sum.to_f / write.length)
50
+ MetricNumber.new(io, 'IOPS')
51
+ else
52
+ nil
53
+ end
54
+ end
55
+ end
56
+ end
57
+
58
+ field 'ip' do
59
+ summary "The guest tools reported IP address."
60
+ property 'guest.ipAddress'
61
+ end
62
+
63
+ field 'template' do
64
+ summary "Is this VM a template?"
65
+ property 'config.template'
66
+ end
67
+
68
+ field 'uptime' do
69
+ summary "VM's uptime in seconds"
70
+ properties %w(runtime.bootTime)
71
+ block { |t| t ? TimeDiff.new(Time.now-t) : nil }
72
+ end
73
+
74
+ field 'storage.used' do
75
+ summary "Total storage used"
76
+ properties %w(storage)
77
+ block do |storage|
78
+ MetricNumber.new(storage.perDatastoreUsage.map(&:committed).sum, 'B')
79
+ end
80
+ end
81
+
82
+ field 'storage.unshared' do
83
+ summary "Total storage unshared"
84
+ properties %w(storage)
85
+ block do |storage|
86
+ MetricNumber.new(storage.perDatastoreUsage.map(&:unshared).sum, 'B')
87
+ end
88
+ end
89
+
90
+ field 'storage.provisioned' do
91
+ summary "Total storage provisioned"
92
+ properties %w(storage)
93
+ block do |storage|
94
+ MetricNumber.new(storage.perDatastoreUsage.map { |x| x.uncommitted + x.committed }.sum, 'B')
95
+ end
96
+ end
97
+
98
+ field 'guest.id' do
99
+ summary 'Guest OS identifier'
100
+ property 'summary.config.guestId'
101
+ end
102
+
103
+ field 'tools.running' do
104
+ summary 'Are guest tools running?'
105
+ properties %w(guest.toolsRunningStatus)
106
+ block { |status| status == 'guestToolsRunning' }
107
+ end
108
+
109
+ field 'tools.uptodate' do
110
+ summary "Are guest tools up to date?"
111
+ properties %w(guest.toolsVersionStatus)
112
+ block { |status| status == 'guestToolsCurrent' }
113
+ end
114
+
115
+ field 'mac' do
116
+ summary "Mac address"
117
+ properties %w(config.hardware)
118
+ block { |hw| hw.device.grep(VIM::VirtualEthernetCard).map(&:macAddress) }
119
+ end
120
+
22
121
  def display_info
23
122
  config, runtime, guest = collect :config, :runtime, :guest
24
123
  RVC::Util.err "Information currently unavailable" unless config and runtime and guest
@@ -51,7 +150,12 @@ class RbVmomi::VIM::VirtualMachine
51
150
  dev.backing.class.name
52
151
  end
53
152
  guest_net = guest.net.find { |x| x.macAddress == dev.macAddress }
54
- puts " #{dev.deviceInfo.label}: #{backing_info} #{dev.connectable.connected ? :connected : :disconnected} #{dev.macAddress} #{guest_net ? (guest_net.ipAddress * ' ') : ''}"
153
+ puts " #{dev.name}: #{backing_info} #{dev.connectable.connected ? :connected : :disconnected} #{dev.macAddress} #{guest_net ? (guest_net.ipAddress * ' ') : ''}"
154
+ end
155
+
156
+ puts "storage:"
157
+ storage.perDatastoreUsage.map do |usage|
158
+ puts " #{usage.datastore.name}: committed=#{usage.committed.metric}B uncommitted=#{usage.uncommitted.metric}B unshared=#{usage.unshared.metric}B"
55
159
  end
56
160
  end
57
161
 
@@ -72,6 +176,7 @@ class RbVmomi::VIM::VirtualMachine
72
176
  'networks' => RVC::FakeFolder.new(self, :rvc_children_networks),
73
177
  'files' => RVC::FakeFolder.new(self, :rvc_children_files),
74
178
  'snapshots' => RVC::RootSnapshotFolder.new(self),
179
+ 'devices' => RVC::FakeFolder.new(self, :rvc_children_devices),
75
180
  }
76
181
  end
77
182
 
@@ -96,6 +201,12 @@ class RbVmomi::VIM::VirtualMachine
96
201
  [File.basename(file.name), objs.first]
97
202
  end]
98
203
  end
204
+
205
+ def rvc_children_devices
206
+ devices, = collect 'config.hardware.device'
207
+ devices.each { |x| x.rvc_vm = self }
208
+ Hash[devices.map { |x| [x.name, x] }]
209
+ end
99
210
  end
100
211
 
101
212
  class RVC::RootSnapshotFolder