AWS で使用料金明細をタブ区切りテキストで取得する。(利用明細のS3出力を有効化していない期間のデータサルベージ)
正確にいうと JSON でダウンロードしたものをタブ区切りテキストに変換する話ですけど、まあいいか。
AWS の利用料金明細は月別レポートや詳細な請求レポート等を S3 に自動保存できますから、そのように設定されているのが普通だと思います。これはこれで便利なのですが設定を有効にした日以降のデータしか手に入りません。
ちょいと事情があってAWS の過去の usage をデータ化して比較しようと思ったところ、手元のアカウントでは S3 出力を有効化したのが割と最近だったために過去の請求明細がデータで手に入らない。。。どうにか方法はないかと思って考えた挙句、管理コンソールの「請求書」画面の裏で叩いている、以下のURLから情報が取れそうなことが分かりました。
https://console.aws.amazon.com/billing/rest/v1.0/bill?year=YYYY&month=MM
このURLは、AWSのコンソールにログインした後ならブラウザで叩きホーダイです。(対象期間が多い方はブックマークレットを作ったほうが良いのでしょうけど、それを作っている間に手作業で保存できる可能性も高いかも。)
で、ダウンロードで、取得できるのは以下のような JSON 形式のデータです。
[ { "linkedBillIdentifiers": [], "startDate": 1343779200000, "allocatedBills": null, "bills": [ { "invoice": { "billingPeriodEndDate": null, "invoiceVersionId": null, "marketplaceId": null, "invoiceStatus": "Paid", "invoiceAmount": null, "invoiceType": null, "invoiceDueDate": null, "description": null, "retriable": false, "invoiceId": "12345678", "customerId": null, "billingPeriodStartDate": null, "invoiceSettleDate": 1346739288000, "accountId": null, "invoiceFxAmount": null, "invoiceCreationDate": 1346718207000, "invoiceGroupId": "12345678" }, "billVersionId": "33584063", "billTypeCode": "Anniversary", "billId": "12345678", "marketplaceId": "xxxxxxxxxxxxx", "cutOffDate": 1440365059666, "payerAccountId": "123456789012", "totalFxCharge": null, "lineItems": [ { "lineItemId": "123456789", "description": "$0.000 per GB - data transfer out under the monthly global free tier", "productName": "AWS Data Transfer", "productCode": "AWSDataTransfer", "chargePeriodStartDate": 1344579530000, "offeringId": "0", "usageAmount": "0.89573851", "usageUnitName": "GB", "instanceType": "Bandwidth", "chargePeriodEndDate": 1346457599000, "pricePerUnit": { "amount": 0, "baseCurrencyCode": "USD" }, "chargeAmountBeforeTax": { "amount": 0, "baseCurrencyCode": "USD" }, "blended": false, "riType": "None", "fxChargeAmountAfterTax": null, "pricingPlanId": "12345", "sellerOfRecordName": null, "lineItemType": "Usage", "clientProductCode": "AWSDataTransfer", "usageType": "APN1-DataTransfer-Out-Bytes", "operation": null, "region": "Asia Pacific (Tokyo) Region", "chargeAmountAfterTax": { "amount": 123.45, "baseCurrencyCode": "USD" }, "fxChargeAmountBeforeTax": null }, . . . "totalChargeAfterTax": { "amount": 123.45, "baseCurrencyCode": "USD" }, "totalChargeBeforeTax": { "amount": 123.45, "baseCurrencyCode": "USD" }, "estimated": false } ], "endDate": 1346457599000 } ]
こういうデータは jq で処理するに限るので、例えば以下のような感じで処理します。私がほしい明細データは ..bills.lineItems[] の部分にありますから、この部分をまとめて抜く処理と、その中から部分的に抽出する処理に分けています。 (以下の例は jq のパラメータを読みやすくするために整形していますが、本来は改行や余計な空白ナシのワンライナーで記述します)
jq -r '{ ProductCode:.[].bills[].lineItems[] } | "\(.ProductCode.productCode)\t \(.ProductCode.usageType)\t \(.ProductCode.operation)\t \(.ProductCode.description)\t \(.ProductCode.chargePeriodStartDate / 1000)\t \(.ProductCode.chargePeriodEndDate / 1000)\t \(.ProductCode.usageAmount)\t \(.ProductCode.pricePerUnit.baseCurrencyCode)\t \(.ProductCode.chargeAmountBeforeTax.amount)\t \(.ProductCode.chargeAmountAfterTax.amount)"'
こうすると、以下のような出力が得られます。タブ区切りなので、他のツールでの使いまわしが便利です。出力する項目の調整は jq 側で自由に弄れますから、必要に応じて適当に加減すればよい、と。
AWSDataTransfer APN1-DataTransfer-Out-Bytes null $0.000 per GB - data transfer out under the monthly global free tier 1344579530000 1346457599000 0.89573851 USD 0 0 . . .
さて、ブラウザ経由でダウンロードした JSON をチマチマと TSV に変換するのは単なるコピペ仕事なので省略したい。よって以下のようなスクリプトにしてみました。Firefox で AWS コンソールにログインの後、セッションクッキーの情報を Firefox のLive http headers あたりで抜いてきて aws_console_cookie に指定すれば使えます。用いる cookie は "aws-creds=" を含むものです。対象期間はお好みでどうぞ。
#!/bin/bash startdate=2011/01 enddate=2015/07 aws_console_cookie='Cookie: xxxxxx' do_main() { startyear=${startdate%%/*} startmonth=${startdate##*/} endyear=${enddate%%/*} endmonth=${enddate##*/} startdatenum="${startyear}${startmonth}" enddatenum="${endyear}${endmonth}" for y in $( seq $startyear $endyear ); do for m in $( seq 1 12 ); do if [ $m -ge 1 ] && [ $m -le 9 ]; then m="0${m}" fi targetdatenum="${y}${m}" if [ $startdatenum -le $targetdatenum ] && [ $targetdatenum -le $enddatenum ]; then wgetcmd awsreport $y $m fi done done } wgetcmd() { PREFIX=$1 YEAR=$2 MONTH=$3 wget --header "$aws_console_cookie" \ --output-document ${PREFIX}.${YEAR}.${MONTH}.json \ "https://console.aws.amazon.com/billing/rest/v1.0/bill?year=${YEAR}&month=${MONTH}" awsreport2tsv ${PREFIX}.${YEAR}.${MONTH}.json } awsreport2tsv() { filename=$1 if [ -e $filename ]; then echo $filename ${filename%%.json} filename_tsv=${filename%%.json}.tsv cat $filename | jq -r '{ ProductCode:.[].bills[].lineItems[] } | "\(.ProductCode.productCode)\t\(.ProductCode.usageType)\t\(.ProductCode.operation)\t\(.ProductCode.RateId)\t\(.ProductCode.description)\t\(.ProductCode.chargePeriodStartDate)\t\(.ProductCode.chargePeriodEndDate)\t\(.ProductCode.usageAmount)\t\(.ProductCode.pricePerUnit.baseCurrencyCode)\t\(.ProductCode.chargeAmountBeforeTax.amount)\t\(.ProductCode.Credits)\t\(.ProductCode.TaxAmount)\t\(.ProductCode.TotalCost)\t\(.ProductCode.chargeAmountAfterTax.amount)"' > $filename_tsv fi } do_main "$@"