Skip to content

Instantly share code, notes, and snippets.

@oieioi
Last active September 1, 2020 03:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save oieioi/46c46cca4af3823082bbfb43feb04dd3 to your computer and use it in GitHub Desktop.
Save oieioi/46c46cca4af3823082bbfb43feb04dd3 to your computer and use it in GitHub Desktop.
Notify Slack of your daily AWS costs and usage using Lambda
require 'aws-sdk'
require 'net/http'
require 'uri'
require 'json'
# エントリーポイント
# See https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/lambda-ruby.html
def lambda_handler(event:, context:)
fetch_cost
.then { |res| pretty_response(res) }
.then { |message| notify_slack(message) }
{ statusCode: 200, body: 'ok' }
end
# 請求情報の取得
# 請求情報の取得
def fetch_cost(time = Time.now)
client = Aws::CostExplorer::Client.new(region: 'us-east-1')
client.get_cost_and_usage(
time_period: {
start: Date.new(time.year, time.month, 1).strftime('%F'),
end: Date.new(time.year, time.month, -1).strftime('%F'),
},
granularity: 'MONTHLY',
metrics: ['AmortizedCost'],
group_by: [ { type: "DIMENSION",key: 'SERVICE' }]
)
end
# APIの返り値の整形
def pretty_response(res)
total_amount = 0
# 適当
total_unit = nil
service_billings = []
res.
results_by_time[0].
groups.
sort { |a, b| b.metrics['AmortizedCost'].amount.to_f <=> a.metrics['AmortizedCost'].amount.to_f }.
each { |item|
# 小数点2以下は切り上げ
amount = item.metrics['AmortizedCost'].amount.to_f.ceil(2)
next if amount.zero?
unit = item.metrics['AmortizedCost'].unit
service_billings << "#{item.keys[0]}: #{amount} #{unit}"
# 総額計算
total_amount = total_amount + amount
total_unit ||= item.metrics['AmortizedCost'].unit
}
<<~EOS
#{res.results_by_time[0].time_period.start}〜#{res.results_by_time[0].time_period.end}の請求額はおよそ #{total_amount.ceil(2)} #{total_unit} です。
----- 内訳 -----
#{service_billings.join("\n")}
EOS
end
# Slackに投稿
def notify_slack(message)
uri = URI.parse(ENV['SLACK'])
params = { text: message }
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
res = http.start do
request = Net::HTTP::Post.new(uri.path)
request.set_form_data(payload: params.to_json)
http.request(request)
end
unless res.is_a? Net::HTTPSuccess
raise 'Failed POST Slack'
end
res
end
@oieioi
Copy link
Author

oieioi commented Aug 26, 2020

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment