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
@@ -0,0 +1,122 @@
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
+ module RVC
22
+
23
+ module ObjectWithFields
24
+ module ClassMethods
25
+ def fields inherited=true
26
+ @fields ||= {}
27
+ if inherited
28
+ ancestors.select { |x| x.respond_to? :fields }.
29
+ map { |x| x.fields(false) }.
30
+ reverse.inject({}) { |b,v| b.merge v }
31
+ else
32
+ @fields
33
+ end
34
+ end
35
+
36
+ def field name, &b
37
+ name = name.to_s
38
+ @fields ||= {}
39
+ @fields[name] = RVC::Field.new(name).tap { |f| f.instance_eval &b }
40
+ end
41
+ end
42
+
43
+ def field name
44
+ name = name.to_s
45
+ field = self.class.fields[name]
46
+ if field == nil
47
+ return nil
48
+ 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
60
+ end
61
+ end
62
+ end
63
+ else
64
+ props = []
65
+ field.properties.each do |propstr|
66
+ obj = self
67
+ propstr.split('.').each { |prop| obj = obj.send(prop) }
68
+ props << obj
69
+ end
70
+ end
71
+ props = [self] if props.empty?
72
+ field.block.call *props
73
+ end
74
+ end
75
+
76
+ class Field
77
+ ALL_FIELD_NAMES = Set.new
78
+
79
+ def initialize name
80
+ @name = name
81
+ @summary = nil
82
+ @properties = []
83
+ @perfmetrics = []
84
+ @perfmetric_settings = {}
85
+ @block = nil
86
+ @default = false
87
+ ALL_FIELD_NAMES << name
88
+ end
89
+
90
+ def summary x=nil
91
+ x ? (@summary = x) : @summary
92
+ end
93
+
94
+ def properties x=nil
95
+ x ? (@properties.concat x) : @properties
96
+ end
97
+
98
+ def perfmetrics x=nil
99
+ x ? (@perfmetrics.concat x) : @perfmetrics
100
+ end
101
+
102
+ def perfmetric_settings x=nil
103
+ x ? (@perfmetric_settings.merge! x) : @perfmetric_settings
104
+ end
105
+
106
+ def block &x
107
+ x ? (@block = x) : @block
108
+ end
109
+
110
+ def default val=true
111
+ @default = val
112
+ end
113
+
114
+ def default?; @default; end
115
+
116
+ def property prop
117
+ @properties = [prop]
118
+ @block = lambda { |x| x }
119
+ end
120
+ end
121
+
122
+ end
@@ -1,3 +1,23 @@
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
+
1
21
  module RVC
2
22
 
3
23
  class FilesystemSession
@@ -18,10 +18,21 @@
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/field'
22
+
21
23
  module RVC
22
24
 
23
25
  module InventoryObject
26
+ include ObjectWithFields
27
+ extend ObjectWithFields::ClassMethods
28
+
24
29
  module ClassMethods
30
+ include ObjectWithFields::ClassMethods
31
+
32
+ def ls_r
33
+ ""
34
+ end
35
+
25
36
  def ls_properties
26
37
  %w()
27
38
  end
@@ -29,12 +40,20 @@ module InventoryObject
29
40
  def folder?
30
41
  false
31
42
  end
43
+
44
+ def traverse?
45
+ false
46
+ end
32
47
  end
33
48
 
34
49
  def self.included m
35
50
  m.extend ClassMethods
36
51
  end
37
52
 
53
+ field 'rel_path' do
54
+ block { |me| me.rvc_relative_path_str($shell.fs.cur) }
55
+ end
56
+
38
57
  attr_reader :rvc_parent, :rvc_arc
39
58
 
40
59
  def display_info
@@ -68,6 +87,22 @@ module InventoryObject
68
87
  rvc_path.map { |k,v| k } * '/'
69
88
  end
70
89
 
