lib/vagrant-orchestrate/command/push.rb in vagrant-orchestrate-0.4.0 vs lib/vagrant-orchestrate/command/push.rb in vagrant-orchestrate-0.4.1
- old
+ new
@@ -1,8 +1,9 @@
require "optparse"
require "vagrant"
+# Borrowed from http://stackoverflow.com/questions/12374645/splitting-an-array-into-equal-parts-in-ruby
class Array
def in_groups(num_groups)
return [] if num_groups == 0
slice_size = (size / Float(num_groups)).ceil
each_slice(slice_size).to_a
@@ -37,11 +38,10 @@
o.on("-f", "--force", "Suppress prompting in between groups") do
options[:force] = true
end
end
- # Parse the options
argv = parse_options(opts)
return unless argv
machines = []
with_target_vms(argv) do |machine|
@@ -52,20 +52,21 @@
end
end
if machines.empty?
@env.ui.info("No servers with :managed provider found. Skipping.")
- return
+ return 0
end
- # This environment variable is used as a signal to the filtermanaged
- # action so that we don't filter managed commands that are really just
- # the implementation of a push action.
-
options[:parallel] = true
strategy = options[:strategy] || @env.vagrantfile.config.orchestrate.strategy
@env.ui.info("Pushing to managed servers using #{strategy} strategy.")
+
+ # Handle a couple of them more tricky edges.
+ strategy = :serial if machines.size == 1
+ strategy = :blue_green if strategy.to_sym == :canary_blue_green && machines.size == 2
+
case strategy.to_sym
when :serial
options[:parallel] = false
result = deploy(options, machines)
when :parallel
@@ -73,31 +74,42 @@
when :canary
# A single canary server and then the rest
result = deploy(options, machines.take(1), machines.drop(1))
when :blue_green
# Split into two (almost) equal groups
- groups = machines.in_groups(2)
+ groups = split(machines)
result = deploy(options, groups.first, groups.last)
when :canary_blue_green
# A single canary and then two equal groups
canary = machines.take(1)
- groups = machines.drop(1).in_groups(2)
+ groups = split(machines.drop(1))
result = deploy(options, canary, groups.first, groups.last)
else
@env.ui.error("Invalid deployment strategy specified")
result = false
end
return 1 unless result
0
end
- # rubocop:enable Metrics/AbcSize, MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
+ def split(machines)
+ groups = machines.in_groups(2)
+ # Move an item from the first to second group if they are unbalanced so that
+ # the smaller group is pushed to first.
+ groups.last.unshift(groups.first.pop) if groups.any? && groups.first.size > groups.last.size
+ groups
+ end
+
def deploy(options, *groups)
+ groups.select! { |g| g.size > 0 }
groups.each_with_index do |machines, index|
- @logger.debug("Orchestrating push to group number #{index + 1} of #{groups.size}.")
- @logger.debug(" -- Hosts: #{machines.collect { |m| m.name.to_s }.join(',')}")
+ next if machines.empty?
+ if groups.size > 1
+ @env.ui.info("Orchestrating push to group number #{index + 1} of #{groups.size}.")
+ @env.ui.info(" -- Hosts: #{machines.collect { |m| m.name.to_s }.join(',')}")
+ end
ENV["VAGRANT_ORCHESTRATE_COMMAND"] = "PUSH"
begin
batchify(machines, :up, options)
batchify(machines, :provision, options)
batchify(machines, :reload, options) if options[:reboot]
@@ -106,19 +118,22 @@
ensure
ENV.delete "VAGRANT_ORCHESTRATE_COMMAND"
end
# Don't prompt on the last group, that would be annoying
- unless index == groups.size - 1 || options[:force]
+ if index == groups.size - 1 || options[:force]
+ @logger.debug("Suppressing prompt because --force specified.") if options[:force]
+ else
return false unless prompt_for_continue
end
end
end
+ # rubocop:enable Metrics/AbcSize, MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
def prompt_for_continue
result = @env.ui.ask("Deployment paused for manual review. Would you like to continue? (y/n)")
if result.upcase != "Y"
- @env.ui.info("Deployment push action by user")
+ @env.ui.info("Deployment push action cancelled by user")
return false
end
true
end