Azure EAポータルからAPIで課金情報を取得してみる

# はじめに

AzureをEA契約で使用している皆様へ
突然ですが、どのように課金情報をご覧になっていますか？
EAポータルで直接見たり、PowerBIに落とし込んで見たり、様々な方法があると思います。
そんな中、最近こんな機能がGAされていました。
[Announcing General Availability of Consumption and Charge APIs for Enterprise Azure customers](https://azure.microsoft.com/ja-jp/blog/announcing-general-availability-of-consumption-and-charge-apis-for-enterprise-azure-customers/)

そうです。__EAポータル用の課金情報取得APIです！！__
Public Previewは昨年からされていたものの、ようやく正式リリースになりました。

# APIについて

今回GAされたAPIは以下の通りです。

 * Balance and Summary API
 * Usage Details API
 * Marketplace Store Charge API
 * Price Sheet API
 * Billing Periods API
 
今回はその中でも使用したリソース及び課金額が取得できるUsage Details APIを使用します。

## Usage Detail API
|Method|Request URI|
|:-----|:----------|
|GET|https://consumption.azure.com/v2/enrollments/{enrollmentNumber}/usagedetails|
|GET|https://consumption.azure.com/v2/enrollments/{enrollmentNumber}/billingPeriods/{billingPeriod}/usagedetails|
|GET|https://consumption.azure.com/v2/enrollments/{enrollmentNumber}/usagedetailsbycustomdate?startTime=2017-01-01&endTime=2017-01-10|
下二つのURIのように期間指定をしない場合は当月分の課金情報が取得されます。
レスポンスは以下のようにJSON形式で返されます。

```json:response.json
{
    "id": "string",
    "data": [
        {                       
        "accountId": 0,
        "productId": 0,
        "resourceLocationId": 0,
        "consumedServiceId": 0,
        "departmentId": 0,
        "accountOwnerEmail": "string",
        "accountName": "string",
        "serviceAdministratorId": "string",
        "subscriptionId": 0,
        "subscriptionGuid": "string",
        "subscriptionName": "string",
        "date": "2017-04-27T23:01:43.799Z",
        "product": "string",
        "meterId": "string",
        "meterCategory": "string",
        "meterSubCategory": "string",
        "meterRegion": "string",
        "meterName": "string",
        "consumedQuantity": 0,
        "resourceRate": 0,
        "Cost": 0,
        "resourceLocation": "string",
        "consumedService": "string",
        "instanceId": "string",
        "serviceInfo1": "string",
        "serviceInfo2": "string",
        "additionalInfo": "string",
        "tags": "string",
        "storeServiceIdentifier": "string",
        "departmentName": "string",
        "costCenter": "string",
        "unitOfMeasure": "string",
        "resourceGroup": "string"
        }
    ],
    "nextLink": "string"
}
```

## 今回の目的
このままJSONファイルとして取得して管理してもいいのですが、何かと勝手が悪いため__csv形式で自動的に保存されるような仕組み__を作成しようと思います。
[EA 契約における Azure 使用状況と料金をタイムリーに把握しよう](https://blogs.msdn.microsoft.com/ainaba-csa/2016/07/21/azure-consumption-and-billing-on-enterprise-agreement/)
↑ここにもcsvでダウンロードできるって書いてあるので行けるはず！
と思ったのですが、意外と苦戦しました。

# 構成
基本的な流れとしては上記のRequest URIをInvoke-WebRequestでGETし、帰ってきたJSONデータをcsvに変換するといった内容です。
ただ、一回のAPIで取得できる件数が1,000件となっているので、課金情報が1,000件以上ある場合はJSONの最後に記載されている"nextLink"のURIを叩き続きを取得するような仕組みを実装しています。
（使用量によっては1日分の情報で1,000件超えることもあります。。）

リクエストに必要は加入契約番号、アクセスキー、期間指定はスクリプトに入れ込むのもアレなので
引数としてParamに入れてます。


# 作成スクリプト
今回作成したスクリプトが以下になります

```ps1:get_csv.ps1
Param( 
 [string]$EnrollmentNo, 
 [string]$Accesskey, 
 [string]$startTime,
 [string]$endTime
) 

function nextcsv{
Param(
    [string]$nextLink
)

Remove-Item $filename_detailRpt
$count ++
$filename_detailRpt = ".\Usage-Details_" + (Get-Date).ToString('yyyyMMddHHmmss')+ "_" + $count + ".json" 
$filename_detailRptcsv = ".\Usage-Details_" + (Get-Date).ToString('yyyyMMddHHmmss') + "_" + $count +  ".csv" 
$filename_outputcsv = ".\output_" + (Get-Date).ToString('yyyyMMddHHmmss') + ".csv"

Write-Host "Gathering billing Reports number $count ..." -ForegroundColor Green 
Invoke-WebRequest $nextLink -Headers $authHeaders -OutFile $filename_detailRpt
$json = get-content $filename_detailRpt -raw -encoding UTF8
$json = ConvertFrom-JSON $json
$csv = $json.data |
       Select "cost","accountId","productId","resourceLocationId", `
       "consumedServiceId","departmentId","accountOwnerEmail","accountName", `
       "serviceAdministratorId","subscriptionId","subscriptionGuid","subscriptionName", `
       "date","product","meterId","meterCategory","meterSubCategory", `
       "meterRegion","meterName","consumedQuantity","resourceRate", `
       "resourceLocation","consumedService","instanceId","serviceInfo1", `
       "serviceInfo2","additionalInfo","tags","storeServiceIdentifier", `
       "departmentName","costCenter","unitOfMeasure","resourceGroup" |
       ConvertTo-CSV -NoTypeInformation
$csv | Set-Content $filename_detailRptcsv
$nextLink = $json.nextLink

if([String]::IsNullOrEmpty($nextLink)){
    Remove-Item $filename_detailRpt
    Write-host "Merge csv Files" -ForegroundColor Green
    Get-ChildItem "*.csv" | Foreach{
        Import-Csv -Path $_ -encoding Default |
        Select "cost","accountId","productId","resourceLocationId", `
       "consumedServiceId","departmentId","accountOwnerEmail","accountName", `
       "serviceAdministratorId","subscriptionId","subscriptionGuid","subscriptionName", `
       "date","product","meterId","meterCategory","meterSubCategory", `
       "meterRegion","meterName","consumedQuantity","resourceRate", `
       "resourceLocation","consumedService","instanceId","serviceInfo1", `
       "serviceInfo2","additionalInfo","tags","storeServiceIdentifier", `
       "departmentName","costCenter","unitOfMeasure","resourceGroup" |
       Export-Csv -Append -NoTypeInformation -encoding Default -Path $filename_outputcsv
    }
    Remove-Item Usage-Details_*.csv
    Write-host "Completed Successfully!" -ForegroundColor Green
}else{
    nextcsv($nextLink)
}
}

$count = 1
$baseurlRest = "https://consumption.azure.com/v2/enrollments/" 

$authHeaders = @{"authorization"="bearer $accesskey";"api-version"="1.0"} 

$filename_detailRpt = ".\Usage-Details_" + (Get-Date).ToString('yyyyMMddHHmmss')+ "_" + $count + ".json" 
$filename_detailRptcsv = ".\Usage-Details_" + (Get-Date).ToString('yyyyMMddHHmmss') + "_" + $count +  ".csv" 


Write-Host "Gathering billing Reports number $count ..." -ForegroundColor Green 
$url= $baseurlRest + $enrollmentNo + "/usagedetailsbycustomdate?startTime=" `
      + $startTime + "&endTime=" + $endTime 

Invoke-WebRequest $url -Headers $authHeaders -OutFile $filename_detailRpt

$json = get-content $filename_detailRpt -raw -encoding UTF8
$json = ConvertFrom-JSON $json
$csv = $json.data |
       Select "cost","accountId","productId","resourceLocationId", `
       "consumedServiceId","departmentId","accountOwnerEmail","accountName", `
       "serviceAdministratorId","subscriptionId","subscriptionGuid","subscriptionName", `
       "date","product","meterId","meterCategory","meterSubCategory", `
       "meterRegion","meterName","consumedQuantity","resourceRate", `
       "resourceLocation","consumedService","instanceId","serviceInfo1", `
       "serviceInfo2","additionalInfo","tags","storeServiceIdentifier", `
       "departmentName","costCenter","unitOfMeasure","resourceGroup" |
       ConvertTo-CSV -NoTypeInformation
$csv | Set-Content $filename_detailRptcsv
$nextLink = $json.nextLink

if([String]::IsNullOrEmpty($nextLink)){
    Remove-Item $filename_detailRpt
}else{
    nextcsv($nextLink)
}
```

# 取得データ
実際にスクリプトを実行すると
<img width="542" alt="PS.png" src="https://qiita-image-store.s3.amazonaws.com/0/181154/af5ce116-ef97-56f5-6f69-53feb40aeb82.png">
このように進行し(センシティブな情報が多いために黒塗りが多くてすみません。。)、
![image.png](https://qiita-image-store.s3.amazonaws.com/0/181154/b9ab9cf4-c0ce-cdc6-8339-87c136f4a15a.png)
csvファイルが出力されます。

今回作成したスクリプトだととってこれる情報を全てcsvに落とし込んでいますが、Selectの部分の項目を必要最低限にすることでスリムなcsvにすることも可能です。
### 全部のデータを落とし込んだ場合
<img width="945" alt="PS2.png" src="https://qiita-image-store.s3.amazonaws.com/0/181154/38100557-f523-90d0-f2a1-3cf8ea8f0006.png">
量が多くてすこぶる見辛い
### 特定のデータだけ落とし込んだ場合
<img width="842" alt="PS3.png" src="https://qiita-image-store.s3.amazonaws.com/0/181154/f0c9a324-6833-6a2d-7b86-46aaa51162e3.png">
ある程度はすっきりとした外観に！

実際にデータを参照する際はcsvをテーブル化してサブスクリプションやリソースグループでフィルタリングすると見やすいです。
各列の情報は以下の通りです。

|列名|表示内容|
|:--|:-----|
|cost|実際に発生した課金額|
|accountName|課金が紐づくEAアカウント名|
|subscriptionName|課金が紐づくサブスクリプション名|
|date|課金が発生した日付け|
|product|サービス名|
|consumedQuantity|サービスを使用した量|
|resourceRate|サービスを使用した単位ごとの課金額|
|resourceLocation|リソースの地域|
|tags|付与されているタグ|
|departmentName|EAポータルでの部門名|
|unitOfMeasure|サービスの課金を換算する単位|
|resourceGroup|リソースグループ名|

# 最後に
このように機械的にcsvが取得できれば、このcsvをデータベースにため込んで何かしらのアプリケーションから取得できるようにしたり、色々と活用できそうです。
私は一旦力尽きたので、気が向いたらそういった仕組みの実装も考えます。
この分野の情報は調べてもあまり出てこないので、皆さんガシガシ使って情報を豊富にしていきましょう！