devlopment checkpoint of new features in awsbox 0.2 - to be documented and perhaps rebased shortly

This commit is contained in:
Lloyd Hilaiel 2012-05-31 18:13:34 +03:00
Родитель c26e67caff
Коммит 405619b015
3 изменённых файлов: 144 добавлений и 7 удалений

Просмотреть файл

@ -10,7 +10,8 @@ key = require('./lib/key.js'),
ssh = require('./lib/ssh.js'),
git = require('./lib/git.js'),
optimist = require('optimist'),
urlparse = require('urlparse');
urlparse = require('urlparse'),
fs = require('fs');
var verbs = {};
@ -42,7 +43,7 @@ verbs['destroy'] = function(args) {
}
var name = args[0];
validateName(name);
var hostname = name;
var hostname = name;
process.stdout.write("trying to destroy VM for " + hostname + ": ");
vm.destroy(name, function(err, deets) {
@ -88,6 +89,15 @@ verbs['create'] = function(args) {
var hostname = name;
var longName = process.title + ' deployment (' + name + ')';
console.log("reading .awsbox.json");
try {
var awsboxJson = JSON.parse(fs.readFileSync("./.awsbox.json"));
} catch(e) {
console.log("Fatal error! Can't read awsbox.json: " + e);
process.exit(1);
}
console.log("attempting to set up VM \"" + name + "\"");
vm.startImage({
@ -118,8 +128,15 @@ verbs['create'] = function(args) {
checkErr(err);
}
console.log(" ... and your git remote is all set up");
console.log("");
printInstructions(name, deets);
if (awsboxJson.packages) {
console.log(" ... finally, installing custom packages: " + awsboxJson.packages.join(', '));
console.log("");
}
ssh.installPackages(deets.ipAddress, awsboxJson.packages, function(err, r) {
checkErr(err);
printInstructions(name, deets);
});
});
});
});
@ -127,6 +144,34 @@ verbs['create'] = function(args) {
});
};
verbs['create_ami'] = function(args) {
if (!args || args.length != 1) {
throw 'missing required argument: name of instance';
}
var name = args[0];
validateName(name);
var hostname = name;
console.log("restoring to a pristine state, and creating AMI image from " + name);
vm.describe(name, function(err, deets) {
console.log("instance found, ip " + deets.ipAddress + ", restoring");
checkErr(err);
ssh.makePristine(deets.ipAddress, function(err) {
console.log("instance is pristine, creating AMI");
checkErr(err);
vm.createAMI(name, function(err, imageId) {
checkErr(err);
console.log("Created image:", imageId, "- making it public");
vm.makeAMIPublic(imageId, function(err, imageId) {
console.log("All done!");
checkErr(err);
});
});
});
});
};
verbs['list'] = function(args) {
vm.list(function(err, r) {
checkErr(err);

Просмотреть файл

@ -38,7 +38,28 @@ exports.copySSL = function(host, pub, priv, cb) {
});
};
exports.installPackages = function(host, packages, cb) {
if (!packages || !packages.length) cb();
else {
var pkg = packages.shift();
var cmd = 'ssh -o "StrictHostKeyChecking no" ec2-user@' + host + " sudo yum -y install \'" + pkg + "\'";
child_process.exec(cmd, function(err, r) {
if (err) return cb(err);
var cmd = 'ssh -o "StrictHostKeyChecking no" ec2-user@' + host + " 'echo \"" + pkg + "\" >> packages.txt'";
child_process.exec(cmd, function(err, r) {
if (err) return cb(err);
exports.installPackages(host, packages, cb);
});
});
}
};
exports.addSSHPubKey = function(host, pubkey, cb) {
var cmd = 'ssh -o "StrictHostKeyChecking no" ec2-user@' + host + " 'echo \'" + pubkey + "\' >> .ssh/authorized_keys'";
child_process.exec(cmd, cb);
};
exports.makePristine = function(host, cb) {
var cmd = 'ssh -o "StrictHostKeyChecking no" ec2-user@' + host + " './pristinify.sh'";
child_process.exec(cmd, cb);
};

Просмотреть файл

@ -4,7 +4,7 @@ jsel = require('JSONSelect'),
key = require('./key.js'),
sec = require('./sec.js');
const TEMPLATE_IMAGE_ID = 'ami-6cb56f05';
const TEMPLATE_IMAGE_ID = 'ami-bad574d3';
function extractInstanceDeets(horribleBlob) {
var instance = {};
@ -15,9 +15,9 @@ function extractInstanceDeets(horribleBlob) {
var name = jsel.match('.tagSet :has(.key:val("Name")) > .value', horribleBlob);
if (name.length) {
instance.fullName = name[0];
// if this is a 'browserid deployment', we'll only display the hostname chosen by the
// if this is a 'awsbox deployment', we'll only display the hostname chosen by the
// user
var m = /^browserid deployment \((.*)\)$/.exec(instance.fullName);
var m = /^awsbox deployment \((.*)\)$/.exec(instance.fullName);
instance.name = m ? m[1] : instance.fullName;
} else {
instance.name = instance.instanceId;
@ -25,6 +25,16 @@ function extractInstanceDeets(horribleBlob) {
return instance;
}
exports.describe = function(name, cb) {
exports.list(function(err, r) {
if (err) return cb('failed to list vms: ' + err);
deets = findInstance(r, name);
if (!deets) return cb('no such vm');
cb(null, deets);
});
};
exports.list = function(cb) {
aws.call('DescribeInstances', {}, function(result) {
var instances = {};
@ -73,6 +83,67 @@ exports.destroy = function(name, cb) {
});
};
function dateBasedVersion() {
var d = new Date();
function pad(n){return n<10 ? '0'+n : n}
return d.getUTCFullYear()+'.'
+ pad(d.getUTCMonth()+1)+'.'
+ pad(d.getUTCDate())+'-'
+ pad(d.getUTCHours())+'.'
+ pad(d.getUTCMinutes());
}
exports.createAMI = function(name, cb) {
exports.list(function(err, r) {
if (err) return cb('failed to list vms: ' + err);
deets = findInstance(r, name);
if (!deets) return cb('no such vm');
aws.call('CreateImage', {
InstanceId: deets.instanceId,
Name: "awsbox deployment image v" + dateBasedVersion(),
Description: "An image for use with awsbox.org, a DIY PaaS for noders"
}, function(result) {
try { return cb(result.Errors.Error.Message); } catch(e) {};
result = jsel.match('.imageId', result)[0];
cb(null, result);
});
});
};
exports.makeAMIPublic = function(imageId, cb) {
var startTime = new Date();
function attempt() {
aws.call('ModifyImageAttribute', {
ImageId: imageId,
'LaunchPermission.Add.1.Group': 'all'
}, function(result) {
try {
if (result.Errors.Error.Message) {
if (result.Errors.Error.Message.indexOf('currently pending') !== -1) {
throw "pending"
}
return cb(result.Errors.Error.Message);
}
cb(null);
} catch(e) {};
if (new Date() - startTime > 120 * 1000) {
return cb("timed out waiting for instance to become public");
}
setTimeout(function() { attempt(); }, 2000);
});
}
attempt();
};
function returnSingleImageInfo(result, cb) {
if (!result) return cb('no results from ec2 api');
try { return cb(result.Errors.Error.Message); } catch(e) {};