rvc 1.6.0 → 1.7.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -19,41 +19,9 @@
19
19
  # THE SOFTWARE.
20
20
 
21
21
  require 'rvc/known_hosts'
22
+ require 'rvc/vim'
22
23
 
23
- URI_REGEX = %r{
24
- ^
25
- (?:
26
- ([^@:]+)
27
- (?::
28
- ([^@]*)
29
- )?
30
- @
31
- )?
32
- ([^@:]+)
33
- (?::(\d{1,5}))?
34
- (?::([0-9a-z]{64}))?
35
- $
36
- }x
37
-
38
- class RbVmomi::VIM
39
- include RVC::InventoryObject
40
-
41
- def children
42
- rootFolder.children
43
- end
44
-
45
- def self.folder?
46
- true
47
- end
48
-
49
- def display_info
50
- puts serviceContent.about.fullName
51
- end
52
-
53
- def _connection
54
- self
55
- end
56
- end
24
+ RVC::SCHEMES['vim'] = lambda { |uri| connect uri, {} }
57
25
 
58
26
  opts :connect do
59
27
  summary 'Open a connection to ESX/VC'
@@ -64,14 +32,13 @@ end
64
32
  rvc_alias :connect
65
33
 
66
34
  def connect uri, opts
67
- match = URI_REGEX.match uri
68
- Trollop.die "invalid hostname" unless match
69
-
70
- username = match[1] || ENV['RBVMOMI_USER']
71
- password = match[2] || ENV['RBVMOMI_PASSWORD']
72
- host = match[3]
73
- port = match[4] || 443
74
- certdigest = match[5] || opts[:certdigest]
35
+ uri = RVC::URIParser.parse uri unless uri.is_a? URI
36
+
37
+ username = uri.user || ENV['RBVMOMI_USER']
38
+ password = uri.password || ENV['RBVMOMI_PASSWORD']
39
+ host = uri.host
40
+ port = uri.port || 443
41
+ certdigest = opts[:certdigest] # TODO put in URI
75
42
  bad_cert = false
76
43
 
77
44
  vim = nil
@@ -114,7 +81,7 @@ def connect uri, opts
114
81
  if env_rev && env_rev.to_f == 0
115
82
  vim.rev = env_rev
116
83
  else
117
- vim.rev = [rev, env_rev || '5.0'].min
84
+ vim.rev = [rev, env_rev || '5.1'].min
118
85
  end
119
86
  end
120
87
 
@@ -170,14 +137,10 @@ def connect uri, opts
170
137
  vim.define_singleton_method(:_host) { host }
171
138
 
172
139
  conn_name = host.dup
173
- conn_name = "#{conn_name}:1" if $shell.connections.member? conn_name
174
- conn_name.succ! while $shell.connections.member? conn_name
175
-
176
- $shell.connections[conn_name] = vim
177
- $shell.session.set_connection conn_name,
178
- 'host' => host,
179
- 'username' => username,
180
- 'rev' => opts[:rev]
140
+ conn_name = "#{conn_name}:1" if shell.connections.member? conn_name
141
+ conn_name.succ! while shell.connections.member? conn_name
142
+
143
+ shell.connections[conn_name] = vim
181
144
  end
182
145
 
183
146
  def prompt_password
@@ -242,7 +205,7 @@ opts :tasks do
242
205
  end
243
206
 
244
207
  def tasks
245
- conn = single_connection [$shell.fs.cur]
208
+ conn = single_connection [shell.fs.cur]
246
209
 
247
210
  begin
248
211
  view = conn.serviceContent.viewManager.CreateListView
@@ -319,7 +282,10 @@ def logbundles servers, opts
319
282
  puts "#{Time.now}: Generating log bundles..."
320
283
  bundles =
321
284
  begin
322
- diagMgr.GenerateLogBundles_Task(:includeDefault => include_default, :host => hosts).wait_for_completion
285
+ diagMgr.GenerateLogBundles_Task(
286
+ :includeDefault => include_default,
287
+ :host => hosts
288
+ ).wait_for_completion
323
289
  rescue VIM::TaskInProgress
324
290
  $!.task.wait_for_completion
325
291
  end
@@ -18,6 +18,9 @@
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
+ VIM::Datastore
23
+
21
24
  opts :on do
22
25
  summary "Power on VMs"
23
26
  arg :vm, nil, :multi => true, :lookup => VIM::VirtualMachine
@@ -85,9 +88,10 @@ def wait_for_shutdown vms, opts
85
88
  end
