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


374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
# File 'lib/dash/sshkit_with_ext.rb', line 374

def on_roles(roles, hosts:, parallel: true, rolling: false, &block)
  if parallel
    # See CompleteAll#execute: thread-locals do not cross Thread.new.
    timing_entry = DashTimings.current_entry

    threads = roles.filter_map do |role|
      if (role_hosts = role.hosts & hosts).any?
        Thread.new do
          DashTimings.current_entry = timing_entry
          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