Python で Azure の リソースグループ単位で日々の使用料金を取得し、ローカルファイルに保存してみました


## 概要
Azure SDK for Python を利用して、テナントに紐付いているサブスクリプション毎にリソースグループ単位での日々の使用料金を取得し、そのデータをローカルファイルに保存するための Python プログラムです。

### 実行環境
macOS Big Sur 11.1 
python 3.8.3

### 実行プログラム

```python:GetCostDetail_to_LocalFile.py
import time
import json
import argparse
from tabulate import tabulate
from azure.identity import AzureCliCredential
from azure.mgmt.resource import SubscriptionClient
from azure.mgmt.costmanagement import CostManagementClient
from datetime import datetime
import pandas as pd


# 接続しているテナントのサブスクリプションを操作するオブジェクトを取得
def GetSubscriptionObject():
    subscription_client = SubscriptionClient(
        credential=AzureCliCredential()
    )
    return subscription_client


# CostManagement情報 を操作するオブジェクトを取得
def GetCostManagementObject():
    costmgmt_client = CostManagementClient(
        credential=AzureCliCredential()
    )
    return costmgmt_client


# 指定した Subscription について CostManagement からコストを取得
def GetCostManagement(costmgmt_client, subs_id):

    # Query costmanagement（先月の情報を取得する）
    SCOPE = '/subscriptions/{}'.format(subs_id)
    costmanagement = costmgmt_client.query.usage(
        SCOPE,
        {
            "type": "Usage",
            # "timeframe": "MonthToDate",
            "timeframe": "TheLastMonth",
            "dataset": {
                "granularity": "Daily",
                "aggregation": {
                    "totalCost": {
                        "name": "PreTaxCost",
                        "function": "Sum"
                    }
                },
                "grouping": [
                    {
                        "type": "Dimension",
                        "name": "ResourceGroup"
                    }
                ]
            }
        }
    )
    return costmanagement


# サブスクリプションIDを指定しリソースグループ毎に CostManagement情報を取得
def GetSubscriptionCsotManagement():

    # サブスクリプションを操作するオブジェクトの取得
    subscription_list = GetSubscriptionObject()    

    # CostManagementを操作するオブジェクトの取得
    costmgmt_client = GetCostManagementObject()

    # 取得コストの キーと値
    row_key = ['UsageCost', 'Date', 'ResourceGroup', 'Currency']
    row_value = []

    # サブスクリプション毎に CostManagement からコストを取得
    for n, subs in enumerate(subscription_list.subscriptions.list()):

        # 指定のサブスクリプションの CostManagement からコストを取得
        print("\n\n ##### サブスクリプション ： {} #####".format(subs.display_name))
        costmanagement = GetCostManagement(costmgmt_client, subs.subscription_id)

        # rowsカラムデータを取得し、サブスクリプションのコスト合計値の取得
        SubTotalCost = sum(cost[0] for cost in costmanagement.rows)
        
        # その合計値が「0」の場合、次のサブスクリプションへ
        if SubTotalCost == 0 :
            continue   

        # 取得したコスト情報を日付で昇順ソートし、辞書型に変換する
        row_value = sorted(costmanagement.rows, key=lambda x:x[1], reverse=False)
        row_dict = [dict(zip(row_key,item)) for item in row_value]

        # リソースグループでソートして、とりあえずファイルに保存しておく
        rows = sorted(row_dict, key=lambda x:x['ResourceGroup'], reverse=False)
        UsageDataToLocalFile(rows, subs.display_name)

    costmgmt_client.close()
    subscription_list.close()
    return n+1


def UsageDataToLocalFile(rows, subname):
    
    # データを DataFrame化し、不必要項目(Currency)の削除と必要項目(Subscription)の追加
    dfl=pd.DataFrame(rows)
    dfl.drop("Currency", axis=1, inplace=True)
    dfl['Subscription'] = subname

    # json形式への変換
    rowl_key = ['UsageCost', 'Date', 'ResourceGroup', 'Subscription']
    rowl_dict = [dict(zip(rowl_key,item)) for item in dfl.values]
    print(tabulate(rowl_dict, headers='keys'))

    # 保存するファイル名の生成
    now = datetime.now()
    filename = './output/UsageCost_' + subname + '_' + now.strftime('%Y%m%d_%H%M%S') + '.json'
    print(filename)

    # json.dump関数でファイルに書き込む
    fw = open(filename,'w')
    json.dump(rowl_dict,fw,indent=4)
    fw.close()


if __name__ == '__main__':    
    parser = argparse.ArgumentParser(description='リソースグループ単位の日々コストデータをローカルファイルに保存')
    args = parser.parse_args()

    start = time.time()
    cnt = GetSubscriptionCsotManagement()
    generate_time = time.time() - start

    print("\n  サブスクリプション数 : " + str(cnt))
    print("  取得時間:{0}".format(generate_time) + " [sec] \n")
```

### プログラムの実行
 