86
89
  end
87
90
  return if all_off
88
- sleep [opts[:delay], finish_time - Time.now].min
91
+ sleep_time = [opts[:delay], finish_time - Time.now].min
92
+ sleep sleep_time if sleep_time > 0
89
93
  end
90
- puts "WARNING: At least one VM did not shut down!"
94
+ err "At least one VM did not shut down!"
91
95
  end
92
96
 
93
97
 
@@ -272,7 +276,7 @@ rvc_alias :kill, :k
272
276
  def kill vms
273
277
  on_vms = vms.select { |x| x.summary.runtime.powerState == 'poweredOn' }
274
278
  off on_vms unless on_vms.empty?
275
- CMD.basic.destroy vms unless vms.empty?
279
+ shell.cmds.basic.destroy vms unless vms.empty?
276
280
  end
277
281
 
278
282
  opts :answer do
@@ -285,9 +289,13 @@ def answer str, vms
285
289
  vms.each do |vm|
286
290
  begin
287
291
  if q = vm.runtime.question
288
- choice = q.choice.choiceInfo.find { |x| x.label == str }
289
- err("invalid answer") unless choice
290
- vm.AnswerVM :questionId => q.id, :answerChoice => choice.key
292
+ choices = q.choice.choiceInfo
293
+ choice = choices.find { |x| x.label == str }
294
+ if !choice
295
+ puts "#{vm.name}: #{choice} invalid, choices: #{choices.map{ |x| x.label }}"
296
+ else
297
+ vm.AnswerVM :questionId => q.id, :answerChoice => choice.key
298
+ end
291
299
  end
292
300
  rescue
293
301
  puts "#{vm.name rescue vm}: #{$!.message}"
@@ -628,3 +636,16 @@ def vm_ip vm
628
636
  err "no IP known for this VM"
629
637
  end
630
638
  end
