概要
AWS CostExplorer を利用してアカウント毎の当月の累計請求情報と日別請求情報を取得する Pythonプログラムを作成してみました。親組織の下に複数の子組織がぶら下がっており、そのすべてのアカウントの請求情報を取得しています。表示は請求金額の多いアカウントから降順にソートしています。
実行環境
macOS Monterey 12.3.1
python 3.8.12
実行プログラム
CostExplorer_Account_All.py
from datetime import datetime, timedelta, date
import boto3
import pandas as pd
from pandas_datareader.data import get_quote_yahoo
# 実行月の初日を取得
def get_begin_of_month() -> str:
return date.today().replace(day=1).isoformat()
# 実行日を取得
def get_today() -> str:
return date.today().isoformat()
# 請求金額取得対象期間の取得
def get_total_cost_date_range() -> (str, str):
start_date = get_begin_of_month()
end_date = get_today()
# get_cost_and_usage()のstartとendに同じ日付は指定不可のため、
# 「今日が1日」なら、「先月1日から今月1日(今日)」までの範囲にする
if start_date == end_date:
end_of_month = datetime.strptime(start_date, '%Y-%m-%d') + timedelta(days=-1)
begin_of_month = end_of_month.replace(day=1)
return begin_of_month.date().isoformat(), end_date
return start_date, end_date
# 請求金額データの取得
def get_billing_data(parent_acct):
# データ取得期間の取得
(start, end) = get_total_cost_date_range()
# CostExplorerへのセッションオープン
session = boto3.session.Session(profile_name=parent_acct)
client = session.client('ce')
# 請求データ(アカウント毎の日々の請求データ)の取得
response = client.get_cost_and_usage(
TimePeriod={
'Start': start,
'End' : end,
},
Granularity='DAILY',
Metrics=[
'NetUnblendedCost'
],
GroupBy=[
{
'Type': 'DIMENSION',
'Key': 'LINKED_ACCOUNT'
}
]
)
# pprint.pprint(response)
return response
# 組織の全アカウント情報の取得:辞書型
def get_organization_accounts(master_acct):
# 親組織へ接続する
session = boto3.session.Session(profile_name=master_acct)
organizations = session.client('organizations')
# 全組織のアカウント情報を取得する
pagenator = organizations.get_paginator('list_accounts')
response_iterator = pagenator.paginate()
# アカウント情報用リストの定義
row_id = []
row_name = []
# 各アカウントの Account ID と Account Name の取得
for response in response_iterator:
for acct in response['Accounts']:
# 取得するアカウント情報のリスト化
row_id.append(acct['Id'])
row_name.append(acct['Name'])
# 取得した全アカウント情報を辞書型へ
accounts = pd.DataFrame({"Id":row_id, "Name":row_name})
return accounts
# 組織の全Accountの請求金額データの集計
def get_account_all_billings(master_acct, crate):
# 組織の全アカウント情報の取得
accounts = get_organization_accounts(master_acct)
# print(accounts, "\n")
# 請求金額データの取得
response = get_billing_data(master_acct)
# 整形する請求データの入れ物
merged_cost = pd.DataFrame(
columns=['Id']
)
# 請求データの整形
for item in response['ResultsByTime']:
# ['Groups']のデータ取得(アカウント毎の請求データ)
normalized_json = pd.json_normalize(item['Groups'])
# アカウントIDの取得
split_keys = pd.DataFrame(
normalized_json['Keys'].tolist(),
columns=['Id']
)
# アカウントID毎の請求金額の取得
cost = pd.concat(
[split_keys, normalized_json['Metrics.NetUnblendedCost.Amount']],
axis=1
)
# 請求金額データのカラムタイプの変更 object -> float
cost['Metrics.NetUnblendedCost.Amount'] = cost['Metrics.NetUnblendedCost.Amount'].astype('float')
# 請求金額を日本円に換算
cost['Metrics.NetUnblendedCost.Amount'] = round(cost['Metrics.NetUnblendedCost.Amount']*crate, 2)
# ['TimePeriod']['Start']のデータ取得(請求日データ)
renamed_cost = cost.rename(
columns={'Metrics.NetUnblendedCost.Amount': item['TimePeriod']['Start']}
)
# アカウント毎に請求データと請求日のマージ(右側への列追加)
merged_cost = pd.merge(merged_cost, renamed_cost, on='Id', how='right')
# アカウントIDをキーにしてアカウント名を列結合
merged_cost = pd.merge(merged_cost, accounts, on="Id", how="left")
# アカウント名の列を先頭列に作成
merged_cost.insert(loc=0, column='AccountName', value=merged_cost['Name'])
# 不要カラムの削除
merged_cost.drop(['Id', 'Name'], axis=1, inplace=True)
# 各行の合計を最後の列に追加
merged_cost['Total'] = round(merged_cost.sum(numeric_only=True, axis=1), 2)
# ['Total']列からか請求金額の総合計を求める
grand_total = round(merged_cost['Total'].sum(), 2)
# 合計で降順ソートし、インデックスとしてアカウント名を指定する
merged_cost.sort_values(by='Total',ascending=False, inplace=True)
merged_cost.set_index("AccountName", inplace=True)
# print(merged_cost, "\n")
return merged_cost, grand_total
# 請求金額データの通知表示への変更
def post_billings(cost_df, grand_total, crate):
# タイトルメッセージの表示
post_msg = "総合計 : " + str(grand_total) + "\t\tUSD-JPY : " + str(crate)
print("\n", post_msg, "\n")
# 行と列の入替え
cost_df = cost_df.transpose()
# Total行(最後の行)の取得
df_total = cost_df.tail(1)
df_total = df_total.transpose()
# 通知データの表示
print(df_total, "\n")
print(cost_df, "\n")
# print(df_total.to_markdown(), "\n")
# print(cost_df.to_markdown(), "\n")
# 現在の USD - JPY の為替レートの取得
def get_currency_rate() :
res1 = get_quote_yahoo('USDJPY=X')
res2 = res1["price"].values
crate = res2[0]
return crate
# メイン
if __name__ == '__main__':
# 今の為替レートを取得する
crate = get_currency_rate()
# 組織の全Accountの請求金額データの日別集計
merged_cost, grand_total = get_account_all_billings('aws-master', crate)
# 請求金額データの通知表示への変更
post_billings(merged_cost, grand_total, crate)
プログラムの実行
## 取得した請求情報
$ python CostExplorer_Account_All.py
総合計 : 343731.76 USD-JPY : 138.466
Total
AccountName
tech-west01 60901.42
tech-sss0 45757.98
tech-nnn 45605.74
tech-aaa 39343.08
tech-sss1 37918.29
tech-sss2 37123.14
tech-msc 33269.26
tech-ppp2 15901.64
tech-ppp1 9992.31
tech-ccc 8767.92
tech-iiii 3844.35
aws-master 2714.93
tech-west02 2591.41
tech-west03 0.29
AccountName tech-west01 tech-sss0 tech-nnn tech-aaa tech-sss1 tech-sss2 tech-msc tech-ppp2 tech-ppp1 tech-ccc tech-iiii aws-master tech-west02 tech-west03
2022-08-01 7593.18 6052.79 4932.19 4879.19 4654.60 4324.92 3002.95 5973.81 1351.75 1074.39 523.46 326.44 317.31 0.01
2022-08-02 2057.32 1504.15 1109.00 1236.32 1206.34 971.21 874.90 339.63 478.58 278.21 34.67 78.37 81.92 0.01
2022-08-03 2057.31 1533.33 1124.64 1233.67 1208.55 970.13 479.49 339.64 197.96 278.24 34.66 78.60 81.92 0.01
2022-08-04 2057.31 1497.49 966.46 1233.01 1209.94 1040.24 479.44 340.45 198.02 278.20 34.66 76.85 81.92 0.01
2022-08-05 1910.21 1471.02 606.73 1233.64 1209.91 1007.24 535.00 339.64 379.39 278.22 34.67 76.74 81.92 0.01
2022-08-06 1900.15 1117.67 606.72 1236.91 1210.63 1023.21 479.43 339.64 197.95 278.21 34.66 76.56 81.92 0.01
2022-08-07 1900.15 1108.01 1096.33 1238.06 1210.65 1206.18 479.43 339.63 197.99 278.20 36.11 76.86 81.92 0.01
2022-08-08 1900.15 1509.14 1644.58 1235.06 1210.61 1238.48 479.51 339.63 242.53 278.22 67.09 77.65 81.92 0.01
2022-08-09 1900.15 1362.44 1207.37 1238.57 1210.61 1395.15 480.46 339.65 197.95 278.22 197.87 78.13 81.92 0.01
2022-08-10 1900.16 1534.39 1728.75 1240.72 1210.62 1329.57 479.47 339.78 198.00 278.21 175.28 77.71 81.92 0.01
2022-08-11 1900.19 1157.14 1762.85 1236.29 1210.71 1030.80 479.53 339.64 198.04 278.21 35.13 78.44 81.92 0.01
2022-08-12 1900.15 1142.52 1832.74 1235.03 1210.60 1061.85 479.54 339.64 198.08 278.21 35.14 77.23 81.92 0.01
2022-08-13 1890.46 1137.89 1779.75 1237.30 1210.62 1289.60 479.42 339.64 198.13 278.22 90.34 78.06 81.92 0.01
2022-08-14 1900.15 1137.89 1749.45 1231.07 1210.63 1386.38 479.55 339.64 198.18 278.21 221.71 77.86 81.92 0.01
2022-08-15 1900.15 1137.88 1769.66 1232.67 1210.64 1324.38 479.57 339.63 198.22 278.21 51.77 77.65 81.92 0.01
2022-08-16 1900.15 1139.29 1780.08 1232.36 1210.64 1029.58 479.52 339.63 198.27 278.22 51.83 78.04 81.93 0.01
2022-08-17 1900.15 1464.42 1780.93 1237.39 1210.60 1103.22 479.58 354.43 387.35 278.21 107.98 78.46 81.92 0.01
2022-08-18 1900.15 1356.63 1937.99 1229.80 1216.85 1316.66 667.99 357.37 305.02 278.21 173.08 78.30 81.92 0.01
2022-08-19 1890.46 1146.20 1815.77 1229.56 1231.82 1383.88 479.97 357.38 154.55 278.21 173.08 78.19 81.92 0.01
2022-08-20 1900.21 1137.89 1783.08 1242.34 1210.62 1374.06 479.42 393.39 154.60 278.20 189.27 79.25 81.92 0.01
2022-08-21 1900.15 1140.11 1746.58 1250.46 1210.60 1026.26 479.47 380.98 154.65 278.21 197.57 78.94 81.92 0.01
2022-08-22 1900.15 2029.57 1736.61 1251.68 1210.60 1096.59 479.50 378.18 154.70 278.22 173.08 92.26 81.92 0.01
2022-08-23 1900.15 1715.23 1487.77 1248.20 1210.62 1278.06 479.47 399.01 883.99 278.22 175.76 110.99 81.92 0.01
2022-08-24 1900.15 2244.65 1335.71 1251.72 1210.61 1364.39 571.73 422.49 2179.95 278.22 173.07 105.10 81.92 0.01
2022-08-25 1890.45 1787.77 1366.54 1245.16 1200.92 1321.06 15451.43 364.34 269.73 278.22 173.07 170.70 81.92 0.01
2022-08-26 1900.16 2258.65 1357.86 1253.39 1210.64 1026.41 1098.25 357.37 154.59 278.23 173.07 79.50 81.92 0.01
2022-08-27 1900.15 1152.57 1390.85 1257.33 1210.60 1136.54 924.22 357.43 154.62 278.22 173.08 80.94 81.92 0.01
2022-08-28 1900.15 1139.32 1460.57 1252.34 1210.64 1241.27 487.31 441.84 154.67 278.23 171.13 137.46 81.92 0.01
2022-08-29 1551.60 1641.93 708.18 983.84 566.87 825.82 543.71 268.11 54.85 181.72 132.06 53.65 62.25 0.01
Total 60901.42 45757.98 45605.74 39343.08 37918.29 37123.14 33269.26 15901.64 9992.31 8767.92 3844.35 2714.93 2591.41 0.29
まとめ
この Pythonプログラムを利用することにより、検証環境のAWSの請求金額の日々の推移を管理し、少しでも利用料抑制に役立てればと考えています。この日々の推移を Microsoft Teams に通知するプログラムを追加実装する予定です。
参考記事
以下の記事を参考にさせていただきました。感謝申し上げます。
Cost Explorer API でアカウント毎に日別の請求額を取得する
pandas結合