class Cult::Commander
Attributes
node[R]
project[R]
Public Class Methods
new(project:, node:)
click to toggle source
# File lib/cult/commander.rb, line 12 def initialize(project:, node:) @project = project @node = node end
Public Instance Methods
bootstrap!()
click to toggle source
# File lib/cult/commander.rb, line 128 def bootstrap! bootstrap_role = CLI.fetch_item('bootstrap', from: Role) install!(bootstrap_role) end
connect(user: nil) { |ssh)| ... }
click to toggle source
# File lib/cult/commander.rb, line 141 def connect(user: nil, &block) 5.times do |attempt| begin user ||= node.user puts "Connecting with user=#{user}, host=#{node.host}, " + "key=#{node.ssh_private_key_file}" Net::SSH.start(node.host, user, port: node.ssh_port, user_known_hosts_file: node.ssh_known_hosts_file, timeout: 5, auth_methods: ['publickey'], keys_only: true, keys: [node.ssh_private_key_file]) do |ssh| return (yield ssh) end rescue Errno::ECONNREFUSED, Net::SSH::ConnectionTimeout puts "Connection refused. Retrying" sleep attempt * 3 end end end
create_build_tar(role)
click to toggle source
# File lib/cult/commander.rb, line 31 def create_build_tar(role) io = StringIO.new Bundle.new(io) do |bundle| puts "Building bundle..." role.build_order.each do |r| (r.artifacts + r.build_tasks).each do |transferable| bundle.add_file(project, r, node, transferable) end end end io.rewind io end
create_sync_tar(pass:, roles: nil)
click to toggle source
# File lib/cult/commander.rb, line 102 def create_sync_tar(pass:, roles: nil) io = StringIO.new Bundle.new(io) do |bundle| find_sync_tasks(pass: pass, roles: roles).each do |task| bundle.add_file(project, task.role, node, task) end end io.rewind io end
esc(s)
click to toggle source
# File lib/cult/commander.rb, line 17 def esc(s) Shellwords.escape(s) end
exec_remote!(ssh:, role:, task:)
click to toggle source
# File lib/cult/commander.rb, line 47 def exec_remote!(ssh:, role:, task:) token = SecureRandom.hex task_bin = role.relative_path(task.path) puts "Executing: #{task.remote_path} on #{node.name}" res = ssh.exec! <<~BASH cd #{esc(role.remote_path)}; \ ./#{esc(task_bin)} && \ echo #{esc(token)} BASH if res.chomp.end_with?(token) res = res.gsub(token, '') puts Rainbow(res.gsub(/^/, ' ')).darkgray.italic true else puts Rainbow(res).red puts "Failed" false end end
find_sync_tasks(pass:, roles: nil)
click to toggle source
# File lib/cult/commander.rb, line 85 def find_sync_tasks(pass:, roles: nil) selected_roles = node.build_order if roles selected_roles.select! { |r| roles.include?(r) } end r = [] selected_roles.each do |role| r += role.event_tasks.select do |t| t.event == :sync && t.pass == pass end end r end
install!(role)
click to toggle source
# File lib/cult/commander.rb, line 70 def install!(role) connect(user: role.user) do |ssh| io = create_build_tar(role) send_tar(io, ssh) role.build_order.each do |r| puts "Installing role: #{Rainbow(r.name).blue}" r.build_tasks.each do |task| exec_remote!(ssh: ssh, role: r, task: task) end end end end
ping()
click to toggle source
# File lib/cult/commander.rb, line 133 def ping connect do |ssh| ssh.exec!("uptime").chomp end rescue nil end
send_tar(io, ssh)
click to toggle source
# File lib/cult/commander.rb, line 22 def send_tar(io, ssh) filename = SecureRandom.hex + ".tar" puts "Uploading bundle: #{filename}" scp = Net::SCP.new(ssh) scp.upload!(io, filename) ssh.exec! "tar -xf #{esc(filename)} && rm #{esc(filename)}" end
sync!(pass:, roles: nil)
click to toggle source
# File lib/cult/commander.rb, line 115 def sync!(pass:, roles: nil) io = create_sync_tar(pass: pass, roles: roles) return if io.eof? connect do |ssh| send_tar(io, ssh) find_sync_tasks(pass: pass, roles: roles).each do |task| exec_remote!(ssh: ssh, role: task.role, task: task) end end end