90
+ def rvc_relative_path ref
91
+ my_path = rvc_path
92
+ ref_path = ref.rvc_path
93
+ ref_objs = Set.new(ref_path.map { |x| x[1] })
94
+ common = my_path.take_while { |x| ref_objs.member? x[1] }
95
+ fail unless common
96
+ path_to_ref = my_path.reverse.take_while { |x| x[1] != common.last[1] }.reverse
97
+ num_ups = ref_path.size - common.size
98
+ ups = (['..']*num_ups).zip(ref_path.reverse[1..-1].map(&:first))
99
+ ups + path_to_ref
100
+ end
101
+
102
+ def rvc_relative_path_str ref
103
+ rvc_relative_path(ref).map { |k,v| k } * '/'
104
+ end
105
+
71
106
  def rvc_link parent, arc
72
107
  return if @rvc_parent
73
108
  @rvc_parent = parent
@@ -118,15 +153,3 @@ class RootNode
118
153
  end
119
154
 
120
155
  end
121
-
122
- class RbVmomi::VIM
123
- include RVC::InventoryObject
124
-
125
- def children
126
- rootFolder.children
127
- end
128
-
129
- def self.folder?
130
- true
131
- end
132
- end
@@ -1,3 +1,23 @@
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
+
1
21
  require 'digest/sha2'
2
22
  require 'fileutils'
3
23
  require 'rbconfig'
@@ -1,3 +1,23 @@
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
+
1
21
  module RVC
2
22
 
3
23
  class MemorySession
@@ -19,6 +19,7 @@
19
19
  # THE SOFTWARE.
20
20
 
21
21
  require 'rvc/util'
22
+ require 'shellwords'
22
23
 
23
24
  module RVC
24
25
 
@@ -31,6 +32,7 @@ class CmdModule
31
32
  def initialize module_name
32
33
  @module_name = module_name
33
34
  @opts = {}
35
+ @completors = {}
34
36
  super()
35
37
  end
36
38
 
@@ -38,20 +40,73 @@ class CmdModule
38
40
  @opts.keys
39
41
  end
40
42
 
43
+ def has_command? cmd
44
+ @opts.member? cmd
45
+ end
46
+
41
47
  def opts cmd, &b
42
- @opts[cmd] = b
48
+ if cmd.to_s =~ /[A-Z]/
49
+ fail "Camel-casing is not allowed (#{cmd.to_s})"
50
+ end
51
+
52
+ @opts[cmd] = OptionParser.new cmd.to_s, &b
53
+
54
+ @opts[cmd].specs.each do |name,spec|
55
+ if name.to_s =~ /[A-Z]/
56
+ fail "Camel-casing is not allowed (#{cmd.to_s} option #{name})"
57
+ end
58
+ end
59
+ end
60
+
61
+ def raw_opts cmd, summary
62
+ @opts[cmd] = RawOptionParser.new cmd.to_s, summary
43
63
  end
44
64
 
45
65
  def opts_for cmd
46
66
  @opts[cmd]
47
67
  end
48
68
 
69
+ def rvc_completor cmd, &b
70
+ @completors[cmd] = b
71
+ end
72
+
73
+ def completor_for cmd
74
+ @completors[cmd]
75
+ end
76
+
49
77
  def rvc_alias cmd, target=nil
50
78
  target ||= cmd
51
79
  RVC::ALIASES[target.to_s] = "#{@module_name}.#{cmd}"
52
80
  end
53
81
  end
54
82
 
83
+ def self.complete_for_cmd line, word
84
+ if line == nil
85
+ return []
86
+ end
87
+ mod, cmd, args = Shell.parse_input line
88
+ return [] unless mod != nil
89
+ #XXX assumes you aren't going to have any positional arguments with spaces
90
+ if(/ $/.match(line))
91
+ argnum = args.size
92
+ else
93
+ argnum = args.size - 1
94
+ end
95
+
96
+ completor = mod.completor_for(cmd.to_sym)
97
+ if completor == nil
98
+ return []
99
+ end
100
+
101
+ candidates = completor.call(line, args, word, argnum)
102
+ if candidates == nil
103
+ []
104
+ else
105
+ prefix_regex = /^#{Regexp.escape word}/
106
+ candidates.select { |x,a| x =~ prefix_regex }
107
+ end
108
+ end
109
+
55
110
  BULTIN_MODULE_PATH = [File.expand_path(File.join(File.dirname(__FILE__), 'modules')),
56
111
  File.join(ENV['HOME'], ".rvc")]
57
112
  ENV_MODULE_PATH = (ENV['RVC_MODULE_PATH'] || '').split ':'
