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,276 @@
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 :type do
22
+ summary "Display information about a VMODL type"
23
+ arg :name, "VMODL type name"
24
+ end
25
+
26
+ rvc_alias :type
27
+
28
+ def type name
29
+ klass = RbVmomi::VIM.type(name) rescue err("#{name.inspect} is not a VMODL type.")
30
+ $shell.introspect_class klass
31
+ nil
32
+ end
33
+
34
+
35
+ opts :help do
36
+ summary "Display this text"
37
+ arg :path, "Limit commands to those applicable to the given object", :required => false
38
+ end
39
+
40
+ rvc_alias :help
41
+
42
+ HELP_ORDER = %w(basic vm)
43
+
44
+ def help path
45
+ obj = lookup(path) if path
46
+
47
+ if obj
48
+ puts "Relevant commands for #{obj.class}:"
49
+ else
50
+ puts "All commands:"
51
+ end
52
+
53
+ MODULES.sort_by do |mod_name,mod|
54
+ HELP_ORDER.index(mod_name) || HELP_ORDER.size
55
+ end.each do |mod_name,mod|
56
+ opts = mod.instance_variable_get(:@opts)
57
+ opts.each do |method_name,method_opts|
58
+ parser = RVC::OptionParser.new method_name, &method_opts
59
+ next unless obj.nil? or parser.applicable.any? { |x| obj.is_a? x }
60
+ aliases = ALIASES.select { |k,v| v == "#{mod_name}.#{method_name}" }.keys
61
+ aliases_text = aliases.empty? ? '' : " (#{aliases*', '})"
62
+ puts "#{mod_name}.#{method_name}#{aliases_text}: #{parser.summary?}" if parser.summary?
63
+ end
64
+ end
65
+
66
+ if not obj
67
+ puts (<<-EOS)
68
+
69
+ To see detailed help for a command, use its --help option.
70
+ To show only commands relevant to a specific object, use "help /path/to/object".
71
+ EOS
72
+ end
73
+ end
74
+
75
+
76
+ opts :debug do
77
+ summary "Toggle VMOMI logging to stderr"
78
+ end
79
+
80
+ rvc_alias :debug
81
+
82
+ def debug
83
+ debug = $shell.debug = !$shell.debug
84
+ $shell.connections.each do |name,conn|
85
+ conn.debug = debug
86
+ end
87
+ end
88
+
89
+
90
+ opts :quit do
91
+ summary "Exit RVC"
92
+ end
93
+
94
+ rvc_alias :quit
95
+ rvc_alias :quit, :exit
96
+ rvc_alias :quit, :q
97
+
98
+ def quit
99
+ exit
100
+ end
101
+
102
+
103
+ opts :reload do
104
+ summary "Reload RVC command modules"
105
+ end
106
+
107
+ rvc_alias :reload
108
+
109
+ def reload
110
+ RVC.reload_modules
111
+ end
112
+
113
+
114
+ opts :cd do
115
+ summary "Change directory"
116
+ arg :path, "Directory to change to"
117
+ end
118
+
119
+ rvc_alias :cd
120
+
121
+ def cd path
122
+ $shell.fs.cd(path) or err "Not found: #{path.inspect}"
123
+ $shell.fs.mark '', find_ancestor_loc(RbVmomi::VIM::Datacenter)
124
+ $shell.fs.mark '@', find_ancestor_loc(RbVmomi::VIM)
125
+ $shell.fs.marks.delete_if { |k,v| k =~ /^\d+$/ }
126
+ end
127
+
128
+ def find_ancestor_loc klass
129
+ dc_loc = $shell.fs.loc.dup
130
+ dc_loc.pop while dc_loc.obj and not dc_loc.obj.is_a? klass
131
+ dc_loc.obj ? dc_loc : nil
132
+ end
133
+
134
+
135
+ opts :ls do
136
+ summary "List objects in a directory"
137
+ arg :path, "Directory to list", :required => false, :default => '.'
138
+ end
139
+
140
+ rvc_alias :ls
141
+ rvc_alias :ls, :l
142
+
143
+ def ls path
144
+ loc = $shell.fs.lookup_loc(path) or err "Not found: #{path.inspect}"
145
+ obj = loc.obj
146
+ children = obj.children
147
+ name_map = children.invert
148
+ children, fake_children = children.partition { |k,v| v.is_a? VIM::ManagedEntity }
149
+ i = 0
150
+
151
+ fake_children.each do |name,obj|
152
+ puts "#{i} #{name}#{obj.ls_text(nil)}"
153
+ mark_loc = loc.dup.tap { |x| x.push name, obj }
154
+ $shell.fs.mark i.to_s, mark_loc
155
+ i += 1
156
+ end
157
+
158
+ return if children.empty?
159
+
160
+ filterSpec = VIM.PropertyFilterSpec(:objectSet => [], :propSet => [])
161
+ filteredTypes = Set.new
162
+
163
+ children.each do |name,obj|
164
+ filterSpec.objectSet << { :obj => obj }
165
+ filteredTypes << obj.class
166
+ end
167
+
168
+ filteredTypes.each do |x|
169
+ filterSpec.propSet << {
170
+ :type => x.wsdl_name,
171
+ :pathSet => x.ls_properties+%w(name),
172
+ }
173
+ end
174
+
175
+ connection = single_connection(children.map { |k,v| v })
176
+ results = connection.propertyCollector.RetrieveProperties(:specSet => [filterSpec])
177
+
178
+ results.each do |r|
179
+ name = name_map[r.obj]
180
+ text = r.obj.ls_text r
181
+ realname = r['name'] if name != r['name']
182
+ puts "#{i} #{name}#{realname && " [#{realname}]"}#{text}"
183
+ mark_loc = loc.dup.tap { |x| x.push name, r.obj }
184
+ $shell.fs.mark i.to_s, mark_loc
185
+ i += 1
186
+ end
187
+ end
188
+
189
+
190
+ opts :info do
191
+ summary "Display information about an object"
192
+ arg :path, nil, :lookup => Object
193
+ end
194
+
195
+ rvc_alias :info
196
+ rvc_alias :info, :i
197
+
198
+ def info obj
199
+ if obj.respond_to? :display_info
200
+ obj.display_info
201
+ else
202
+ puts "class: #{obj.class.name}"
203
+ end
204
+ end
205
+
206
+
207
+ opts :destroy do
208
+ summary "Destroy managed entities"
209
+ arg :obj, nil, :lookup => VIM::ManagedEntity, :multi => true
210
+ end
211
+
212
+ rvc_alias :destroy
213
+
214
+ def destroy objs
215
+ tasks objs, :Destroy
216
+ end
217
+
218
+
219
+ opts :mark do
220
+ summary "Save a path for later use"
221
+ arg :key, "Name for this mark"
222
+ arg :path, "Any object", :required => false, :default => '.'
223
+ end
224
+
225
+ rvc_alias :mark
226
+ rvc_alias :mark, :m
227
+
228
+ def mark key, path
229
+ err "invalid mark name" unless key =~ /^\w+$/
230
+ obj = $shell.fs.lookup_loc(path) or err "Not found: #{path.inspect}"
231
+ $shell.fs.mark key, obj
232
+ end
233
+
234
+
235
+ opts :mv do
236
+ summary "Move/rename an entity"
237
+ arg :src, "Source path"
238
+ arg :dst, "Destination path"
239
+ end
240
+
241
+ rvc_alias :mv
242
+
243
+ def mv src, dst
244
+ src_dir = File.dirname(src)
245
+ dst_dir = File.dirname(dst)
246
+ err "cross-directory mv not yet supported" unless src_dir == dst_dir
247
+ dst_name = File.basename(dst)
248
+ obj = lookup(src)
249
+ obj.Rename_Task(:newName => dst_name).wait_for_completion
250
+ end
251
+
252
+
253
+ opts :disconnect do
254
+ summary "Disconnect from a server"
255
+ arg :connection, nil, :type => :string, :lookup => RbVmomi::VIM
256
+ end
257
+
258
+ rvc_alias :disconnect
259
+
260
+ def disconnect connection
261
+ $shell.connections.delete_if { |k,v| v == connection }
262
+ end
263
+
264
+
265
+ opts :mkdir do
266
+ summary "Create a folder"
267
+ arg :path, "Folder to create", :type => :string
268
+ end
269
+
270
+ rvc_alias :mkdir
271
+
272
+ # TODO dispatch to datastore.mkdir if path is in a datastore
273
+ def mkdir path
274
+ parent = lookup! File.dirname(path), RbVmomi::VIM::Folder
275
+ parent.CreateFolder(:name => File.basename(path))
276
+ end
@@ -0,0 +1,63 @@
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 :download do
22
+ summary "Download a file from a datastore"
23
+ arg 'datastore-path', "Filename on the datastore"
24
+ arg 'local-path', "Filename on the local machine"
25
+ end
26
+
27
+ def download datastore_path, local_path
28
+ file = lookup(datastore_path)
29
+ err "not a datastore file" unless file.is_a? RbVmomi::VIM::Datastore::FakeDatastoreFile
30
+ file.datastore.download file.path, local_path
31
+ end
32
+
33
+ opts :upload do
34
+ summary "Upload a file to a datastore"
35
+ arg 'local-path', "Filename on the local machine"
36
+ arg 'datastore-path', "Filename on the datastore"
37
+ end
38
+
39
+ def upload local_path, datastore_path
40
+ datastore_dir_path = File.dirname datastore_path
41
+ dir = lookup(datastore_dir_path)
42
+ err "datastore directory does not exist" unless dir.is_a? RbVmomi::VIM::Datastore::FakeDatastoreFolder
43
+ err "local file does not exist" unless File.exists? local_path
44
+ real_datastore_path = "#{dir.path}/#{File.basename(datastore_path)}"
45
+ dir.datastore.upload real_datastore_path, local_path
46
+ end
47
+
48
+ opts :mkdir do
49
+ summary "Create a directory on a datastore"
50
+ arg 'path', "Directory to create on the datastore"
51
+ end
52
+
53
+ def mkdir datastore_path
54
+ datastore_dir_path = File.dirname datastore_path
55
+ dir = lookup(datastore_dir_path)
56
+ err "datastore directory does not exist" unless dir.is_a? RbVmomi::VIM::Datastore::FakeDatastoreFolder
57
+ ds = dir.datastore
58
+ dc = ds.path.find { |o,x| o.is_a? RbVmomi::VIM::Datacenter }[0]
59
+ name = "#{dir.datastore_path}/#{File.basename(datastore_path)}"
60
+ dc._connection.serviceContent.fileManager.MakeDirectory :name => name,
61
+ :datacenter => dc,
62
+ :createParentDirectories => false
63
+ end
@@ -0,0 +1,29 @@
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 :reboot do
22
+ summary "Reboot a host"
23
+ arg :host, nil, :lookup => VIM::HostSystem, :multi => true
24
+ opt :force, "Reboot even if in maintenance mode", :default => false
25
+ end
26
+
27
+ def reboot hosts, opts
28
+ tasks hosts, :RebootHost, :force => opts[:force]
29
+ end
@@ -0,0 +1,95 @@
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 :create do
22
+ summary "Create a resource pool"
23
+ arg :name, "Name of the new resource pool."
24
+ arg :parent, nil, :lookup => RbVmomi::VIM::ResourcePool
25
+ opt :cpu_limit, "CPU limit in Mhz", :type => :int
26
+ opt :cpu_reservation, "CPU reservation in Mhz", :type => :int
27
+ opt :cpu_shares, "CPU shares level or number", :default => 'normal'
28
+ opt :cpu_expandable, "Whether CPU reservation can be expanded"
29
+ opt :mem_limit, "Memory limit in MB", :type => :int
30
+ opt :mem_reservation, "Memory reservation in MB", :type => :int
31
+ opt :mem_shares, "Memory shares level or number", :default => 'normal'
32
+ opt :mem_expandable, "Whether memory reservation can be expanded"
33
+ end
34
+
35
+ def shares_from_string str
36
+ case str
37
+ when 'normal', 'low', 'high'
38
+ { :level => str, :shares => 0 }
39
+ when /^\d+$/
40
+ { :level => 'custom', :shares => str.to_i }
41
+ else
42
+ err "Invalid shares argument #{str.inspect}"
43
+ end
44
+ end
45
+
46
+ def create name, parent, opts
47
+ spec = {
48
+ :cpuAllocation => {
49
+ :limit => opts[:cpu_limit],
50
+ :reservation => opts[:cpu_reservation],
51
+ :expandableReservation => opts[:cpu_expandable],
52
+ :shares => shares_from_string(opts[:cpu_shares]),
53
+ },
54
+ :memoryAllocation => {
55
+ :limit => opts[:mem_limit],
56
+ :reservation => opts[:mem_reservation],
57
+ :expandableReservation => opts[:mem_expandable],
58
+ :shares => shares_from_string(opts[:mem_shares]),
59
+ },
60
+ }
61
+ parent.CreateResourcePool(:name => name, :spec => spec)
62
+ end
63
+
64
+
65
+ opts :update do
66
+ summary "Update a resource pool"
67
+ arg :pool, nil, :lookup => RbVmomi::VIM::ResourcePool
68
+ opt :name, "New name for the resource pool", :type => :string
69
+ opt :cpu_limit, "CPU limit in Mhz", :type => :int
70
+ opt :cpu_reservation, "CPU reservation in Mhz", :type => :int
71
+ opt :cpu_shares, "CPU shares level or number", :default => 'normal'
72
+ opt :cpu_expandable, "Whether CPU reservation can be expanded"
73
+ opt :mem_limit, "Memory limit in MB", :type => :int
74
+ opt :mem_reservation, "Memory reservation in MB", :type => :int
75
+ opt :mem_shares, "Memory shares level or number", :default => 'normal'
76
+ opt :mem_expandable, "Whether memory reservation can be expanded"
77
+ end
78
+
79
+ def update pool, opts
80
+ spec = {
81
+ :cpuAllocation => {
82
+ :limit => opts[:cpu_limit],
83
+ :reservation => opts[:cpu_reservation],
84
+ :expandableReservation => opts[:cpu_expandable],
85
+ :shares => shares_from_string(opts[:cpu_shares]),
86
+ },
87
+ :memoryAllocation => {
88
+ :limit => opts[:mem_limit],
89
+ :reservation => opts[:mem_reservation],
90
+ :expandableReservation => opts[:mem_expandable],
91
+ :shares => shares_from_string(opts[:mem_shares]),
92
+ },
93
+ }
94
+ pool.UpdateConfig(:name => opts[:name], :spec => spec)
95
+ end