rvc 1.6.0 → 1.7.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 (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
@@ -18,40 +18,59 @@
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
  require 'tmpdir'
22
24
  require 'digest/sha2'
23
25
  require 'zip'
24
26
  require 'rbconfig'
25
27
 
26
- case RbConfig::CONFIG['host_os']
27
- when /mswin/, /mingw/
28
- VMRC_NAME = "vmware-vmrc-win32-x86-3.0.0-309851"
29
- VMRC_SHA256 = "8d8f9655121db5987bef1c2fa3a08ef2c4dd7769eb230bbd5b3ba9fd9576db56"
30
- VMRC_BIN = "vmware-vmrc.exe"
31
- when /linux/
32
- VMRC_NAME = "vmware-vmrc-linux-x86-3.0.0-309851"
33
- VMRC_SHA256 = "c86ecd9d9a1dd909a119c19d28325cb87d6e2853885d3014a7dac65175dd2ae1"
34
- VMRC_BIN = "vmware-vmrc"
35
- else
36
- VMRC_NAME = nil
37
- VMRC_SHA256 = nil
38
- VMRC_BIN = nil
39
- $stderr.puts "No VMRC available for OS #{RbConfig::CONFIG['host_os']}"
28
+ VMRC_CHECKSUMS = {
29
+ "i686-linux" => "b8f11c92853502c3dd208da79514a66d2dd4734b8564aceb9952333037859d04",
30
+ "x86_64-linux" => "86ec4bc6f23da0c33045d9bf48d9fe66ab2f426b523d8b37531646819891bf54",
31
+ "i686-mswin" => "f8455f0df038fbc8e817e4381af44fa2141496cb4e2b61f505f75bc447841949",
32
+ }
33
+
34
+ PACKAGE_VERSION = 'A'
35
+ ARCH = RbConfig::CONFIG['arch']
36
+ ON_WINDOWS = (RbConfig::CONFIG['host_os'] =~ /(mswin|mingw)/) != nil
37
+
38
+ def vmrc_url arch
39
+ "http://cloud.github.com/downloads/vmware/rvc/vmware-vmrc-public-#{arch}-#{PACKAGE_VERSION}.zip"
40
40
  end
41
41
 
42
- VMRC_BASENAME = "#{VMRC_NAME}.xpi"
43
- VMRC_URL = "http://cloud.github.com/downloads/vmware/rvc/#{VMRC_BASENAME}"
42
+ def local_vmrc_dir arch
43
+ File.join(Dir.tmpdir, "vmware-vmrc-#{arch}-#{Process.uid}-#{PACKAGE_VERSION}")
44
+ end
45
+
46
+ def check_installed
47
+ File.exists? local_vmrc_dir(ARCH)
48
+ end
44
49
 
45
- def find_local_vmrc
46
- return nil if VMRC_NAME.nil?
47
- path = File.join(Dir.tmpdir, VMRC_NAME, 'plugins', VMRC_BIN)
50
+ def find_vmrc arch, version
51
+ path = if version == '3.0.0'
52
+ basename = ON_WINDOWS ? 'vmware-vmrc.exe' : 'vmware-vmrc'
53
+ File.join(local_vmrc_dir(arch), version, 'plugins', basename)
54
+ else
55
+ fail "VMRC5 not yet supported on win32" if ON_WINDOWS
56
+ File.join(local_vmrc_dir(arch), version, 'vmware-vmrc-5.0', 'run.sh')
57
+ end
48
58
  File.exists?(path) && path
49
59
  end
50
60
 
51
- def find_vmrc
52
- find_local_vmrc || search_path('vmrc')
61
+ def choose_vmrc_version vim_version
62
+ if vim_version >= '5.1.0'
63
+ '5.0.0'
64
+ else
65
+ '3.0.0'
66
+ end
53
67
  end
54
68
 
69
+ fail unless choose_vmrc_version('4.1.0') == '3.0.0'
70
+ fail unless choose_vmrc_version('5.0.1') == '3.0.0'
71
+ fail unless choose_vmrc_version('5.1.0') == '5.0.0'
72
+ fail unless choose_vmrc_version('6.0.0') == '5.0.0'
73
+
55
74
 
56
75
  opts :view do
57
76
  summary "Spawn a VMRC"
@@ -65,10 +84,13 @@ rvc_alias :view, :vmrc
65
84
  rvc_alias :view, :v
66
85
 
67
86
  def view vms, opts
68
- unless vmrc = find_vmrc
87
+ conn = single_connection vms
88
+ vim_version = conn.serviceContent.about.version
89
+ vmrc_version = choose_vmrc_version vim_version
90
+ unless vmrc = find_vmrc(ARCH, vmrc_version)
69
91
  if opts[:install]
70
92
  install
71
- vmrc = find_vmrc
93
+ vmrc = find_vmrc(ARCH, vmrc_version)
72
94
  else
73
95
  err "VMRC not found. You may need to run vmrc.install."
74
96
  end
@@ -82,8 +104,7 @@ def view vms, opts
82
104
  end
83
105
  end
84
106
 
85
- case RbConfig::CONFIG['host_os']
86
- when /mswin/, /mingw/
107
+ if ON_WINDOWS
87
108
  def spawn_vmrc vmrc, moref, host, ticket
88
109
  err "Ruby 1.9 required" unless Process.respond_to? :spawn
89
110
  Process.spawn vmrc, '-h', host, '-p', ticket, '-M', moref,
@@ -109,10 +130,12 @@ opts :install do
109
130
  end
110
131
 
111
132
  def install
112
- zip_filename = File.join(Dir.tmpdir, VMRC_BASENAME)
113
- download VMRC_URL, zip_filename
114
- verify zip_filename, VMRC_SHA256
115
- extract zip_filename, File.join(Dir.tmpdir, VMRC_NAME)
133
+ err "No VMRC available for architecture #{ARCH}" unless VMRC_CHECKSUMS.member? ARCH
134
+ zip_filename = "#{local_vmrc_dir(ARCH)}.zip"
135
+ url = vmrc_url ARCH
136
+ download url, zip_filename
137
+ verify zip_filename, VMRC_CHECKSUMS[ARCH]
138
+ extract zip_filename, local_vmrc_dir(ARCH)
116
139
  puts "VMRC was installed successfully."
117
140
  end
118
141
 
@@ -136,6 +159,7 @@ def download url_str, dest
136
159
  io.write segment
137
160
  end
138
161
  end
162
+ res.value
139
163
  end
140
164
  rescue Exception
141
165
  err "Error downloading VMRC: #{$!.class}: #{$!.message}"
@@ -143,9 +167,13 @@ def download url_str, dest
143
167
  end
144
168
 
145
169
  def verify filename, expected_hash
146
- puts "Checking integrity..."
147
- hexdigest = Digest::SHA256.file(filename).hexdigest
148
- err "Hash mismatch" if hexdigest != VMRC_SHA256
170
+ if expected_hash == :nocheck
171
+ puts "WARNING: skipping hash check"
172
+ else
173
+ puts "Checking integrity..."
174
+ hexdigest = Digest::SHA256.file(filename).hexdigest
175
+ err "Hash mismatch: expected #{expected_hash}, found #{hexdigest}" if hexdigest != expected_hash
176
+ end
149
177
  end
150
178
 
151
179
  def extract src, dst
@@ -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
  VNC = ENV['VNC'] || search_path('tightvnc') || search_path('vncviewer') || search_path('vinagre')
22
24
 
23
25
  opts :view do
@@ -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 'rvc/command_slate'
22
+
23
+ module RVC
24
+
25
+ class Namespace
26
+ attr_reader :name, :shell, :parent, :slate, :namespaces, :commands, :aliases
27
+
28
+ def inspect
29
+ "#<RVC::Namespace:#{name}>"
30
+ end
31
+
32
+ def initialize name, shell, parent
33
+ @name = name
34
+ @shell = shell
35
+ @parent = parent
36
+ @slate = CommandSlate.new self
37
+ @namespaces = {}
38
+ @commands = {}
39
+ @aliases = {}
40
+ end
41
+
42
+ def load_code code, filename
43
+ @slate.instance_eval code, filename
44
+ end
45
+
46
+ def child_namespace name
47
+ if ns = namespaces[name]
48
+ return ns
49
+ else
50
+ namespaces[name] = Namespace.new(name, shell, self)
51
+ end
52
+ end
53
+
54
+ def lookup cmdpath, accept=Command
55
+ if cmdpath.empty?
56
+ if accept == Command
57
+ return nil
58
+ elsif accept == Namespace
59
+ return self
60
+ end
61
+ elsif cmdpath.length == 1 and accept == Command
62
+ sym = cmdpath[0]
63
+ if @aliases.member? sym
64
+ @shell.cmds.lookup @aliases[sym], accept
65
+ else
66
+ @commands[sym]
67
+ end
68
+ else
69
+ sym = cmdpath[0]
70
+ child = @namespaces[sym]
71
+ return nil if child == nil
72
+ child.lookup cmdpath[1..-1], accept
73
+ end
74
+ end
75
+
76
+ def [] sym
77
+ @namespaces[sym]
78
+ end
79
+
80
+ def method_missing sym, *args
81
+ if cmd = @commands[sym]
82
+ cmd.invoke *args
83
+ elsif args.empty? and x = self[sym]
84
+ x
85
+ else
86
+ super
87
+ end
88
+ end
89
+
90
+ def load_module_dir dir, verbose
91
+ puts "loading module directory #{dir}" if verbose
92
+ Dir.foreach(dir) do |f|
93
+ path = File.join(dir, f)
94
+ if f[0..0] == '.'
95
+ next
96
+ elsif File.directory? path
97
+ ns_name = f.to_sym
98
+ child_namespace(ns_name).load_module_dir(path, verbose)
99
+ elsif f =~ /\.rb$/
100
+ ns_name = f[0...-3].to_sym
101
+ puts "loading #{ns_name} from #{path}" if verbose
102
+ begin
103
+ code = File.read path
104
+ child_namespace(ns_name).load_code(code, path)
105
+ rescue
106
+ puts "#{$!.class} while loading #{f}: #{$!.message}"
107
+ $!.backtrace.each { |x| puts x }
108
+ end
109
+ end
110
+ end
111
+ end
112
+ end
113
+
114
+ end
@@ -19,21 +19,23 @@
19
19
  # THE SOFTWARE.
20
20
 
21
21
  require 'trollop'
22
+ require 'set'
23
+
24
+ module RVC
22
25
 
23
26
  begin
24
27
  require 'chronic'
25
- RVC::HAVE_CHRONIC = true
28
+ HAVE_CHRONIC = true
26
29
  rescue LoadError
27
- RVC::HAVE_CHRONIC = false
30
+ HAVE_CHRONIC = false
28
31
  end
29
32
 
30
- module RVC
31
-
32
33
  class OptionParser < Trollop::Parser
33
34
  attr_reader :applicable
34
35
 
35
- def initialize cmd, &b
36
+ def initialize cmd, fs, &b
36
37
  @cmd = cmd
38
+ @fs = fs
37
39
  @summary = nil
38
40
  @args = []
39
41
  @has_options = false
@@ -41,8 +43,8 @@ class OptionParser < Trollop::Parser
41
43
  @seen_multi = false
42
44
  @applicable = Set.new
43
45
  super() do
44
- opt :help, "Show this message", :short => 'h'
45
46
  instance_eval &b
47
+ opt :help, "Show this message", :short => 'h'
46
48
  end
47
49
  end
48
50
 
@@ -97,7 +99,7 @@ class OptionParser < Trollop::Parser
97
99
 
98
100
  @specs.each do |name,spec|
99
101
  next unless klass = spec[:lookup] and path = opts[name]
100
- opts[name] = RVC::Util.lookup_single! path, klass
102
+ opts[name] = @fs.lookup_single! path, klass
101
103
  end
102
104
 
103
105
  argv = leftovers
@@ -136,10 +138,10 @@ class OptionParser < Trollop::Parser
136
138
 
137
139
  def postprocess_arg x, spec
138
140
  if spec[:lookup]
139
- RVC::Util.lookup!(x, spec[:lookup]).
141
+ @fs.lookup!(x, spec[:lookup]).
140
142
  tap { |a| RVC::Util.err "no matches for #{x.inspect}" if a.empty? }
141
143
  elsif spec[:lookup_parent]
142
- RVC::Util.lookup!(File.dirname(x), spec[:lookup_parent]).
144
+ @fs.lookup!(File.dirname(x), spec[:lookup_parent]).
143
145
  map { |y| [y, File.basename(x)] }.
144
146
  tap { |a| RVC::Util.err "no matches for #{File.dirname(x).inspect}" if a.empty? }
145
147
  else
@@ -163,16 +165,11 @@ end
163
165
  class RawOptionParser
164
166
  attr_reader :applicable
165
167
 
166
- def initialize cmd, summary
168
+ def initialize cmd
167
169
  @cmd = cmd
168
- @summary = summary
169
170
  @applicable = []
170
171
  end
171
172
 
172
- def summary?
173
- @summary
174
- end
175
-
176
173
  def parse args
177
174
  [args, {}]
178
175
  end
@@ -19,8 +19,10 @@
19
19
  # THE SOFTWARE.
20
20
 
21
21
  require 'ffi'
22
+ require 'readline'
22
23
 
23
- module RVC::ReadlineFFI
24
+ module RVC
25
+ module ReadlineFFI
24
26
  extend FFI::Library
25
27
  libreadline = ENV['RVC_READLINE'] == nil ? 'readline.so' : ENV['RVC_READLINE']
26
28
  ffi_lib libreadline
@@ -28,6 +30,7 @@ module RVC::ReadlineFFI
28
30
  attach_variable :rl_char_is_quoted_p, :rl_char_is_quoted_p, :rl_linebuf_func_t
29
31
  attach_variable :rl_line_buffer, :rl_line_buffer, :string
30
32
  end
33
+ end
31
34
 
32
35
  unless Readline.respond_to? :line_buffer
33
36
  def Readline.line_buffer
@@ -0,0 +1,84 @@
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 'rvc/util'
22
+
23
+ module RVC
24
+
25
+ class RubyEvaluator
26
+ include RVC::Util
27
+
28
+ def initialize shell
29
+ @binding = toplevel
30
+ @shell = shell
31
+ end
32
+
33
+ def toplevel
34
+ binding
35
+ end
36
+
37
+ def do_eval input, file
38
+ begin
39
+ eval input, @binding, file
40
+ rescue Exception => e
41
+ bt = e.backtrace
42
+ bt = bt.reverse.drop_while { |x| !(x =~ /toplevel/) }.reverse
43
+ bt[-1].gsub! ':in `toplevel\'', '' if bt[-1]
44
+ e.set_backtrace bt
45
+ raise
46
+ end
47
+ end
48
+
49
+ def this
50
+ @shell.fs.cur
51
+ end
52
+
53
+ def dc
54
+ @shell.fs.lookup("~").first
55
+ end
56
+
57
+ def conn
58
+ @shell.fs.lookup("~@").first
59
+ end
60
+
61
+ def rvc_exec command
62
+ @shell.eval_command command
63
+ end
64
+
65
+ def method_missing sym, *a
66
+ if a.empty?
67
+ if @shell.cmds.namespaces.member? sym
68
+ @shell.cmds.namespaces[sym]
69
+ elsif sym.to_s =~ /_?([\w\d]+)(!?)/ && objs = @shell.fs.marks[$1]
70
+ if $2 == '!'
71
+ objs
72
+ else
73
+ objs.first
74
+ end
75
+ else
76
+ super
77
+ end
78
+ else
79
+ super
80
+ end
81
+ end
82
+ end
83
+
84
+ end