diff --git a/scripts/deploy_dev.js b/scripts/deploy_dev.js deleted file mode 100755 index 21c2308170cc8ca5a2ab8a2de76e4653575bdcc6..0000000000000000000000000000000000000000 --- a/scripts/deploy_dev.js +++ /dev/null @@ -1,132 +0,0 @@ -#!/usr/bin/env node - -/* - * Deploy dev.diresworb.org, for fun and profit. - */ - -const -aws = require('./deploy/aws.js'); -path = require('path'); -vm = require('./deploy/vm.js'), -key = require('./deploy/key.js'), -ssh = require('./deploy/ssh.js'), -git = require('./deploy/git.js'), -dns = require('./deploy/dns.js'), -util = require('util'), -events = require('events'), -fs = require('fs'); - -// verify we have files we need - -// a class capable of deploying and emmitting events along the way -function DevDeployer() { - events.EventEmitter.call(this); - - this.sslpub = process.env['DEV_SSL_PUB']; - this.sslpriv = process.env['DEV_SSL_PRIV']; - this.keypairs = []; - if (process.env['ADDITIONAL_KEYPAIRS']) { - this.keypairs = process.env['ADDITIONAL_KEYPAIRS'].split(','); - } - - if (!this.sslpub || !this.sslpriv) { - throw("you must provide ssl cert paths via DEV_SSL_PUB & DEV_SSL_PRIV"); - } - - if (!fs.statSync(this.sslpub).isFile() || !fs.statSync(this.sslpriv).isFile()) { - throw("DEV_SSL_PUB & DEV_SSL_PRIV must be paths to actual files. duh"); - } -} - -util.inherits(DevDeployer, events.EventEmitter); - -DevDeployer.prototype.setup = function(cb) { - var self = this; - git.currentSHA(function(err, r) { - if (err) return cb(err); - self.sha = r; - vm.startImage(function(err, r) { - if (err) return cb(err); - self.emit('progress', "starting new image"); - vm.waitForInstance(r.instanceId, function(err, d) { - if (err) return cb(err); - self.deets = d; - self.emit('progress', "image started"); - vm.setName(r.instanceId, "dev.diresworb.org (" + self.sha + ")", function(err, r) { - if (err) return cb(err); - self.emit('progress', "name set"); - cb(null); - }); - }); - }); - }); -} - -DevDeployer.prototype.configure = function(cb) { - var self = this; - var config = { public_url: "https://dev.diresworb.org" }; - ssh.copyUpConfig(self.deets.ipAddress, config, function (err) { - if (err) return cb(err); - ssh.copySSL(self.deets.ipAddress, self.sslpub, self.sslpriv, function(err) { - if (err) return cb(err); - - // now copy up addtional keypairs - var i = 0; - function copyNext() { - if (i == self.keypairs.length) return cb(null); - ssh.addSSHPubKey(self.deets.ipAddress, self.keypairs[i++], function(err) { - if (err) return cb(err); - self.emit('progress', "key added..."); - copyNext(); - }); - } - copyNext(); - }); - }); -} - -DevDeployer.prototype.pushCode = function(cb) { - var self = this; - git.push(this.deets.ipAddress, function(d) { self.emit('build_output', d); }, cb); -} - -DevDeployer.prototype.updateDNS = function(cb) { - var self = this; - dns.deleteRecord('dev.diresworb.org', function() { - dns.updateRecord('', 'dev.diresworb.org', self.deets.ipAddress, cb); - }); -} - -var deployer = new DevDeployer(); - -deployer.on('progress', function(d) { - console.log("PR: " + d); -}); - -deployer.on('build_output', function(d) { - console.log("BO: " + d); -}); - -function checkerr(err) { - if (err) { - process.stderr.write("fatal error: " + err + "\n"); - process.exit(1); - } -} - -var startTime = new Date(); -deployer.setup(function(err) { - checkerr(err); - deployer.configure(function(err) { - checkerr(err); - deployer.updateDNS(function(err) { - checkerr(err); - deployer.pushCode(function(err) { - checkerr(err); - console.log("dev.diresworb.org (" + deployer.sha + ") deployed to " + - deployer.deets.ipAddress + " in " + - ((new Date() - startTime) / 1000.0).toFixed(2) + "s"); - }); - }); - }); -}); diff --git a/scripts/deploy_server.js b/scripts/deploy_server.js deleted file mode 100755 index f38338ee1bba2f6338472d75c2dd3a3385df2a97..0000000000000000000000000000000000000000 --- a/scripts/deploy_server.js +++ /dev/null @@ -1,293 +0,0 @@ -#!/usr/bin/env node - -const -temp = require('temp'), -path = require('path'), -util = require('util'), -events = require('events'), -git = require('./deploy/git.js'), -https = require('https'), -vm = require('./deploy/vm.js'), -jsel = require('JSONSelect'), -fs = require('fs'), -express = require('express'), -irc = require('irc'); - -console.log("deploy server starting up"); - -// a class capable of deploying and emmitting events along the way -function Deployer() { - events.EventEmitter.call(this); - - // a directory where we'll keep code - this._codeDir = process.env['CODE_DIR'] || temp.mkdirSync(); - console.log("code dir is:", this._codeDir); - var self = this; - - git.init(this._codeDir, function(err) { - if (err) { - console.log("can't init code dir:", err); - process.exit(1); - } - self.emit('ready'); - }); -} - -util.inherits(Deployer, events.EventEmitter); - -Deployer.prototype._getLatestRunningSHA = function(cb) { - var self = this; - - // failure is not fatal. maybe nothing is running? - var fail = function(err) { - self.emit('info', { msg: "can't get current running sha", reason: err }); - cb(null, null); - } - - https.get({ host: 'dev.diresworb.org', path: '/ver.txt' }, function(res) { - var buf = ""; - res.on('data', function (c) { buf += c }); - res.on('end', function() { - try { - var sha = buf.split(' ')[0]; - if (sha.length == 7) { - self.emit('info', 'latest running is ' + sha); - return cb(null, sha); - } - fail('malformed ver.txt: ' + buf); - } catch(e) { - fail(e); - } - }); - }).on('error', function(err) { - fail(err); - }); - -} - -Deployer.prototype._cleanUpOldVMs = function() { - var self = this; - // what's our sha - git.currentSHA(self._codeDir, function(err, latest) { - if (err) return self.emit('info', err); - vm.list(function(err, r) { - if (err) return self.emit('info', err); - // only check the vms that have 'dev.diresworb.org' as a name - jsel.forEach("object:has(:root > .name:contains(?))", [ "dev.diresworb.org" ], r, function(o) { - // don't delete the current one - if (o.name.indexOf(latest) == -1) { - self.emit('info', 'decommissioning VM: ' + o.name + ' - ' + o.instanceId); - vm.destroy(o.name, function(err, r) { - if (err) self.emit('info', 'decomissioning failed: ' + err); - else self.emit('info', 'decomissioning succeeded of ' + r); - }) - } - }); - }); - }); -} - -Deployer.prototype._deployNewCode = function(cb) { - var self = this; - - function splitAndEmit(chunk) { - if (chunk) chunk = chunk.toString(); - if (typeof chunk === 'string') { - chunk.split('\n').forEach(function (line) { - line = line.trim(); - if (line.length) self.emit('progress', line); - }); - } - } - - var npmInstall = spawn('npm', [ 'install' ], { cwd: self._codeDir }); - - npmInstall.stdout.on('data', splitAndEmit); - npmInstall.stderr.on('data', splitAndEmit); - - npmInstall.on('exit', function(code, signal) { - if (code != 0) { - self.emit('error', "can't npm install to prepare to run deploy_dev"); - return; - } - var p = spawn('scripts/deploy_dev.js', [], { cwd: self._codeDir }); - - p.stdout.on('data', splitAndEmit); - p.stderr.on('data', splitAndEmit); - - p.on('exit', function(code, signal) { - return cb(code != 0); - }); - }); -}; - -Deployer.prototype._pullLatest = function(cb) { - var self = this; - git.pull(this._codeDir, 'git://github.com/mozilla/browserid', 'dev', function(l) { - self.emit('progress', l); - }, function(err) { - if (err) return cb(err); - git.currentSHA(self._codeDir, function(err, latest) { - if (err) return cb(err); - self.emit('info', 'latest available sha is ' + latest); - self._getLatestRunningSHA(function(err, running) { - if (latest != running) { - self.emit('deployment_begins', { - sha: latest, - }); - var startTime = new Date(); - - self._deployNewCode(function(err, res) { - if (err) return cb(err); - // deployment is complete! - self.emit('deployment_complete', { - sha: latest, - time: (new Date() - startTime) - }); - // finally, let's clean up old servers - self._cleanUpOldVMs(); - cb(null, null); - }); - } else { - self.emit('info', 'up to date'); - cb(null, null); - } - }); - }); - }); -} - -// may be invoked any time we suspect updates have occured to re-deploy -// if needed -Deployer.prototype.checkForUpdates = function() { - var self = this; - - if (this._busy) return; - - this._busy = true; - self.emit('info', 'checking for updates'); - - self._pullLatest(function(err, sha) { - if (err) self.emit('error', err); - self._busy = false; - }); -} - -var deployer = new Deployer(); - -var currentLogFile = null; -// a directory where we'll keep deployment logs -var deployLogDir = process.env['DEPLOY_LOG_DIR'] || temp.mkdirSync(); - -var deployingSHA = null; - -console.log("deployment log dir is:", deployLogDir); - -[ 'info', 'ready', 'error', 'deployment_begins', 'deployment_complete', 'progress' ].forEach(function(evName) { - deployer.on(evName, function(data) { - if (typeof data != 'string') data = JSON.stringify(data, null, 2); - var msg = evName + ": " + data; - console.log(msg) - if (currentLogFile) currentLogFile.write(msg + "\n"); - }); -}); - -// irc integration! -var ircClient = null; -const ircChannel = '#identity'; -function ircSend(msg) { - if (!ircClient) { - ircClient = new irc.Client('irc.mozilla.org', 'browserid_deployer', { - channels: [ircChannel] - }); - ircClient.on('error', function(e) { - console.log('irc error: ', e); - }); - ircClient.once('join' + ircChannel, function(e) { - ircClient.say(ircChannel, msg); - }); - } else { - ircClient.say(ircChannel, msg); - } -} - -function ircDisconnect() { - setTimeout(function() { - if (ircClient) { - ircClient.disconnect(); - ircClient = null; - } - }, 1000); -} - - -// now when deployment begins, we log all events -deployer.on('deployment_begins', function(r) { - currentLogFile = fs.createWriteStream(path.join(deployLogDir, r.sha + ".txt")); - currentLogFile.write("deployment of " + r.sha + " begins\n"); - deployingSHA = r.sha; - ircSend("deploying " + r.sha + " - status https://deployer.hacksign.in/" + r.sha + ".txt"); -}); - -function closeLogFile() { - if (currentLogFile) { - currentLogFile.end(); - currentLogFile = null; - } -} - -deployer.on('deployment_complete', function(r) { - ircSend("deployment of " + deployingSHA + " completed successfully in " + - (r.time / 1000.0).toFixed(2) + "s"); - ircDisconnect(); - - closeLogFile(); - deployingSHA = null; - - // always check to see if we should try another deployment after one succeeds to handle rapid fire - // commits - deployer.checkForUpdates(); -}); - -deployer.on('error', function(r) { - ircSend("deployment of " + deployingSHA + " failed. check logs for deets"); - ircDisconnect(); - - closeLogFile(); - deployingSHA = null; - - // on error, try again in 2 minutes - setTimeout(function () { - deployer.checkForUpdates(); - }, 2 * 60 * 1000); -}); - - -// we check every 3 minutes no mattah what. (checks are cheap, github webhooks are flakey) -setInterval(function () { - deployer.checkForUpdates(); -}, (1000 * 60 * 3)); - -// check for updates at startup -deployer.on('ready', function() { - deployer.checkForUpdates(); - - var app = express.createServer(); - - app.get('/check', function(req, res) { - deployer.checkForUpdates(); - res.send('ok'); - }); - - app.get('/', function(req, res) { - var what = "idle"; - if (deployingSHA) what = "deploying " + deployingSHA; - res.send(what); - }); - - app.use(express.static(deployLogDir)); - - app.listen(process.env['PORT'] || 8080, function() { - console.log("deploy server bound"); - }); -});