はじめに
azbill という Azure クラウドサービスの利用明細・課金情報を出力してくれる CLI ツールを Go 言語で作ったので紹介します。主に Enterprise Agreement (EA) で Azure を導入している組織向けで、例えば部署ごと・リソースの種類ごと・タグごとの使用量を算出するといったようなコスト分析のためのデータを出力するツールです。
azbill を使うと EA の課金アカウントや Azure サブスクリプションに含まれるすべてのリソースの使用量・課金額を日次で取得し、CSV や JSONL の形式でファイルに保存できます。
このような利用明細の取得は Azure CLI でもできると思われるかもしれませんが、現行の Azure CLI は新しいバージョンの Consumption API に対応しておらず、予約 VM の利用状況といったような情報がとれません。 azbill を使えばそのような最新のメトリクスが取得できますし、CSV やフラットな JSON といったような、気の利いた出力が可能です。
azbill は現時点で次の種類の課金アカウントに対応しています。
- Microsoft Online Services Program (個人のクレジットカードによる従量課金契約はこれに含まれます)
- Enterprise Agreement (企業向けの年間契約)
インストール
azbill には Windows・macOS・Linux 向けにビルドされたバイナリがありますのでそれをダウンロードしご利用してください。ひとつの実行ファイルのみで動作します。
Go がインストールされているシステムであれば、次のコマンドでインストールすることもできます。
$ go get -u github.com/yaegashi/azbill
使用法
多くのコマンドラインオプションや環境変数による設定があります。 azbill -h
で表示されるヘルプを参照してください。
$ azbill -h
Azure billing data exporter
Usage:
azbill [command]
Available Commands:
accounts List billing accounts you have access to
help Help about any command
invoices List invoices
login Force auth-dev login
subscriptions List subscriptions
tenants List tenants
usage-details List usage details
Flags:
--auth string auth source [dev,env,file,cli] (env:AZBILL_AUTH, default:dev)
--auth-dev string auth dev store (env:AZBILL_AUTH_DEV, default:auth_dev.json)
--auth-file string auth file store (env:AZBILL_AUTH_FILE, default:auth_file.json)
--client string Azure client (env:AZURE_CLIENT_ID, default:4a034c56-da44-48ce-90db-039a408974bd)
--config-dir string config dir (env:AZBILL_CONFIG_DIR, default:~/.azbill)
--format string output format [csv,json,flatten,pretty] (env:AZBILL_FORMAT, default:csv)
-h, --help help for azbill
-o, --output string output file
-q, --quiet quiet
--tenant string Azure tenant (env:AZURE_TENANT_ID, default:common)
-v, --version version for azbill
Use "azbill [command] --help" for more information about a command.
認証
azbill login
で Azure AD のデバイス承認フローによるサインインができます。 ブラウザで https://microsoft.com/devicelogin を開き、表示されたコードを入力した後にサインインしてください。
$ azbill login
2020/07/06 23:05:05 To sign in, use a web browser to open the page https://microsoft.com/devicelogin and enter the code HL94ZL7Y8 to authenticate.
2020/07/06 23:05:21 Saving auth-dev token in /Users/yaegashi/.azbill/auth_dev.json
ホームとは異なるテナントにゲストとしてサインインするには --tenant
で指定してください。
$ azbill login --tenant l0wdev.onmicrosoft.com
認証トークンは ~/.azbill/auth_dev.json
ファイルに保存されます。 --auth-dev
オプションにより保存するファイルを指定できます。相対パスを指定した場合は --config-dir
で指定したディレクトリ (デフォルト ~/.azbill
) 内に保存されます。
また Azure Blob Storage の SAS つき URL を指定することもできます。これは CI/CD サービスの環境で azbill を実行する場合に便利です。 SAS つき URL は秘匿すべき情報ですので、 --auth-dev
ではなく環境変数 AZBILL_AUTH_DEV
で設定するようにしてください。
Azure SDK for Go がサポートする他の認証方式を使うこともできます。 Azure CLI で認証済みの場合は --auth cli
を使うのが簡単です。 Azure CLI で生成したサービスプリンシパルの JSON ファイルを使う場合は --auth file
を使い、ファイルの場所を --auth-file
で指定してください。
出力フォーマット
出力フォーマットは --format
で指定します。基本は csv
または json
の 2 種類です。カンマ区切りで flatten
または pretty
を追加指定できます。
--format |
説明 |
---|---|
csv |
1レコードが 1 行のCSV 形式で出力します (デフォルト) |
json |
1 レコードが 1 JSON オブジェクトで、それらを改行で区切った JSONL 形式で出力します |
json,flatten |
入れ子でない JSON オブジェクトを出力します。flatten でも同じ意味です。 |
json,pretty |
インデントつきの JSON オブジェクトを出力します。pretty でも同じ意味です。 |
json,flatten,pretty |
入れ子でないインデントつきの JSON オブジェクトを出力します。flatten,pretty でも同じ意味です。 |
JSON 形式
次は --format json,pretty
を指定した時の 1 レコードの出力です。 JSON 形式の場合、丸め誤差を避けるために数字は文字列で表現されていることに注意してください。
{
"properties": {
"billingPeriodStartDate": "2020-05-03T00:00:00Z",
"billingPeriodEndDate": "2020-06-02T00:00:00Z",
"billingProfileId": "/subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
"billingProfileName": "Pay-As-You-Go",
"subscriptionId": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
"subscriptionName": "Pay-As-You-Go",
"date": "2020-06-01T00:00:00Z",
"meterId": "d54686f0-77ff-43f3-9e7c-2099030d32a7",
"meterDetails": {
"meterName": "Public Queries",
"meterCategory": "Azure DNS",
"meterSubCategory": "",
"unitOfMeasure": "10000000"
},
"quantity": "0.000997",
"effectivePrice": "55.3250345781466",
"cost": "0.055159059474412",
"unitPrice": "0",
"billingCurrency": "JPY",
"resourceLocation": "Unknown",
"consumedService": "Microsoft.Network",
"resourceId": "/subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/dns/providers/Microsoft.Network/dnszones/l0w.dev",
"resourceName": "l0w.dev",
"resourceGroup": "dns",
"offerId": "MS-AZR-0003P",
"isAzureCreditEligible": false,
"publisherType": "Azure",
"chargeType": "Usage",
"frequency": "UsageBased"
},
"id": "/subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/providers/Microsoft.Billing/billingPeriods/202006/providers/Microsoft.Consumption/usageDetails/de545724-82e8-f099-bc3b-53c5f0ae1711",
"name": "de545724-82e8-f099-bc3b-53c5f0ae1711",
"type": "Microsoft.Consumption/usageDetails",
"tags": null,
"kind": "legacy"
}
フラット形式
次は --format json,flatten,pretty
を指定した時の出力です。フラットな JSON オブジェクトとなります。
{
"id": "/subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/providers/Microsoft.Billing/billingPeriods/202006/providers/Microsoft.Consumption/usageDetails/de545724-82e8-f099-bc3b-53c5f0ae1711",
"kind": "legacy",
"name": "de545724-82e8-f099-bc3b-53c5f0ae1711",
"properties.billingCurrency": "JPY",
"properties.billingPeriodEndDate": "2020-06-02T00:00:00Z",
"properties.billingPeriodStartDate": "2020-05-03T00:00:00Z",
"properties.billingProfileId": "/subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
"properties.billingProfileName": "Pay-As-You-Go",
"properties.chargeType": "Usage",
"properties.consumedService": "Microsoft.Network",
"properties.cost": "0.055159059474412",
"properties.date": "2020-06-01T00:00:00Z",
"properties.effectivePrice": "55.3250345781466",
"properties.frequency": "UsageBased",
"properties.isAzureCreditEligible": false,
"properties.meterDetails.meterCategory": "Azure DNS",
"properties.meterDetails.meterName": "Public Queries",
"properties.meterDetails.meterSubCategory": "",
"properties.meterDetails.unitOfMeasure": "10000000",
"properties.meterId": "d54686f0-77ff-43f3-9e7c-2099030d32a7",
"properties.offerId": "MS-AZR-0003P",
"properties.publisherType": "Azure",
"properties.quantity": "0.000997",
"properties.resourceGroup": "dns",
"properties.resourceId": "/subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/dns/providers/Microsoft.Network/dnszones/l0w.dev",
"properties.resourceLocation": "Unknown",
"properties.resourceName": "l0w.dev",
"properties.subscriptionId": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
"properties.subscriptionName": "Pay-As-You-Go",
"properties.unitPrice": "0",
"tags": null,
"type": "Microsoft.Consumption/usageDetails"
}
CSV 形式
次は --format csv
を指定した時の出力です。
id,kind,name,properties.accountName,properties.accountOwnerId,properties.additionalInfo,properties.billingAccountId,properties.billingAccountName,properties.billingCurrency,properties.billingPeriodEndDate,properties.billingPeriodStartDate,properties.billingProfileId,properties.billingProfileName,properties.chargeType,properties.consumedService,properties.cost,properties.costCenter,properties.date,properties.effectivePrice,properties.frequency,properties.invoiceSection,properties.isAzureCreditEligible,properties.meterDetails.meterCategory,properties.meterDetails.meterName,properties.meterDetails.meterSubCategory,properties.meterDetails.serviceFamily,properties.meterDetails.unitOfMeasure,properties.meterId,properties.offerId,properties.partNumber,properties.planName,properties.product,properties.productOrderId,properties.productOrderName,properties.publisherName,properties.publisherType,properties.quantity,properties.reservationId,properties.reservationName,properties.resourceGroup,properties.resourceId,properties.resourceLocation,properties.resourceName,properties.serviceInfo1,properties.serviceInfo2,properties.subscriptionId,properties.subscriptionName,properties.term,properties.unitPrice,tags,type
/subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/providers/Microsoft.Billing/billingPeriods/202006/providers/Microsoft.Consumption/usageDetails/de545724-82e8-f099-bc3b-53c5f0ae1711,legacy,de545724-82e8-f099-bc3b-53c5f0ae1711,,,,,,JPY,2020-06-02T00:00:00Z,2020-05-03T00:00:00Z,/subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX,Pay-As-You-Go,Usage,Microsoft.Network,0.055159059474412,,2020-06-01T00:00:00Z,55.3250345781466,UsageBased,,false,Azure DNS,Public Queries,,,10000000,d54686f0-77ff-43f3-9e7c-2099030d32a7,MS-AZR-0003P,,,,,,,Azure,0.000997,,,dns,/subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/dns/providers/Microsoft.Network/dnszones/l0w.dev,Unknown,l0w.dev,,,XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX,Pay-As-You-Go,,0,{},Microsoft.Consumption/usageDetails
1 行目の CSV ヘッダは json,flatten
指定時のキーと同じものです。 JSON 形式では省かれたキーもすべて含まれています。エンコーディングは BOM つきの UTF-8 で、改行コードは CRLF であるため Microsoft Excel で直接開くことができます。
例
アクセス可能な課金アカウントを CSV 形式で出力します。
$ azbill accounts
アクセス可能な Azure AD テナントを JSONL 形式で出力します。
$ azbill tenants --format json
アクセス可能なサブスクリプションをフラットな JSONL 形式で出力します。
$ azbill subscriptions --format flatten
Microsoft Online Service Program アカウント: サブスクリプション XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
の 2020 年 6 月の利用明細をフラットなインデントした JSONL 形式で出力します。
$ azbill usage-details --format flatten,pretty -S XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX --start 2020-06-01 --end 2020-06-30 -o usage.jsonl
2020/07/06 23:43:59 Loading auth-dev token in /Users/yaegashi/.azbill/auth_dev.json
2020/07/06 23:43:59 Requesting with consumption.UsageDetailsClient
2020/07/06 23:43:59 scope: "subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
2020/07/06 23:43:59 filter: "properties/usageStart eq '2020-06-01' and properties/usageEnd eq '2020-06-30'"
2020/07/06 23:44:11 Writing to "usage.jsonl" in json,flatten,pretty
. 138 records
2020/07/06 23:44:11 Done 138 records in 16.893702ms, 8168.724653 records/sec
Enterprise Agreement アカウント: 課金アカウント XXXXXXXX
のビリング期間 202006
の利用明細を CSV 形式で出力します。
$ azbill usage-details --format csv -A XXXXXXXX -P 202006 -o usage.csv
2020/07/06 23:45:15 Loading auth-dev token in /Users/yaegashi/.azbill/auth_dev.json
2020/07/06 23:45:15 Requesting with consumption.UsageDetailsClient
2020/07/06 23:45:15 scope: "providers/Microsoft.Billing/billingAccounts/XXXXXXXX/providers/Microsoft.Billing/billingPeriods/202006"
2020/07/06 23:45:15 filter: ""
2020/07/06 23:45:34 Writing to "usage.csv" in csv
.................................................. 5000 records
.................................................. 10000 records
.................................................. 15000 records
.................... 17001 records
2020/07/06 23:46:38 Done 17001 records in 1m4.325743007s, 264.295431 records/sec
azbill の開発
azbill の CLI コマンド階層およびフラグ処理には cobra-comder を使用しています (cobra-cmder で Go の CLI を簡単に作る を参照)。
azbill では Azure SDK for Go を使用していますが、現行の SDK ではまだ対応していない新しいバージョンの Azure REST API を使用しています。 バージョン 2019-11-01 の Consumption 利用明細 API などです。
このため AutoRest ツールにより、新しいバージョンの OpenAPI 仕様書から SDK をコード生成しています。生成されたコードは azure-sdk-for-go ディレクトリにあります。
生成を自動的に行うシェルスクリプトが gen.sh です。
このような AutoRest による Azure SDK コードの生成については、別の記事で詳しく説明したいと思います。