UNPKG

masson

Version:

Module execution engine for cluster deployments.

143 lines (127 loc) 6.06 kB
--- title: Connection module: masson/bootstrap/connection layout: module --- # Bootstrap Connection Prepare the system to receive password-less root login and initialize an SSH connection. Additionnally, it disable SELINUX which require a restart. The restart is handle by Masson and the installation procedure will continue as soon as an SSH connection is again available. fs = require 'fs' {exec} = require 'child_process' misc = require 'mecano/lib/misc' connect = require 'ssh2-connect' collect = require './lib/collect' bootstrap = require './lib/bootstrap' module.exports = [] module.exports.push 'masson/bootstrap/log' ## Configuration The goal of the bootstrap configuration is to provide a way to gain superuser access to the remote server. There are a few ways to achieve it. You should declare a "bootstrap.public_key" property. If it matches you're local private key found at "~/.ssh/id_rsa", if it is deployed on the remote server for the root user (commonly found inside the "/root/.ssh/authorized_keys" file) and if the remote server is ready to accept root SSH connections (the "PermitRootLogin" property inside the "/etc/ssh/sshd_config" configuration file), then there nothing else to configuration. Otherwise, the server will be prepared to do so. You must declare a super user with sudo permissions using the "username" and "password" properties. The script will use those credentials to loggin and will try to become root with the "su -" command. Use the "cmd" property if you must use a different command (such as "sudo su -"). Options include: * `cmd` (string) Command used to become the root user on the remote server, default to "su -". * `public_key` (array|string) List of public keys to be written on the remote root "authorized_keys" file. * `password` (string) Password of the user with super user permissions, required if current user running masson doesnt yet have remote access as root. * `username` (string) Username of the user with super user permissions, required if current user running masson doesnt yet have remote access as root. Example: ```json { "bootstrap": { "username": "vagrant", "password": "vagrant", "cmd": "sudo su -", "public_key": "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAuYziVgwFAXvExxIj5HgAywFeSfu9zxoLc5bCdeJhS/gh4EtpMN0McHd21M4btuopMAL/sctT4+SiBqwOIERw0rGWrat4WE2qBReEc+6hvdoiUx+7WglDCYePbV91N+x421UYzHhNPUg62jXIfg+o5zG/tdEDbpBAq2EX3vRsncenlhB+p/LsSkY+2+tBJLW172BN1ncKjImFglMwW+7OxGP2U9LoMMFyUs1zS65p8WgHHi/+6ZNsP0wIhKPPl8BiFJ6dLiNjlRuXLX9fGcQDJGrlYbad5Thb5wpQe1EZCF9qBloUkdj7aTIu+dainTP/I87Eo2Y47KsSydvopjqceQ== david@adaltas.com" } } ``` module.exports.push (ctx) -> ctx.config.bootstrap ?= {} ctx.config.bootstrap.host ?= if ctx.config.ip then ctx.config.ip else ctx.config.host ctx.config.bootstrap.port ?= ctx.config.port or 22 ctx.config.bootstrap.public_key ?= [] ctx.config.bootstrap.public_key = [ctx.config.bootstrap.public_key] if typeof ctx.config.bootstrap.public_key is 'string' ctx.config.bootstrap.cmd ?= 'su -' ## Connection Masson need to connect over ssh as root and, for this, it can prepare its own private key by declaring the "bootstrap.private_key" option. However, it is important in such circumstances that we guarantee no existing key would be overwritten. module.exports.push name: 'Bootstrap # Connection', required: true, timeout: -1, callback: (ctx, next) -> {private_key} = ctx.config.bootstrap close = -> ctx.ssh?.end() ctx.run.on 'error', close ctx.run.on 'end', close attempts = 0 has_rebooted = false modified = false do_private_key = -> return do_ssh() unless private_key ctx.log "Place SSH private key inside \"~/.ssh\"" # Handle tilde misc.path.normalize '~/.ssh/id_rsa', (id_rsa) -> fs.readFile id_rsa, 'ascii', (err, content) -> return next Error err if err and err.code isnt 'ENOENT' return next Error "Could not overwritte existing key" if not err and content.trim() isnt private_key.trim() return do_ssh() if content is private_key exec """ mkdir -p ~/.ssh chmod 700 ~/.ssh echo '#{private_key}' > ~/.ssh/id_rsa chmod 600 ~/.ssh/id_rsa """, (err, stdout, stderr) -> return next err if err do_ssh() do_ssh = -> attempts++ ctx.log "SSH login #{attempts} to root@#{ctx.config.host}" config = misc.merge {}, ctx.config.bootstrap, host: ctx.config.ip or ctx.config.host private_key: null # make sure "bootstap.private_key" isnt used by ssh2 username: 'root' password: null readyTimeout: 120 * 1000 # default to 10s, now 2mn connect config, (err, connection) -> # First attempt failed, we go collecting bootstrap information on err return do_collect() if err and attempts is 1 # Once we are sure the server went for reboot, we wait for a new connection if has_rebooted and err and (['ETIMEDOUT', 'ECONNREFUSED', 'EHOSTUNREACH'].indexOf(err.code) isnt -1) ctx.log 'Wait for reboot' return setTimeout do_ssh, 10 # We detect a reboot if attempts isnt 1 and not has_rebooted has_rebooted = true if err return setTimeout do_ssh, 10 return next err if err ctx.log "SSH connected" ctx.ssh = connection next null, if modified then ctx.OK else ctx.PASS do_collect = -> modified = true ctx.log 'Collect login information' collect ctx.config.bootstrap, (err) -> return next err if err do_boot() do_boot = -> ctx.log 'Deploy ssh key' bootstrap ctx, (err) -> return next err if err ctx.log 'Reboot and login' do_ssh() do_private_key()