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
@@ -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