Module: SSHKitDslRoles

Defined in:
lib/dash/sshkit_with_ext.rb

Instance Method Summary collapse

Instance Method Details

#on_roles(roles, hosts:, parallel: true, rolling: false, &block) ⇒ Object

Execute on hosts grouped by role.

Unlike on() which deduplicates hosts, this allows the same host to have multiple concurrent connections when it appears in multiple roles.

Options:

hosts: The hosts to run on (required)
parallel: When true, each role runs in its own thread with separate
        connections. When false, hosts run in parallel but roles on each
        host run sequentially (default: true)
rolling:  When true, each role's own `boot` config paces its hosts through
        the SSHKit runner, so one role can boot serially while its
        siblings still boot in parallel. Only for commands that start
        containers — it would needlessly serialize read-only commands.
        Requires parallel: there is no per-role runner otherwise.

Example:

on_roles(roles) do |host, role|
# deploy role to host
end


305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
# File 'lib/dash/sshkit_with_ext.rb', line 305

def on_roles(roles, hosts:, parallel: true, rolling: false, &block)
  if parallel
    threads = roles.filter_map do |role|
      if (role_hosts = role.hosts & hosts).any?
        Thread.new do
          on(role_hosts, rolling ? role.boot_runner_options(role_hosts) : {}) { |host| instance_exec(host, role, &block) }
        rescue StandardError => e
          raise SSHKit::Runner::ExecuteError.new(e), "Exception while executing on #{role}: #{e.message}"
        end
      end
    end

    exceptions = []
    threads.each do |t|
      begin
        t.join
      rescue SSHKit::Runner::ExecuteError => e
        exceptions << e
      end
    end

    if exceptions.one?
      raise exceptions.first
    elsif exceptions.many?
      raise exceptions.first, [ "Exceptions on #{exceptions.count} roles:", exceptions.map(&:message) ].join("\n")
    end
  else
    # Host-first iteration: hosts run in parallel, roles on each host run sequentially
    on(hosts) do |host|
      roles.each do |role|
        instance_exec(host, role, &block) if role.hosts.include?(host.to_s)
      end
    end
  end
end