masson
Version:
Module execution engine for cluster deployments.
77 lines (69 loc) • 2.6 kB
text/coffeescript
util = require 'util'
connect = require 'ssh2-connect'
each = require 'each'
###
Note: we should use `echo password | sudo -S su -` as a more resilient approach.
###
module.exports = (ctx, callback) ->
{username, password, cmd, public_key} = ctx.config.bootstrap
public_key = public_key.join '\n'
ctx.log "SSH login to #{username}@#{ctx.config.host}"
connect ctx.config.bootstrap, (err, c) ->
return callback err if err
c.shell (err, stream) ->
return callback err if err
steps = []
if username isnt 'root' then steps.push
cmd: "#{cmd}\n"
callback: (data, callback) ->
if /mot de passe/.test(data.toLowerCase()) or /password/.test(data.toLowerCase())
stream.write password
stream.write '\n'
callback()
if /^\[root[\@]/.test data
callback()
steps.push
cmd: "sed -i.back 's/.*PermitRootLogin.*/PermitRootLogin yes/' /etc/ssh/sshd_config\n"
callback: (data, callback) ->
callback() if /\[.+@.+ .+\]/.test data
steps.push
# There is a bug in CentOS 6 / SELinux that results in all client presented certificates to be ignored when SELinux is set to Enforcing.
cmd: "sed -i.back 's/^SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config\n"
callback: (data, callback) ->
callback() if /\[.+@.+ .+\]/.test data
steps.push
cmd: "mkdir -p ~/.ssh; chmod 700 ~/.ssh\n"
callback: (data, callback) ->
callback() if /\[.+@.+ .+\]/.test data
steps.push
cmd: "echo '#{public_key}' >> ~/.ssh/authorized_keys\n"
callback: (data, callback) ->
callback() if /\[.+@.+ .+\]/.test data
steps.push
cmd: 'reboot\n'
callback: (data, callback) ->
callback() if /going down/.test data # or /reboot/.test data
# Callback spaghetti
current_callback = current_next = null
stream.on 'data', (data) ->
return unless current_callback
ctx.log data.toString().split('\n').map((line) -> "<< #{line}").join('\n')
current_callback data.toString(), ->
current_next()
process.stdin.resume()
each(steps)
.parallel(1)
.on 'item', (step, next) ->
current_callback = step.callback
current_next = next
ctx.log ">> #{step.cmd}"
stream.write step.cmd
.on 'both', (err) ->
process.stdin.pause()
setTimeout ->
c.end()
, 3000
c.on 'error', (err) ->
callback err
c.on 'end', ->
callback err