AWS Price List API で雑に月額を出してみる

[cloudpack あら便利カレンダー 2017](https://cloudpack.github.io/benri2017/) の20日目です。

# まえがき

[AWS Price List API](http://docs.aws.amazon.com/ja_jp/awsaccountbilling/latest/aboutv2/price-changes.html) を使うと AWS 各種サービスの使用料金を**巨大な JSON** の形式で取得できます。

例えば EC2 のインスタンス使用料金を知りたい場合、 `https://pricing.us-east-1.amazonaws.com/offers/v1.0/aws/AmazonEC2/current/region_index.json` を取得し、そこに含まれる目的のリージョンのオファーファイルを取得します。 

```
$ curl -I https://pricing.us-east-1.amazonaws.com/offers/v1.0/aws/AmazonEC2/20170605233259/ap-northeast-1/index.json
HTTP/1.1 200 OK
Content-Type: application/octet-stream
Content-Length: 10293063
Connection: keep-alive
Date: Mon, 19 Jun 2017 04:27:13 GMT
Last-Modified: Tue, 06 Jun 2017 00:55:29 GMT
ETag: "35bdcd83d7f7863f5f26550206b0e624"
Accept-Ranges: bytes
Server: AmazonS3
Age: 24112
X-Cache: Hit from cloudfront
Via: 1.1 41f313008af830d498dcb13814523bd7.cloudfront.net (CloudFront)
X-Amz-Cf-Id: 1oUuTPzPmELzB65fwzB1ds1ezCEpBn8ZWVANIJT-rURfG2p8buOFMg==
```

上記は東京リージョンの EC2 の例ですが、 `Content-Length: 10293063` というどう見ても人間が素で読む量ではないし、テキストエディターに読み込むのも若干ためらわれるサイズです。

公式のドキュメントによると…

- [オファーファイルでの料金の確認 - AWS 請求情報とコスト管理](http://docs.aws.amazon.com/ja_jp/awsaccountbilling/latest/aboutv2/procedures.html)

> JSON ファイルを使用して EC2 のリザーブドインスタンスを確認するには
> 
> 1. JSON ファイルをからダウンロードします。
> 1. 適切なプログラムで JSON ファイルを開きます。この例では、Notepad++ を使用します。
> 1. Ctrl キーを押しながら F キーを押します。
> 1. [Find what:] に [reserved] と入力します。
> 1. [Find All in Current Document] を選択します。

とあんまりなので、もう少し楽に価格を調べられる雑スクリプトを作りました。

# スクリプト本体

```js:ec2ZatsuPrice.js
const region          = process.env["AWS_REGION"]       || "us-east-1";
const instanceType    = process.env["INSTANCE_TYPE"]    || "c4.large";
const tenancy         = process.env["TENANCY"]          || "Shared";
const operatingSystem = process.env["OPERATING_SYSTEM"] || "Linux";
const offerType       = process.env["OFFER_TYPE"]       || "OnDemand";

// ↑フィルター条件をenvで指定してね

const axios = require("axios");

const api = axios.create({
  baseURL: "https://pricing.us-east-1.amazonaws.com"
});

Promise.resolve().then(() => {
  return api.get("/offers/v1.0/aws/AmazonEC2/current/region_index.json")
}).then(regionIndexResponse => {
  const currentVersionUrl = regionIndexResponse.data.regions[region].currentVersionUrl;

  return api.get(currentVersionUrl);
}).then(currentVersionResponse => {
  const filteredProducts = [];

  for (productCode in currentVersionResponse.data.products) {
    const product = currentVersionResponse.data.products[productCode];

    if (product.attributes.instanceType !== instanceType) continue;
    if (product.attributes.tenancy !== tenancy) continue;
    if (product.attributes.operatingSystem !== operatingSystem) continue;

    filteredProducts.push(product);
  }

  if (filteredProducts.length > 1) {
    console.log(`絞りきれなかったかも… (${filteredProducts.length} products)`);
    process.exit(1);
  };

  const offers = currentVersionResponse.data.terms[offerType][filteredProducts[0].sku];

  if (Object.keys(offers).length > 1) {
    console.log(`絞りきれなかったかも… (${Object.keys(offers).length} offers)`);
    process.exit(1);
  };

  const offer = offers[Object.keys(offers)[0]];
  const priceDimension = offer.priceDimensions[Object.keys(offer.priceDimensions)[0]];
  const pricePerUnit = parseFloat(priceDimension.pricePerUnit.USD);
  const monthlyPrice = pricePerUnit * 24 * 30;

  console.log(JSON.stringify({
    region,
    instanceType,
    tenancy,
    operatingSystem,
    monthlyPrice,

    description: priceDimension.description,
  }, undefined, 2))
}).catch(e => console.log(e));
```

あまり古くない Node.js と [axios](https://github.com/mzabriskie/axios) が必要です。

# 使い方

叩くだけです。

```shell-session
$ node ec2ZatsuPrice.js
{
  "region": "us-east-1",
  "instanceType": "c4.large",
  "tenancy": "Shared",
  "operatingSystem": "Linux",
  "monthlyPrice": 72.00000000000001,
  "description": "$0.1 per On Demand Linux c4.large Instance Hour"
}
```

条件を変えたいときは環境変数で。

```shell-session
$ AWS_REGION=us-west-2 INSTANCE_TYPE=r3.xlarge node ec2ZatsuPrice.js
{
  "region": "us-west-2",
  "instanceType": "r3.xlarge",
  "tenancy": "Shared",
  "operatingSystem": "Linux",
  "monthlyPrice": 239.76000000000002,
  "description": "$0.333 per On Demand Linux r3.xlarge Instance Hour"
}
```

オレゴンの r3.xlarge 、オンデマンドの Linux インスタンスは月額だいたい240ドルくらいということがわかります。

# 雑な部分

- EC2 しか対応してません
- Reserved Instances （1プロダクト複数オファーターム）に対応してません
- 1カ月 == 30日で決め打ちです
- 変えられるべき条件は他にも沢山ある気がします
- その他未知の不具合があると思います

# 最後に

もう少しまともなやつをそのうち作ろうと思います。