misc.tech.notes

主に技術的な雑記的な

AWS Price List APIから欲しい情報だけ抜き取るAPIをAPI Gateway + Lambdaで作った

この記事はAWS Advent Calendar 2015の11日の記事です。

qiita.com

経緯

それは昨日(2015-12-10)の出来事でした。
全世界待望(?)の料金を取得するための公式APIが公開されました。

aws.typepad.com

過去にこんなのこんなのを作って、公式HPで使っているデータソースのJSONのURLやフォーマットが変わる度に(´・ω・`)ショボーンとしてきた身としては、「これは!!」となったわけです。

で、喜び勇んで試しに叩いてみたら

そんなこんなで

みたいな話になったので勢いで作ってみましたよと。

成果物

ソース

github.com

APIドキュメント(swagger-ui)

Swagger UI

フィードバックはGitHubの方からお願いします :-)
エラー処理とか雑なんでエラー時に普通にスタックトレースとか返ってくるので、Issueに貼り付けてやってくださいw

使い方

APIドキュメント見れば大枠はわかると思うので、ここでは各属性の指定方法を説明したいと思います。

とりあえずコマンドからのサンプルを貼っておきます。これをベースに説明したいと思います。

curl -X POST --header 'Content-Type: application/json' --header 'Accept: application/json' -d '[{
  "key": "instanceType",
  "value": "m4.4xlarge"
},
{
  "key": "location",
  "value": "US West (Oregon)"
},
{
  "key": "operatingSystem",
  "value": "Linux"
}]
' 'https://eaoftu7rfi.execute-api.us-east-1.amazonaws.com/public/v1/offer/AmazonEC2?term=OnDemand'

Method

POSTのみに対応します(CORS対応のためにOPTIONも叩くことはできます)

URL

まず、ベースとなるのが以下の部分です。

https://eaoftu7rfi.execute-api.us-east-1.amazonaws.com/public/v1/offer/

次に、その後の AmazonEC2 の部分がサービスを示します。それぞれ何が使えるかは本家のAPIに準拠します。
なので、以下の offerCode で何が使えるか確認できます。

https://pricing.us-east-1.amazonaws.com/offers/v1.0/aws/index.json

そして、クエリストリングの term で購入方式を指定します。ここは、確認した範囲では OnDemand or Reserved しかないようです。EC2やRDS等以外の Reserved の概念が存在しないサービスについては OnDemand を指定してください。

Body

JSONフォーマットで各プロダクトの属性名が key 、その内容を valueで指定します。それぞれの内容は公式APIのデータが以下のようになっており、その中の attributes の内容がそのまま該当します。

{
  "formatVersion" : "v1.0",
  "disclaimer" : "This pricing list is for informational purposes only. All prices are subject to the additional terms included in the pricing pages on http://aws.amazon.com. All Free Tier prices are also subject to the terms included at https://aws.amazon.com/free/",
  "offerCode" : "AmazonRDS",
  "version" : "20151001000000",
  "publicationDate" : "2015-11-15T04:02:20Z",
  "products" : {
    "FNR4GZ675EW5UXJW" : {
      "sku" : "FNR4GZ675EW5UXJW",
      "productFamily" : "Database Instance",
      "attributes" : {
        "servicecode" : "AmazonRDS",
        "location" : "US West (Oregon)",
        "locationType" : "AWS Region",
        "instanceType" : "db.t2.small",
        "currentGeneration" : "Yes",
        "instanceClass" : "Burstable performance instances",
        "vcpu" : "1",
        "memory" : "2",
        "piopsOptimized" : "No",
        "networkPerformance" : "Low",
        "engineCode" : "10",
        "databaseEngine" : "SQL Server",
        "databaseEdition" : "Express",
        "deploymentOption" : "Single-AZ",
        "usagetype" : "USW2-InstanceUsage:db.t2.small",
        "operation" : "CreateDBInstance:0010"
      }
    },

複数の条件は全て AND で繋がります。指定された条件を全て満たすデータが返却されます。

結果

上記コマンドの結果は以下のようになります。

[
  {
    "product": {
      "sku": "8YGPZRQEKSSY8VWV",
      "productFamily": "Compute Instance",
      "attributes": {
        "enhancedNetworkingSupported": "Yes",
        "currentGeneration": "Yes",
        "operation": "RunInstances",
        "instanceType": "m4.4xlarge",
        "vcpu": "16",
        "storage": "EBS only",
        "location": "US West (Oregon)",
        "memory": "64 GiB",
        "processorFeatures": "Intel AVX; Intel AVX2; Intel Turbo",
        "networkPerformance": "High",
        "usagetype": "USW2-HostBoxUsage:m4.4xlarge",
        "processorArchitecture": "64-bit",
        "tenancy": "Host",
        "servicecode": "AmazonEC2",
        "dedicatedEbsThroughput": "2000 Mbps",
        "instanceFamily": "General purpose",
        "locationType": "AWS Region",
        "licenseModel": "No License required",
        "preInstalledSw": "NA",
        "clockSpeed": "2.4 GHz",
        "physicalProcessor": "Intel Xeon E5-2676 v3 (Haswell)",
        "operatingSystem": "Linux"
      }
    },
    "price": [
      {
        "sku": "8YGPZRQEKSSY8VWV",
        "termAttributes": {},
        "effectiveDate": "2015-12-01T00:00:00Z",
        "offerTermCode": "JRTCKXETXF",
        "priceDimensions": {
          "8YGPZRQEKSSY8VWV.JRTCKXETXF.6YS6EN2CT7": {
            "description": "$0.000 per Linux m4.4xlarge Dedicated Host Instance hour",
            "pricePerUnit": {
              "USD": "0.0000000000"
            },
            "rateCode": "8YGPZRQEKSSY8VWV.JRTCKXETXF.6YS6EN2CT7",
            "endRange": "Inf",
            "beginRange": "0",
            "appliesTo": [],
            "unit": "Hrs"
          }
        }
      }
    ]
  },
  {
    "product": {
      "sku": "ZPAH28S2QQZ64QB5",
      "productFamily": "Compute Instance",
      "attributes": {
        "enhancedNetworkingSupported": "Yes",
        "currentGeneration": "Yes",
        "operation": "RunInstances",
        "instanceType": "m4.4xlarge",
        "vcpu": "16",
        "storage": "EBS only",
        "location": "US West (Oregon)",
        "memory": "64 GiB",
        "processorFeatures": "Intel AVX; Intel AVX2; Intel Turbo",
        "networkPerformance": "High",
        "usagetype": "USW2-DedicatedUsage:m4.4xlarge",
        "processorArchitecture": "64-bit",
        "tenancy": "Dedicated",
        "servicecode": "AmazonEC2",
        "dedicatedEbsThroughput": "2000 Mbps",
        "instanceFamily": "General purpose",
        "locationType": "AWS Region",
        "licenseModel": "No License required",
        "preInstalledSw": "NA",
        "clockSpeed": "2.4 GHz",
        "physicalProcessor": "Intel Xeon E5-2676 v3 (Haswell)",
        "operatingSystem": "Linux"
      }
    },
    "price": [
      {
        "sku": "ZPAH28S2QQZ64QB5",
        "termAttributes": {},
        "effectiveDate": "2015-12-01T00:00:00Z",
        "offerTermCode": "JRTCKXETXF",
        "priceDimensions": {
          "ZPAH28S2QQZ64QB5.JRTCKXETXF.6YS6EN2CT7": {
            "description": "$1.109 per Dedicated Usage Linux m4.4xlarge Instance Hour",
            "pricePerUnit": {
              "USD": "1.1090000000"
            },
            "rateCode": "ZPAH28S2QQZ64QB5.JRTCKXETXF.6YS6EN2CT7",
            "endRange": "Inf",
            "beginRange": "0",
            "appliesTo": [],
            "unit": "Hrs"
          }
        }
      }
    ]
  },
  {
    "product": {
      "sku": "BMEYUTP658QKQRTP",
      "productFamily": "Compute Instance",
      "attributes": {
        "enhancedNetworkingSupported": "Yes",
        "currentGeneration": "Yes",
        "operation": "RunInstances",
        "instanceType": "m4.4xlarge",
        "vcpu": "16",
        "storage": "EBS only",
        "location": "US West (Oregon)",
        "memory": "64 GiB",
        "processorFeatures": "Intel AVX; Intel AVX2; Intel Turbo",
        "networkPerformance": "High",
        "usagetype": "USW2-BoxUsage:m4.4xlarge",
        "processorArchitecture": "64-bit",
        "tenancy": "Shared",
        "servicecode": "AmazonEC2",
        "dedicatedEbsThroughput": "2000 Mbps",
        "instanceFamily": "General purpose",
        "locationType": "AWS Region",
        "licenseModel": "No License required",
        "preInstalledSw": "NA",
        "clockSpeed": "2.4 GHz",
        "physicalProcessor": "Intel Xeon E5-2676 v3 (Haswell)",
        "operatingSystem": "Linux"
      }
    },
    "price": [
      {
        "sku": "BMEYUTP658QKQRTP",
        "termAttributes": {},
        "effectiveDate": "2015-12-01T00:00:00Z",
        "offerTermCode": "JRTCKXETXF",
        "priceDimensions": {
          "BMEYUTP658QKQRTP.JRTCKXETXF.6YS6EN2CT7": {
            "description": "$1.008 per On Demand Linux m4.4xlarge Instance Hour",
            "pricePerUnit": {
              "USD": "1.0080000000"
            },
            "rateCode": "BMEYUTP658QKQRTP.JRTCKXETXF.6YS6EN2CT7",
            "endRange": "Inf",
            "beginRange": "0",
            "appliesTo": [],
            "unit": "Hrs"
          }
        }
      }
    ]
  }
]

制限事項

  • 対象が100件を超える条件はエラーが返ります
  • 最大40MBのJSONをパースして検索するヘビーな処理なので 10 request/sec のスロットルを設定してます *1

ざっくり構築方法

1. ソースを取得

git clone git@github.com:willyworks/aws-price-api.git

2. Lambda functionをデプロイ

virtualenv -p /path/to/python2.7 .venv
. .venv/bin/activate
pip install -r requirements.txt
lamvery deploy

デプロイは拙作のこちらを使ってます。詳しくはLambda縛り Advent Calendar 2015の16日で書きたいと思ってます。

github.com

3. Amazon API Gateway Swagger ImporterでAPIを定義する

Amazon API Gateway Swagger ImporterでAPIを一発で定義する | Developers.IO

4. Lambda functionの紐付けとMapping Templates設定

こんな感じ。

f:id:FumblePerson:20151211234611p:plain

Mapping Templates↓

{
    "offer" : "$input.params('offer')",
    "term": "$input.params('term')",
    "condition": $input.json('$')
}

4. CORS設定

docs.aws.amazon.com

5. Deploy API!!

所感など

  • Price List API生で使うのツラい
  • 変更通知がSNSで受けれるらしいし、データストアに突っ込んで通知をトリガーに更新させることを想定してる?
  • LambdaもAPIのデータ受け取るのに一番時間かかってる。Lambdaから叩ける低レイテンシなキャッシュほしい。*2
  • Reservedで期間指定できるようにしたり、もうちょっとAPIの改善もしたいかも

というわけで

以上です!当初は以下のどちらかにしようと思ってましたが、予定を変更してお送りしました!

  • KinesisJava以外のKCLの仕様と実装について
  • OpsWorksのTips系

この辺はまたの機会に!

*1:個人アカウントなので課金状況見て止める可能性があります(ただお金くれとはいはないから、個人事業の方に仕事くれる形とかで支援してくれても良いんですよ :-) ?)

*2:AppEngineのMemcache(無料)的な。っていうかAppEngineで作ったら良かったんじゃね?w