lib/amazon-pricing/definitions/rds-instance-type.rb
require 'amazon-pricing/definitions/instance-type'
module AwsPricing
class RdsInstanceType < InstanceType
def initialize(region, api_name, name)
@category_types = {}
@region = region
@name = name
@api_name = api_name
# Let's look up using the standard name but need to remove leading "db." to do so
api_name_for_lookup = api_name.sub("db.", "")
@disk_in_gb = InstanceType.get_disk(api_name_for_lookup)
@platform = InstanceType.get_platform(api_name_for_lookup)
@disk_type = InstanceType.get_disk_type(api_name_for_lookup)
@memory_in_mb = InstanceType.get_memory(api_name_for_lookup)
@compute_units = InstanceType.get_compute_units(api_name_for_lookup)
@virtual_cores = InstanceType.get_virtual_cores(api_name_for_lookup)
end
# database_type = :mysql, :oracle, :sqlserver
# type_of_instance = :ondemand, :light, :medium, :heavy
def available?(database_type = :mysql, type_of_instance = :ondemand, is_multi_az, is_byol)
db = get_category_type(database_type, is_multi_az, is_byol)
return false if db.nil?
db.available?(type_of_instance)
end
def update_pricing(database_type, type_of_instance, json, is_multi_az, is_byol)
db = get_category_type(database_type, is_multi_az, is_byol)
if db.nil?
db = DatabaseType.new(self, database_type)
if is_multi_az == true and is_byol == true
@category_types["#{database_type}_byol_multiaz"] = db
elsif is_multi_az == true and is_byol == false
@category_types["#{database_type}_multiaz"] = db
elsif is_multi_az == false and is_byol == true
@category_types["#{database_type}_byol"] = db
else
@category_types[database_type] = db
end
end
if type_of_instance == :ondemand
values = RdsInstanceType::get_values(json, database_type)
price = coerce_price(values[database_type.to_s])
db.set_price_per_hour(type_of_instance, nil, price)
else
# Amazon has another data error where they are still exposing reserved instance types when they do not actually exist (e.g. SQL Server t1.micro).
# Just warn and continue.
if db.ondemand_price_per_hour.nil?
$stderr.puts "WARNING: Skipping RDS instance type #{api_name}:#{database_type}:#{type_of_instance}:#{is_multi_az}:#{is_byol} due to lack of on-demand pricing"
return
end
json['valueColumns'].each do |val|
# As of 2014-04-02 we see entries w/o pricing, e.g. sqlserver_web heavy 1 year reservation = {"prices"=>{"USD"=>{}}, "name"=>"yrTerm1"}
if val['prices']['USD'].empty?
#puts "The following instance type does not have pricing: #{@region.name} : #{@api_name} : #{database_type} : #{type_of_instance} : #{val['name']} : #{is_multi_az} : #{is_byol}"
next
end
price = coerce_price(val['prices']['USD'])
case val["name"]
when "yrTerm1", "yrTerm1Standard"
db.set_prepay(type_of_instance, :year1, price)
when "yrTerm3", "yrTerm3Standard"
db.set_prepay(type_of_instance, :year3, price)
when "yrTerm1Hourly"
db.set_price_per_hour(type_of_instance, :year1, price)
when "yrTerm3Hourly"
db.set_price_per_hour(type_of_instance, :year3, price)
when "yearTerm1Hourly"
db.set_price_per_hour(type_of_instance, :year1, price)
when "yearTerm3Hourly"
db.set_price_per_hour(type_of_instance, :year3, price)
else
$stderr.puts "[#{__method__}] WARNING: unknown term:#{val["name"]}"
end
end
end
# Copy byol prices from oracle_se to oracle_{ee,se1,se2}
if database_type == :oracle_se && is_byol
update_pricing :oracle_ee, type_of_instance, json, is_multi_az, is_byol
update_pricing :oracle_se1, type_of_instance, json, is_multi_az, is_byol
update_pricing :oracle_se2, type_of_instance, json, is_multi_az, is_byol
end
end
def update_pricing_new(database_type, type_of_instance, prices, term = nil, is_multi_az, is_byol)
db = get_category_type(database_type, is_multi_az, is_byol)
if db.nil?
db = DatabaseType.new(self, database_type)
if is_multi_az == true and is_byol == true
@category_types["#{database_type}_byol_multiaz"] = db
elsif is_multi_az == true and is_byol == false
@category_types["#{database_type}_multiaz"] = db
elsif is_multi_az == false and is_byol == true
@category_types["#{database_type}_byol"] = db
else
@category_types[database_type] = db
end
end
terms_to_years = {
"yrTerm1" => :year1,
"yrTerm3" => :year3,
"yrTerm1Standard" => :year1,
"yrTerm3Standard" => :year3
}
years = terms_to_years[term]
if years.nil?
$stderr.puts "[#{__method__}] WARNING: unknown term:#{val["name"]}"
end
prices.each do |price|
p = coerce_price(price['prices']['USD'])
case price['name']
when 'upfront'
db.set_prepay(type_of_instance, years, p.to_f) unless type_of_instance == :noupfront || p == "N/A"
when 'monthlyStar'
# note for partialupfront, this purposely differs from AWS' "effective hourly" since we do not
# include the amortization of the partialupfront cost into this rate.
db.set_price_per_hour(type_of_instance, years, p.to_f * 12 / 365 / 24) unless type_of_instance == :allupfront || p == "N/A"
else
# Do nothing for other names
end
end
# Copy byol prices from oracle_se to oracle_{ee,se1,se2}
if database_type == :oracle_se && is_byol
update_pricing_new :oracle_ee, type_of_instance, prices, term, is_multi_az, is_byol
update_pricing_new :oracle_se1, type_of_instance, prices, term, is_multi_az, is_byol
update_pricing_new :oracle_se2, type_of_instance, prices, term, is_multi_az, is_byol
end
end
def update_pricing2(database_type, type_of_instance, is_multi_az, is_byol, ondemand_pph = nil, year1_prepay = nil, year3_prepay = nil, year1_pph = nil, year3_pph = nil)
db = get_category_type(database_type, is_multi_az, is_byol)
if db.nil?
db = DatabaseType.new(self, database_type)
if is_multi_az == true and is_byol == true
@category_types["#{database_type}_byol_multiaz"] = db
elsif is_multi_az == true and is_byol == false
@category_types["#{database_type}_multiaz"] = db
elsif is_multi_az == false and is_byol == true
@category_types["#{database_type}_byol"] = db
else
@category_types[database_type] = db
end
end
db.set_price_per_hour(type_of_instance, nil, coerce_price(ondemand_pph)) unless ondemand_pph.nil?
db.set_prepay(type_of_instance, :year1, coerce_price(year1_prepay)) unless year1_prepay.nil?
db.set_prepay(type_of_instance, :year3, coerce_price(year3_prepay)) unless year3_prepay.nil?
db.set_price_per_hour(type_of_instance, :year1, coerce_price(year1_pph)) unless year1_pph.nil?
db.set_price_per_hour(type_of_instance, :year3, coerce_price(year3_pph)) unless year3_pph.nil?
end
protected
# Returns [api_name, name]
# e.g. memDBCurrentGen, db.m3.medium
def self.get_name(instance_type, api_name, is_reserved = false)
# Temporary hack: Amazon has released r3 instances but pricing has api_name with asterisk (e.g. "r3.large *")
api_name.sub!(" *", "")
# Note: These api names are specific to RDS, not sure why Amazon has given them different API names (note: they have leading "db.")
#'cr1.8xl' => 'High-Memory Cluster Eight Extra Large',
#'micro' => 'Micro',
#'sm' => 'Standard Small',
#'xxlHiMem' => 'Hi-Memory Double Extra Large'
if ["db.cr1.8xl", "db.micro", "db.sm", "db.xxlHiMem", "sm", "micro", "xxlHiMem"].include? api_name
case api_name
when "db.cr1.8xl"
api_name = "db.cr1.8xlarge"
when "db.xxlHiMem", "xxlHiMem"
api_name = "db.m2.2xlarge"
when "db.micro", "micro"
api_name = "db.t1.micro"
when "db.sm", "sm"
api_name = "db.m1.small"
end
end
# Let's look up using the standard name but need to remove leading "db." to do so
api_name_for_lookup = api_name.sub("db.", "")
# Let's handle new instances more gracefully
unless @@Name_Lookup.has_key? api_name_for_lookup
raise UnknownTypeError, "Unknown instance type #{instance_type} #{api_name}", caller
end
name = @@Name_Lookup[api_name_for_lookup]
[api_name, name]
end
end
end