rvc 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. data/LICENSE +19 -0
  2. data/README.rdoc +120 -0
  3. data/Rakefile +39 -0
  4. data/TODO +4 -0
  5. data/VERSION +1 -0
  6. data/bin/rvc +104 -0
  7. data/lib/rvc.rb +31 -0
  8. data/lib/rvc/completion.rb +110 -0
  9. data/lib/rvc/extensions/ClusterComputeResource.rb +42 -0
  10. data/lib/rvc/extensions/ComputeResource.rb +47 -0
  11. data/lib/rvc/extensions/Datacenter.rb +36 -0
  12. data/lib/rvc/extensions/Datastore.rb +188 -0
  13. data/lib/rvc/extensions/DistributedVirtualPortgroup.rb +38 -0
  14. data/lib/rvc/extensions/DistributedVirtualSwitch.rb +40 -0
  15. data/lib/rvc/extensions/Folder.rb +33 -0
  16. data/lib/rvc/extensions/HostSystem.rb +48 -0
  17. data/lib/rvc/extensions/ManagedEntity.rb +28 -0
  18. data/lib/rvc/extensions/Network.rb +28 -0
  19. data/lib/rvc/extensions/ResourcePool.rb +52 -0
  20. data/lib/rvc/extensions/VirtualMachine.rb +72 -0
  21. data/lib/rvc/fs.rb +123 -0
  22. data/lib/rvc/inventory.rb +125 -0
  23. data/lib/rvc/modules.rb +74 -0
  24. data/lib/rvc/modules/basic.rb +276 -0
  25. data/lib/rvc/modules/datastore.rb +63 -0
  26. data/lib/rvc/modules/host.rb +29 -0
  27. data/lib/rvc/modules/resource_pool.rb +95 -0
  28. data/lib/rvc/modules/vim.rb +128 -0
  29. data/lib/rvc/modules/vm.rb +607 -0
  30. data/lib/rvc/modules/vmrc.rb +72 -0
  31. data/lib/rvc/modules/vnc.rb +111 -0
  32. data/lib/rvc/option_parser.rb +114 -0
  33. data/lib/rvc/path.rb +37 -0
  34. data/lib/rvc/readline-ffi.rb +41 -0
  35. data/lib/rvc/shell.rb +220 -0
  36. data/lib/rvc/ttl_cache.rb +44 -0
  37. data/lib/rvc/util.rb +168 -0
  38. data/test/_test_completion.rb +27 -0
  39. data/test/_test_option_parser.rb +6 -0
  40. data/test/inventory_fixtures.rb +15 -0
  41. data/test/test_fs.rb +113 -0
  42. data/test/test_parse_path.rb +41 -0
  43. metadata +146 -0
