AWS Price List Query API（aws pricingコマンド）でAmazonEC2サービスの情報を取得してみる

以前、下記記事にてPowerQueryでBulk APIを利用してみました。

[PowerQueryでAWS Price List API (AKA the Bulk API) からオファーファイルの一覧を取得する](https://qiita.com/SAITO_Keita/items/a41861a030efcfd1f46c)

今回はドキュメントにある`Query API`でAmazonEC2の情報を取得してみます。

[クエリ API を使用する](https://docs.aws.amazon.com/awsaccountbilling/latest/aboutv2/using-pelong.html)

## AWS Price List Query APIについて

[クエリ API を使用する](https://docs.aws.amazon.com/awsaccountbilling/latest/aboutv2/using-pelong.html)

上記ドキュメントに説明がありますが、`AWS Price List Query API`は`SKU`レベルの料金を取得する事ができるAPIとなり現在`Savings Plans`には対応していないとあります。

またAPIの実行に関して、SDKの仕様がおすすめとあるので、今回はコマンドラインツールである`aws-cli v2`をPowerShellから実行してみます。

## エンドポイントについて

[aws-cli / pricing](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/pricing/index.html)

`aws-cli`ではサブコマンド `pricing`が該当し、サービスエンドポイントは下記の2箇所となります。

- https://api.pricing.us-east-1.amazonaws.com
- https://api.pricing.ap-south-1.amazonaws.com

このため、`aws-cli`でコマンドを実行する際は、regionを`us-east-1`か`ap-south-1`を選択します。

## aws pricingで提供されるコマンド

`pricing`ではサブコマンドとして下記の3つが提供されていました。

- describe-services
- get-attribute-values
- get-products

### describe-services

`describe-services`はAWSの`ServiceCode`と対応する`AttributeNames`を返す

AmazonEC2サービスで取得できる`AttrivuteNames`を取得する場合は下記のようにコマンド実行。

```PowerShell
aws pricing describe-services --region us-east-1 --service-code AmazonEC2 --output json
```

```json
{
    "Services": [
        {
            "ServiceCode": "AmazonEC2",
            "AttributeNames": [
                "instanceCapacityMetal",
                "volumeType",
                "maxIopsvolume",
                "instance",
                "classicnetworkingsupport",
                "instanceCapacity10xlarge",
                "fromRegionCode",
                "locationType",
                "toLocationType",
                "instanceFamily",
                "operatingSystem",
                "toRegionCode",
                "clockSpeed",
                "LeaseContractLength",
                "ecu",
                "networkPerformance",
                "instanceCapacity8xlarge",
                "group",
                "maxThroughputvolume",
                "gpuMemory",
                "ebsOptimized",
                "vpcnetworkingsupport",
                "maxVolumeSize",
                "gpu",
                "intelAvxAvailable",
                "processorFeatures",
                "instanceCapacity4xlarge",
                "servicecode",
                "groupDescription",
                "elasticGraphicsType",
                "volumeApiName",
                "processorArchitecture",
                "physicalCores",
                "fromLocation",
                "snapshotarchivefeetype",
                "marketoption",
                "availabilityzone",
                "productFamily",
                "fromLocationType",
                "enhancedNetworkingSupported",
                "intelTurboAvailable",
                "memory",
                "dedicatedEbsThroughput",
                "vcpu",
                "OfferingClass",
                "instanceCapacityLarge",
                "capacitystatus",
                "termType",
                "storage",
                "toLocation",
                "intelAvx2Available",
                "storageMedia",
                "regionCode",
                "physicalProcessor",
                "provisioned",
                "servicename",
                "PurchaseOption",
                "instancesku",
                "productType",
                "instanceCapacity18xlarge",
                "instanceType",
                "tenancy",
                "usagetype",
                "normalizationSizeFactor",
                "instanceCapacity16xlarge",
                "instanceCapacity2xlarge",
                "maxIopsBurstPerformance",
                "instanceCapacity12xlarge",
                "instanceCapacity32xlarge",
                "instanceCapacityXlarge",
                "licenseModel",
                "currentGeneration",
                "preInstalledSw",
                "transferType",
                "location",
                "instanceCapacity24xlarge",
                "instanceCapacity9xlarge",
                "instanceCapacityMedium",
                "operation",
                "resourceType"
            ]
        }
    ],
    "FormatVersion": "aws_v1"
}
```

### get-attribute-vales

`get-attribute-values`は`ServiceCode`と`AttributeNames`を指定すると、含まれている値のリストを返します。

```PowerShell
aws pricing get-attribute-values --service-code AmazonEC2 --attribute-name instanceType --region us-east-1 --output json
```

```json
# 出力件数が多いので途中まで
{
    "AttributeValues": [
        {
            "Value": "a1.2xlarge"
        },
        {
            "Value": "a1.4xlarge"
        },
        {
            "Value": "a1.large"
        },
        {
            "Value": "a1.medium"
        },
        {
            "Value": "a1.metal"
        },
        {
            "Value": "a1.xlarge"
        },
        {
            "Value": "a1"
        },
        {
            "Value": "c1.medium"
        },
        {
            "Value": "c1.xlarge"
        },
-- More  --
```

### get-products

`get-products`ではsku単位の製品情報と価格情報を取得できます。

AmazonEC2サービスではリージョン、テナンシー、OS、事前インストールソフトウェア、キャパシティ予約などなど組み合わせとなる項目が非常に多く。

`get-products`コマンドで`AmazonEC2`サービスを取得する際は、filterを適切に利用しないとだいぶ大変なことになります。
（AmazonEC2サービスは組み合わせが爆発していて……）

このため今回実行するコマンドでは、`filter`オプションで下記を指定して実行してみます。
※フィルタの掛け方によっては、件数が膨大となりページング処理が必要になるので注意が必要です。

- region ap-northeast-1
- operatingSystem Linux
- productFamily Compute Instance
- preInstalledSw NA
- tenancy Shared
- capacitystatus Used

フィルタオプションの指定方法は、"Type=TERM_MATCH,Field=regionCode,Value=ap-northeast-1" のように

- typeにTERM_MATCH。
- FiledにAttributeNames。
- Valueにフィルタする値

といった形式でオプションを設定します。

```PowerShell

#AmazonEC2サービスで下記の条件でフィルタ

# region ap-northeast-1
# operatingSystem Linux
# productFamily Compute Instance
# preInstalledSw NA
# tenancy Shared
# capacitystatus Used

# 実行方法①　filterオプションに直書き
$target=aws pricing get-products --service-code AmazonEC2 --region us-east-1 --filters "Type=TERM_MATCH,Field=regionCode,Value=ap-northeast-1" "Type=TERM_MATCH,Field=operatingSystem,Value=Linux" "Type=TERM_MATCH,Field=productFamily,Value=Compute Instance" "Type=TERM_MATCH,Field=preInstalledSw,Value=NA" "Type=TERM_MATCH,Field=tenancy,Value=Shared" "Type=TERM_MATCH,Field=capacitystatus,Value=Used" --output json

# 実行方法②　変数filterを作ってから渡す
$filters = @()
$filters += "Type=TERM_MATCH,Field=regionCode,Value=ap-northeast-1"
$filters += "Type=TERM_MATCH,Field=operatingSystem,Value=Linux"
$filters += "Type=TERM_MATCH,Field=productFamily,Value=Compute Instance"
$filters += "Type=TERM_MATCH,Field=preInstalledSw,Value=NA"
$filters += "Type=TERM_MATCH,Field=tenancy,Value=Shared"
$filters += "Type=TERM_MATCH,Field=capacitystatus,Value=Used"

$target=aws pricing get-products --service-code AmazonEC2 --region us-east-1 --filters $filters --output json

```

戻ってきた値を参照すると、AmazonEC2サービスの構造はなかなか複雑そうです。
`priceList`の中の更にjsonで情報が格納されていたり、それが深い構造（productとterms）になっていたり……

色々と大変なので、ここではproductの一覧を下記のように展開するだけ展開してみます。

```PowerShell
$target | ConvertFrom-json | select -ExpandProperty priceList | ConvertFrom-Json | Select-Object -ExpandProperty product | Select-Object -ExpandProperty attributes
```

## 総評

`AWS Price List Query API`（aws-cli pricingサブコマンド）を利用して

- `describe-services`を使い対象サービスではどのような`AttributeNames`があるのか
- `get-attribute-vales`を使い、どのような値が存在するのか
- `get-products`ではSKUピンポイントでどのような価格があるか

といった部分を確認するにはよさそうです。

`get-products`については、AmazonEC2サービスで利用しようとすると、パターンが多すぎてフィルタしないことにはとんでもないことになる部分が残念ですが。