@@ -65,13 +120,18 @@ def self.reload_modules verbose=true
65
120
  Dir.glob(globs) do |f|
66
121
  module_name = File.basename(f)[0...-3]
67
122
  puts "loading #{module_name} from #{f}" if verbose
68
- code = File.read f
69
- unless RVC::MODULES.member? module_name
70
- m = CmdModule.new module_name
71
- CMD.define_singleton_method(module_name.to_sym) { m }
72
- RVC::MODULES[module_name] = m
123
+ begin
124
+ code = File.read f
125
+ unless RVC::MODULES.member? module_name
126
+ m = CmdModule.new module_name
127
+ CMD.define_singleton_method(module_name.to_sym) { m }
128
+ RVC::MODULES[module_name] = m
129
+ end
130
+ RVC::MODULES[module_name].instance_eval code, f
131
+ rescue
132
+ puts "#{$!.class} while loading #{f}: #{$!.message}"
133
+ $!.backtrace.each { |x| puts x }
73
134
  end
74
- RVC::MODULES[module_name].instance_eval code, f
75
135
  end
76
136
  end
77
137
 
@@ -0,0 +1,37 @@
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
+ opts :show do
22
+ summary "Show alarms on the given entities"
23
+ arg :entity, nil, :lookup => VIM::ManagedEntity, :multi => true
24
+ end
25
+
26
+ IGNORE_STATUSES = %w(green gray)
27
+
28
+ def show objs
29
+ alarm_states = objs.map(&:triggeredAlarmState).flatten.uniq
30
+ alarm_states.each do |alarm_state|
31
+ info = alarm_state.alarm.info
32
+ colored_alarm_status = status_color alarm_state.overallStatus, alarm_state.overallStatus
33
+ puts "#{alarm_state.entity.name}: #{info.name} (#{colored_alarm_status}): #{info.description}"
34
+ end
35
+ end
36
+
37
+ rvc_alias :show, :alarms
@@ -44,20 +44,18 @@ HELP_ORDER = %w(basic vm)
44
44
  def help path
45
45
  if mod = RVC::MODULES[path]
46
46
  opts = mod.instance_variable_get(:@opts)
47
- opts.each do |method_name,method_opts|
48
- parser = RVC::OptionParser.new method_name, &method_opts
47
+ opts.each do |method_name,parser|
49
48
  help_summary parser, path, method_name
50
49
  end
51
50
  return
52
51
  elsif tgt = RVC::ALIASES[path]
53
52
  fail unless tgt =~ /^(.+)\.(.+)$/
54
- opts_block = RVC::MODULES[$1].opts_for($2.to_sym)
55
- RVC::OptionParser.new(tgt, &opts_block).educate
53
+ RVC::MODULES[$1].opts_for($2.to_sym).educate
56
54
  return
57
55
  elsif path =~ /^(.+)\.(.+)$/ and
58
56
  mod = RVC::MODULES[$1] and
59
- opts_block = mod.opts_for($2.to_sym)
60
- RVC::OptionParser.new(path, &opts_block).educate
57
+ parser = mod.opts_for($2.to_sym)
58
+ parser.educate
61
59
  return
62
60
  end
63
61
 
@@ -73,8 +71,7 @@ def help path
73
71
  HELP_ORDER.index(mod_name) || HELP_ORDER.size
74
72
  end.each do |mod_name,mod|
75
73
  opts = mod.instance_variable_get(:@opts)
76
- opts.each do |method_name,method_opts|
77
- parser = RVC::OptionParser.new method_name, &method_opts
74
+ opts.each do |method_name,parser|
78
75
  next unless obj.nil? or parser.applicable.any? { |x| obj.is_a? x }
79
76
  help_summary parser, mod_name, method_name
80
77
  end
@@ -105,32 +102,9 @@ rvc_alias :debug
105
102
  def debug
106
103
  debug = $shell.debug = !$shell.debug
107
104
  $shell.connections.each do |name,conn|
108
- conn.debug = debug
105
+ conn.debug = debug if conn.respond_to? :debug
109
106
  end
