Skip to content

Instantly share code, notes, and snippets.

@junkangli
Created December 5, 2018 08:37
Show Gist options
  • Save junkangli/fff222fba6110214e08d1649817b822a to your computer and use it in GitHub Desktop.
Save junkangli/fff222fba6110214e08d1649817b822a to your computer and use it in GitHub Desktop.
This is an AWS Lambda function that gets the various AWS costs for the previous month and publishes the result to a SNS topic. It is meant to be triggered on a monthly schedule by a CloudWatch event rule.
const AWS = require('aws-sdk');
const snsTopicArn = process.env.SNSTopicArn;
const idepAccountNumbers = process.env.IDEPAWSAccountNumbers.split(',').map(item => item.trim());
const ninetyninesmeAccountNumbers = process.env.Project99SMEAWSAccountNumbers.split(',').map(item => item.trim());
AWS.config.update({ region: 'us-east-1' });
const costexplorer = new AWS.CostExplorer();
const getTotal = (params) => {
return costexplorer.getCostAndUsage(params).promise();
};
const getIDEPTotal = (params) => {
params.Filter = {
And: [{
Dimensions: {
Key: 'LINKED_ACCOUNT',
Values: idepAccountNumbers
}
}, {
Dimensions: {
Key: 'RECORD_TYPE',
Values: ['Usage']
}
}]
};
return costexplorer.getCostAndUsage(params).promise();
};
const get99SMETotal = (params) => {
params.Filter = {
And: [{
Dimensions: {
Key: 'LINKED_ACCOUNT',
Values: ninetyninesmeAccountNumbers
}
}, {
Dimensions: {
Key: 'RECORD_TYPE',
Values: ['Usage']
}
}]
};
return costexplorer.getCostAndUsage(params).promise();
};
const getMarketplaceCost = (params) => {
params.Filter = {
Dimensions: {
Key: 'BILLING_ENTITY',
Values: ['AWS Marketplace']
}
};
return costexplorer.getCostAndUsage(params).promise();
};
const getServiceCost = (params) => {
params.Filter = {
Not: {
Dimensions: {
Key: 'BILLING_ENTITY',
Values: ['AWS Marketplace']
}
}
};
return costexplorer.getCostAndUsage(params).promise();
};
const getRefund = (params) => {
params.Filter = {
Dimensions: {
Key: 'RECORD_TYPE',
Values: ['Refund']
}
};
return costexplorer.getCostAndUsage(params).promise();
};
const getSupportCost = (refund) => {
refund.amount = -1 * refund.amount;
return refund;
};
const parseResponse = (data) => {
console.log(JSON.stringify(data));
let amount = parseFloat(data["ResultsByTime"][0]["Total"]["UnblendedCost"]["Amount"]);
let unit = data["ResultsByTime"][0]["Total"]["UnblendedCost"]["Unit"];
let estimated = data["ResultsByTime"][0]["Estimated"];
return {
unit: unit,
amount: amount.toFixed(2),
estimated: estimated
};
};
const formatItemCost = (label, cost) => {
return label + ': ' + cost.unit + ' ' + cost.amount + (cost.estimated ? '*' : '') + '\n';
};
exports.handler = (event, context, callback) => {
const now = new Date();
let startDate = new Date(now.getFullYear(), now.getMonth() - 1, 1);
let endDate = new Date(now.getFullYear(), now.getMonth(), 1);
let start = startDate.toISOString().slice(0, 10);
let end = endDate.toISOString().slice(0, 10);
var params = {
Granularity: "MONTHLY",
Metrics: ["UnblendedCost"],
TimePeriod: {
Start: start,
End: end
}
};
let getMarketplaceCostPromise = getMarketplaceCost(params);
let getServiceCostPromise = getServiceCost(params);
let getRefundPromise = getRefund(params);
let getIDEPTotalPromise = getIDEPTotal(params);
let get99SMETotalPromise = get99SMETotal(params);
let eventText = 'Month of ' + startDate.toLocaleString('en-us', {month: "long"}) + '\n';
Promise.all([getMarketplaceCostPromise, getServiceCostPromise, getRefundPromise, getIDEPTotalPromise, get99SMETotalPromise])
.then(function (data) {
let marketplaceCost = parseResponse(data[0]);
let serviceCost = parseResponse(data[1]);
let refund = parseResponse(data[2]);
let idepCost = parseResponse(data[3]);
let proj99smeCost = parseResponse(data[4]);
eventText += formatItemCost('AWS Marketplace', marketplaceCost);
eventText += formatItemCost('AWS Services', serviceCost);
eventText += formatItemCost('AWS Support (derived from refunds)', getSupportCost(refund));
eventText += formatItemCost('IDEP Sub-total', idepCost);
eventText += formatItemCost('99%SME Sub-total', proj99smeCost);
if (marketplaceCost.estimated || serviceCost.estimated || refund.estimated || idepCost.estimated || proj99smeCost.estimated) {
eventText += '*Values are estimated.';
}
console.log(eventText);
AWS.config.update({ region: 'ap-southeast-1' });
var snsParams = {
Message: eventText,
Subject: "Monthly AWS Costs",
TopicArn: snsTopicArn
};
var publishPromise = new AWS.SNS().publish(snsParams).promise();
publishPromise.then(
function(snsResponse) {
console.log(`Message sent to topic ${snsParams.TopicArn}`);
console.log("MessageID is " + snsResponse.MessageId);
}).catch(
function(err) {
console.error(err, err.stack);
}
);
callback(null, data);
});
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment