概要
- CloudWatchのapiのListMetricsで課金情報が取得できるAWSのサービス一覧を取得して、それを元にapiのGetMetricStatisticsを呼ぶことで各AWSのサービス毎の料金を取得できる
- AWSの管理画面から請求アラートを受け取るを有効にしておく必要がある
- Promiseを使ってるため、nodejsのバージョンは6.10を選択する
許可が必要なIAMポリシー
{
"Version": "2012-10-17",
"Statement": [
{
"Action": ["cloudwatch:ListMetrics", "cloudwatch:GetMetricStatistics"],
"Effect": "Allow",
"Resource": "*"
}
]
}
ソースコード
- 環境編SLACK_API_TOKENとPOST_CHANNELは任意の値を設定する
package.json
{
"name": "estimated-charges",
"version": "1.0.0",
"main": "index.js"
"license": "MIT",
"dependencies": {
"@slack/client": "^3.10.0",
"aws-sdk": "^2.85.0",
"moment": "^2.18.1"
}
}
index.js
'use strict';
const WebClient = require('@slack/client').WebClient
const AWS = require('aws-sdk')
const moment = require('moment')
const cloudwatch = new AWS.CloudWatch({
region: 'us-east-1',
endpoint: 'http://monitoring.us-east-1.amazonaws.com'
})
const listMetrics = () => {
return new Promise((resolve, reject) => {
cloudwatch.listMetrics({ MetricName: 'EstimatedCharges' }, (error, data) => {
if (error) {
reject(error)
} else {
resolve(data)
}
})
})
}
const getMetricStatistics = (serviceName, startTime, endTime) => {
const dimensions = [
{ Name: 'Currency', Value: 'USD' }
]
if (serviceName) {
dimensions.push({ Name: 'ServiceName', Value: serviceName })
}
return new Promise((resolve, reject) => {
const params = {
MetricName: 'EstimatedCharges',
Namespace: 'AWS/Billing',
Period: 86400,
StartTime: startTime,
EndTime: endTime,
Statistics: ['Maximum'],
Dimensions: dimensions
}
cloudwatch.getMetricStatistics(params, (error, data) => {
if (error) {
reject(error)
} else {
resolve({ name: serviceName, data: data })
}
})
})
}
exports.handler = (event, context, callback) => {
listMetrics().then(data => {
const now = moment().toISOString()
const yesterday = moment(now).subtract(1, 'd').toISOString()
const promises = data['Metrics'].map(metric => {
return metric['Dimensions'][0]
}).filter(dimension => {
return dimension['Name'] == 'ServiceName'
}).map(dimension => {
return dimension['Value']
}).filter((serviceName, index, self) => {
return self.indexOf(serviceName) === index
}).map(serviceName => {
return getMetricStatistics(serviceName, yesterday, now)
})
promises.unshift(getMetricStatistics(null, yesterday, now))
Promise.all(promises).then(data => {
const results = data.filter(result => {
const datapoints = result.data['Datapoints']
return (datapoints.length != 0 && datapoints[0]['Maximum'] != 0)
})
if (results.length == 0) {
return
}
const fields = results.filter(result => {
return result.name != null
}).sort((result1, result2) => {
const charge1 = result1.data['Datapoints'][0]['Maximum']
const charge2 = result2.data['Datapoints'][0]['Maximum']
return (charge2 - charge1)
}).map(result => {
const datapoint = result.data['Datapoints'][0]
return { title: result.name, value: `$${datapoint['Maximum']}`, short: true }
})
const datapoint = results[0].data['Datapoints'][0]
const client = new WebClient(process.env.SLACK_API_TOKEN)
client.chat.postMessage(process.env.POST_CHANNEL, `AWS料金 $${datapoint['Maximum']}`, { attachments: [{ color: 'good', fields: fields }] }, (error, response) => {
if (error) { console.error(error) }
})
}, reason => {
console.error(reason)
})
}, reason => {
console.error(reason)
})
}