rvc 1.6.0 → 1.7.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/bin/rvc +46 -70
- data/devel/test-dependencies.sh +4 -0
- data/lib/rvc.rb +5 -6
- data/lib/rvc/command.rb +65 -0
- data/lib/rvc/command_slate.rb +112 -0
- data/lib/rvc/completion.rb +89 -58
- data/lib/rvc/connection.rb +48 -0
- data/lib/rvc/extensions/DistributedVirtualPortgroup.rb +1 -1
- data/lib/rvc/extensions/DistributedVirtualSwitch.rb +3 -3
- data/lib/rvc/extensions/HostSystem.rb +90 -0
- data/lib/rvc/extensions/VirtualMachine.rb +37 -7
- data/lib/rvc/field.rb +59 -12
- data/lib/rvc/fs.rb +34 -4
- data/lib/rvc/inventory.rb +5 -1
- data/lib/rvc/modules/alarm.rb +2 -0
- data/lib/rvc/modules/basic.rb +66 -61
- data/lib/rvc/modules/cluster.rb +117 -22
- data/lib/rvc/modules/connection.rb +40 -0
- data/lib/rvc/modules/core.rb +4 -16
- data/lib/rvc/modules/datacenter.rb +2 -0
- data/lib/rvc/modules/datastore.rb +11 -78
- data/lib/rvc/modules/device.rb +40 -5
- data/lib/rvc/modules/diagnostics.rb +169 -0
- data/lib/rvc/modules/esxcli.rb +9 -5
- data/lib/rvc/modules/find.rb +5 -3
- data/lib/rvc/modules/host.rb +46 -3
- data/lib/rvc/modules/issue.rb +2 -0
- data/lib/rvc/modules/mark.rb +5 -3
- data/lib/rvc/modules/perf.rb +99 -33
- data/lib/rvc/modules/permissions.rb +2 -0
- data/lib/rvc/modules/resource_pool.rb +2 -0
- data/lib/rvc/modules/role.rb +3 -1
- data/lib/rvc/modules/snapshot.rb +12 -4
- data/lib/rvc/modules/statsinterval.rb +13 -11
- data/lib/rvc/modules/vds.rb +67 -10
- data/lib/rvc/modules/vim.rb +19 -53
- data/lib/rvc/modules/vm.rb +27 -6
- data/lib/rvc/modules/vm_guest.rb +490 -0
- data/lib/rvc/modules/vmrc.rb +60 -32
- data/lib/rvc/modules/vnc.rb +2 -0
- data/lib/rvc/namespace.rb +114 -0
- data/lib/rvc/option_parser.rb +12 -15
- data/lib/rvc/readline-ffi.rb +4 -1
- data/lib/rvc/ruby_evaluator.rb +84 -0
- data/lib/rvc/shell.rb +68 -83
- data/lib/rvc/uri_parser.rb +59 -0
- data/lib/rvc/util.rb +134 -29
- data/lib/rvc/{extensions/PerfCounterInfo.rb → version.rb} +2 -4
- data/lib/rvc/{memory_session.rb → vim.rb} +10 -32
- data/test/modules/foo.rb +9 -0
- data/test/modules/foo/bar.rb +9 -0
- data/test/test_completion.rb +17 -0
- data/test/test_fs.rb +9 -11
- data/test/test_help.rb +46 -0
- data/test/test_helper.rb +12 -0
- data/test/test_metric.rb +1 -2
- data/test/test_modules.rb +38 -0
- data/test/test_parse_path.rb +1 -2
- data/test/test_shell.rb +138 -0
- data/test/test_uri.rb +34 -0
- metadata +115 -81
- data/lib/rvc/extensions/PerformanceManager.rb +0 -83
- data/lib/rvc/filesystem_session.rb +0 -101
- data/lib/rvc/modules.rb +0 -138
data/lib/rvc/modules/vmrc.rb
CHANGED
@@ -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
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
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
|
-
|
43
|
-
|
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
|
46
|
-
|
47
|
-
|
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
|
52
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
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
|
-
|
147
|
-
|
148
|
-
|
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
|
data/lib/rvc/modules/vnc.rb
CHANGED
@@ -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
|
data/lib/rvc/option_parser.rb
CHANGED
@@ -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
|
-
|
28
|
+
HAVE_CHRONIC = true
|
26
29
|
rescue LoadError
|
27
|
-
|
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] =
|
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
|
-
|
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
|
-
|
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
|
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
|
data/lib/rvc/readline-ffi.rb
CHANGED
@@ -19,8 +19,10 @@
|
|
19
19
|
# THE SOFTWARE.
|
20
20
|
|
21
21
|
require 'ffi'
|
22
|
+
require 'readline'
|
22
23
|
|
23
|
-
module RVC
|
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
|