Class: VagrantPlugins::Orchestrate::Command::Push

Inherits:
Object
  • Object
show all
Includes:
Vagrant::Util, CommandMixins
Defined in:
lib/vagrant-orchestrate/command/push.rb

Instance Method Summary collapse

Methods included from CommandMixins

#filter_unmanaged, #super_delete

Instance Method Details

#batchify(machines, action, options) ⇒ Object



172
173
174
175
176
177
178
179
180
181
# File 'lib/vagrant-orchestrate/command/push.rb', line 172

def batchify(machines, action, options)
  @env.batch(options[:parallel]) do |batch|
    machines.each do |machine|
      # This is necessary to disable the low level provisioning in the
      # Vagrant builtin provisioner.
      options[:provision_enabled] = false unless options[:provision]
      batch.action(machine, action, options)
    end
  end
end

#deploy(options, *groups) ⇒ Object

rubocop:disable MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity



135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/vagrant-orchestrate/command/push.rb', line 135

def deploy(options, *groups)
  groups.select! { |g| g.size > 0 }
  groups.each_with_index do |machines, index|
    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, :push, options)
    ensure
      @logger.debug("Finished orchestrating push to group number #{index + 1} of #{groups.size}.")
      status_source = options[:status].local_path
      super_delete(status_source) if File.exist?(status_source)
      ENV.delete "VAGRANT_ORCHESTRATE_COMMAND"
    end

    # Don't prompt on the last group, that would be annoying
    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

#executeObject

rubocop:disable MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/vagrant-orchestrate/command/push.rb', line 30

def execute
  options = {}
  options[:force] = @env.vagrantfile.config.orchestrate.force_push
  options[:provision] = true

  opts = OptionParser.new do |o|
    o.banner = "Usage: vagrant orchestrate push"
    o.separator ""

    o.on("--[no-]provision", "Enable or disable provisioning. Default is true") do |p|
      options[:provision] = p
    end

    o.on("--reboot", "Reboot a managed server after the provisioning step") do
      options[:reboot] = true
    end

    o.on("--strategy strategy", "The orchestration strategy to use. Default is serial") do |v|
      options[:strategy] = v
    end

    o.on("-f", "--force", "Suppress prompting in between groups") do
      options[:force] = true
    end
  end

  argv = parse_options(opts)
  return unless argv

  guard_clean

  machines = filter_unmanaged(argv)
  return 0 if machines.empty?

  @start_time = Time.now

  retrieve_creds(machines) if @env.vagrantfile.config.orchestrate.credentials

  # Write the status file to disk so that it can be used as part of the
  # push action.
  status = RepoStatus.new(@env.root_path)
  status.write(@env.tmp_path)
  options[:status] = status

  @env.action_runner.run(VagrantPlugins::ManagedServers::Action::InitDeploymentTracker,
                         tracker_host: @env.vagrantfile.config.orchestrate.tracker_host,
                         tracker_logging_enabled: @env.vagrantfile.config.orchestrate.tracker_logging_enabled,
                         ui: @env.ui)
  @env.action_runner.run(VagrantPlugins::ManagedServers::Action::TrackDeploymentStart,
                         tracker_host: @env.vagrantfile.config.orchestrate.tracker_host,
                         status: status,
                         args: ARGV.drop(2).join(" "))

  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 = :half_half if strategy.to_sym == :canary_half_half && machines.size == 2

  begin
    case strategy.to_sym
    when :serial
      options[:parallel] = false
      result = deploy(options, machines)
    when :parallel
      result = deploy(options, machines)
    when :canary
      # A single canary server and then the rest
      result = deploy(options, machines.take(1), machines.drop(1))
    when :half_half
      # Split into two (almost) equal groups
      groups = split(machines)
      result = deploy(options, groups.first, groups.last)
    when :canary_half_half
      # A single canary and then two equal groups
      canary = machines.take(1)
      groups = split(machines.drop(1))
      result = deploy(options, canary, groups.first, groups.last)
    else
      @env.ui.error("Invalid deployment strategy specified")
      result = false
    end
  ensure
    @env.action_runner.run(VagrantPlugins::ManagedServers::Action::TrackDeploymentEnd,
                           tracker_host: @env.vagrantfile.config.orchestrate.tracker_host,
                           start_time: @start_time,
                           success: result)
  end

  return 1 unless result
  0
end

#guard_cleanObject



197
198
199
200
201
202
# File 'lib/vagrant-orchestrate/command/push.rb', line 197

def guard_clean
  return if ENV["VAGRANT_ORCHESTRATE_NO_GUARD_CLEAN"] || \
            @env.vagrantfile.config.orchestrate.disable_commit_guard
  message = "ERROR!\nThere are files that need to be committed first."
  RepoStatus.clean? && RepoStatus.committed? && !RepoStatus.untracked? || abort(message)
end

#prompt_for_continueObject

rubocop:enable MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity



163
164
165
166
167
168
169
170
# File 'lib/vagrant-orchestrate/command/push.rb', line 163

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 cancelled by user")
    return false
  end
  true
end

#retrieve_creds(machines) ⇒ Object



183
184
185
186
187
188
189
190
191
192
193
194
195
# File 'lib/vagrant-orchestrate/command/push.rb', line 183

def retrieve_creds(machines)
  creds = VagrantPlugins::Orchestrate::Action::SetCredentials.new
  (username, password) = creds.retrieve_creds(@env.vagrantfile.config.orchestrate.credentials, @env.ui)

  # Apply the credentials to the machine info, or back out if we were unable to procure them.
  if username && password
    machines.each do |machine|
      creds.apply_creds(machine, username, password)
    end
  else
    @env.ui.warn "Vagrant-orchestrate did find any credentials. Continuing with default credentials."
  end
end

#split(machines) ⇒ Object

rubocop:enable MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity



126
127
128
129
130
131
132
# File 'lib/vagrant-orchestrate/command/push.rb', line 126

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