110
- end
111
-
112
-
113
- opts :quit do
114
- summary "Exit RVC"
115
- end
116
-
117
- rvc_alias :quit
118
- rvc_alias :quit, :exit
119
- rvc_alias :quit, :q
120
-
121
- def quit
122
- exit
123
- end
124
-
125
-
126
- opts :reload do
127
- summary "Reload RVC command modules"
128
- end
129
-
130
- rvc_alias :reload
131
-
132
- def reload
133
- RVC.reload_modules
107
+ puts "debug mode #{debug ? 'en' : 'dis'}abled"
134
108
  end
135
109
 
136
110
 
@@ -162,6 +136,10 @@ rvc_alias :ls
162
136
  rvc_alias :ls, :l
163
137
 
164
138
  def ls obj
139
+ if obj.respond_to?(:rvc_ls)
140
+ return obj.rvc_ls
141
+ end
142
+
165
143
  children = obj.children
166
144
  name_map = children.invert
167
145
  children, fake_children = children.partition { |k,v| v.is_a? VIM::ManagedEntity }
@@ -187,7 +165,7 @@ def ls obj
187
165
  filteredTypes.each do |x|
188
166
  filterSpec.propSet << {
189
167
  :type => x.wsdl_name,
190
- :pathSet => x.ls_properties+%w(name),
168
+ :pathSet => x.ls_properties+%w(name overallStatus),
191
169
  }
192
170
  end
193
171
 
@@ -198,22 +176,85 @@ def ls obj
198
176
  name = name_map[r.obj]
199
177
  text = r.obj.ls_text(r) rescue " (error)"
200
178
  realname = r['name'] if name != r['name']