```
## 実行状況
$ python GetCostDetail_to_LocalFile.py                                          

 ##### サブスクリプション ： SAG-01 #####
    UsageCost      Date  ResourceGroup    Subscription
-------------  --------  ---------------  --------------
   0.00107688  20210927  cloudsi          SAS-01
   0.00105312  20210928  cloudsi          SAS-01
   0.00105708  20210929  cloudsi          SAS-01
   0.00105312  20210930  cloudsi          SAS-01
1890.69        20210922  container-proj   SAS-01
2217.1         20210923  container-proj   SAS-01
2217.46        20210924  container-proj   SAS-01
2217.1         20210925  container-proj   SAS-01
2217.1         20210926  container-proj   SAS-01
  81.7764      20210927  container-proj   SAS-01
   1.38154     20210928  container-proj   SAS-01
   6.40875     20210929  container-proj   SAS-01
   3.56386     20210930  container-proj   SAS-01
   0.159663    20210917  suzusuzu-rg      SAG-01
./output/UsageCost_SAS-01_20211003_235023.json


 ##### サブスクリプション ： CSC-01 #####
  UsageCost      Date  ResourceGroup                      Subscription
-----------  --------  ---------------------------------  --------------
    9.64932  20210901  cloud-shell-storage-southeastasia  CSC-01
    9.70044  20210902  cloud-shell-storage-southeastasia  CSC-01
    9.6406   20210903  cloud-shell-storage-southeastasia  CSC-01
         ：
        省略
         ：
  サブスクリプション数 : 17
  取得時間:139.42919826507568 [sec] 


## 実行結果
$ tree -a ./output
./output
├── UsageCost_NSN-01_20211004_171046.json
├── UsageCost_PSP1-01_20211004_170946.json
├── UsageCost_PSP2-01_20211004_171018.json
├── UsageCost_SAS-01_20211004_170841.json
├── UsageCost_SSS-01_20211004_170911.json
├── UsageCost_STS1-01_20211004_171032.json
├── UsageCost_STS2-01_20211004_170856.json
├── UsageCost_WJW-01_20211004_170922.json
├── UsageCost_CSC-01_20211004_170849.json
├── UsageCost_IAPP-01_20211004_171010.json
├── UsageCost_SC-01_20211004_171041.json
└── UsageCost_TECH-01_20211004_170933.json

0 directories, 12 files


## jsonファイル（UsageCost_SAS-01_20211004_170841.json）の中身
[
    {
        "UsageCost": 0.0010768751999999996,
        "Date": 20210927,
        "ResourceGroup": "cloudsi",
        "Subscription": "SAS-01"
    },
    {
        "UsageCost": 0.0010531205999999996,
        "Date": 20210928,
        "ResourceGroup": "cloudsi",
        "Subscription": "SAS-01"
    },
    {
        "UsageCost": 0.0010570796999999994,
        "Date": 20210929,
        "ResourceGroup": "cloudsi",
        "Subscription": "SAS-01"
    },
    {
        "UsageCost": 0.0010531205999999996,
        "Date": 20210930,
        "ResourceGroup": "cloudsi",
        "Subscription": "SAS-01"
    },
    {
        "UsageCost": 1890.690199999999,
        "Date": 20210922,
        "ResourceGroup": "container-proj",
        "Subscription": "SAS-01"
    },
    {
        "UsageCost": 2217.095999999999,
        "Date": 20210923,
        "ResourceGroup": "container-proj",
        "Subscription": "SAS-01"
    },
    {
        "UsageCost": 2217.464401293399,
        "Date": 20210924,
        "ResourceGroup": "container-proj",
        "Subscription": "SAS-01"
    },
    {
        "UsageCost": 2217.098852751499,
        "Date": 20210925,
        "ResourceGroup": "container-proj",
        "Subscription": "SAS-01"
    },
    {
        "UsageCost": 2217.099069952124,
        "Date": 20210926,
        "ResourceGroup": "container-proj",
        "Subscription": "SAS-01"
    },
    {
        "UsageCost": 81.77639075169996,
        "Date": 20210927,
        "ResourceGroup": "container-proj",
        "Subscription": "SAS-01"
    },
    {
        "UsageCost": 1.381541163285482,
        "Date": 20210928,
        "ResourceGroup": "container-proj",
        "Subscription": "SAS-01"
    },
    {
        "UsageCost": 6.408747207481177,
        "Date": 20210929,
        "ResourceGroup": "container-proj",
        "Subscription": "SAS-01"
    },
    {
        "UsageCost": 3.5638642035112853,
        "Date": 20210930,
        "ResourceGroup": "container-proj",
        "Subscription": "SAS-01"
    },
    {
        "UsageCost": 0.15966258479999992,
        "Date": 20210917,
        "ResourceGroup": "suzusuzu-rg",
        "Subscription": "SAS-01"
    }
]
```

### まとめ

Azure portal で確認するのもよいですが、プログラムでゴリゴリしたいときはこちらですね。手元にデータを集めることにより後で分析や予想ができるようになります。