rvc 1.6.0 → 1.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. data/Rakefile +1 -1
  2. data/VERSION +1 -1
  3. data/bin/rvc +46 -70
  4. data/devel/test-dependencies.sh +4 -0
  5. data/lib/rvc.rb +5 -6
  6. data/lib/rvc/command.rb +65 -0
  7. data/lib/rvc/command_slate.rb +112 -0
  8. data/lib/rvc/completion.rb +89 -58
  9. data/lib/rvc/connection.rb +48 -0
  10. data/lib/rvc/extensions/DistributedVirtualPortgroup.rb +1 -1
  11. data/lib/rvc/extensions/DistributedVirtualSwitch.rb +3 -3
  12. data/lib/rvc/extensions/HostSystem.rb +90 -0
  13. data/lib/rvc/extensions/VirtualMachine.rb +37 -7
  14. data/lib/rvc/field.rb +59 -12
  15. data/lib/rvc/fs.rb +34 -4
  16. data/lib/rvc/inventory.rb +5 -1
  17. data/lib/rvc/modules/alarm.rb +2 -0
  18. data/lib/rvc/modules/basic.rb +66 -61
  19. data/lib/rvc/modules/cluster.rb +117 -22
  20. data/lib/rvc/modules/connection.rb +40 -0
  21. data/lib/rvc/modules/core.rb +4 -16
  22. data/lib/rvc/modules/datacenter.rb +2 -0
  23. data/lib/rvc/modules/datastore.rb +11 -78
  24. data/lib/rvc/modules/device.rb +40 -5
  25. data/lib/rvc/modules/diagnostics.rb +169 -0
  26. data/lib/rvc/modules/esxcli.rb +9 -5
  27. data/lib/rvc/modules/find.rb +5 -3
  28. data/lib/rvc/modules/host.rb +46 -3
  29. data/lib/rvc/modules/issue.rb +2 -0
  30. data/lib/rvc/modules/mark.rb +5 -3
  31. data/lib/rvc/modules/perf.rb +99 -33
  32. data/lib/rvc/modules/permissions.rb +2 -0
  33. data/lib/rvc/modules/resource_pool.rb +2 -0
  34. data/lib/rvc/modules/role.rb +3 -1
  35. data/lib/rvc/modules/snapshot.rb +12 -4
  36. data/lib/rvc/modules/statsinterval.rb +13 -11
  37. data/lib/rvc/modules/vds.rb +67 -10
  38. data/lib/rvc/modules/vim.rb +19 -53
  39. data/lib/rvc/modules/vm.rb +27 -6
  40. data/lib/rvc/modules/vm_guest.rb +490 -0
  41. data/lib/rvc/modules/vmrc.rb +60 -32
  42. data/lib/rvc/modules/vnc.rb +2 -0
  43. data/lib/rvc/namespace.rb +114 -0
  44. data/lib/rvc/option_parser.rb +12 -15
  45. data/lib/rvc/readline-ffi.rb +4 -1
  46. data/lib/rvc/ruby_evaluator.rb +84 -0
  47. data/lib/rvc/shell.rb +68 -83
  48. data/lib/rvc/uri_parser.rb +59 -0
  49. data/lib/rvc/util.rb +134 -29
  50. data/lib/rvc/{extensions/PerfCounterInfo.rb → version.rb} +2 -4
  51. data/lib/rvc/{memory_session.rb → vim.rb} +10 -32
  52. data/test/modules/foo.rb +9 -0
  53. data/test/modules/foo/bar.rb +9 -0
  54. data/test/test_completion.rb +17 -0
  55. data/test/test_fs.rb +9 -11
  56. data/test/test_help.rb +46 -0
  57. data/test/test_helper.rb +12 -0
  58. data/test/test_metric.rb +1 -2
  59. data/test/test_modules.rb +38 -0
  60. data/test/test_parse_path.rb +1 -2
  61. data/test/test_shell.rb +138 -0
  62. data/test/test_uri.rb +34 -0
  63. metadata +115 -81
  64. data/lib/rvc/extensions/PerformanceManager.rb +0 -83
  65. data/lib/rvc/filesystem_session.rb +0 -101
  66. data/lib/rvc/modules.rb +0 -138
