-
Notifications
You must be signed in to change notification settings - Fork 9
/
cli.js
executable file
·116 lines (106 loc) · 3.57 KB
/
cli.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
106
107
108
109
110
111
112
113
114
115
116
#!/usr/bin/env node
var _ = require('lodash');
var AWS = require('aws-sdk');
var chalk = require('chalk');
var moment = require('moment');
var program = require('commander');
var ec2Type = false;
var awsRegions = {};
var zones = {};
var lowPrice = false;
var lowZone = false;
program
.version('0.3.0')
.usage('[options] <EC2 instance types ...>')
.option('-r, --region <AWS region>', 'Limit to the given region')
.action(function(type) {
ec2Type = type;
})
.parse(process.argv);
console.log('Checking spot prices for ' + ec2Type + ' instance type.');
function getRegions() {
return new Promise(function(resolve, reject) {
var ec2 = new AWS.EC2({apiVersion: '2016-04-01', region: 'us-west-2'});
ec2.describeRegions({}, function(err, data) {
if (err) {
console.log(err, err.stack);
return reject(err);
}
var promises = [];
if (data && data.Regions) {
_.each(data.Regions, function(region) {
if (region.RegionName && !awsRegions.hasOwnProperty(region.RegionName)) {
awsRegions[region.RegionName] = {};
promises.push(getRegionSpots(region.RegionName));
}
})
}
return Promise.all(promises).then(resolve);
});
});
}
function getRegionSpots(regionName) {
return new Promise(function(resolve, reject) {
var ec2 = new AWS.EC2({apiVersion: '2016-04-01', region: regionName});
var params = {
InstanceTypes: [ec2Type],
ProductDescriptions: ['Linux/UNIX', 'Linux/UNIX (Amazon VPC)'],
StartTime: moment().subtract(4, 'hours').utc().toDate()
};
ec2.describeSpotPriceHistory(params, function(err, data) {
if (err) {
console.log(err, err.stack);
return reject(err);
}
if (data && data.SpotPriceHistory) {
_.each(data.SpotPriceHistory, function(sdata) {
if (sdata.SpotPrice && sdata.Timestamp && sdata.AvailabilityZone) {
var sdate = moment(sdata.Timestamp);
if (!zones.hasOwnProperty(sdata.AvailabilityZone) || zones[sdata.AvailabilityZone].lastDate < sdate) {
zones[sdata.AvailabilityZone] = {
lastDate: sdate,
lastPrice: sdata.SpotPrice,
zone: sdata.AvailabilityZone
};
if (!lowPrice || Number(sdata.SpotPrice) < lowPrice) {
lowPrice = Number(sdata.SpotPrice);
lowZone = sdata.AvailabilityZone;
}
}
}
});
}
resolve();
});
});
}
function handleResults() {
console.log('\n' + _.padEnd('AWS Zone', 24) + ' ' + _.padEnd('Hourly Rate', 12));
console.log(_.pad('', 24, '-') + ' ' + _.pad('', 12, '-'));
var sortedZones = _.values(zones);
sortedZones = _.sortBy(sortedZones, function(val) { return Number(val.lastPrice); }, 'zone');
_.each(sortedZones, function(data) {
var msg = _.padEnd(data.zone, 24) + ' ' + _.padEnd('$' + data.lastPrice, 12);
if (data.zone === lowZone || data.lastPrice === lowPrice) {
msg = chalk.green(msg);
} else if (lowPrice * 1.1 >= data.lastPrice) {
msg = chalk.yellow(msg);
}
console.log(msg);
});
console.log(chalk.green('\nCheapest hourly rate for ' + ec2Type + ' is $' + lowPrice + ' in zone ' + lowZone));
}
if (program.region) {
console.log('Limiting results to region ' + program.region);
getRegionSpots(program.region)
.then(handleResults)
.catch(function(err) {
console.log('error', err);
});
} else {
getRegions(program.region)
.then(handleResults)
.catch(function(err) {
console.log('error', err);
});
}