vagrant-skytap 0.1.6 → 0.1.7

Sign up to get free protection for your applications and to get access to all the features.
data/eng-10269.diff ADDED
@@ -0,0 +1,577 @@
1
+ # HG changeset patch
2
+ # Parent 586410d23ff4907e87ce5ee2c7eee574f0749ab0
3
+ # Parent 586410d23ff4907e87ce5ee2c7eee574f0749ab0
4
+ ENG-10269 add parallelization support for `vagrant up`.
5
+
6
+ diff -r 586410d23ff4 lib/vagrant-skytap/action.rb
7
+ --- a/lib/vagrant-skytap/action.rb Thu Nov 19 21:24:21 2015 -0800
8
+ +++ b/lib/vagrant-skytap/action.rb Thu Nov 19 21:50:44 2015 -0800
9
+ @@ -168,6 +168,11 @@
10
+ end
11
+ end
12
+
13
+ + # Some middlewares perform further actions after the succeeding
14
+ + # middleware returns. Provision and SyncedFolders, specifically,
15
+ + # both require the machine to be booted. This requirement can be
16
+ + # satisfied by putting the WaitForCommunicator middleware further
17
+ + # down in the sequence.
18
+ def self.action_prepare_boot
19
+ Vagrant::Action::Builder.new.tap do |b|
20
+ b.use PrepareNFSSettings
21
+ @@ -187,6 +192,14 @@
22
+ # This action is called to bring the box up from nothing.
23
+ def self.action_up
24
+ Vagrant::Action::Builder.new.tap do |b|
25
+ + b.use action_create
26
+ + b.use action_run_vm
27
+ + end
28
+ + end
29
+ +
30
+ + # This action is called by our modified "up" command.
31
+ + def self.action_create
32
+ + Vagrant::Action::Builder.new.tap do |b|
33
+ b.use HandleBox
34
+ b.use ConfigValidate
35
+ b.use InitializeAPIClient
36
+ @@ -204,23 +217,58 @@
37
+ b1.use StoreExtraData
38
+ b1.use SetUpVm
39
+ end
40
+ - b.use Call, IsRunning do |env, b1|
41
+ + b.use Call, IsStopped do |env, b1|
42
+ if env[:result]
43
+ + b1.use UpdateHardware
44
+ + b1.use SetHostname
45
+ + end
46
+ + end
47
+ + end
48
+ + end
49
+ +
50
+ +# # This action is called by our modified "up" command.
51
+ +# def self.action_update_properties
52
+ +# Vagrant::Action::Builder.new.tap do |b|
53
+ +# b.use InitializeAPIClient
54
+ +# b.use FetchEnvironment
55
+ +# b.use Call, IsStopped do |env, b1|
56
+ +# if env[:result]
57
+ +# b1.use UpdateHardware
58
+ +# b1.use SetHostname
59
+ +# end
60
+ +# end
61
+ +# end
62
+ +# end
63
+ +
64
+ + # This action is called by our modified "up" command after
65
+ + # all the VMs have been created. The action is called once
66
+ + # for each machine, but by default, the RunEnvironment
67
+ + # middleware will run all the machines in parallel; after
68
+ + # the first invocation, RunEnvironment is a no-op.
69
+ + def self.action_run_vm
70
+ + Vagrant::Action::Builder.new.tap do |b|
71
+ + b.use InitializeAPIClient
72
+ + b.use FetchEnvironment
73
+ + b.use Call, InitialState do |env, b1|
74
+ + case env[:result]
75
+ + when :running
76
+ b1.use MessageAlreadyRunning
77
+ next
78
+ + when :suspended
79
+ + b1.use Message, "The machine will be resumed"
80
+ + when :stopped
81
+ + b1.use action_prepare_boot
82
+ end
83
+
84
+ - b1.use Call, IsStopped do |env2, b2|
85
+ + b1.use Call, IsParallelized do |env2, b2|
86
+ if env2[:result]
87
+ - b2.use UpdateHardware
88
+ - b2.use SetHostname
89
+ - b2.use action_prepare_boot
90
+ + b2.use RunEnvironment
91
+ + else
92
+ + b2.use RunVm
93
+ end
94
+ -
95
+ - b2.use RunVm
96
+ - b2.use WaitForCommunicator
97
+ end
98
+ end
99
+ + b.use WaitForCommunicator
100
+ end
101
+ end
102
+
103
+ @@ -251,6 +299,8 @@
104
+ autoload :ExistenceCheck, action_root.join("existence_check")
105
+ autoload :FetchEnvironment, action_root.join("fetch_environment")
106
+ autoload :InitializeAPIClient, action_root.join("initialize_api_client")
107
+ + autoload :InitialState, action_root.join("initial_state")
108
+ + autoload :IsParallelized, action_root.join("is_parallelized")
109
+ autoload :IsRunning, action_root.join("is_running")
110
+ autoload :IsStopped, action_root.join("is_stopped")
111
+ autoload :IsSuspended, action_root.join("is_suspended")
112
+ @@ -263,6 +313,7 @@
113
+ autoload :PrepareNFSValidIds, action_root.join("prepare_nfs_valid_ids")
114
+ autoload :ReadSSHInfo, action_root.join("read_ssh_info")
115
+ autoload :ReadState, action_root.join("read_state")
116
+ + autoload :RequiresBoot, action_root.join("requires_boot")
117
+ autoload :RunEnvironment, action_root.join("run_environment")
118
+ autoload :RunVm, action_root.join("run_vm")
119
+ autoload :SetHostname, action_root.join("set_hostname")
120
+ diff -r 586410d23ff4 lib/vagrant-skytap/action/initial_state.rb
121
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
122
+ +++ b/lib/vagrant-skytap/action/initial_state.rb Thu Nov 19 21:50:44 2015 -0800
123
+ @@ -0,0 +1,20 @@
124
+ +module VagrantPlugins
125
+ + module Skytap
126
+ + module Action
127
+ + # This is specifically for the "up" action. When we run in parallel, we have
128
+ + # to know which machines were initially powered off so we can set up operations
129
+ + # which will happen after the machine is ready
130
+ + class InitialState
131
+ + def initialize(app, env)
132
+ + @app = app
133
+ + @logger = Log4r::Logger.new("vagrant_skytap::action::initial_state")
134
+ + end
135
+ +
136
+ + def call(env)
137
+ + env[:result] = env[:initial_states][env[:machine].id]
138
+ + @app.call(env)
139
+ + end
140
+ + end
141
+ + end
142
+ + end
143
+ +end
144
+ diff -r 586410d23ff4 lib/vagrant-skytap/action/is_parallelized.rb
145
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
146
+ +++ b/lib/vagrant-skytap/action/is_parallelized.rb Thu Nov 19 21:50:44 2015 -0800
147
+ @@ -0,0 +1,21 @@
148
+ +module VagrantPlugins
149
+ + module Skytap
150
+ + module Action
151
+ + # This can be used with "Call" built-in to check if the action
152
+ + # is being performed as part of a parallel operation.
153
+ + class IsParallelized
154
+ + def initialize(app, env)
155
+ + @app = app
156
+ + @logger = Log4r::Logger.new("vagrant_skytap::action::is_parallelized")
157
+ + end
158
+ +
159
+ + def call(env)
160
+ + env[:result] = env[:parallel]
161
+ + @logger.info("Parallelization is #{env[:result] ? 'on' : 'off'}")
162
+ +
163
+ + @app.call(env)
164
+ + end
165
+ + end
166
+ + end
167
+ + end
168
+ +end
169
+ diff -r 586410d23ff4 lib/vagrant-skytap/action/requires_boot.rb
170
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
171
+ +++ b/lib/vagrant-skytap/action/requires_boot.rb Thu Nov 19 21:50:44 2015 -0800
172
+ @@ -0,0 +1,20 @@
173
+ +module VagrantPlugins
174
+ + module Skytap
175
+ + module Action
176
+ + # This can be used with "Call" built-in to check if the machine
177
+ + # was stopped at the beginning of the command and needs the prepare_boot
178
+ + # action. If this information is not captured,
179
+ + class RequiresBoot
180
+ + def initialize(app, env)
181
+ + @app = app
182
+ + @logger = Log4r::Logger.new("vagrant_skytap::action::requires_boot")
183
+ + end
184
+ +
185
+ + def call(env)
186
+ + env[:result] = env[:require_boot].collect(&:id).include?(env[:machine].id)
187
+ + @app.call(env)
188
+ + end
189
+ + end
190
+ + end
191
+ + end
192
+ +end
193
+ diff -r 586410d23ff4 lib/vagrant-skytap/action/run_environment.rb
194
+ --- a/lib/vagrant-skytap/action/run_environment.rb Thu Nov 19 21:24:21 2015 -0800
195
+ +++ b/lib/vagrant-skytap/action/run_environment.rb Thu Nov 19 21:50:44 2015 -0800
196
+ @@ -3,7 +3,8 @@
197
+ module VagrantPlugins
198
+ module Skytap
199
+ module Action
200
+ - # Runs the Skytap environment.
201
+ + # Runs multiple VMs in parallel. The :first_machine flag is used to prevent
202
+ + # redundant REST calls on subsequent invocations.
203
+ class RunEnvironment
204
+ include Vagrant::Util::Retryable
205
+
206
+ @@ -16,8 +17,14 @@
207
+ end
208
+
209
+ def call(env)
210
+ - env[:ui].info(I18n.t("vagrant_skytap.launching_instance"))
211
+ - environment.run!
212
+ + # Since the middleware sequence is called for each machine, use a
213
+ + # flag to ensure that we only make the request once.
214
+ + if env[:first_machine]
215
+ + env[:ui].info(I18n.t("vagrant_skytap.running_environment"))
216
+ + vm_ids = env[:machines].try(:collect, &:id)
217
+ + @logger.info("Running VMs: #{vm_ids}")
218
+ + env[:environment].run!(vm_ids)
219
+ + end
220
+
221
+ @app.call(env)
222
+ end
223
+ diff -r 586410d23ff4 lib/vagrant-skytap/api/environment.rb
224
+ --- a/lib/vagrant-skytap/api/environment.rb Thu Nov 19 21:24:21 2015 -0800
225
+ +++ b/lib/vagrant-skytap/api/environment.rb Thu Nov 19 21:50:44 2015 -0800
226
+ @@ -28,7 +28,9 @@
227
+ end
228
+
229
+ def properties(env)
230
+ - EnvironmentProperties.read(env[:machine].env.local_data_path)
231
+ + # This can be called outside the context of a particular machine
232
+ + path = env[:local_data_path] || env[:machine].env.local_data_path
233
+ + EnvironmentProperties.read(path)
234
+ end
235
+
236
+ def check_vm_before_adding(env, vm)
237
+ @@ -78,6 +80,10 @@
238
+ super
239
+ end
240
+
241
+ + def run!(vm_ids = nil)
242
+ + set_runstate :running, vm_ids: vm_ids
243
+ + end
244
+ +
245
+ def delete
246
+ retry_while_resource_busy do
247
+ api_client.delete(url)
248
+ diff -r 586410d23ff4 lib/vagrant-skytap/api/runstate_operations.rb
249
+ --- a/lib/vagrant-skytap/api/runstate_operations.rb Thu Nov 19 21:24:21 2015 -0800
250
+ +++ b/lib/vagrant-skytap/api/runstate_operations.rb Thu Nov 19 21:50:44 2015 -0800
251
+ @@ -20,12 +20,17 @@
252
+ end
253
+
254
+ def poweroff!
255
+ - set_runstate :halted, :stopped
256
+ + set_runstate :halted, completed_runstate: :stopped
257
+ end
258
+
259
+ - def set_runstate(new_runstate, completed_runstate = nil)
260
+ - completed_runstate ||= new_runstate
261
+ - update_with_retry(runstate: new_runstate)
262
+ + def set_runstate(new_runstate, opts = {})
263
+ + completed_runstate = opts.delete(:completed_runstate) || new_runstate
264
+ +
265
+ + params = {runstate: new_runstate}.tap do |ret|
266
+ + ret[:multiselect] = opts[:vm_ids] if opts[:vm_ids]
267
+ + end
268
+ + update_with_retry(params)
269
+ +
270
+ wait_for_runstate(completed_runstate) unless runstate == completed_runstate
271
+ end
272
+
273
+ diff -r 586410d23ff4 lib/vagrant-skytap/command/start_mixins.rb
274
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
275
+ +++ b/lib/vagrant-skytap/command/start_mixins.rb Thu Nov 19 21:50:44 2015 -0800
276
+ @@ -0,0 +1,47 @@
277
+ +module VagrantPlugins
278
+ + module Skytap
279
+ + module Command
280
+ + module StartMixins
281
+ +
282
+ + # Would be nice to just extend this, then alias #build_start_options
283
+ + # and add default options flag.
284
+ + #include VagrantPlugins::CommandUp::StartMixins
285
+ +
286
+ + # This adds the standard `start` command line flags to the given
287
+ + # OptionParser, storing the result in the `options` dictionary.
288
+ + #
289
+ + # @param [OptionParser] parser
290
+ + # @param [Hash] options
291
+ + def build_start_options(parser, options)
292
+ + # Setup the defaults
293
+ + options[:provision_types] = nil
294
+ +
295
+ + # Add the options
296
+ + parser.on("--[no-]provision", "Enable or disable provisioning") do |p|
297
+ + options[:provision_enabled] = p
298
+ + options[:provision_ignore_sentinel] = true
299
+ + end
300
+ +
301
+ + parser.on("--provision-with x,y,z", Array,
302
+ + "Enable only certain provisioners, by type.") do |list|
303
+ + options[:provision_types] = list.map { |type| type.to_sym }
304
+ + options[:provision_enabled] = true
305
+ + options[:provision_ignore_sentinel] = true
306
+ + end
307
+ + end
308
+ +
309
+ + # This validates the provisioner flags and raises an exception
310
+ + # if there are invalid ones.
311
+ + def validate_provisioner_flags!(options)
312
+ + (options[:provision_types] || []).each do |type|
313
+ + klass = Vagrant.plugin("2").manager.provisioners[type]
314
+ + if !klass
315
+ + raise Vagrant::Errors::ProvisionerFlagInvalid,
316
+ + name: type.to_s
317
+ + end
318
+ + end
319
+ + end
320
+ + end
321
+ + end
322
+ + end
323
+ +end
324
+ diff -r 586410d23ff4 lib/vagrant-skytap/command/up.rb
325
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
326
+ +++ b/lib/vagrant-skytap/command/up.rb Thu Nov 19 21:50:44 2015 -0800
327
+ @@ -0,0 +1,138 @@
328
+ +require 'optparse'
329
+ +
330
+ +require "vagrant"
331
+ +require "byebug"
332
+ +
333
+ +require_relative 'start_mixins'
334
+ +
335
+ +# This is a modified copy of the built-in "up" command, which alters how
336
+ +# parallelization is implemented. Instead of making concurrent requests to run
337
+ +# individual VMs, we make a single REST call to update the runstates of
338
+ +# multiple VMs within the containing Skytap environment.
339
+ +
340
+ +module VagrantPlugins
341
+ + module Skytap
342
+ + module Command
343
+ + class Up < Vagrant.plugin("2", :command)
344
+ + include StartMixins
345
+ +
346
+ + def self.synopsis
347
+ + "starts and provisions the vagrant environment"
348
+ + end
349
+ +
350
+ + def execute
351
+ + options = {}
352
+ + options[:destroy_on_error] = true
353
+ + options[:parallel] = true
354
+ + options[:provision_ignore_sentinel] = false
355
+ +
356
+ + opts = OptionParser.new do |o|
357
+ + o.banner = "Usage: vagrant up [options] [name]"
358
+ + o.separator ""
359
+ + o.separator "Options:"
360
+ + o.separator ""
361
+ +
362
+ + build_start_options(o, options)
363
+ +
364
+ + o.on("--[no-]destroy-on-error",
365
+ + "Destroy machine if any fatal error happens (default to true)") do |destroy|
366
+ + options[:destroy_on_error] = destroy
367
+ + end
368
+ +
369
+ + o.on("--[no-]parallel",
370
+ + "Enable or disable parallelism if provider supports it") do |parallel|
371
+ + options[:parallel] = parallel
372
+ + end
373
+ +
374
+ + o.on("--provider PROVIDER", String,
375
+ + "Back the machine with a specific provider") do |provider|
376
+ + options[:provider] = provider
377
+ + end
378
+ + end
379
+ +
380
+ + # Parse the options
381
+ + argv = parse_options(opts)
382
+ + return if !argv
383
+ +
384
+ + # Validate the provisioners
385
+ + validate_provisioner_flags!(options)
386
+ +
387
+ + # Go over each VM and bring it up
388
+ + @logger.debug("'Up' each target VM...")
389
+ +
390
+ + # Create the VMs, then pass all the machines to the run action
391
+ + machines = []
392
+ + names = argv
393
+ + if names.empty?
394
+ + autostart = false
395
+ + @env.vagrantfile.machine_names_and_options.each do |n, o|
396
+ + autostart = true if o.key?(:autostart)
397
+ + o[:autostart] = true if !o.key?(:autostart)
398
+ + names << n.to_s if o[:autostart]
399
+ + end
400
+ +
401
+ + # If we have an autostart key but no names, it means that
402
+ + # all machines are autostart: false and we don't start anything.
403
+ + names = nil if autostart && names.empty?
404
+ + end
405
+ +
406
+ + if names
407
+ + with_target_vms(names, provider: options[:provider]) do |machine|
408
+ + @env.ui.info(I18n.t(
409
+ + "vagrant.commands.up.upping",
410
+ + name: machine.name,
411
+ + provider: machine.provider_name))
412
+ +
413
+ + machines << machine
414
+ + machine.action(:create, options)
415
+ + end
416
+ +
417
+ + # Capture states before the parallel runstate operation.
418
+ + # Checking state is relatively expensive. we should be smarter
419
+ + # about what information to capture. For example, we can
420
+ + # determine which machines were newly created, and put them in
421
+ + # the :stopped collection. Or call them :created? No, that
422
+ + # would likely be confusing
423
+ + #require_boot = machines.select{|m| m.state.id == :stopped}
424
+ + initial_states = machines.inject({}) do |acc, m|
425
+ + acc[m.id] = m.state.id
426
+ + acc
427
+ + end
428
+ +
429
+ + machines.each_with_index do |machine, i|
430
+ + machine.action(:run_vm, options.merge(
431
+ + first_machine: i == 0,
432
+ + machines: machines,
433
+ + #require_boot: require_boot,
434
+ + initial_states: initial_states
435
+ + ))
436
+ + end
437
+ + end
438
+ +
439
+ + if machines.empty?
440
+ + @env.ui.info(I18n.t("vagrant.up_no_machines"))
441
+ + return 0
442
+ + end
443
+ +
444
+ + # Output the post-up messages that we have, if any
445
+ + machines.each do |m|
446
+ + next if !m.config.vm.post_up_message
447
+ + next if m.config.vm.post_up_message == ""
448
+ +
449
+ + # Add a newline to separate things.
450
+ + @env.ui.info("", prefix: false)
451
+ +
452
+ + m.ui.success(I18n.t(
453
+ + "vagrant.post_up_message",
454
+ + name: m.name.to_s,
455
+ + message: m.config.vm.post_up_message))
456
+ + end
457
+ +
458
+ + # Success, exit status 0
459
+ + 0
460
+ + end
461
+ + end
462
+ + end
463
+ + end
464
+ +end
465
+ +
466
+ diff -r 586410d23ff4 lib/vagrant-skytap/plugin.rb
467
+ --- a/lib/vagrant-skytap/plugin.rb Thu Nov 19 21:24:21 2015 -0800
468
+ +++ b/lib/vagrant-skytap/plugin.rb Thu Nov 19 21:50:44 2015 -0800
469
+ @@ -24,7 +24,7 @@
470
+ Config
471
+ end
472
+
473
+ - provider(:skytap, parallel: false) do
474
+ + provider(:skytap, parallel: true) do
475
+ # Setup logging and i18n
476
+ setup_logging
477
+ setup_i18n
478
+ @@ -34,6 +34,11 @@
479
+ Provider
480
+ end
481
+
482
+ + command("up", primary: true) do
483
+ + require_relative "command/up"
484
+ + Command::Up
485
+ + end
486
+ +
487
+ # This initializes the internationalization strings.
488
+ def self.setup_i18n
489
+ I18n.load_path << File.expand_path("locales/en.yml", Skytap.source_root)
490
+ diff -r 586410d23ff4 locales/en.yml
491
+ --- a/locales/en.yml Thu Nov 19 21:24:21 2015 -0800
492
+ +++ b/locales/en.yml Thu Nov 19 21:50:44 2015 -0800
493
+ @@ -3,8 +3,8 @@
494
+ already_status: |-
495
+ The machine is already %{status}.
496
+
497
+ - launching_instance: |-
498
+ - Launching an instance with the following settings...
499
+ + running_environment: |-
500
+ + Starting VMs ...
501
+ launching_vm: |-
502
+ Launching a VM with the following settings...
503
+ not_created: |-
504
+ @@ -53,6 +53,11 @@
505
+ vm_url_required:
506
+ The URL of a Skytap VM must be specified via "vm_url"
507
+
508
+ + commands:
509
+ + up:
510
+ + creating: |-
511
+ + Creating machine '%{name}' with '%{provider}' provider...
512
+ +
513
+ errors:
514
+ instance_ready_timeout: |-
515
+ The instance never became "ready" in Skytap. The timeout currently
516
+ diff -r 586410d23ff4 spec/acceptance/provider/up_spec.rb
517
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
518
+ +++ b/spec/acceptance/provider/up_spec.rb Thu Nov 19 21:50:44 2015 -0800
519
+ @@ -0,0 +1,33 @@
520
+ +# This tests that an instance can be halted correctly
521
+ +shared_examples 'provider/up' do |provider, options|
522
+ + if !options[:box]
523
+ + raise ArgumentError,
524
+ + "box option must be specified for provider: #{provider}"
525
+ + end
526
+ +
527
+ + include_context 'acceptance'
528
+ +
529
+ + before do
530
+ + environment.skeleton('generic')
531
+ + #assert_execute('vagrant', 'box', 'add', 'basic', options[:box])
532
+ + end
533
+ +
534
+ + after do
535
+ + assert_execute('vagrant', 'destroy', '--force')
536
+ + end
537
+ +
538
+ + it 'should bring up the machine and halt it' do
539
+ + status("Test: machine can be brought up")
540
+ + up_result = execute("vagrant", "up")
541
+ + expect(up_result).to exit_with(0)
542
+ +
543
+ + status("Test: machine is running after up")
544
+ + echo_result = execute("vagrant", "ssh", "-c", "echo foo")
545
+ + expect(echo_result).to exit_with(0)
546
+ + expect(echo_result.stdout).to match(/foo\n$/)
547
+ +
548
+ + status("Test: machine can be halted")
549
+ + halt_result = execute("vagrant", "halt")
550
+ + expect(halt_result).to exit_with(0)
551
+ + end
552
+ +end
553
+ diff -r 586410d23ff4 spec/acceptance/skeletons/generic/Vagrantfile
554
+ --- a/spec/acceptance/skeletons/generic/Vagrantfile Thu Nov 19 21:24:21 2015 -0800
555
+ +++ b/spec/acceptance/skeletons/generic/Vagrantfile Thu Nov 19 21:50:44 2015 -0800
556
+ @@ -1,15 +1,14 @@
557
+ Vagrant.configure("2") do |config|
558
+ - config.vm.box = "skytap-dummy"
559
+ + config.vm.box = "skytap/empty"
560
+
561
+ config.vm.provider :skytap do |skytap, override|
562
+ - skytap.username = "user"
563
+ - skytap.api_token = "9999999999999999999999"
564
+ - skytap.base_url = "https://example.com/"
565
+ + skytap.vm_url = "/vms/7285844"
566
+ + skytap.vpn_url = "/vpns/vpn-711360"
567
+ +# skytap.vpn_url = "/vpns/vpn-3195669"
568
+ end
569
+
570
+ config.vm.define "vm1" do |ubuntu|
571
+ - ubuntu.vm.provider :skytap do |box|
572
+ - box.vm_url = "https://example.com/vms/1"
573
+ - end
574
+ + ubuntu.ssh.username = "skytap"
575
+ + ubuntu.ssh.password = "ChangeMe!"
576
+ end
577
+ end