201
- puts "#{i} #{name}#{realname && " [#{realname}]"}#{text}"
179
+ colored_name = status_color name, r['overallStatus']
180
+ puts "#{i} #{colored_name}#{realname && " [#{realname}]"}#{text}"
202
181
  r.obj.rvc_link obj, name
203
182
  CMD.mark.mark i.to_s, [r.obj]
204
183
  i += 1
205
184
  end
206
185
  end
207
186
 
208
-
209
187
  opts :info do
210
188
  summary "Display information about an object"
211
189
  arg :path, nil, :lookup => Object
212
- end
190
+ end
213
191
 
214
192
  rvc_alias :info
215
193
  rvc_alias :info, :i
216
194
 
195
+ opts :show do
196
+ summary "Display information about an object"
197
+ arg :arg0, nil, :type => :string
198
+ arg :arg1, nil, :type => :string, :required => false
199
+ end
200
+
201
+ rvc_alias :show
202
+
203
+ rvc_completor :show do |line, args, word, index|
204
+ choices = RVC::Completion.fs_candidates word
205
+ obj = lookup_single '.'
206
+ if index == 0
207
+ if obj.class == VIM::Datacenter || obj.class == VIM
208
+ choices << ['portgroups', ' ']
209
+ choices << ['vds', ' ']
210
+ end
211
+ if obj.class < VIM::DistributedVirtualSwitch
212
+ choices << ['running-config', ' ']
213
+ choices << ['interface', ' ']
214
+ #choices << ['vlan', ' ']
215
+ #choices << ['lldp', ' ']
216
+ #choices << ['cdp', ' ']
217
+ end
218
+ #elsif index == 1
219
+ # if args[0] == 'vlan'
220
+ # choices << ['summary', ' ']
221
+ # end
222
+ end
223
+ choices
224
+ end
225
+
226
+ def show arg0, arg1
227
+ arg1 ||= '.'
228
+ begin
229
+ obj = lookup_single arg1
230
+ rescue
231
+ obj = nil
232
+ end
233
+
234
+ case arg0
235
+ when 'running-config'
236
+ if obj.class < VIM::DistributedVirtualSwitch
237
+ MODULES['vds'].show_running_config obj
238
+ else
239
+ if arg1 != '.'
240
+ err "'#{arg1}' is not a vDS!"
241
+ else
242
+ err "you need to be inside a vDS"
243
+ end
244
+ end
245
+ when 'portgroups'
246
+ MODULES['vds'].show_all_portgroups [obj]
247
+ when 'vds'
248
+ MODULES['vds'].show_all_vds [obj]
249
+ when 'interface'
250
+ MODULES['vds'].show_all_ports [obj]
251
+ #when 'vlan'
252
+ else
253
+ path = lookup_single arg0
254
+ info path
255
+ end
256
+ end
257
+
217
258
  def info obj
218
259
  puts "path: #{obj.rvc_path_str}"
219
260
  if obj.respond_to? :display_info
@@ -248,15 +289,15 @@ def reload_entity objs
248
289
  end
249
290
 
250
291
 
251
- opts :show do
292
+ opts :what do
252
293
  summary "Basic information about the given objects"
253
294
  arg :obj, nil, :multi => true, :required => false, :lookup => Object
254
295
  end
255
296
 
256
- rvc_alias :show
257
- rvc_alias :show, :w
297
+ rvc_alias :what
298
+ rvc_alias :what, :w
258
299
 
259
- def show objs
300
+ def what objs
260
301
  objs.each do |obj|
261
302
  puts "#{obj.rvc_path_str}: #{obj.class}"
262
303
  end
@@ -344,3 +385,93 @@ def events obj, opts
344
385
  ensure
345
386
  collector.DestroyCollector if collector
346
387
  end
388
+
389
+
390
+ opts :fields do
391
+ summary "Show available fields on an object"
392
+ arg :obj, nil, :required => false, :default => '.', :lookup => RVC::InventoryObject
393
+ end
394
+
395
+ def fields obj
396
+ obj.class.ancestors.select { |x| x.respond_to? :fields }.each do |klass|
397
+ fields = klass.fields false
398
+ next if fields.empty?
399
+ puts "Fields on #{klass}:"
400
+ fields.each do |name,field|
401
+ puts " #{name}: #{field.summary}"
402
+ end
403
+ end
404
+ end
405
+
406
+ rvc_alias :fields
407
+
408
+
409
+ opts :table do
410
+ summary "Display a table with the selected fields"
411
+
412
+ text <<-EOS
413
+
414
+ You may specify the fields to display using multiple -f options, or
415
+ separate them with ':'. The available fields for an object are
416
+ shown by the "fields" command.
417
+ EOS
418
+ text ""
419
+
420
+ arg :obj, nil, :multi => true, :lookup => RVC::InventoryObject
421
+ opt :field, "Field to display", :multi => true, :type => :string
422
+ opt :sort, "Field to sort by", :type => :string
423
+ opt :reverse, "Reverse sort order"
424
+ end
425
+
426
+ rvc_completor :table do |line, args, word, argnum|
427
+ if argnum > 0 and args[argnum-1] == '-f'
428
+ RVC::Field::ALL_FIELD_NAMES.map { |x| [x, ' '] }
429
+ else
430
+ RVC::Completion.fs_candidates word
431
+ end
432
+ end
433
+
434
+ def table objs, opts
435
+ if opts[:field_given]
436
+ fields = opts[:field].map { |x| x.split ':' }.flatten(1)
437
+ else
438
+ fields = objs.map(&:class).uniq.
439
+ map { |x| x.fields.select { |k,v| v.default? } }.
440
+ map(&:keys).flatten(1).uniq
441
+ end
442
+
443
+ data = retrieve_fields(objs, fields).values
444
+
445
+ if f = opts[:sort]
446
+ data.sort! { |a,b| table_sort_compare a[f], b[f] }
447
+ data.reverse! if opts[:reverse]
448
+ end
449
+
450
+ # Invert field components to get an array of header rows
451
+ field_components = fields.map { |x| x.split '.' }
452
+ header_rows = []
453
+ field_components.each_with_index do |cs,i|
454
+ cs.each_with_index do |c,j|
455
+ header_rows[j] ||= [nil]*field_components.length
456
+ header_rows[j][i] = c
457
+ end
458
+ end
459
+
460
+ table = Terminal::Table.new
461
+ header_rows.each { |row| table.add_row row }
462
+ table.add_separator
463
+ data.each do |h|
464
+ table.add_row(fields.map { |f| h[f] == nil ? 'N/A' : h[f] })
465
+ end
466
+ puts table
467
+ end
468
+
469
+ def table_sort_compare a, b
470
+ return a <=> b if a != nil and b != nil
471
+ return 0 if a == nil and b == nil
472
+ return -1 if a == nil
473
+ return 1 if b == nil
474
+ fail
475
+ end
476
+
477
+ rvc_alias :table