@@ -0,0 +1,48 @@
1
+ # Copyright (c) 2012 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
+ module RVC
22
+
23
+ # This module should be mixed in with all connection classes.
24
+ module Connection
25
+ include InventoryObject
26
+
27
+ module ClassMethods
28
+ include InventoryObject::ClassMethods
29
+
30
+ def folder?
31
+ true
32
+ end
33
+ end
34
+
35
+ def self.included m
36
+ m.extend ClassMethods
37
+ end
38
+
39
+ def _connection
40
+ self
41
+ end
42
+ end
43
+
44
+ class NullConnection
45
+ include Connection
46
+ end
47
+
48
+ end
@@ -217,7 +217,7 @@ class RbVmomi::VIM::DistributedVirtualPortgroup
217
217
  puts ""
218
218
  end
219
219
  child.rvc_link self, name
220
- CMD.mark.mark i.to_s, [child]
220
+ $shell.cmds.mark.mark i.to_s, [child]
221
221
  i += 1
222
222
  end
223
223
  end
@@ -58,11 +58,11 @@ class RbVmomi::VIM::DistributedVirtualSwitch
58
58
  vlan.vlanId.each { |range| trunk_ranges << Range.new(range.start,range.end) }
59
59
  end
60
60
  end
61
- trunks = RVC::MODULES['vds'].merge_ranges(trunk_ranges).map { |r|
61
+ trunks = $shell.cmds.vds.merge_ranges(trunk_ranges).map { |r|
62
62
  if r.begin == r.end then "#{r.begin}" else "#{r.begin}-#{r.end}" end
63
63
  }.join ','
64
64
 
65
- tags = RVC::MODULES['vds'].merge_ranges(tag_ranges).map { |r|
65
+ tags = $shell.cmds.vds.merge_ranges(tag_ranges).map { |r|
66
66
  if r.begin == r.end then "#{r.begin}" else "#{r.begin}-#{r.end}" end
67
67
  }.join ','
68
68
  str = ""
@@ -141,7 +141,7 @@ class RbVmomi::VIM::DistributedVirtualSwitch
141
141
  portgroups = RVC::FakeFolder.new(self, :portgroup_children)
142
142
  portgroups.define_singleton_method :display_info, lambda {
143
143
  vds = self.rvc_parent
144
- RVC::MODULES['basic'].table vds.portgroup, {}
144
+ $shell.cmds.basic.table vds.portgroup, {}
145
145
  }
146
146
 
147
147
  {
@@ -31,7 +31,97 @@ 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
+ field 'state.connection' do
35
+ summary "State of connection to VC."
36
+ property 'runtime.connectionState'
37
+ end
38
+
39
+ field 'state.power' do
40
+ summary "Host power state."
41
+ property 'runtime.powerState'
42
+ end
43
+
44
+ field 'uptime' do
45
+ summary "Host's uptime in days"
46
+ properties %w(runtime.bootTime)
47
+ block { |t| t ? MetricNumber.new(((Time.now-t) / (24 * 60 * 60)), 'd') : nil }
48
+ end
49
+
50
+ field 'num.vms' do
51
+ summary "Number of VMs on the host"
52
+ properties %w(vm)
53
+ block { |t| t ? t.length : nil }
54
+ end
55
+
56
+ field 'num.poweredonvms' do
57
+ summary "Number of VMs on the host"
58
+ properties %w(vm)
59
+ block do |vms|
60
+ if vms && vms.length > 0
61
+ conn = vms.first._connection
62
+ pc = conn.propertyCollector
63
+ vmsProps = pc.collectMultiple(vms, 'runtime.powerState')
64
+ vmsProps.select{|vm, p| p['runtime.powerState'] == 'poweredOn'}.length
65
+ end
66
+ end
67
+ end
68
+
69
+ field 'cpuusage' do
70
+ summary "Realtime CPU usage in percent"
71
+ properties %w(summary.hardware.numCpuCores summary.hardware.cpuMhz summary.quickStats)
72
+ block do |cores, mhz, stats|
73
+ if cores && mhz && stats
74
+ value = stats.overallCpuUsage.to_f * 100 / (cores * mhz)
75
+ MetricNumber.new(value, '%')
76
+ end
77
+ end
78
+ end
79
+
80
+ field 'memusage' do
81
+ summary "Realtime Mem usage in percent"
82
+ properties %w(summary.hardware.memorySize summary.quickStats)
83
+ block do |mem, stats|
84
+ if mem && stats
85
+ value = stats.overallMemoryUsage.to_f * 100 / (mem / 1024.0 / 1024.0)
86
+ MetricNumber.new(value, '%')
87
+ end
88
+ end
89
+ end
90
+
91
+ [['.realtime', 1], ['.5min', 5 * 3], ['.10min', 10 * 3]].each do |label, max_samples|
92
+ field "cpuusage#{label}" do
93
+ summary "CPU Usage in Percent"
94
+ perfmetrics %w(cpu.usage)
95
+ perfmetric_settings :max_samples => max_samples
96
+ block do |value|
97
+ if value
98
+ value = value.sum.to_f / value.length / 100
99
+ MetricNumber.new(value, '%')
100
+ else
101
+ nil
102
+ end
103
+ end
104
+ end
105
+ end
106
+
107
+ [['.realtime', 1], ['.5min', 5 * 3], ['.10min', 10 * 3]].each do |label, max_samples|
108
+ field "memusage#{label}" do
109
+ summary "Mem Usage in Percent"
110
+ perfmetrics %w(mem.usage)
111
+ perfmetric_settings :max_samples => max_samples
112
+ block do |value|
113
+ if value
114
+ value = value.sum.to_f / value.length / 100
115
+ MetricNumber.new(value, '%')
116
+ else
117
+ nil
118
+ end
119
+ end
120
+ end
121
+ end
122
+
34
123
  def display_info
124
+ super
35
125
  summary = self.summary
36
126
  runtime = summary.runtime
37
127
  stats = summary.quickStats
@@ -28,26 +28,34 @@ class RbVmomi::VIM::VirtualMachine
28
28
 
29
29
  field 'storagebw' do
30
30
  summary "Storage Bandwidth"
31
- perfmetrics %w(disk.read.average disk.write.average)
31
+ perfmetrics %w(virtualDisk.read virtualDisk.write)
32
32
  block do |read, write|
33
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')
34
+ read = read.select{|x| x != -1}
35
+ write = write.select{|x| x != -1}
36
+ if read.length > 0 && write.length > 0
37
+ io = (read.sum.to_f / read.length) + (write.sum.to_f / write.length)
38
+ MetricNumber.new(io * 1024, 'B/s')
39
+ end
36
40
  else
37
41
  nil
38
42
  end
39
43
  end
40
44
  end
41
45
 
42
- [['', 5], ['.realtime', 1], ['.5min', 5 * 3], ['.10min', 10 * 3]].each do |label, max_samples|
46
+ [['', 5], ['.realtime', 3], ['.5min', 5 * 3], ['.10min', 10 * 3]].each do |label, max_samples|
43
47
  field "storageiops#{label}" do
44
48
  summary "Storage IOPS"
45
- perfmetrics %w(disk.numberReadAveraged.average disk.numberWriteAveraged.average)
49
+ perfmetrics %w(virtualDisk.numberReadAveraged virtualDisk.numberWriteAveraged)
46
50
  perfmetric_settings :max_samples => max_samples
47
51
  block do |read, write|
48
52
  if read && write
49
- io = (read.sum.to_f / read.length) + (write.sum.to_f / write.length)
50
- MetricNumber.new(io, 'IOPS')
53
+ read = read.select{|x| x != -1}
54
+ write = write.select{|x| x != -1}
55
+ if read.length > 0 && write.length > 0
56
+ io = (read.sum.to_f / read.length) + (write.sum.to_f / write.length)
57
+ MetricNumber.new(io, 'IOPS')
58
+ end
51
59
  else
52
60
  nil
53
61
  end
@@ -55,6 +63,24 @@ class RbVmomi::VIM::VirtualMachine
55
63
  end
56
64
  end
57
65
 
66
+ ['Read', 'Write'].each do |type|
67
+ [['', 5], ['.realtime', 1], ['.5min', 5 * 3], ['.10min', 10 * 3]].each do |label, max_samples|
68
+ field "storagelatency.#{type.downcase}#{label}" do
69
+ summary "Storage Latency #{type}"
70
+ perfmetrics ["virtualDisk.total#{type}Latency"]
71
+ perfmetric_settings :max_samples => max_samples
72
+ block do |latency|
73
+ if latency
74
+ io = (latency.sum.to_f / latency.length)
75
+ MetricNumber.new(io, 'ms')
76
+ else
77
+ nil
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
83
+
58
84
  field 'ip' do
59
85
  summary "The guest tools reported IP address."
60
86
  property 'guest.ipAddress'
@@ -157,6 +183,10 @@ class RbVmomi::VIM::VirtualMachine
157
183
  storage.perDatastoreUsage.map do |usage|
158
184
  puts " #{usage.datastore.name}: committed=#{usage.committed.metric}B uncommitted=#{usage.uncommitted.metric}B unshared=#{usage.unshared.metric}B"
159
185
  end
186
+
187
+ if runtime.dasVmProtection
188
+ puts "HA protected: #{runtime.dasVmProtection.dasProtected ? 'yes' : 'no'}"
189
+ end
160
190
  end
161
191
 
162
192
  def self.ls_properties
@@ -18,6 +18,8 @@
18
18
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
19
  # THE SOFTWARE.
20
20
 
21
+ require 'set'
22
+
21
23
  module RVC
22
24
 
23
25
  module ObjectWithFields
@@ -39,24 +41,69 @@ module ObjectWithFields
39
41
  @fields[name] = RVC::Field.new(name).tap { |f| f.instance_eval &b }
40
42
  end
41
43
  end
44
+
45
+ def field_properties names
46
+ out = []
47
+ names.each do |name|
48
+ name = name.to_s
49
+ field = self.class.fields[name]
50
+ if field == nil
51
+ nil
52
+ elsif self.class < VIM::ManagedObject
53
+ out += field.properties
54
+ end
55
+ end
56
+ out.uniq
57
+ end
58
+
59
+ def perfmetrics names
60
+ out = []
61
+ names.each do |name|
62
+ name = name.to_s
63
+ field = self.class.fields[name]
64
+ if field == nil
65
+ nil
66
+ else
67
+ perfmetrics = field.perfmetrics
68
+ if perfmetrics.length > 0
69
+ perfopts = field.perfmetric_settings.dup
70
+ perfopts[:max_samples] ||= 5
71
+ out << {:metrics => perfmetrics, :opts => perfopts}
72
+ end
73
+ end
74
+ end
75
+ out.uniq
76
+ end
42
77
 
43
- def field name
78
+ def field name, props_values = {}, perf_values = {}
44
79
  name = name.to_s
45
80
  field = self.class.fields[name]
46
81
  if field == nil
47
82
  return nil
48
83
  elsif self.class < VIM::ManagedObject
49
- *props = collect *field.properties
50
- if field.perfmetrics.length > 0
51
- perfmgr = self._connection.serviceContent.perfManager
52
- perfopts = field.perfmetric_settings.dup
53
- perfopts[:max_samples] ||= 5
54
- stats = perfmgr.retrieve_stats [self], field.perfmetrics, perfopts
55
- props += field.perfmetrics.map do |x|
56
- if stats[self]
57
- stats[self][:metrics][x]
58
- else
59
- nil
84
+ properties = field.properties
85
+ if properties.all?{|x| props_values.has_key?(x)}
86
+ props = properties.map{|x| props_values[x]}
87
+ else
88
+ *props = collect *field.properties
89
+ end
90
+ perfmetrics = field.perfmetrics
91
+ if perfmetrics.length > 0
92
+ if perfmetrics.all?{|x| perf_values.has_key?(x)}
93
+ props += perfmetrics.map do |x|
94
+ perf_values[x]
95
+ end
96
+ else
97
+ perfmgr = self._connection.serviceContent.perfManager
98
+ perfopts = field.perfmetric_settings.dup
99
+ perfopts[:max_samples] ||= 5
100
+ stats = perfmgr.retrieve_stats [self], field.perfmetrics, perfopts
101
+ props += field.perfmetrics.map do |x|
102
+ if stats[self]
103
+ stats[self][:metrics][x]
104
+ else
105
+ nil
106
+ end
60
107
  end
61
108
  end
62
109
  end
@@ -21,7 +21,7 @@
21
21
  module RVC
22
22
 
23
23
  class FS
24
- attr_reader :root, :cur
24
+ attr_reader :root, :cur, :marks
25
25
 
26
26
  MARK_PATTERN = /^~(?:([\d\w]*|~|@))$/
27
27
  REGEX_PATTERN = /^%/
@@ -31,6 +31,7 @@ class FS
31
31
  fail unless root.is_a? RVC::InventoryObject
32
32
  @root = root
33
33
  @cur = root
34
+ @marks = {}
34
35
  end
35
36
 
36
37
  def display_path
@@ -39,7 +40,7 @@ class FS
39
40
 
40
41
  def cd dst
41
42
  fail unless dst.is_a? RVC::InventoryObject
42
- $shell.session.set_mark '~', [@cur]
43
+ @marks['~'] = [@cur]
43
44
  @cur = dst
44
45
  end
45
46
 
@@ -70,7 +71,7 @@ class FS
70
71
  # XXX shouldnt be nil
71
72
  [(cur.respond_to?(:parent) && cur.parent) ? cur.parent : (cur.rvc_parent || cur)]
72
73
  when MARK_PATTERN
73
- if first and objs = $shell.session.get_mark($1)
74
+ if first and objs = @marks[$1]
74
75
  objs
75
76
  else
76
77
  []
@@ -83,7 +84,7 @@ class FS
83
84
  cur.children.select { |k,v| k =~ regex }.map { |k,v| v.rvc_link(cur, k); v }
84
85
  else
85
86
  # XXX check for ambiguous child
86
- if first and arc =~ /^\d+$/ and objs = $shell.session.get_mark(arc)
87
+ if first and arc =~ /^\d+$/ and objs = @marks[arc]
87
88
  objs
88
89
  else
89
90
  if child = cur.traverse_one(arc)
@@ -96,6 +97,35 @@ class FS
96
97
  end
97
98
  end
98
99
 
100
+ def delete_numeric_marks
101
+ @marks.reject! { |k,v| k =~ /^\d+$/ }
102
+ end
103
+
104
+ # Utility methods
105
+
106
+ def lookup_single path
107
+ objs = lookup path
108
+ Util.err "Not found: #{path.inspect}" if objs.empty?
109
+ Util.err "More than one match for #{path.inspect}" if objs.size > 1
110
+ objs.first
111
+ end
112
+
113
+ def lookup! path, types
114
+ types = [types] unless types.is_a? Enumerable
115
+ lookup(path).tap do |objs|
116
+ objs.each do |obj|
117
+ Util.err "Expected #{types*'/'} but got #{obj.class} at #{path.inspect}" unless types.any? { |type| obj.is_a? type }
118
+ end
119
+ end
120
+ end
121
+
122
+ def lookup_single! path, type
123
+ objs = lookup!(path, type)
124
+ Util.err "Not found: #{path.inspect}" if objs.empty?
125
+ Util.err "More than one match for #{path.inspect}" if objs.size > 1
126
+ objs.first
127
+ end
128
+
99
129
  private
100
130
 
101
131
  def glob_to_regex str
@@ -139,8 +139,12 @@ end
139
139
  class RootNode
140
140
  include RVC::InventoryObject
141
141
 
142
+ def initialize shell
143
+ @shell = shell
144
+ end
145
+
142
146
  def children
143
- $shell.connections
147
+ @shell.connections
144
148
  end
145
149
 
146
150
  def self.folder?
@@ -18,6 +18,8 @@
18
18
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
19
  # THE SOFTWARE.
20
20
 
21
+ require 'rvc/vim'
22
+
21
23
  opts :show do
22
24
  summary "Show alarms on the given entities"
23
25
  arg :entity, nil, :lookup => VIM::ManagedEntity, :multi => true