module AwsPricing::Ec2Common
Public Instance Methods
ensure_existence_of_instance_type(region, region_name, api_name, operating_system, type_json)
click to toggle source
let's make sure instance_type for this region has been setup correctly
# File lib/amazon-pricing/common/ec2_common.rb 79 def ensure_existence_of_instance_type(region, region_name, api_name, operating_system, type_json) 80 # input: region 81 # region_name 82 # api_name 83 # operating_system 84 # json: ri_v2 which describes instance_type (under region) 85 instance_type = find_or_create_instance_type(region, api_name, operating_system) 86 if not instance_type.nil? 87 set_od_price_if_missing(region, region_name, api_name, operating_system, instance_type, type_json) 88 end 89 instance_type 90 end
fetch_ec2_instance_pricing(url, type_of_instance, operating_system)
click to toggle source
Retrieves the EC2 on-demand instance pricing. type_of_instance = :ondemand, :light, :medium, :heavy
# File lib/amazon-pricing/common/ec2_common.rb 7 def fetch_ec2_instance_pricing(url, type_of_instance, operating_system) 8 res = PriceList.fetch_url(url) 9 res['config']['regions'].each do |reg| 10 region_name = reg['region'] 11 region = get_region(region_name) 12 if region.nil? 13 $stderr.puts "[fetch_ec2_instance_pricing] WARNING: unable to find region #{region_name}" 14 next 15 end 16 # e.g. type = {"type"=>"hiCPUODI", "sizes"=>[{"size"=>"med", "valueColumns"=>[{"name"=>"mswinSQL", "prices"=>{"USD"=>"N/A"}}]}, {"size"=>"xl", "valueColumns"=>[{"name"=>"mswinSQL", "prices"=>{"USD"=>"2.427"}}]}]} 17 reg['instanceTypes'].each do |type| 18 # e.g. size = {"size"=>"xl", "valueColumns"=>[{"name"=>"mswinSQL", "prices"=>{"USD"=>"2.427"}}]} 19 # Amazon now can return array or hash here (hash = only 1 item) 20 items = type['sizes'] 21 items = [type] if items.nil? 22 items.each do |size| 23 begin 24 api_name, name = Ec2InstanceType.get_name(type["type"], size["size"], type_of_instance != :ondemand) 25 instance_type = region.add_or_update_ec2_instance_type(api_name, name) 26 instance_type.update_pricing(operating_system, type_of_instance, size) 27 rescue UnknownTypeError 28 $stderr.puts "[fetch_ec2_instance_pricing] WARNING: encountered #{$!.message}" 29 end 30 end 31 end 32 end 33 end
fetch_ec2_instance_pricing_ri_v2(url, operating_system)
click to toggle source
With v2 of RIs they have an entirely new format that needs to be parsed
# File lib/amazon-pricing/common/ec2_common.rb 36 def fetch_ec2_instance_pricing_ri_v2(url, operating_system) 37 res = PriceList.fetch_url(url) 38 res['config']['regions'].each do |reg| 39 region_name = reg['region'] 40 region = get_region(region_name) 41 if region.nil? 42 $stderr.puts "[fetch_ec2_instance_pricing_ri_v2] WARNING: unable to find region #{region_name}" 43 next 44 end 45 reg['instanceTypes'].each do |type| 46 api_name = type["type"] 47 instance_type = ensure_existence_of_instance_type(region, region_name, api_name, operating_system, type) 48 if instance_type.nil? 49 $stderr.puts "[fetch_ec2_instance_pricing_ri_v2] WARNING: new reserved instances not found for #{api_name} in #{region_name} using #{url}" 50 next 51 end 52 53 type["terms"].each do |term| 54 term["purchaseOptions"].each do |option| 55 case option["purchaseOption"] 56 when "noUpfront" 57 reservation_type = :noupfront 58 when "allUpfront" 59 reservation_type = :allupfront 60 when "partialUpfront" 61 reservation_type = :partialupfront 62 end 63 64 duration = term["term"] 65 prices = option["valueColumns"] 66 upfront = prices.select{|i| i["name"] == "upfront"}.first 67 price = upfront["prices"]["USD"] 68 instance_type.update_pricing_new(operating_system, reservation_type, price, duration, true) unless reservation_type == :noupfront || price == "N/A" 69 hourly = prices.select{|i| i["name"] == "monthlyStar"}.first 70 price = hourly["prices"]["USD"] 71 instance_type.update_pricing_new(operating_system, reservation_type, price, duration, false) unless reservation_type == :allupfront || price == "N/A" 72 end 73 end 74 end 75 end 76 end
find_or_create_instance_type(region, api_name, operating_system)
click to toggle source
see if instance_type is missing; normally fetch_ec2_instance_pricing
() adds instance_type and od-pricing; but if there's AWS inconsistency, make sure we add instance_type now.
# File lib/amazon-pricing/common/ec2_common.rb 94 def find_or_create_instance_type(region, api_name, operating_system) 95 instance_type = nil 96 if not region.instance_type_available?(api_name, :ondemand, operating_system) 97 begin 98 api_name, name = Ec2InstanceType.get_name("", #unused 99 api_name, 100 false) #!:ondemand 101 instance_type = region.add_or_update_ec2_instance_type(api_name, name) 102 rescue UnknownTypeError 103 $stderr.puts "[#{__method__}] WARNING: unknown Ec2InstanceType:#{api_name} ignored" 104 end 105 elsif 106 instance_type = region.get_ec2_instance_type(api_name) 107 end 108 instance_type 109 end
set_od_price_if_missing(region, region_name, api_name, operating_system, instance_type, type_json)
click to toggle source
OnDemand pricing might be missing, and it's a prerequisite for it to be there for our model. one reason it's missing, is AWS added a new instance type, and we only find it now in ri
# File lib/amazon-pricing/common/ec2_common.rb 113 def set_od_price_if_missing(region, region_name, api_name, operating_system, instance_type, type_json) 114 type_json["terms"].each do |term| 115 # handle case of ondemand pricing missing; turns out od-pricing is also in ri-pricing 116 # (assumes od pricing has been set, iff both api_name+os are available) 117 if not region.instance_type_available?(api_name, :ondemand, operating_system) 118 # nb: we actually don't each-iterate below, and ignore extraneous iterations 119 term["onDemandHourly"].each do |od_option| 120 # handle case of ondemand pricing missing from non-ri case, let's try populating it here 121 # [{purchaseOption:"ODHourly",rate:"perhr",prices:{USD:"13.338"}}], 122 if od_option["purchaseOption"] != "ODHourly" || od_option["rate"] != "perhr" 123 $stderr.puts "[set_od_price_if_missing] WARNING unexpected od_option #{od_option}" 124 end 125 price = od_option["prices"]["USD"] 126 instance_type.update_pricing_new(operating_system, :ondemand, price) 127 $stderr.puts "od pricing update #{api_name} price #{price} for #{region_name}/#{operating_system}" 128 # prevent iteration, since it doesn't make sense, noting it's (theoretically) possible 129 break 130 end 131 end 132 end 133 # assert if we're still missing :ondemand, we'll eventually fail in our model 134 if not region.instance_type_available?(api_name, :ondemand, operating_system) 135 raise "new reserved instances missing ondemand for #{api_name} in #{region_name}/#{operating_system}}" 136 end 137 end