639
+
640
+
641
+ opts :screenshot do
642
+ summary "Take a screenshot of a VM"
643
+ arg :vm, nil, :lookup => VIM::VirtualMachine
644
+ arg 'local-path', "Filename on the local machine"
645
+ end
646
+
647
+ rvc_alias :screenshot
648
+
649
+ def screenshot vm, local_path
650
+ http_download vm._connection, "/screen?id=#{vm._ref}", local_path
651
+ end
@@ -0,0 +1,490 @@
1
+ opts :authenticate do
2
+ summary "Authenticate within guest"
3
+ arg :vm, nil, :lookup => VIM::VirtualMachine
4
+ opt :interactive_session, "Allow command to interact with desktop", :default => false, :type => :bool
5
+ opt :password, "Password in guest", :type => :string
6
+ opt :username, "Username in guest", :default => "root", :type => :string
7
+ end
8
+
9
+ def authenticate vm, opts
10
+ auth = ((@auths ||= {})[vm] ||= {})[opts[:username]]
11
+
12
+ if opts[:password].nil? or opts[:password].empty?
13
+ opts[:password] = ask("password: ") { |q| q.echo = false }
14
+ end
15
+
16
+ auth = VIM.NamePasswordAuthentication(
17
+ :username => opts[:username],
18
+ :password => opts[:password],
19
+ :interactiveSession => opts[:interactive_session]
20
+ )
21
+
22
+ @auths[vm][opts[:username]] = auth
23
+ begin
24
+ check_auth vm, opts
25
+ rescue
26
+ clear_auth vm, opts
27
+ err "Could not authenticate: #{$!}"
28
+ end
29
+ end
30
+
31
+
32
+ opts :check_auth do
33
+ summary "Check credentials"
34
+ arg :vm, nil, :lookup => VIM::VirtualMachine
35
+ opt :username, "Username in guest", :default => "root", :type => :string
36
+ end
37
+
38
+ def check_auth vm, opts
39
+ auth = get_auth vm, opts
40
+
41
+ guestOperationsManager = vm._connection.serviceContent.guestOperationsManager
42
+
43
+ err "This command requires vSphere 5 or greater" unless guestOperationsManager.respond_to? :authManager
44
+ guestOperationsManager.authManager.ValidateCredentialsInGuest(
45
+ :vm => vm,
46
+ :auth => auth
47
+ )
48
+ end
49
+
50
+
51
+ opts :list_auth do
52
+ summary "List available credentials"
53
+ arg :vm, nil, :lookup => VIM::VirtualMachine, :required => false
54
+ end
55
+
56
+ def list_auth vm
57
+ if @auths.nil?
58
+ puts "No credentials available."
59
+ return
60
+ end
61
+
62
+ if vm.nil?
63
+ auth_list = @auths
64
+ elsif !@auths.member? vm
65
+ puts "No credentials available."
66
+ return
67
+ else
68
+ auth_list = { vm => @auths[vm] }
69
+ end
70
+
71
+ auth_list.each_key do |vmkey|
72
+ puts vmkey.rvc_path_str
73
+ auth_list[vmkey].each_key do |userkey|
74
+ puts " #{userkey}"
75
+ end
76
+ end
77
+ end
78
+
79
+
80
+ opts :clear_auth do
81
+ summary "Clear credentials"
82
+ arg :vm, nil, :lookup => VIM::VirtualMachine, :required => false
83
+ opt :username, "Username in guest", :default => "root", :type => :string
84
+ end
85
+
86
+ def clear_auth vm, opts
87
+ unless @auths.nil? or vm.nil?
88
+ if @auths.member? vm
89
+ @auths[vm].delete opts[:username]
90
+ @auths.delete vm if @auths[vm].empty?
91
+ @auths = nil if @auths.empty?
92
+ end
93
+ end
94
+ end
95
+
96
+
97
+ def get_auth vm, opts
98
+ auth = @auths.fetch(vm).fetch(opts[:username])
99
+ ensure
100
+ err "No credentials found. You must authenticate before executing this command." if auth.nil?
101
+ end
102
+
103
+
104
+ # File commands
105
+ opts :chmod do
106
+ summary "Change file attributes"
107
+ arg :vm, nil, :lookup => VIM::VirtualMachine
108
+ opt :group_id, "Group ID of file", :type => :int
109
+ opt :guest_path, "Path in guest to change ownership of", :required => true, :type => :string
110
+ opt :owner_id, "Owner ID of file", :type => :int
111
+ opt :permissions, "Permissions of file", :type => :string
112
+ opt :username, "Username in guest", :default => "root", :type => :string
113
+ end
114
+
115
+ def chmod vm, opts
116
+ guestOperationsManager = vm._connection.serviceContent.guestOperationsManager
117
+ err "This command requires vSphere 5 or greater" unless guestOperationsManager.respond_to? :fileManager
118
+ fileManager = guestOperationsManager.fileManager
119
+
120
+ opts[:permissions] = opts[:permissions].to_i(8) if opts[:permissions]
121
+
122
+ auth = get_auth vm, opts
123
+
124
+ fileManager.
125
+ ChangeFileAttributesInGuest(
126
+ :vm => vm,
127
+ :auth => auth,
128
+ :guestFilePath => opts[:guest_path],
129
+ :fileAttributes => VIM.GuestPosixFileAttributes(
130
+ :groupId => opts[:group_id],
131
+ :ownerId => opts[:owner_id],
132
+ :permissions => opts[:permissions]
133
+ )
134
+ )
135
+ end
136
+
137
+
138
+ opts :mktmpdir do
139
+ summary "Create temporary directory in guest"
140
+ arg :vm, nil, :lookup => VIM::VirtualMachine
141
+ opt :guest_path, "Path in guest to create temporary directory in", :type => :string
142
+ opt :prefix, "Prefix of temporary directory", :required => true, :type => :string
143
+ opt :suffix, "Suffix of temporary directory", :required => true, :type => :string
144
+ opt :username, "Username in guest", :default => "root", :type => :string
145
+ end
146
+
147
+ def mktmpdir vm, opts
148
+ guestOperationsManager = vm._connection.serviceContent.guestOperationsManager
149
+ err "This command requires vSphere 5 or greater" unless guestOperationsManager.respond_to? :fileManager
150
+ fileManager = guestOperationsManager.fileManager
151
+
152
+ auth = get_auth vm, opts
153
+
154
+ dirname = fileManager.
155
+ CreateTemporaryDirectoryInGuest(
156
+ :vm => vm,
157
+ :auth => auth,
158
+ :prefix => opts[:prefix],
159
+ :suffix => opts[:suffix],
160
+ :directoryPath => opts[:guest_path]
161
+ )
162
+ puts dirname
163
+ return dirname
164
+ end
165
+
166
+
167
+ opts :mktmpfile do
168
+ summary "Create temporary file in guest"
169
+ arg :vm, nil, :lookup => VIM::VirtualMachine
170
+ opt :guest_path, "Path in guest to create temporary file in", :type => :string
171
+ opt :prefix, "Prefix of temporary directory", :required => true, :type => :string
172
+ opt :suffix, "Suffix of temporary directory", :required => true, :type => :string
173
+ opt :username, "Username in guest", :default => "root", :type => :string
174
+ end
175
+
176
+ def mktmpfile vm, opts
177
+ guestOperationsManager = vm._connection.serviceContent.guestOperationsManager
178
+ err "This command requires vSphere 5 or greater" unless guestOperationsManager.respond_to? :fileManager
179
+ fileManager = guestOperationsManager.fileManager
180
+
181
+ auth = get_auth vm, opts
182
+
183
+ filename = fileManager.
184
+ CreateTemporaryFileInGuest(
185
+ :vm => vm,
186
+ :auth => auth,
187
+ :prefix => opts[:prefix],
188
+ :suffix => opts[:suffix],
189
+ :directoryPath => opts[:guest_path]
190
+ )
191
+ puts filename
192
+ return filename
193
+ end
194
+
195
+
196
+ opts :rmdir do
197
+ summary "Delete directory in guest"
198
+ arg :vm, nil, :lookup => VIM::VirtualMachine
199
+ opt :guest_path, "Path of directory in guest to delete", :required => true, :type => :string
200
+ opt :recursive, "Delete all subdirectories", :default => false, :type => :bool
201
+ opt :username, "Username in guest", :default => "root", :type => :string
202
+ end
203
+
204
+ def rmdir vm, opts
205
+ guestOperationsManager = vm._connection.serviceContent.guestOperationsManager
206
+ err "This command requires vSphere 5 or greater" unless guestOperationsManager.respond_to? :fileManager
207
+ fileManager = guestOperationsManager.fileManager
208
+
209
+ auth = get_auth vm, opts
210
+
211
+ fileManager.
212
+ DeleteDirectoryInGuest(
213
+ :vm => vm,
214
+ :auth => auth,
215
+ :directoryPath => opts[:guest_path],
216
+ :recursive => opts[:recursive]
217
+ )
218
+ end
219
+
220
+
221
+ opts :rmfile do
222
+ summary "Delete file in guest"
223
+ arg :vm, nil, :lookup => VIM::VirtualMachine
224
+ opt :guest_path, "Path of file in guest to delete", :required => true, :type => :string
225
+ opt :username, "Username in guest", :default => "root", :type => :string
226
+ end
227
+
228
+ def rmfile vm, opts
229
+ guestOperationsManager = vm._connection.serviceContent.guestOperationsManager
230
+ err "This command requires vSphere 5 or greater" unless guestOperationsManager.respond_to? :fileManager
231
+ fileManager = guestOperationsManager.fileManager
232
+
233
+ auth = get_auth vm, opts
234
+
235
+ fileManager.
236
+ DeleteFileInGuest(
237
+ :vm => vm,
238
+ :auth => auth,
239
+ :filePath => opts[:guest_path]
240
+ )
241
+ end
242
+
243
+
244
+ opts :download_file do
245
+ summary "Download file from guest"
246
+ arg :vm, nil, :lookup => VIM::VirtualMachine
247
+ opt :guest_path, "Path in guest to download from", :required => true, :type => :string
248
+ opt :local_path, "Local file to download to", :required => true, :type => :string
249
+ opt :username, "Username in guest", :default => "root", :type => :string
250
+ end
251
+
252
+ def download_file vm, opts
253
+ guestOperationsManager = vm._connection.serviceContent.guestOperationsManager
254
+ err "This command requires vSphere 5 or greater" unless guestOperationsManager.respond_to? :fileManager
255
+ fileManager = guestOperationsManager.fileManager
256
+
257
+ auth = get_auth vm, opts
258
+
259
+ download_url = fileManager.
260
+ InitiateFileTransferFromGuest(
261
+ :vm => vm,
262
+ :auth => auth,
263
+ :guestFilePath => opts[:guest_path]
264
+ ).url
265
+
266
+ download_uri = URI.parse(download_url.gsub /http(s?):\/\/\*:[0-9]*/, "")
267
+ download_path = "#{download_uri.path}?#{download_uri.query}"
268
+
269
+ http_download vm._connection, download_path, opts[:local_path]
270
+ end
271
+
272
+
273
+ opts :upload_file do
274
+ summary "Upload file to guest"
275
+ arg :vm, nil, :lookup => VIM::VirtualMachine
276
+ opt :group_id, "Group ID of file", :type => :int
277
+ opt :guest_path, "Path in guest to upload to", :required => true, :type => :string
278
+ opt :local_path, "Local file to upload", :required => true, :type => :string
279
+ opt :overwrite, "Overwrite file", :default => false, :type => :bool
280
+ opt :owner_id, "Owner ID of file", :type => :int
281
+ opt :permissions, "Permissions of file", :type => :string
282
+ opt :username, "Username in guest", :default => "root", :type => :string
283
+ end
284
+
285
+ def upload_file vm, opts
286
+ guestOperationsManager = vm._connection.serviceContent.guestOperationsManager
287
+ err "This command requires vSphere 5 or greater" unless guestOperationsManager.respond_to? :fileManager
288
+ fileManager = guestOperationsManager.fileManager
289
+
290
+ opts[:permissions] = opts[:permissions].to_i(8) if opts[:permissions]
291
+
292
+ auth = get_auth vm, opts
293
+
294
+ file = File.new(opts[:local_path], 'rb')
295
+
296
+ upload_url = fileManager.
297
+ InitiateFileTransferToGuest(
298
+ :vm => vm,
299
+ :auth => auth,
300
+ :guestFilePath => opts[:guest_path],
301
+ :fileAttributes => VIM.GuestPosixFileAttributes(
302
+ :groupId => opts[:group_id],
303
+ :ownerId => opts[:owner_id],
304
+ :permissions => opts[:permissions]
305
+ ),
306
+ :fileSize => file.size,
307
+ :overwrite => opts[:overwrite]
308
+ )
309
+
310
+ upload_uri = URI.parse(upload_url.gsub /http(s?):\/\/\*:[0-9]*/, "")
311
+ upload_path = "#{upload_uri.path}?#{upload_uri.query}"
312
+
313
+ http_upload vm._connection, opts[:local_path], upload_path
314
+ end
315
+
316
+
317
+ opts :ls_guest do
318
+ summary "List files in guest"
319
+ arg :vm, nil, :lookup => VIM::VirtualMachine
320
+ opt :guest_path, "Path in guest to get directory listing", :required => true, :type => :string
321
+ opt :index, "Which to start the list with", :type => :int, :default => nil
322
+ opt :match_pattern, "Filename filter (regular expression)", :type => :string
323
+ opt :max_results, "Maximum number of results", :type => :int, :default => nil
324
+ opt :username, "Username in guest", :default => "root", :type => :string
325
+ end
326
+
327
+ def ls_guest vm, opts
328
+ guestOperationsManager = vm._connection.serviceContent.guestOperationsManager
329
+ err "This command requires vSphere 5 or greater" unless guestOperationsManager.respond_to? :fileManager
330
+ fileManager = guestOperationsManager.fileManager
331
+
332
+ auth = get_auth vm, opts
333
+
334
+ files = fileManager.
335
+ ListFilesInGuest(
336
+ :vm => vm,
337
+ :auth => auth,
338
+ :filePath => opts[:guest_path],
339
+ :index => opts[:index],
340
+ :maxResults => opts[:max_results],
341
+ :matchPattern => opts[:match_pattern]
342
+ )
343
+
344
+ files.files.each do |file|
345
+ puts file.path
346
+ end
347
+
348
+ puts "Remaining: #{files.remaining}" unless files.remaining.zero?
349
+
350
+ return files
351
+ end
352
+
353
+
354
+ opts :mkdir do
355
+ summary "Make directory in guest"
356
+ arg :vm, nil, :lookup => VIM::VirtualMachine
357
+ opt :guest_path, "Path of directory in guest to create", :required => true, :type => :string
358
+ opt :create_parent_directories, "Create parent directories", :default => false, :type => :bool
359
+ opt :username, "Username in guest", :default => "root", :type => :string
360
+ end
361
+
362
+ def mkdir vm, opts
363
+ guestOperationsManager = vm._connection.serviceContent.guestOperationsManager
364
+ err "This command requires vSphere 5 or greater" unless guestOperationsManager.respond_to? :fileManager
365
+ fileManager = guestOperationsManager.fileManager
366
+
367
+ auth = get_auth vm, opts
368
+
369
+ fileManager.
370
+ MakeDirectoryInGuest(
371
+ :vm => vm,
372
+ :auth => auth,
373
+ :directoryPath => opts[:guest_path],
374
+ :createParentDirectories => opts[:create_parent_directories]
375
+ )
376
+ end
377
+
378
+
379
+ opts :mvdir do
380
+ summary "Move directory in guest"
381
+ arg :vm, nil, :lookup => VIM::VirtualMachine
382
+ opt :src_guest_path, "Path in guest to move from", :required => true, :type => :string
383
+ opt :dst_guest_path, "Path in guest to move to", :required => true, :type => :string
384
+ opt :username, "Username in guest", :default => "root", :type => :string
385
+ end
386
+
387
+ def mvdir vm, opts
388
+ guestOperationsManager = vm._connection.serviceContent.guestOperationsManager
389
+ err "This command requires vSphere 5 or greater" unless guestOperationsManager.respond_to? :fileManager
390
+ fileManager = guestOperationsManager.fileManager
391
+
392
+ auth = get_auth vm, opts
393
+
394
+ fileManager.
395
+ MoveDirectoryInGuest(
396
+ :vm => vm,
397
+ :auth => auth,
398
+ :srcDirectoryPath => opts[:src_guest_path],
399
+ :dstDirectoryPath => opts[:dst_guest_path]
400
+ )
401
+ end
402
+
403
+
404
+ opts :mvfile do
405
+ summary "Move file in guest"
406
+ arg :vm, nil, :lookup => VIM::VirtualMachine
407
+ opt :dst_guest_path, "Path in guest to move to", :required => true, :type => :string
408
+ opt :overwrite, "Overwrite file", :default => true, :type => :bool
409
+ opt :src_guest_path, "Path in guest to move from", :required => true, :type => :string
410
+ opt :username, "Username in guest", :default => "root", :type => :string
411
+ end
412
+
413
+ def mvfile vm, opts
414
+ guestOperationsManager = vm._connection.serviceContent.guestOperationsManager
415
+ err "This command requires vSphere 5 or greater" unless guestOperationsManager.respond_to? :fileManager
416
+ fileManager = guestOperationsManager.fileManager
417
+
418
+ auth = get_auth vm, opts
419
+
420
+ fileManager.
421
+ MoveFileInGuest(
422
+ :vm => vm,
423
+ :auth => auth,
424
+ :srcFilePath => opts[:src_guest_path],
425
+ :dstFilePath => opts[:dst_guest_path],
426
+ :overwrite => opts[:overwrite]
427
+ )
428
+ end
429
+
430
+
431
+ # Process commands
432
+ opts :start_program do
433
+ summary "Run program in guest"
434
+ arg :vm, nil, :lookup => VIM::VirtualMachine
435
+ opt :arguments, "Arguments of command", :default => "", :type => :string
436
+ opt :background, "Don't wait for process to finish", :default => false, :type => :bool
437
+ opt :delay, "Interval in seconds", :type => :float, :default => 5.0
438
+ opt :env, "Environment variable(s) to set (e.g. VAR=value)", :multi => true, :type => :string
439
+ opt :program_path, "Path to program in guest", :required => true, :type => :string
440
+ opt :timeout, "Timeout in seconds", :type => :int, :default => nil
441
+ opt :username, "Username in guest", :default => "root", :type => :string
442
+ opt :working_directory, "Working directory of the program to run", :type => :string
443
+ conflicts :background, :timeout
444
+ conflicts :background, :delay
445
+ end
446
+
447
+ def start_program vm, opts
448
+ guestOperationsManager = vm._connection.serviceContent.guestOperationsManager
449
+ err "This command requires vSphere 5 or greater" unless guestOperationsManager.respond_to? :processManager
450
+ processManager = guestOperationsManager.processManager
451
+
452
+ auth = get_auth vm, opts
453
+
454
+ pid = processManager.
455
+ StartProgramInGuest(
456
+ :vm => vm,
457
+ :auth => auth,
458
+ :spec => VIM.GuestProgramSpec(
459
+ :arguments => opts[:arguments],
460
+ :programPath => opts[:program_path],
461
+ :envVariables => opts[:env],
462
+ :workingDirectory => opts[:working_directory]
463
+ )
464
+ )
465
+
466
+ Timeout.timeout opts[:timeout] do
467
+ while true
468
+ processes = processManager.
469
+ ListProcessesInGuest(
470
+ :vm => vm,
471
+ :auth => auth,
472
+ :pids => [pid]
473
+ )
474
+ process = processes.first
475
+
476
+ if !process.endTime.nil?
477
+ if process.exitCode != 0
478
+ err "Process failed with exit code #{process.exitCode}"
479
+ end
480
+ break
481
+ elsif opts[:background]
482
+ break
483
+ end
484
+
485
+ sleep opts[:delay]
486
+ end
487
+ end
488
+ rescue Timeout::Error
489
+ err "Timed out waiting for process to finish."
490
+ end