AWS の料金一覧画面から Google スプレッドシートに値をコピペするのに疲れたので、なんとか EC2 の料金表を自動生成できないかと思いました。試行錯誤の結果、ようやくデータ構造までは把握できました。
AWS Price List Service API
AWS Price List Service API (AWS Price List Service)で AWS の料金データを取得できます。今回は取っ掛かりとして AWS CLI を使うので、Pricing サブコマンドでやることになります。
この API は、使えるエンドポイントが以下に限られます。
このため、.aws/config は以下のようにしています。
$ cat .aws/config
[default]
output = json
region = us-east-1
Pricing で使えるサブコマンドは、以下の3種類です。
サブコマンド名 | 機能 |
---|---|
describe-services | サービスとその属性名の一覧 |
get-attribute-values | サービス毎の属性値の一覧 |
get-products | 価格の一覧 |
describe-services
describe-services を何も指定せずに呼び出すと、サービスとその属性名の一覧がずらずらと表示されます。なお便宜上、(JSONではなく)テキスト形式で出力しています。
$ aws pricing describe-services --output=text | head -5
SERVICES AWSBudgets
ATTRIBUTENAMES productFamily
ATTRIBUTENAMES servicecode
ATTRIBUTENAMES groupDescription
ATTRIBUTENAMES termType
いろんなサービスがありますね。。
$ aws pricing describe-services --output=text | grep ^SERVICES | wc -l
92
$ aws pricing describe-services --output=text | grep ^SERVICES | head -5
SERVICES AWSBudgets
SERVICES AWSCloudTrail
SERVICES AWSCodeCommit
SERVICES AWSCodeDeploy
SERVICES AWSCodePipeline
今回目的とするサービス(EC2)の正式なサービス名を調べます。
$ aws pricing describe-services --output=text | grep -i ec2
SERVICES AmazonEC2
これ以降は、コマンドを発行する際にサービスコードを明示することで、なるべくデータ量を減らすようにします。
AmazonEC2 サービスで使えそうな属性名の候補を調べます。
$ aws pricing describe-services --output=text --service-code AmazonEC2 | wc -l
62
$ aws pricing describe-services --output=text --service-code AmazonEC2 | \
grep -Ei '(type|cpu|ecu|memory)'
ATTRIBUTENAMES volumeType
ATTRIBUTENAMES locationType
ATTRIBUTENAMES ecu
ATTRIBUTENAMES gpuMemory
ATTRIBUTENAMES elasticGpuType
ATTRIBUTENAMES memory
ATTRIBUTENAMES vcpu
ATTRIBUTENAMES termType
ATTRIBUTENAMES instanceType
ATTRIBUTENAMES usagetype
AmazonEC2 に限っても、ATTRIBUTENAME(属性名)だけで 62 個もある…。
get-attribute-values
次に "instanceType" という属性名に着目して、その属性値の候補を取得します。
$ aws pricing get-attribute-values --output=text --service-code AmazonEC2 \
--attribute-name instanceType | wc -l
122
$ aws pricing get-attribute-values --output=text --service-code AmazonEC2 \
--attribute-name instanceType | grep -E 't[12]'
ATTRIBUTEVALUES t1.micro
ATTRIBUTEVALUES t2.2xlarge
ATTRIBUTEVALUES t2.large
ATTRIBUTEVALUES t2.medium
ATTRIBUTEVALUES t2.micro
ATTRIBUTEVALUES t2.nano
ATTRIBUTEVALUES t2.small
ATTRIBUTEVALUES t2.xlarge
インスタンスタイプだけで 122 個…。この調子ですべての組み合わせを表示しようとすると、表のサイズが爆発するのは明白です。API サーバにも無意味に負荷をかけそうなので、最初はとりあえず t1.micro の Linux インスタンス(かつ東京リージョンのみ)に絞ってやってみています。
get-products
このサブコマンドで価格の値が取れるのですが、そのままでは使い勝手がよくありません。
$ aws pricing get-products --service-code AmazonEC2 \
--filters Type=TERM_MATCH,Field=instanceType,Value=t1.micro \
Type=TERM_MATCH,Field=operatingSystem,Value=Linux \
'Type=TERM_MATCH,Field=location,Value=Asia Pacific (Tokyo)' \
> t1-micro-linux-tokyo.txt
$ cat t1-micro-linux-tokyo.txt
{
"PriceList": [
"{\"product\":{\"productFamily\":\"Compute Instance\",\"attributes\":{\"memory(以下、死ぬほど長い文字列)...
jq というコマンドを通すといい感じに整形してくれるらしいのですが、どうもうまくパースしてくれません。いろいろと試してみたところ、配列の中身全体が "" で囲まれているのが問題のようです。ということで、この引用符を外してやると、うまく見えるようになりました。ついでにバックスラッシュも外します。
$ cat t1-micro-linux-tokyo.txt | \
sed -e 's/\\//g' -e 's/"{/{/g' -e 's/}"/}/g' | \
jq
{
"PriceList": [
{
"product": {
"productFamily": "Compute Instance",
"attributes": {
"memory": "0.613 GiB",
"vcpu": "1",
"instanceType": "t1.micro",
"tenancy": "Shared",
"usagetype": "APN1-BoxUsage:t1.micro",
"locationType": "AWS Region",
"storage": "EBS only",
"normalizationSizeFactor": "0.5",
"instanceFamily": "Micro instances",
"operatingSystem": "Linux",
"servicecode": "AmazonEC2",
"physicalProcessor": "Variable",
"licenseModel": "No License required",
"ecu": "Variable",
"currentGeneration": "No",
"preInstalledSw": "NA",
"networkPerformance": "Very Low",
"location": "Asia Pacific (Tokyo)",
"servicename": "Amazon Elastic Compute Cloud",
"processorArchitecture": "32-bit or 64-bit",
"operation": "RunInstances"
},
"sku": "ERVWZ4V3UBYH4NQH"
},
"serviceCode": "AmazonEC2",
"terms": {
"OnDemand": {
"ERVWZ4V3UBYH4NQH.JRTCKXETXF": {
"priceDimensions": {
"ERVWZ4V3UBYH4NQH.JRTCKXETXF.6YS6EN2CT7": {
"unit": "Hrs",
"endRange": "Inf",
"description": "$0.026 per On Demand Linux t1.micro Instance Hour",
"appliesTo": [],
"rateCode": "ERVWZ4V3UBYH4NQH.JRTCKXETXF.6YS6EN2CT7",
"beginRange": "0",
"pricePerUnit": {
"USD": "0.0260000000"
}
}
},
"sku": "ERVWZ4V3UBYH4NQH",
"effectiveDate": "2017-12-01T00:00:00Z",
"offerTermCode": "JRTCKXETXF",
"termAttributes": {}
}
},
"Reserved": {
"ERVWZ4V3UBYH4NQH.NQ3QZPMQV9": {
"priceDimensions": {
"ERVWZ4V3UBYH4NQH.NQ3QZPMQV9.2TG2D8R56U": {
"unit": "Quantity",
"description": "Upfront Fee",
"appliesTo": [],
"rateCode": "ERVWZ4V3UBYH4NQH.NQ3QZPMQV9.2TG2D8R56U",
"pricePerUnit": {
"USD": "316"
}
},
"ERVWZ4V3UBYH4NQH.NQ3QZPMQV9.6YS6EN2CT7": {
"unit": "Hrs",
"endRange": "Inf",
"description": "USD 0.0 per Linux/UNIX (Amazon VPC), t1.micro reserved instance applied",
"appliesTo": [],
"rateCode": "ERVWZ4V3UBYH4NQH.NQ3QZPMQV9.6YS6EN2CT7",
"beginRange": "0",
"pricePerUnit": {
"USD": "0.0000000000"
}
}
},
"sku": "ERVWZ4V3UBYH4NQH",
"effectiveDate": "2015-04-30T23:59:59Z",
"offerTermCode": "NQ3QZPMQV9",
"termAttributes": {
"LeaseContractLength": "3yr",
"OfferingClass": "standard",
"PurchaseOption": "All Upfront"
}
},
"ERVWZ4V3UBYH4NQH.6QCMYABX3D": {
"priceDimensions": {
"ERVWZ4V3UBYH4NQH.6QCMYABX3D.2TG2D8R56U": {
"unit": "Quantity",
"description": "Upfront Fee",
"appliesTo": [],
"rateCode": "ERVWZ4V3UBYH4NQH.6QCMYABX3D.2TG2D8R56U",
"pricePerUnit": {
"USD": "138"
}
},
"ERVWZ4V3UBYH4NQH.6QCMYABX3D.6YS6EN2CT7": {
"unit": "Hrs",
"endRange": "Inf",
"description": "USD 0.0 per Linux/UNIX (Amazon VPC), t1.micro reserved instance applied",
"appliesTo": [],
"rateCode": "ERVWZ4V3UBYH4NQH.6QCMYABX3D.6YS6EN2CT7",
"beginRange": "0",
"pricePerUnit": {
"USD": "0.0000000000"
}
}
},
"sku": "ERVWZ4V3UBYH4NQH",
"effectiveDate": "2015-04-30T23:59:59Z",
"offerTermCode": "6QCMYABX3D",
"termAttributes": {
"LeaseContractLength": "1yr",
"OfferingClass": "standard",
"PurchaseOption": "All Upfront"
}
},
"ERVWZ4V3UBYH4NQH.38NPMPTW36": {
"priceDimensions": {
"ERVWZ4V3UBYH4NQH.38NPMPTW36.2TG2D8R56U": {
"unit": "Quantity",
"description": "Upfront Fee",
"appliesTo": [],
"rateCode": "ERVWZ4V3UBYH4NQH.38NPMPTW36.2TG2D8R56U",
"pricePerUnit": {
"USD": "100"
}
},
"ERVWZ4V3UBYH4NQH.38NPMPTW36.6YS6EN2CT7": {
"unit": "Hrs",
"endRange": "Inf",
"description": "Linux/UNIX (Amazon VPC), t1.micro reserved instance applied",
"appliesTo": [],
"rateCode": "ERVWZ4V3UBYH4NQH.38NPMPTW36.6YS6EN2CT7",
"beginRange": "0",
"pricePerUnit": {
"USD": "0.0090000000"
}
}
},
"sku": "ERVWZ4V3UBYH4NQH",
"effectiveDate": "2016-10-31T23:59:59Z",
"offerTermCode": "38NPMPTW36",
"termAttributes": {
"LeaseContractLength": "3yr",
"OfferingClass": "standard",
"PurchaseOption": "Partial Upfront"
}
},
"ERVWZ4V3UBYH4NQH.HU7G6KETJZ": {
"priceDimensions": {
"ERVWZ4V3UBYH4NQH.HU7G6KETJZ.2TG2D8R56U": {
"unit": "Quantity",
"description": "Upfront Fee",
"appliesTo": [],
"rateCode": "ERVWZ4V3UBYH4NQH.HU7G6KETJZ.2TG2D8R56U",
"pricePerUnit": {
"USD": "62"
}
},
"ERVWZ4V3UBYH4NQH.HU7G6KETJZ.6YS6EN2CT7": {
"unit": "Hrs",
"endRange": "Inf",
"description": "Linux/UNIX (Amazon VPC), t1.micro reserved instance applied",
"appliesTo": [],
"rateCode": "ERVWZ4V3UBYH4NQH.HU7G6KETJZ.6YS6EN2CT7",
"beginRange": "0",
"pricePerUnit": {
"USD": "0.0090000000"
}
}
},
"sku": "ERVWZ4V3UBYH4NQH",
"effectiveDate": "2015-04-30T23:59:59Z",
"offerTermCode": "HU7G6KETJZ",
"termAttributes": {
"LeaseContractLength": "1yr",
"OfferingClass": "standard",
"PurchaseOption": "Partial Upfront"
}
},
"ERVWZ4V3UBYH4NQH.4NA7Y494T4": {
"priceDimensions": {
"ERVWZ4V3UBYH4NQH.4NA7Y494T4.6YS6EN2CT7": {
"unit": "Hrs",
"endRange": "Inf",
"description": "Linux/UNIX (Amazon VPC), t1.micro reserved instance applied",
"appliesTo": [],
"rateCode": "ERVWZ4V3UBYH4NQH.4NA7Y494T4.6YS6EN2CT7",
"beginRange": "0",
"pricePerUnit": {
"USD": "0.0180000000"
}
}
},
"sku": "ERVWZ4V3UBYH4NQH",
"effectiveDate": "2016-08-31T23:59:59Z",
"offerTermCode": "4NA7Y494T4",
"termAttributes": {
"LeaseContractLength": "1yr",
"OfferingClass": "standard",
"PurchaseOption": "No Upfront"
}
}
}
},
"version": "20180131042456",
"publicationDate": "2018-01-31T04:24:56Z"
}
],
"FormatVersion": "aws_v1"
}
返されるデータの構造がわかったので、後は必要な項目だけを抜き出して CSV で出力してやれば、Google スプレッドシートにインポートで取り込めそうです。ということで、今日はここまでです。
っと、ここまで書いてから投稿しようとしたら、AWS Price List API の使用 とかいうよさげなページがあるのに気づいたのでこれから読みます。。。
(参照)