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