@@ -0,0 +1,72 @@
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
+ require 'tmpdir'
22
+
23
+ VMRC_NAME = "vmware-vmrc-linux-x86-3.0.0"
24
+ VMRC_PKGVER = 1
25
+ VMRC_URL = "https://github.com/downloads/vmware/rvc/#{VMRC_NAME}.#{VMRC_PKGVER}.tar.bz2"
26
+
27
+ def find_local_vmrc
28
+ path = File.join(Dir.tmpdir, VMRC_NAME, 'plugins', 'vmware-vmrc')
29
+ File.exists?(path) && path
30
+ end
31
+
32
+ def find_vmrc
33
+ find_local_vmrc || search_path('vmrc')
34
+ end
35
+
36
+
37
+ opts :view do
38
+ summary "Spawn a VMRC"
39
+ arg :vm, nil, :lookup => VIM::VirtualMachine, :multi => true
40
+ end
41
+
42
+ rvc_alias :view
43
+ rvc_alias :view, :vmrc
44
+ rvc_alias :view, :v
45
+
46
+ def view vms
47
+ err "VMRC not found" unless vmrc = find_vmrc
48
+ vms.each do |vm|
49
+ moref = vm._ref
50
+ ticket = vm._connection.serviceInstance.content.sessionManager.AcquireCloneTicket
51
+ host = vm._connection._host
52
+ fork do
53
+ ENV['https_proxy'] = ENV['HTTPS_PROXY'] = ''
54
+ $stderr.reopen("#{ENV['HOME']||'.'}/.rvc-vmrc.log", "w")
55
+ $stderr.puts Time.now
56
+ Process.setpgrp
57
+ exec vmrc, '-M', moref,
58
+ '-h', host,
59
+ '-p', ticket
60
+ end
61
+ end
62
+ end
63
+
64
+ opts :install do
65
+ summary "Install VMRC"
66
+ end
67
+
68
+ def install
69
+ puts "Installing VMRC..."
70
+ system "curl -L #{VMRC_URL} | tar -xj -C #{Dir.tmpdir}" or err("VMRC installation failed")
71
+ puts "VMRC was installed successfully."
72
+ end
@@ -0,0 +1,111 @@
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
+ VNC = ENV['VNC'] || search_path('vinagre') || search_path('tightvnc')
22
+
23
+ opts :view do
24
+ summary "Spawn a VNC client"
25
+ arg :vm, nil, :lookup => VIM::VirtualMachine
26
+ end
27
+
28
+ rvc_alias :view, :vnc
29
+ rvc_alias :view, :V
30
+
31
+ def view vm
32
+ ip = reachable_ip vm.runtime.host
33
+ extraConfig = vm.config.extraConfig
34
+ already_enabled = extraConfig.find { |x| x.key == 'RemoteDisplay.vnc.enabled' && x.value.downcase == 'true' }
35
+ if already_enabled
36
+ puts "VNC already enabled"
37
+ port = extraConfig.find { |x| x.key == 'RemoteDisplay.vnc.port' }.value
38
+ password = extraConfig.find { |x| x.key == 'RemoteDisplay.vnc.password' }.value
39
+ else
40
+ port = unused_vnc_port ip
41
+ password = vnc_password
42
+ vm.ReconfigVM_Task(:spec => {
43
+ :extraConfig => [
44
+ { :key => 'RemoteDisplay.vnc.enabled', :value => 'true' },
45
+ { :key => 'RemoteDisplay.vnc.password', :value => password },
46
+ { :key => 'RemoteDisplay.vnc.port', :value => port.to_s }
47
+ ]
48
+ }).wait_for_completion
49
+ end
50
+ vnc_client ip, port, password
51
+ end
52
+
53
+
54
+ opts :off do
55
+ summary "Close a VM's VNC port"
56
+ arg :vm, nil, :lookup => VIM::VirtualMachine
57
+ end
58
+
59
+ def off vm
60
+ vm.ReconfigVM_Task(:spec => {
61
+ :extraConfig => [
62
+ { :key => 'RemoteDisplay.vnc.enabled', :value => 'false' },
63
+ { :key => 'RemoteDisplay.vnc.password', :value => '' },
64
+ { :key => 'RemoteDisplay.vnc.port', :value => '' }
65
+ ]
66
+ }).wait_for_completion
67
+ end
68
+
69
+
70
+ def reachable_ip host
71
+ ips = host.config.network.vnic.map { |x| x.spec.ip.ipAddress } # TODO optimize
72
+ ips.find do |x|
73
+ begin
74
+ Timeout.timeout(1) { TCPSocket.new(x, 443).close; true }
75
+ rescue
76
+ false
77
+ end
78
+ end or err("could not find IP for server #{host.name}")
79
+ end
80
+
81
+ def unused_vnc_port ip
82
+ 10.times do
83
+ port = 5901 + rand(64)
84
+ unused = (TCPSocket.connect(ip, port).close rescue true)
85
+ return port if unused
86
+ end
87
+ err "no unused port found"
88
+ end
89
+
90
+ # Override this if you don't want a random password
91
+ def vnc_password
92
+ n = 8
93
+ chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'
94
+ (0...n).map { chars[rand(chars.length)].chr }.join
95
+ end
96
+
97
+ # Override this to spawn a VNC client differently
98
+ def vnc_client ip, port, password
99
+ if VNC
100
+ fork do
101
+ $stderr.reopen("#{ENV['HOME']||'.'}/.rvc-vmrc.log", "w")
102
+ Process.setpgrp
103
+ exec VNC, "#{ip}:#{port}"
104
+ end
105
+ puts "spawning #{VNC}"
106
+ puts "#{ip}:#{port} password: #{password}"
107
+ else
108
+ puts "no VNC client configured"
109
+ puts "#{ip}:#{port} password: #{password}"
110
+ end
111
+ end
@@ -0,0 +1,114 @@
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
+ require 'trollop'
22
+
23
+ module RVC
24
+
25
+ class OptionParser < Trollop::Parser
26
+ attr_reader :applicable
27
+
28
+ def initialize cmd, &b
29
+ @cmd = cmd
30
+ @summary = nil
31
+ @args = []
32
+ @has_options = false
33
+ @seen_not_required = false
34
+ @seen_multi = false
35
+ @applicable = Set.new
36
+ super &b
37
+ end
38
+
39
+ def summary str
40
+ @summary = str
41
+ text str
42
+ end
43
+
44
+ def summary?
45
+ @summary
46
+ end
47
+
48
+ def opt name, *a
49
+ super
50
+ @applicable << @specs[name][:lookup] if @specs[name][:lookup]
51
+ @has_options = true unless name == :help
52
+ end
53
+
54
+ def has_options?
55
+ @has_options
56
+ end
57
+
58
+ def arg name, description, opts={}
59
+ opts = {
60
+ :required => true,
61
+ :default => nil,
62
+ :multi => false,
63
+ }.merge opts
64
+ opts[:default] = [] if opts[:multi] and opts[:default].nil?
65
+ fail "Multi argument must be the last one" if @seen_multi
66
+ fail "Can't have required argument after optional ones" if opts[:required] and @seen_not_required
67
+ @applicable << opts[:lookup] if opts[:lookup]
68
+ @args << [name, description, opts[:required], opts[:default], opts[:multi], opts[:lookup]]
69
+ text " #{name}: " + [description, opts[:lookup]].compact.join(' ')
70
+ end
71
+
72
+ def parse argv
73
+ opts = super argv
74
+
75
+ @specs.each do |name,spec|
76
+ next unless klass = spec[:lookup] and path = opts[name]
77
+ opts[name] = lookup! path, klass
78
+ end
79
+
80
+ argv = leftovers
81
+ args = []
82
+ @args.each do |name,desc,required,default,multi,lookup_klass|
83
+ if multi
84
+ err "missing argument '#{name}'" if required and argv.empty?
85
+ a = (argv.empty? ? default : argv.dup)
86
+ a.map! { |x| lookup! x, lookup_klass } if lookup_klass
87
+ args << a
88
+ argv.clear
89
+ else
90
+ x = argv.shift
91
+ err "missing argument '#{name}'" if required and x.nil?
92
+ x = default if x.nil?
93
+ x = lookup! x, lookup_klass if lookup_klass
94
+ args << x
95
+ end
96
+ end
97
+ err "too many arguments" unless argv.empty?
98
+ return args, opts
99
+ end
100
+
101
+ def educate
102
+ arg_texts = @args.map do |name,desc,required,default,multi,lookup_klass|
103
+ text = name
104
+ text = "[#{text}]" if not required
105
+ text = "#{text}..." if multi
106
+ text
107
+ end
108
+ arg_texts.unshift "[opts]" if has_options?
109
+ puts "usage: #{@cmd} #{arg_texts*' '}"
110
+ super
111
+ end
112
+ end
113
+
114
+ end
@@ -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
+ module RVC
22
+ module Path
23
+ def self.parse path
24
+ if path.empty?
25
+ return [[], false, false]
26
+ elsif path == '/'
27
+ return [[], true, true]
28
+ else
29
+ els = path.split '/'
30
+ trailing_slash = path[-1..-1] == '/'
31
+ absolute = !els[0].nil? && els[0].empty?
32
+ els.shift if absolute
33
+ [els, absolute, trailing_slash]
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,41 @@
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
+ require 'ffi'
22
+
23
+ module RVC::ReadlineFFI
24
+ extend FFI::Library
25
+ ffi_lib "readline.so"
26
+ callback :rl_linebuf_func_t, [ :string, :int ], :bool
27
+ attach_variable :rl_char_is_quoted_p, :rl_char_is_quoted_p, :rl_linebuf_func_t
28
+ attach_variable :rl_line_buffer, :rl_line_buffer, :string
29
+ end
30
+
31
+ unless Readline.respond_to? :line_buffer
32
+ def Readline.line_buffer
33
+ RVC::ReadlineFFI.rl_line_buffer
34
+ end
35
+ end
36
+
37
+ unless Readline.respond_to? :char_is_quoted=
38
+ def Readline.char_is_quoted= fn
39
+ RVC::ReadlineFFI.rl_char_is_quoted_p = fn
40
+ end
41
+ end
@@ -0,0 +1,220 @@
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
+ class Shell
24
+ attr_reader :fs, :connections
25
+ attr_accessor :debug
26
+
27
+ def initialize
28
+ @persist_ruby = false
29
+ @fs = RVC::FS.new RVC::RootNode.new
30
+ @ruby_evaluator = RubyEvaluator.new @fs
31
+ @connections = {}
32
+ @debug = false
33
+ end
34
+
35
+ def eval_input input
36
+ if input == '//'
37
+ @persist_ruby = !@persist_ruby
38
+ return
39
+ end
40
+
41
+ if input[0..0] == '!'
42
+ system_fg input[1..-1]
43
+ return
44
+ end
45
+
46
+ ruby = @persist_ruby
47
+ if input =~ /^\//
48
+ input = $'
49
+ ruby = !ruby
50
+ end
51
+
52
+ begin
53
+ if ruby
54
+ eval_ruby input
55
+ else
56
+ eval_command input
57
+ end
58
+ rescue SystemExit, IOError
59
+ raise
60
+ rescue UserError, RuntimeError, RbVmomi::Fault
61
+ if ruby or debug
62
+ puts "#{$!.class}: #{$!.message}"
63
+ puts $!.backtrace * "\n"
64
+ else
65
+ case $!
66
+ when RbVmomi::Fault, UserError
67
+ puts $!.message
68
+ else
69
+ puts "#{$!.class}: #{$!.message}"
70
+ end
71
+ end
72
+ rescue Exception
73
+ puts "#{$!.class}: #{$!.message}"
74
+ puts $!.backtrace * "\n"
75
+ end
76
+ end
77
+
78
+ def eval_command input
79
+ cmd, *args = Shellwords.shellwords(input)
80
+ return unless cmd
81
+ err "invalid command" unless cmd.is_a? String
82
+ case cmd
83
+ when RVC::FS::MARK_REGEX
84
+ CMD.basic.cd cmd
85
+ else
86
+ if cmd.include? '.'
87
+ module_name, cmd, = cmd.split '.'
88
+ elsif ALIASES.member? cmd
89
+ module_name, cmd, = ALIASES[cmd].split '.'
90
+ else
91
+ err "unknown alias #{cmd}"
92
+ end
93
+
94
+ m = MODULES[module_name] or err("unknown module #{module_name}")
95
+
96
+ opts_block = m.opts_for(cmd.to_sym)
97
+ parser = RVC::OptionParser.new cmd, &opts_block
98
+
99
+ begin
100
+ args, opts = parser.parse args
101
+ rescue Trollop::HelpNeeded
102
+ parser.educate
103
+ return
104
+ end
105
+
106
+ if parser.has_options?
107
+ m.send cmd.to_sym, *(args + [opts])
108
+ else
109
+ m.send cmd.to_sym, *args
110
+ end
111
+ end
112
+ nil
113
+ end
114
+
115
+ def eval_ruby input
116
+ result = @ruby_evaluator.do_eval input
117
+ if input =~ /\#$/
118
+ introspect_object result
119
+ else
120
+ pp result
121
+ end
122
+ nil
123
+ end
124
+
125
+ def prompt
126
+ "#{@fs.display_path}#{@persist_ruby ? '~' : '>'} "
127
+ end
128
+
129
+ def introspect_object obj
130
+ case obj
131
+ when RbVmomi::VIM::DataObject, RbVmomi::VIM::ManagedObject
132
+ introspect_class obj.class
133
+ when Array
134
+ klasses = obj.map(&:class).uniq
135
+ if klasses.size == 0
136
+ puts "Array"
137
+ elsif klasses.size == 1
138
+ $stdout.write "Array of "
139
+ introspect_class klasses[0]
140
+ else
141
+ counts = Hash.new 0
142
+ obj.each { |o| counts[o.class] += 1 }
143
+ puts "Array of:"
144
+ counts.each { |k,c| puts " #{k}: #{c}" }
145
+ puts
146
+ $stdout.write "Common ancestor: "
147
+ introspect_class klasses.map(&:ancestors).inject(&:&)[0]
148
+ end
149
+ else
150
+ puts obj.class
151
+ end
152
+ end
153
+
154
+ def introspect_class klass
155
+ q = lambda { |x| x =~ /^xsd:/ ? $' : x }
156
+ if klass < RbVmomi::VIM::DataObject
157
+ puts "Data Object #{klass}"
158
+ klass.full_props_desc.each do |desc|
159
+ puts " #{desc['name']}: #{q[desc['wsdl_type']]}#{desc['is-array'] ? '[]' : ''}"
160
+ end
161
+ elsif klass < RbVmomi::VIM::ManagedObject
162
+ puts "Managed Object #{klass}"
163
+ puts
164
+ puts "Properties:"
165
+ klass.full_props_desc.each do |desc|
166
+ puts " #{desc['name']}: #{q[desc['wsdl_type']]}#{desc['is-array'] ? '[]' : ''}"
167
+ end
168
+ puts
169
+ puts "Methods:"
170
+ klass.full_methods_desc.sort_by(&:first).each do |name,desc|
171
+ params = desc['params']
172
+ puts " #{name}(#{params.map { |x| "#{x['name']} : #{q[x['wsdl_type'] || 'void']}#{x['is-array'] ? '[]' : ''}" } * ', '}) : #{q[desc['result']['wsdl_type'] || 'void']}"
173
+ end
174
+ else
175
+ puts klass
176
+ end
177
+ end
178
+ end
179
+
180
+ class RubyEvaluator
181
+ def initialize fs
182
+ @binding = binding
183
+ @fs = fs
184
+ end
185
+
186
+ def do_eval input
187
+ eval input, @binding
188
+ end
189
+
190
+ def this
191
+ @fs.cur
192
+ end
193
+
194
+ def dc
195
+ @fs.lookup("~")
196
+ end
197
+
198
+ def conn
199
+ @fs.lookup("~@")
200
+ end
201
+
202
+ def method_missing sym, *a
203
+ str = sym.to_s
204
+ if a.empty?
205
+ if MODULES.member? str
206
+ MODULES[str]
207
+ elsif @fs.marks.member?(str)
208
+ @fs.marks[str].obj
209
+ elsif str[0..0] == '_' && @fs.marks.member?(str[1..-1])
210
+ @fs.marks[str[1..-1]].obj
211
+ else
212
+ super
213
+ end
214
+ else
215
+ super
216
+ end
217
+ end
218
+ end
219
+
220
+ end