Skip to content
This repository has been archived by the owner on Oct 5, 2023. It is now read-only.

Adding support for AWS Organizations, billing month, pre-tax billing and aws-sdk. #2

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
5 changes: 5 additions & 0 deletions History.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
1.0.1 - November 8, 2018
-------------------------
- remove obsolete knox package in favour of aws-sdk
- add ability to query a specific month of data
- add support for AWS Organizations

1.0.0 - January 7, 2015
-------------------------
Expand Down
42 changes: 41 additions & 1 deletion Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,46 @@ billing(function (err, costs) {
});
```

You may optionally specify a month to query, using the format 'YYYY-MM', like so:

```js
var month = '2017-10';

var billing = require('aws-billing')(accountId, key, secret, bucket, region, month);

billing(function (err, costs) {
// ..
```

If no month is provided, the month you are in becomes the default.

You may also optionally query an AWS Organizations "linked account", like so:

```js
var month = '2017-10';
var linkedAccountId = '9999-8888-7777';

var billing = require('aws-billing')(accountId, key, secret, bucket, region, month, linkedAccountId);

billing(function (err, costs) {
// ..
});
```

And / or you can request the totals before any sales taxes are added, like so:

```js
var month = '2017-10'; // we are querying October 2017
var linkedAccountId = null; // we have no linked account
var withoutTaxes = true; // but we want pre-sales-tax totals

var billing = require('aws-billing')(accountId, key, secret, bucket, region, month, linkedAccountId, withoutTaxes);

billing(function (err, costs) {
// ..
});
```

The `costs` variable shows the costs for the current billing period by product.

```js
Expand All @@ -49,4 +89,4 @@ The `costs` variable shows the costs for the current billing period by product.

## License

MIT
MIT
67 changes: 52 additions & 15 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
var bind = require('bind');
var csv = require('csv');
var debug = require('debug')('aws-billing');
var Ec2 = require('awssum-amazon-ec2').Ec2;
var knox = require('knox');
var AWS = require('aws-sdk')
var Dates = require('date-math');

/**
Expand All @@ -21,18 +20,24 @@ module.exports = AWSBilling;
* @param {String} secret
* @param {String} bucket
* @param {String} region
* @param {String} month
* @param {String} linkedAccountId
* @param {Boolean} withoutTaxes
*/

function AWSBilling (accountId, key, secret, bucket, region) {
if (!(this instanceof AWSBilling)) return new AWSBilling(accountId, key, secret, bucket, region);
function AWSBilling (accountId, key, secret, bucket, region, month=null, linkedAccountId=null, withoutTaxes=false) {
if (!(this instanceof AWSBilling)) return new AWSBilling(accountId, key, secret, bucket, region, month, linkedAccountId, withoutTaxes);
if (!accountId) throw new Error('AWS Billing requires a accountId.');
if (!key) throw new Error('AWS Billing requires a key.');
if (!secret) throw new Error('AWS Billing requires a secret.');
if (!bucket) throw new Error('AWS Billing requires a bucket.');
if (!region) throw new Error('AWS Billing requires a region.');
this.accountId = accountId;
this.knox = knox.createClient({ key: key, secret: secret, bucket: bucket });
this.ec2 = new Ec2({ accessKeyId: key, secretAccessKey: secret, region: region });
this.bucket = bucket;
this.month = month;
this.linkedAccountId = linkedAccountId;
this.withoutTaxes = withoutTaxes;
this.AWS = new AWS.S3({ accessKeyId: key, secretAccessKey: secret, region: region });
var self = this;
bind.all(this);
return function () { return self.get.apply(self, arguments); };
Expand Down Expand Up @@ -69,26 +74,58 @@ AWSBilling.prototype.get = function (callback) {
AWSBilling.prototype.products = function (callback) {
var accountId = this.accountId.replace(/-/g, '');
var now = new Date();
var file = accountId + '-aws-billing-csv-' +
now.getFullYear() + '-' + pad(now.getMonth() + 1, 2) + '.csv';
var withoutTaxes = this.withoutTaxes;
if (this.month) {
debug('month provided %s ..', this.month);
var file = accountId + '-aws-billing-csv-' +
this.month + '.csv';
}
else {
debug('no month provided ..');
var file = accountId + '-aws-billing-csv-' +
now.getFullYear() + '-' + pad(now.getMonth() + 1, 2) + '.csv';
}
debug('file to open is %s ..', file);
if (this.linkedAccountId) {
var linkedAccountId = this.linkedAccountId.replace(/-/g, '');
debug('linked account ID %s provided', linkedAccountId);
}
debug('getting S3 file %s ..', file);
this.knox.getFile(file, function (err, stream) {
this.AWS.getObject({ Bucket: this.bucket, Key: file }, function (err, res) {
if (err) return callback(err);
debug('got S3 stream ..');
csv()
.from.stream(stream)
.from.string(res.Body)
.to.array(function (data) {
var products = {};
var productCol = data[0].indexOf('ProductCode') + 1;
var costCol = data[0].indexOf('TotalCost');
if (withoutTaxes == true) {
var costCol = data[0].indexOf('CostBeforeTax');
debug('costCol is set to CostBeforeTax');
}
else {
var costCol = data[0].indexOf('TotalCost');
debug('costCol is set to TotalCost');
}
data.forEach(function (row) {
var product = row[productCol].toLowerCase()
.replace(/amazon /, '')
.replace(/aws /, '');
var cost = parseFloat(row[costCol]);
if (product && cost > 0) {
if (!products[product]) products[product] = 0;
products[product] += cost;
if (linkedAccountId) {
var linkedAccountCol = data[0].indexOf('LinkedAccountId');
if (row[linkedAccountCol] == linkedAccountId) {
if (product && cost > 0) {
if (!products[product]) products[product] = 0;
products[product] += cost;
}
}
}
else {
if (product && cost > 0) {
if (!products[product]) products[product] = 0;
products[product] += cost;
}
}
});
debug('parsed AWS product costs');
Expand All @@ -112,4 +149,4 @@ function pad(n, width, z) {
z = z || '0';
n = n + '';
return n.length >= width ? n : new Array(width - n.length + 1).join(z) + n;
}
}
9 changes: 3 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "aws-billing",
"version": "1.0.0",
"version": "1.0.1",
"repository": "git://github.com/segmentio/aws-billing.git",
"license": "MIT",
"description": "AWS billing API for node",
Expand All @@ -12,14 +12,11 @@
"API"
],
"dependencies": {
"awssum": "~1.2.0",
"awssum-amazon": "~1.3.0",
"awssum-amazon-ec2": "~1.4.0",
"aws-sdk": "latest",
"bind": "git://github.com/ianstormtaylor/bind",
"csv": "~0.3.7",
"date-math": "0.0.1",
"debug": "~0.7.4",
"knox": "~0.8.9"
"debug": "~0.7.4"
},
"devDependencies": {
"mocha": "~1.17.1"
Expand Down