/
index.js
105 lines (96 loc) · 3.96 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
var aws = require("aws-lib"),
_ = require("underscore"),
argv = require('optimist').argv,
fs = require('fs'),
sh = require('sh');
if (!argv.config) {
console.log("Must provide --config argument which points to json settings file, such as --config settings.json");
process.exit(1);
}
var options = {};
try {
var config = JSON.parse(fs.readFileSync(argv.config, 'utf8'));
for (var key in config) {
options[key] = config[key];
}
} catch(e) {
console.warn('Invalid JSON config file: ' + options.config);
throw e;
}
var jobs;
// Allow a single job to be passed in as cli args
var single = {};
if (argv.instanceid) {
var instanceid = argv.instanceid;
single[instanceid] = {};
_.each(argv, function(v, k) {
if (_.indexOf(['devices', 'pool', 'description'], k) > -1) {
single[instanceid][k] = argv[k];
}
});
if (!single[instanceid]['pool'] || !single[instanceid]['devices'] || !single[instanceid]['description']) {
console.log('When running a single job, must provide all of instanceid, pool, devices, and description');
process.exit(1);
}
jobs = single;
} else {
jobs = options.jobs;
}
if (!options.awskey ||
!options.awssecret) {
console.log("Must provide all of awskey, awssecret, pool, description, and volume as --config parameters")
process.exit(1);
}
// version 2010-08-31 supports the 'Filter' parameter.
ec2 = aws.createEC2Client(options.awskey, options.awssecret, {version: '2010-08-31'});
// This does the following:
// - Gets the volume-id based on device + instance-id
// - Creates a snapshot based on that volume-id
// - Deletes the oldest snapshot of the pool size is exceeded
function run(selfInstanceId) {
_.each(jobs, function(job, key) {
var id = key.substring(0,4) == 'self' ? selfInstanceId : key;
var devices = job.devices.split(/\s*,\s*/);
_.each(devices, function(device) {
var params = {};
params['Filter.1.Name'] = 'attachment.device';
params['Filter.1.Value.1'] = device;
params['Filter.2.Name'] = 'attachment.instance-id';
params['Filter.2.Value.1'] = id;
ec2.call('DescribeVolumes', params, function(result) {
var volume = result.volumeSet.item.volumeId;
var description = job.description + ' ' + device + ' ' + id;
ec2.call('CreateSnapshot', {VolumeId: volume, Description: description}, function(result) {
if (!result.Errors) {
var params = {};
params['Owner'] = 'self';
params['Filter.1.Name'] = 'description';
params['Filter.1.Value.1'] = description;
ec2.call("DescribeSnapshots", params, function(result) {
if (!result.Errors) {
if (result.snapshotSet.item) {
var snapshots = result.snapshotSet.item;
if (snapshots.length > job.pool) {
snapshots = _.sortBy(snapshots, function(snapshot) { return new Date(snapshot.startTime).getTime(); });
// Delete oldest snapshot within the pool. Assumes pool is not already exceeded.
ec2.call('DeleteSnapshot', {SnapshotId: snapshots[0].snapshotId}, function(result) {
// Do nothing
});
}
}
}
});
}
});
});
});
});
}
function getInstanceId(cb) {
sh('wget -q -O - http://169.254.169.254/latest/meta-data/instance-id').result(function(id) {
cb(id);
});
}
getInstanceId(function(instanceId) {
run(instanceId);
});