Azureの料金データをAPIで取得する

クラウド上でシステム構築する際、料金を確認することが必要になるわけですが、各ベンダーが出している料金計算ツールはなんとなく使いにくい感じがします(個人の感想)。

calculator.aws

azure.microsoft.com

仮想マシンとかは数が多いので、料金を中心に考えた場合どれを選べばいいかはちょっと悩ましかったりします。そこで、簡単に確認できるように料金データをAPIで取得してCSV化してみることを思いつきました。取り急ぎ、Azureで。

APIとしては以下のドキュメントが公開されています。APIの利用に特に認証も必要ないです。

learn.microsoft.com

このAPIを簡単に解析するプログラムをRubyで書いてみました。日本円、東日本リージョン、仮想マシンを対象にしています。

# frozen_string_literal: true

require 'open-uri'
require 'json'
require 'net/http'

# MyAzurePriceTool はAzureの料金情報をAPIを使って取得するツール
class MyAzurePriceTool
  AZURE_PRICE_API = 'https://prices.azure.com/api/retail/prices?currencyCode=\'JPY\''
  AZURE_REGION_CODE = 'japaneast'
  AZURE_SERVICE_NAME = 'Virtual Machines'

  def initialize
    @api_results = []
    @prices = []
  end

  def run
    call_api(request_url)
    price_extract
  end

  def request_url
    filters = []
    filters.push("serviceName eq '#{AZURE_SERVICE_NAME}'")
    filters.push("armregionName eq '#{AZURE_REGION_CODE}'")
    filters.push("priceType eq 'Consumption'")
    "#{AZURE_PRICE_API}&$filter=#{filters.join(' and ')}"
  end

  def call_api(uri)
    j = JSON.parse(URI.parse(uri).open.read, symbolize_names: true)
    @api_results += j[:Items]
    until j[:NextPageLink].nil?
      j = call_api(j[:NextPageLink])
      @api_results.push(j)
    end
  end

  def price_extract
    @api_results.each do |item|
      @prices.push(
        {
          armSkuName: item[:armSkuName],
          armRegionName: item[:armRegionName],
          unitPrice: item[:unitPrice],
          currencyCode: item[:currencyCode],
          productName: item[:productName],
          unitOfMeasure: item[:unitOfMeasure]
        }
      )
    end
  end

  def print_prices
    @prices.each do |price|
      puts price
    end
  end
end

my_azure_price_tool = MyAzurePriceTool.new

my_azure_price_tool.run
my_azure_price_tool.print_prices

これでこんな感じの結果が得られます。

(省略)
{:armSkuName=>"NVsv3_Type1", :armRegionName=>"japaneast", :unitPrice=>927.0144, :currencyCode=>"JPY", :productName=>"NVSv3 Series Dedicated Host", :unitOfMeasure=>"1 Hour"}
{:armSkuName=>"Easv4_Type2", :armRegionName=>"japaneast", :unitPrice=>1070.227, :currencyCode=>"JPY", :productName=>"Easv4 Series Dedicated Host", :unitOfMeasure=>"1 Hour"}
{:armSkuName=>"Standard_A7", :armRegionName=>"japaneast", :unitPrice=>30.0026, :currencyCode=>"JPY", :productName=>"Virtual Machines A Series", :unitOfMeasure=>"1 Hour"}
(省略)

いろいろと決めうちしているので、もう少し汎用性を持たせたいところですが、とりあえずこんなもので。リージョンも東日本リージョンと西日本リージョンが同時に取れたらいいんだけれども、上手い解決方法が思いつきませんでした。