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
@@ -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