rvc 1.5.0 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
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