amazon-pricing 0.1.40 → 0.1.41

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- NmU3NDVjMjhjYmU2ZGNlYWNmNzc2NTgzNzgwM2Y4ZjM4YTIxYWFjOQ==
4
+ NjUzMDA0NDJhZWY5NjllNWI5ZTdmNmQyMjM5ZDY0ZDViOTM2NmMzMQ==
5
5
  data.tar.gz: !binary |-
6
- NWEyNWQzNWRmMzY0NjIzOGU0MjZjMDZiNDExYTM0ZDY0NWIxZWE4MQ==
6
+ ODJjYWM0M2NjMjY2NjIyNmQyMjUwZWQzZWE2YWM4Y2E4ZDEzOTIxNw==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- YjllNmM3Njg1ZjBjOTAzNGE5ZDU1OTUyYWExOGYwYWViODMzOTQwZjZkNzhi
10
- MmJiNTZlMmQ2NGI3YjRkZDlhZWQ5NTc5ZDBlZTZjYTc2MmQ1YzI4OGM3YmE2
11
- NmE5Y2E1ZTNiNmVkZDMyZThiZTAyNDcxY2I5OGJhZDdhNTY4MGI=
9
+ Y2I4ZjIxMTA3YTA4OGRiZTdhMDYyNDEwNTJlMDA5YzdmMjNiYTBlODUzZDNh
10
+ ZDJlYzIyZjEzNDU5OTFlNTNlZTM1Nzk0MGNhN2E0MDU1ZDM5OGZhNTA4ZTRi
11
+ ZmNlMTllNTEzZGQ0YmVhZGYyZjJmZjZmYjJmZGJkOTdmNWVjNzc=
12
12
  data.tar.gz: !binary |-
13
- YjU5NmY0NThlMzA5OWE0NTg1NTYxMmZkMjQ5MjM3NTFkOTc1ZjNlM2Y4OGUz
14
- ZjZjYzQyNjdjNmVhOTE0ZmMxMGM1YjBjMmZlMDgwODVlYmZjODlkZTkyMzZl
15
- ZDJhM2Y1MTM1ZTAwYjQwZmQ1OWFjZmJkZjhjZjM5OTc0NjAxYzg=
13
+ MjYzOWNiNjE0N2Q5NjRkYjVkYjM2ZmU2NjA4NDA4ZTBjYjQzNWQzYWRmYWNi
14
+ NTBmNGY1OTYxZDNjOGFjZGUxOWM2YTQ3YzVjZjg1NTU2MzE1ZDZkZmM2NzE2
15
+ ZjBjNWZhN2EzZGFlMmIyNzQ5ZmRlM2QxMTE5Yzc3MDYwYzk5MWM=
@@ -5,534 +5,7 @@ require 'mechanize'
5
5
 
6
6
  Dir[File.join(File.dirname(__FILE__), 'amazon-pricing/*.rb')].sort.each { |lib| require lib }
7
7
 
8
- #--
9
- # Amazon Web Services Pricing Ruby library
10
- #
11
- # Ruby Gem Name:: amazon-pricing
12
- # Author:: Joe Kinsella (mailto:joe.kinsella@gmail.com)
13
- # Copyright:: Copyright (c) 2011-2013 CloudHealth
14
- # License:: Distributes under the same terms as Ruby
15
- # Home:: http://github.com/CloudHealth/amazon-pricing
16
- #++
17
- module AwsPricing
18
-
19
- # PriceList provides the primary interface for retrieving AWS pricing.
20
- # Upon instantiating a PriceList object, all the corresponding pricing
21
- # information will be retrieved from Amazon via currently undocumented
22
- # json APIs.
23
- class PriceList
24
- attr_accessor :regions
25
-
26
- def get_region(name)
27
- @_regions[@@Region_Lookup[name] || name]
28
- end
29
-
30
- def regions
31
- @_regions.values
32
- end
33
-
34
- def get_instance_types
35
- instance_types = []
36
- @_regions.each do |region|
37
- region.ec2_instance_types.each do |instance_type|
38
- instance_types << instance_type
39
- end
40
- end
41
- instance_types
42
- end
43
-
44
- def get_instance_type(region_name, api_name)
45
- region = get_region(region_name)
46
- raise "Region #{region_name} not found" if region.nil?
47
- region.get_instance_type(api_name)
48
- end
49
-
50
- def self.fetch_url(url)
51
- uri = URI.parse(url)
52
- page = Net::HTTP.get_response(uri)
53
- # Now that AWS switched from json to jsonp, remove first/last lines
54
- body = page.body.gsub("callback(", "").reverse.sub(")", "").reverse
55
- if body.split("\n").last == ";"
56
- # Now remove one more line (rds is returning ";", ec2 empty line)
57
- body = body.reverse.sub(";", "").reverse
58
- elsif body[-1] == ";"
59
- body.chop!
60
- end
61
-
62
- begin
63
- JSON.parse(body)
64
- rescue JSON::ParserError
65
- # Handle "json" with keys that are not quoted
66
- # When we get {foo: "1"} instead of {"foo": "1"}
67
- # http://stackoverflow.com/questions/2060356/parsing-json-without-quoted-keys
68
- JSON.parse(body.gsub(/(\w+)\s*:/, '"\1":'))
69
- end
70
- end
71
-
72
- protected
73
-
74
- attr_accessor :_regions
75
-
76
- def add_region(region)
77
- @_regions[region.name] = region
78
- end
79
-
80
- def find_or_create_region(name)
81
- region = get_region(name)
82
- if region.nil?
83
- region = Region.new(name)
84
- add_region(region)
85
- end
86
- region
87
- end
88
-
89
- EC2_BASE_URL = "http://a0.awsstatic.com/pricing/1/ec2/"
90
- EBS_BASE_URL = "http://a0.awsstatic.com/pricing/1/ebs/"
91
- RDS_BASE_URL = "http://a0.awsstatic.com/pricing/1/rds/"
92
-
93
- # Lookup allows us to map to AWS API region names
94
- @@Region_Lookup = {
95
- 'us-east-1' => 'us-east',
96
- 'us-west-1' => 'us-west',
97
- 'us-west-2' => 'us-west-2',
98
- 'eu-west-1' => 'eu-ireland',
99
- 'ap-southeast-1' => 'apac-sin',
100
- 'ap-southeast-2' => 'apac-syd',
101
- 'ap-northeast-1' => 'apac-tokyo',
102
- 'sa-east-1' => 'sa-east-1'
103
- }
104
-
105
- end
106
-
107
-
108
- class GovCloudEc2PriceList < PriceList
109
- GOV_CLOUD_URL = "http://aws.amazon.com/govcloud-us/pricing/ec2/"
110
- GOV_CLOUD_EBS_URL = "http://aws.amazon.com/govcloud-us/pricing/ebs/"
111
-
112
- def initialize
113
- @_regions = {}
114
- @_regions["us-gov-west-1"] = Region.new("us-gov-west-1")
115
- InstanceType.populate_lookups
116
- get_ec2_instance_pricing
117
- fetch_ec2_ebs_pricing
118
- end
119
-
120
- protected
121
-
122
- def get_ec2_instance_pricing
123
-
124
- client = Mechanize.new
125
- page = client.get(GOV_CLOUD_URL)
126
- tables = page.search("//div[@class='aws-table section']")
127
- create_ondemand_instances(get_rows(tables[0]))
128
- create_ondemand_instances(get_rows(tables[1]))
129
-
130
- for i in 2..7
131
- create_reserved_instances(get_rows(tables[i]), :light)
132
- end
133
- for i in 8..13
134
- create_reserved_instances(get_rows(tables[i]), :medium)
135
- end
136
- for i in 14..19
137
- create_reserved_instances(get_rows(tables[i]), :heavy)
138
- end
139
-
140
- end
141
-
142
- # e.g. [["Prices / Hour", "Amazon Linux", "RHEL", "SLES"], ["m1.small", "$0.053", "$0.083", "$0.083"]]
143
- def create_ondemand_instances(rows)
144
- header = rows[0]
145
- @_regions.values.each do |region|
146
-
147
- rows.slice(1, rows.size).each do |row|
148
- api_name = row[0]
149
- instance_type = region.get_ec2_instance_type(api_name)
150
- if instance_type.nil?
151
- api_name, name = Ec2InstanceType.get_name(nil, row[0], false)
152
- instance_type = region.add_or_update_ec2_instance_type(api_name, name)
153
- end
154
- instance_type.update_pricing2(get_os(header[1]), :ondemand, row[1])
155
- instance_type.update_pricing2(get_os(header[2]), :ondemand, row[2])
156
- instance_type.update_pricing2(get_os(header[3]), :ondemand, row[3])
157
- end
158
- end
159
- end
160
-
161
- # e.g. [["RHEL", "1 yr Term Upfront", "1 yr TermHourly", "3 yr TermUpfront", "3 yr Term Hourly"], ["m1.small", "$68.00", "$0.099", "$105.00", "$0.098"]]
162
- def create_reserved_instances(rows, res_type)
163
- header = rows[0]
164
- operating_system = get_os(header[0])
165
- @_regions.values.each do |region|
166
-
167
- rows.slice(1, rows.size).each do |row|
168
- api_name = row[0]
169
- instance_type = region.get_instance_type(api_name)
170
- if instance_type.nil?
171
- api_name, name = Ec2InstanceType.get_name(nil, row[0], true)
172
- instance_type = region.add_or_update_ec2_instance_type(api_name, name)
173
- end
174
- instance_type.update_pricing2(operating_system, res_type, nil, row[1], row[3], row[2], row[4])
175
- end
176
- end
177
- end
178
-
179
- def fetch_ec2_ebs_pricing
180
- client = Mechanize.new
181
- page = client.get(GOV_CLOUD_EBS_URL)
182
- ebs_costs = page.search("//div[@class='text section']//li")
183
- @_regions.values.each do |region|
184
- region.ebs_price = EbsPrice.new(region)
185
- region.ebs_price.preferred_per_gb = get_ebs_price(ebs_costs[1])
186
- region.ebs_price.preferred_per_iops = get_ebs_price(ebs_costs[2])
187
- region.ebs_price.standard_per_gb = get_ebs_price(ebs_costs[3])
188
- region.ebs_price.standard_per_million_io = get_ebs_price(ebs_costs[4])
189
- region.ebs_price.ssd_per_gb = nil
190
- region.ebs_price.s3_snaps_per_gb = get_ebs_price(ebs_costs[5])
191
- end
192
-
193
- end
194
-
195
- # e.g. $0.065 per GB-Month of provisioned storage
196
- def get_ebs_price(xml_element)
197
- tokens = xml_element.text.split(" ")
198
- tokens[0].gsub("$", "").to_f
199
- end
200
-
201
- def get_os(val)
202
- case val
203
- when "Amazon Linux"
204
- :linux
205
- when "RHEL"
206
- :rhel
207
- when "SLES"
208
- :sles
209
- when "Windows"
210
- :mswin
211
- when "Windows SQL Server Web", "Windows SQL Server Web Edition"
212
- :mswinSQL
213
- when "Windows SQL Server Standard", "Windows SQL Server Standard Edition"
214
- :mswinSQLWeb
215
- else
216
- raise "Unable to identify operating system '#{val}'"
217
- end
218
- end
219
-
220
- def get_rows(html_table)
221
- rows = []
222
- html_table.search(".//tr").each do |tr|
223
- row = []
224
- tr.search(".//td").each do |td|
225
- row << td.inner_text.strip.sub("\n", " ").sub(" ", " ")
226
- end
227
- next if row.size == 1
228
- rows << row unless row.empty?
229
- end
230
- rows
231
- end
232
- end
233
-
234
-
235
- class GovCloudRdsPriceList < PriceList
236
- GOV_CLOUD_URL = "http://aws.amazon.com/govcloud-us/pricing/rds/"
237
-
238
- def initialize
239
- @_regions = {}
240
- @_regions["us-gov-west-1"] = Region.new("us-gov-west-1")
241
- InstanceType.populate_lookups
242
- get_rds_instance_pricing
243
- end
244
-
245
- protected
246
- #@@DB_TYPE = [:mysql, :postgresql, :oracle, :sqlserver]
247
- #@@RES_TYPES = [:light, :medium, :heavy]
248
-
249
- def get_rds_instance_pricing
250
-
251
- client = Mechanize.new
252
- page = client.get(GOV_CLOUD_URL)
253
- tables = page.search("//div[@class='aws-table section']")
254
-
255
- create_ondemand_instances(:mysql, :ondemand, false, false, get_rows(tables[0]))
256
- create_ondemand_instances(:mysql, :ondemand, true, false, get_rows(tables[1]))
257
- # Mysql
258
- no_multi_az_rows, multi_az_rows = get_reserved_rows(get_rows(tables[2]))
259
- create_reserved_instances(:mysql, :light, false, false, no_multi_az_rows)
260
- create_reserved_instances(:mysql, :light, true, false, multi_az_rows)
261
- no_multi_az_rows, multi_az_rows = get_reserved_rows(get_rows(tables[3]))
262
- create_reserved_instances(:mysql, :medium, false, false, no_multi_az_rows)
263
- create_reserved_instances(:mysql, :medium, true, false, multi_az_rows)
264
- no_multi_az_rows, multi_az_rows = get_reserved_rows(get_rows(tables[4]))
265
- create_reserved_instances(:mysql, :heavy, false, false, no_multi_az_rows)
266
- create_reserved_instances(:mysql, :heavy, true, false, multi_az_rows)
267
- # Oracle
268
- #no_multi_az_rows, multi_az_rows = get_reserved_rows(get_rows(tables[7]))
269
- #create_reserved_instances(:oracle_se1, :ondemand, false, false, no_multi_az_rows)
270
- #create_reserved_instances(:oracle_se1, :ondemand, true, false, multi_az_rows)
271
- end
272
-
273
- # e.g. [["General Purpose - Previous Generation", "Price Per Hour"], ["m1.small", "$0.090"], ["m1.medium", "$0.185"]]
274
- def create_ondemand_instances(db_type, res_type, is_multi_az, is_byol, rows)
275
- @_regions.values.each do |region|
276
- # Skip header row
277
- rows.slice(1, rows.size).each do |row|
278
- api_name = row[0]
279
- instance_type = region.get_rds_instance_type(api_name)
280
- if instance_type.nil?
281
- api_name, name = RdsInstanceType.get_name(nil, row[0], false)
282
- instance_type = region.add_or_update_rds_instance_type(api_name, name)
283
- end
284
- instance_type.update_pricing2(db_type, res_type, is_multi_az, is_byol, row[1])
285
- end
286
- end
287
- end
288
-
289
- # e.g. [[" ", "1 yr Term", "3 yr Term"], [" ", "Upfront", "Hourly", "Upfront", "Hourly"], ["m1.small", "$159", "$0.035", "$249", "$0.033"]]
290
- def create_reserved_instances(db_type, res_type, is_multi_az, is_byol, rows)
291
- @_regions.values.each do |region|
292
- rows.each do |row|
293
- api_name = row[0]
294
- instance_type = region.get_rds_instance_type(api_name)
295
- if instance_type.nil?
296
- api_name, name = RdsInstanceType.get_name(nil, row[0], true)
297
- instance_type = region.add_or_update_rds_instance_type(api_name, name)
298
- end
299
- instance_type.update_pricing2(db_type, res_type, is_multi_az, is_byol, nil, row[1], row[3], row[2], row[4])
300
- end
301
- end
302
- end
303
-
304
- def get_reserved_rows(rows)
305
- # Skip 2 header rows
306
- new_rows = rows.slice(2, rows.size)
307
- no_multi_az_rows = new_rows.slice(0, new_rows.size / 2)
308
- multi_az_rows = new_rows.slice(new_rows.size / 2, new_rows.size / 2)
309
- [no_multi_az_rows, multi_az_rows]
310
- end
311
-
312
- def get_rows(html_table)
313
- rows = []
314
- html_table.search(".//tr").each do |tr|
315
- row = []
316
- tr.search(".//td").each do |td|
317
- row << td.inner_text.strip.sub("\n", " ").sub(" ", " ")
318
- end
319
- # Various <tR> elements contain labels which have only 1 <td> - except heavy multi-az ;)
320
- next if row.size == 1 || row[0].include?("Multi-AZ Deployment")
321
- rows << row unless row.empty?
322
- end
323
- rows
324
- end
325
- end
326
-
327
-
328
-
329
- class Ec2PriceList < PriceList
330
-
331
- def initialize
332
- @_regions = {}
333
- InstanceType.populate_lookups
334
- get_ec2_on_demand_instance_pricing
335
- get_ec2_reserved_instance_pricing
336
- fetch_ec2_ebs_pricing
337
- end
338
-
339
- protected
340
-
341
- @@OS_TYPES = [:linux, :mswin, :rhel, :sles, :mswinSQL, :mswinSQLWeb]
342
- @@RES_TYPES = [:light, :medium, :heavy]
343
-
344
- def get_ec2_on_demand_instance_pricing
345
- @@OS_TYPES.each do |os|
346
- fetch_ec2_instance_pricing(EC2_BASE_URL + "#{os}-od.min.js", :ondemand, os)
347
- end
348
- # Rinse & repeat for legacy instances
349
- @@OS_TYPES.each do |os|
350
- fetch_ec2_instance_pricing(EC2_BASE_URL + "previous-generation/#{os}-od.min.js", :ondemand, os)
351
- end
352
- end
353
-
354
- def get_ec2_reserved_instance_pricing
355
- @@OS_TYPES.each do |os|
356
- @@RES_TYPES.each do |res_type|
357
- fetch_ec2_instance_pricing(EC2_BASE_URL + "#{os}-ri-#{res_type}.min.js", res_type, os)
358
- # Rinse & repeat for legacy instances (note: amazon changed URLs for legacy reserved instances)
359
- os_rewrite = os
360
- os_rewrite = "redhatlinux" if os == :rhel
361
- os_rewrite = "suselinux" if os == :sles
362
- os_rewrite = "mswinsqlstd" if os == :mswinSQL
363
- os_rewrite = "mswinsqlweb" if os == :mswinSQLWeb
364
- fetch_ec2_instance_pricing(EC2_BASE_URL + "previous-generation/#{res_type}_#{os_rewrite}.min.js", res_type, os)
365
- end
366
- end
367
- end
368
-
369
- # Retrieves the EC2 on-demand instance pricing.
370
- # type_of_instance = :ondemand, :light, :medium, :heavy
371
- def fetch_ec2_instance_pricing(url, type_of_instance, operating_system)
372
- res = PriceList.fetch_url(url)
373
- res['config']['regions'].each do |reg|
374
- region_name = reg['region']
375
- region = find_or_create_region(region_name)
376
- # e.g. type = {"type"=>"hiCPUODI", "sizes"=>[{"size"=>"med", "valueColumns"=>[{"name"=>"mswinSQL", "prices"=>{"USD"=>"N/A"}}]}, {"size"=>"xl", "valueColumns"=>[{"name"=>"mswinSQL", "prices"=>{"USD"=>"2.427"}}]}]}
377
- reg['instanceTypes'].each do |type|
378
- # e.g. size = {"size"=>"xl", "valueColumns"=>[{"name"=>"mswinSQL", "prices"=>{"USD"=>"2.427"}}]}
379
- # Amazon now can return array or hash here (hash = only 1 item)
380
- items = type['sizes']
381
- items = [type] if items.nil?
382
- items.each do |size|
383
- begin
384
- api_name, name = Ec2InstanceType.get_name(type["type"], size["size"], type_of_instance != :ondemand)
385
-
386
- instance_type = region.add_or_update_ec2_instance_type(api_name, name)
387
- instance_type.update_pricing(operating_system, type_of_instance, size)
388
- rescue UnknownTypeError
389
- $stderr.puts "WARNING: encountered #{$!.message}"
390
- end
391
- end
392
- end
393
- end
394
- end
395
-
396
- def fetch_ec2_ebs_pricing
397
- res = PriceList.fetch_url(EBS_BASE_URL + "pricing-ebs.min.js")
398
- res["config"]["regions"].each do |ebs_types|
399
- region = get_region(ebs_types["region"])
400
- region.ebs_price = EbsPrice.new(region)
401
- region.ebs_price.update_from_json(ebs_types)
402
- end
403
- end
404
-
405
- end
406
-
407
- class RdsPriceList < PriceList
408
-
409
- def initialize
410
- @_regions = {}
411
- InstanceType.populate_lookups
412
- get_rds_on_demand_instance_pricing
413
- get_rds_reserved_instance_pricing
414
- end
415
-
416
- protected
417
-
418
- @@DB_TYPE = [:mysql, :postgresql, :oracle, :sqlserver]
419
- @@RES_TYPES = [:light, :medium, :heavy]
420
-
421
- @@OD_DB_DEPLOY_TYPE = {
422
- :mysql=> {:mysql=>["standard","multiAZ"]},
423
- :postgresql=> {:postgresql=>["standard","multiAZ"]},
424
- :oracle=> {:oracle_se1=>["li-standard","li-multiAZ","byol-standard","byol-multiAZ"], :oracle_se=>["byol-standard","byol-multiAZ"], :oracle_ee=>["byol-standard","byol-multiAZ"]},
425
- :sqlserver=> {:sqlserver_ex=>["li-ex"], :sqlserver_web=>["li-web"], :sqlserver_se=>["li-se", "byol"], :sqlserver_ee=>["byol"]}
426
- }
427
-
428
-
429
- @@RESERVED_DB_DEPLOY_TYPE = {
430
- :oracle=> {:oracle_se1=>["li","byol"], :oracle_se=>["byol"], :oracle_ee=>["byol"]},
431
- :sqlserver=> {:sqlserver_ex=>["li-ex"], :sqlserver_web=>["li-web"], :sqlserver_se=>["li-se","byol"], :sqlserver_ee=>["byol"]}
432
- }
433
-
434
-
435
- def is_multi_az?(type)
436
- return true if type.match("multiAZ")
437
- false
438
- end
439
-
440
- def is_byol?(type)
441
- return true if type.match("byol")
442
- false
443
- end
444
-
445
- def get_rds_on_demand_instance_pricing
446
- @@DB_TYPE.each do |db|
447
- @@OD_DB_DEPLOY_TYPE[db].each {|db_type, db_instances|
448
- db_instances.each do |dp_type|
449
- #
450
- # to find out the byol type
451
- is_byol = is_byol? dp_type
452
-
453
- if [:mysql, :postgresql, :oracle].include? db
454
- fetch_on_demand_rds_instance_pricing(RDS_BASE_URL+"#{db}/pricing-#{dp_type}-deployments.min.js",:ondemand, db_type, is_byol)
455
- elsif db == :sqlserver
456
- fetch_on_demand_rds_instance_pricing(RDS_BASE_URL+"#{db}/sqlserver-#{dp_type}-ondemand.min.js",:ondemand, db_type, is_byol)
457
- end
458
- end
459
- }
460
- end
461
- end
462
-
463
- def get_rds_reserved_instance_pricing
464
- @@DB_TYPE.each do |db|
465
- if [:mysql, :postgresql].include? db
466
- @@RES_TYPES.each do |res_type|
467
- if db == :postgresql and res_type == :heavy
468
- fetch_reserved_rds_instance_pricing(RDS_BASE_URL+"#{db}/pricing-#{res_type}-utilization-reserved-instances.min.js", res_type, db, false)
469
- elsif db == :mysql
470
- fetch_reserved_rds_instance_pricing(RDS_BASE_URL+"#{db}/pricing-#{res_type}-utilization-reserved-instances.min.js", res_type, db, false)
471
- end
472
- end
473
- else
474
- @@RESERVED_DB_DEPLOY_TYPE[db].each {|db_type, db_instance|
475
- @@RES_TYPES.each do |res_type|
476
- db_instance.each do |dp_type|
477
- is_byol = is_byol? dp_type
478
- if db == :oracle
479
- fetch_reserved_rds_instance_pricing(RDS_BASE_URL+"#{db}/pricing-#{dp_type}-#{res_type}-utilization-reserved-instances.min.js", res_type, db_type, is_byol)
480
- elsif db == :sqlserver
481
- fetch_reserved_rds_instance_pricing(RDS_BASE_URL+"#{db}/sqlserver-#{dp_type}-#{res_type}-ri.min.js", res_type, db_type, is_byol)
482
- end
483
- end
484
- end
485
- }
486
- end
487
- end
488
- end
489
-
490
- def fetch_on_demand_rds_instance_pricing(url, type_of_rds_instance, db_type, is_byol)
491
- res = PriceList.fetch_url(url)
492
- res['config']['regions'].each do |reg|
493
- region_name = reg['region']
494
- region = find_or_create_region(region_name)
495
- reg['types'].each do |type|
496
- type['tiers'].each do |tier|
497
- begin
498
- #
499
- # this is special case URL, it is oracle - multiAZ type of deployment but it doesn't have mutliAZ attributes in json.
500
- if url == "http://aws.amazon.com/rds/pricing/oracle/pricing-li-multiAZ-deployments.min.js"
501
- is_multi_az = true
502
- else
503
- is_multi_az = is_multi_az? type["name"]
504
- end
505
- api_name, name = RdsInstanceType.get_name(type["name"], tier["name"], type_of_rds_instance != :ondemand)
506
-
507
- instance_type = region.add_or_update_rds_instance_type(api_name, name)
508
- instance_type.update_pricing(db_type, type_of_rds_instance, tier, is_multi_az, is_byol)
509
- rescue UnknownTypeError
510
- $stderr.puts "WARNING: encountered #{$!.message}"
511
- end
512
- end
513
- end
514
- end
515
- end
516
-
517
- def fetch_reserved_rds_instance_pricing(url, type_of_rds_instance, db_type, is_byol)
518
- res = PriceList.fetch_url(url)
519
- res['config']['regions'].each do |reg|
520
- region_name = reg['region']
521
- region = find_or_create_region(region_name)
522
- reg['instanceTypes'].each do |type|
523
- type['tiers'].each do |tier|
524
- begin
525
- is_multi_az = is_multi_az? type["type"]
526
- api_name, name = RdsInstanceType.get_name(type["type"], tier["size"], true)
527
-
528
- instance_type = region.add_or_update_rds_instance_type(api_name, name)
529
- instance_type.update_pricing(db_type, type_of_rds_instance, tier, is_multi_az, is_byol)
530
- rescue UnknownTypeError
531
- $stderr.puts "WARNING: encountered #{$!.message}"
532
- end
533
- end
534
- end
535
- end
536
- end
537
- end
538
- end
8
+ require 'aws-price-list'
9
+ require 'ec2-price-list'
10
+ require 'gov-cloud-price-list'
11
+ require 'rds-price-list'
@@ -8,5 +8,5 @@
8
8
  # Home:: http://github.com/CloudHealth/amazon-pricing
9
9
  #++
10
10
  module AwsPricing
11
- VERSION = '0.1.40'
11
+ VERSION = '0.1.41'
12
12
  end
@@ -0,0 +1,227 @@
1
+ #--
2
+ # Amazon Web Services Pricing Ruby library
3
+ #
4
+ # Ruby Gem Name:: amazon-pricing
5
+ # Author:: Joe Kinsella (mailto:joe.kinsella@gmail.com)
6
+ # Copyright:: Copyright (c) 2011-2013 CloudHealth
7
+ # License:: Distributes under the same terms as Ruby
8
+ # Home:: http://github.com/CloudHealth/amazon-pricing
9
+ #++
10
+ module AwsPricing
11
+
12
+ # PriceList provides the primary interface for retrieving AWS pricing.
13
+ # Upon instantiating a PriceList object, all the corresponding pricing
14
+ # information will be retrieved from Amazon via currently undocumented
15
+ # json APIs.
16
+ class PriceList
17
+ attr_accessor :regions
18
+
19
+ def get_region(name)
20
+ @_regions[@@Region_Lookup[name] || name]
21
+ end
22
+
23
+ def regions
24
+ @_regions.values
25
+ end
26
+
27
+ def get_instance_types
28
+ instance_types = []
29
+ @_regions.each do |region|
30
+ region.ec2_instance_types.each do |instance_type|
31
+ instance_types << instance_type
32
+ end
33
+ end
34
+ instance_types
35
+ end
36
+
37
+ def get_instance_type(region_name, api_name)
38
+ region = get_region(region_name)
39
+ raise "Region #{region_name} not found" if region.nil?
40
+ region.get_instance_type(api_name)
41
+ end
42
+
43
+ def self.fetch_url(url)
44
+ uri = URI.parse(url)
45
+ page = Net::HTTP.get_response(uri)
46
+ # Now that AWS switched from json to jsonp, remove first/last lines
47
+ body = page.body.gsub("callback(", "").reverse.sub(")", "").reverse
48
+ if body.split("\n").last == ";"
49
+ # Now remove one more line (rds is returning ";", ec2 empty line)
50
+ body = body.reverse.sub(";", "").reverse
51
+ elsif body[-1] == ";"
52
+ body.chop!
53
+ end
54
+
55
+ begin
56
+ JSON.parse(body)
57
+ rescue JSON::ParserError
58
+ # Handle "json" with keys that are not quoted
59
+ # When we get {foo: "1"} instead of {"foo": "1"}
60
+ # http://stackoverflow.com/questions/2060356/parsing-json-without-quoted-keys
61
+ JSON.parse(body.gsub(/(\w+)\s*:/, '"\1":'))
62
+ end
63
+ end
64
+
65
+ protected
66
+
67
+ attr_accessor :_regions
68
+
69
+ def add_region(region)
70
+ @_regions[region.name] = region
71
+ end
72
+
73
+ def find_or_create_region(name)
74
+ region = get_region(name)
75
+ if region.nil?
76
+ region = Region.new(name)
77
+ add_region(region)
78
+ end
79
+ region
80
+ end
81
+
82
+ EC2_BASE_URL = "http://a0.awsstatic.com/pricing/1/ec2/"
83
+ EBS_BASE_URL = "http://a0.awsstatic.com/pricing/1/ebs/"
84
+ RDS_BASE_URL = "http://a0.awsstatic.com/pricing/1/rds/"
85
+
86
+ # Lookup allows us to map to AWS API region names
87
+ @@Region_Lookup = {
88
+ 'us-east-1' => 'us-east',
89
+ 'us-west-1' => 'us-west',
90
+ 'us-west-2' => 'us-west-2',
91
+ 'eu-west-1' => 'eu-ireland',
92
+ 'ap-southeast-1' => 'apac-sin',
93
+ 'ap-southeast-2' => 'apac-syd',
94
+ 'ap-northeast-1' => 'apac-tokyo',
95
+ 'sa-east-1' => 'sa-east-1'
96
+ }
97
+
98
+ end
99
+
100
+
101
+ class GovCloudEc2PriceList < PriceList
102
+ GOV_CLOUD_URL = "http://aws.amazon.com/govcloud-us/pricing/ec2/"
103
+ GOV_CLOUD_EBS_URL = "http://aws.amazon.com/govcloud-us/pricing/ebs/"
104
+
105
+ def initialize
106
+ @_regions = {}
107
+ @_regions["us-gov-west-1"] = Region.new("us-gov-west-1")
108
+ InstanceType.populate_lookups
109
+ get_ec2_instance_pricing
110
+ fetch_ec2_ebs_pricing
111
+ end
112
+
113
+ protected
114
+
115
+ def get_ec2_instance_pricing
116
+
117
+ client = Mechanize.new
118
+ page = client.get(GOV_CLOUD_URL)
119
+ tables = page.search("//div[@class='aws-table section']")
120
+ create_ondemand_instances(get_rows(tables[0]))
121
+ create_ondemand_instances(get_rows(tables[1]))
122
+
123
+ for i in 2..7
124
+ create_reserved_instances(get_rows(tables[i]), :light)
125
+ end
126
+ for i in 8..13
127
+ create_reserved_instances(get_rows(tables[i]), :medium)
128
+ end
129
+ for i in 14..19
130
+ create_reserved_instances(get_rows(tables[i]), :heavy)
131
+ end
132
+
133
+ end
134
+
135
+ # e.g. [["Prices / Hour", "Amazon Linux", "RHEL", "SLES"], ["m1.small", "$0.053", "$0.083", "$0.083"]]
136
+ def create_ondemand_instances(rows)
137
+ header = rows[0]
138
+ @_regions.values.each do |region|
139
+
140
+ rows.slice(1, rows.size).each do |row|
141
+ api_name = row[0]
142
+ instance_type = region.get_ec2_instance_type(api_name)
143
+ if instance_type.nil?
144
+ api_name, name = Ec2InstanceType.get_name(nil, row[0], false)
145
+ instance_type = region.add_or_update_ec2_instance_type(api_name, name)
146
+ end
147
+ instance_type.update_pricing2(get_os(header[1]), :ondemand, row[1])
148
+ instance_type.update_pricing2(get_os(header[2]), :ondemand, row[2])
149
+ instance_type.update_pricing2(get_os(header[3]), :ondemand, row[3])
150
+ end
151
+ end
152
+ end
153
+
154
+ # e.g. [["RHEL", "1 yr Term Upfront", "1 yr TermHourly", "3 yr TermUpfront", "3 yr Term Hourly"], ["m1.small", "$68.00", "$0.099", "$105.00", "$0.098"]]
155
+ def create_reserved_instances(rows, res_type)
156
+ header = rows[0]
157
+ operating_system = get_os(header[0])
158
+ @_regions.values.each do |region|
159
+
160
+ rows.slice(1, rows.size).each do |row|
161
+ api_name = row[0]
162
+ instance_type = region.get_instance_type(api_name)
163
+ if instance_type.nil?
164
+ api_name, name = Ec2InstanceType.get_name(nil, row[0], true)
165
+ instance_type = region.add_or_update_ec2_instance_type(api_name, name)
166
+ end
167
+ instance_type.update_pricing2(operating_system, res_type, nil, row[1], row[3], row[2], row[4])
168
+ end
169
+ end
170
+ end
171
+
172
+ def fetch_ec2_ebs_pricing
173
+ client = Mechanize.new
174
+ page = client.get(GOV_CLOUD_EBS_URL)
175
+ ebs_costs = page.search("//div[@class='text section']//li")
176
+ @_regions.values.each do |region|
177
+ region.ebs_price = EbsPrice.new(region)
178
+ region.ebs_price.preferred_per_gb = get_ebs_price(ebs_costs[1])
179
+ region.ebs_price.preferred_per_iops = get_ebs_price(ebs_costs[2])
180
+ region.ebs_price.standard_per_gb = get_ebs_price(ebs_costs[3])
181
+ region.ebs_price.standard_per_million_io = get_ebs_price(ebs_costs[4])
182
+ region.ebs_price.ssd_per_gb = nil
183
+ region.ebs_price.s3_snaps_per_gb = get_ebs_price(ebs_costs[5])
184
+ end
185
+
186
+ end
187
+
188
+ # e.g. $0.065 per GB-Month of provisioned storage
189
+ def get_ebs_price(xml_element)
190
+ tokens = xml_element.text.split(" ")
191
+ tokens[0].gsub("$", "").to_f
192
+ end
193
+
194
+ def get_os(val)
195
+ case val
196
+ when "Amazon Linux"
197
+ :linux
198
+ when "RHEL"
199
+ :rhel
200
+ when "SLES"
201
+ :sles
202
+ when "Windows"
203
+ :mswin
204
+ when "Windows SQL Server Web", "Windows SQL Server Web Edition"
205
+ :mswinSQL
206
+ when "Windows SQL Server Standard", "Windows SQL Server Standard Edition"
207
+ :mswinSQLWeb
208
+ else
209
+ raise "Unable to identify operating system '#{val}'"
210
+ end
211
+ end
212
+
213
+ def get_rows(html_table)
214
+ rows = []
215
+ html_table.search(".//tr").each do |tr|
216
+ row = []
217
+ tr.search(".//td").each do |td|
218
+ row << td.inner_text.strip.sub("\n", " ").sub(" ", " ")
219
+ end
220
+ next if row.size == 1
221
+ rows << row unless row.empty?
222
+ end
223
+ rows
224
+ end
225
+ end
226
+
227
+ end
@@ -0,0 +1,79 @@
1
+ module AwsPricing
2
+ class Ec2PriceList < PriceList
3
+
4
+ def initialize
5
+ @_regions = {}
6
+ InstanceType.populate_lookups
7
+ get_ec2_on_demand_instance_pricing
8
+ get_ec2_reserved_instance_pricing
9
+ fetch_ec2_ebs_pricing
10
+ end
11
+
12
+ protected
13
+
14
+ @@OS_TYPES = [:linux, :mswin, :rhel, :sles, :mswinSQL, :mswinSQLWeb]
15
+ @@RES_TYPES = [:light, :medium, :heavy]
16
+
17
+ def get_ec2_on_demand_instance_pricing
18
+ @@OS_TYPES.each do |os|
19
+ fetch_ec2_instance_pricing(EC2_BASE_URL + "#{os}-od.min.js", :ondemand, os)
20
+ end
21
+ # Rinse & repeat for legacy instances
22
+ @@OS_TYPES.each do |os|
23
+ fetch_ec2_instance_pricing(EC2_BASE_URL + "previous-generation/#{os}-od.min.js", :ondemand, os)
24
+ end
25
+ end
26
+
27
+ def get_ec2_reserved_instance_pricing
28
+ @@OS_TYPES.each do |os|
29
+ @@RES_TYPES.each do |res_type|
30
+ fetch_ec2_instance_pricing(EC2_BASE_URL + "#{os}-ri-#{res_type}.min.js", res_type, os)
31
+ # Rinse & repeat for legacy instances (note: amazon changed URLs for legacy reserved instances)
32
+ os_rewrite = os
33
+ os_rewrite = "redhatlinux" if os == :rhel
34
+ os_rewrite = "suselinux" if os == :sles
35
+ os_rewrite = "mswinsqlstd" if os == :mswinSQL
36
+ os_rewrite = "mswinsqlweb" if os == :mswinSQLWeb
37
+ fetch_ec2_instance_pricing(EC2_BASE_URL + "previous-generation/#{res_type}_#{os_rewrite}.min.js", res_type, os)
38
+ end
39
+ end
40
+ end
41
+
42
+ # Retrieves the EC2 on-demand instance pricing.
43
+ # type_of_instance = :ondemand, :light, :medium, :heavy
44
+ def fetch_ec2_instance_pricing(url, type_of_instance, operating_system)
45
+ res = PriceList.fetch_url(url)
46
+ res['config']['regions'].each do |reg|
47
+ region_name = reg['region']
48
+ region = find_or_create_region(region_name)
49
+ # e.g. type = {"type"=>"hiCPUODI", "sizes"=>[{"size"=>"med", "valueColumns"=>[{"name"=>"mswinSQL", "prices"=>{"USD"=>"N/A"}}]}, {"size"=>"xl", "valueColumns"=>[{"name"=>"mswinSQL", "prices"=>{"USD"=>"2.427"}}]}]}
50
+ reg['instanceTypes'].each do |type|
51
+ # e.g. size = {"size"=>"xl", "valueColumns"=>[{"name"=>"mswinSQL", "prices"=>{"USD"=>"2.427"}}]}
52
+ # Amazon now can return array or hash here (hash = only 1 item)
53
+ items = type['sizes']
54
+ items = [type] if items.nil?
55
+ items.each do |size|
56
+ begin
57
+ api_name, name = Ec2InstanceType.get_name(type["type"], size["size"], type_of_instance != :ondemand)
58
+
59
+ instance_type = region.add_or_update_ec2_instance_type(api_name, name)
60
+ instance_type.update_pricing(operating_system, type_of_instance, size)
61
+ rescue UnknownTypeError
62
+ $stderr.puts "WARNING: encountered #{$!.message}"
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
68
+
69
+ def fetch_ec2_ebs_pricing
70
+ res = PriceList.fetch_url(EBS_BASE_URL + "pricing-ebs.min.js")
71
+ res["config"]["regions"].each do |ebs_types|
72
+ region = get_region(ebs_types["region"])
73
+ region.ebs_price = EbsPrice.new(region)
74
+ region.ebs_price.update_from_json(ebs_types)
75
+ end
76
+ end
77
+
78
+ end
79
+ end
@@ -0,0 +1,136 @@
1
+ module AwsPricing
2
+ class GovCloudRdsPriceList < PriceList
3
+ GOV_CLOUD_URL = "http://aws.amazon.com/govcloud-us/pricing/rds/"
4
+
5
+ def initialize
6
+ @_regions = {}
7
+ @_regions["us-gov-west-1"] = Region.new("us-gov-west-1")
8
+ InstanceType.populate_lookups
9
+ get_rds_instance_pricing
10
+ end
11
+
12
+ protected
13
+ #@@DB_TYPE = [:mysql, :postgresql, :oracle, :sqlserver]
14
+ #@@RES_TYPES = [:light, :medium, :heavy]
15
+
16
+ def get_rds_instance_pricing
17
+
18
+ client = Mechanize.new
19
+ page = client.get(GOV_CLOUD_URL)
20
+ tables = page.search("//div[@class='aws-table section']")
21
+
22
+ # Mysql
23
+ create_ondemand_instances(:mysql, :ondemand, false, false, get_rows(tables[0]))
24
+ create_ondemand_instances(:mysql, :ondemand, true, false, get_rows(tables[1]))
25
+ no_multi_az_rows, multi_az_rows = get_reserved_rows(get_rows(tables[2]))
26
+ create_reserved_instances(:mysql, :light, false, false, no_multi_az_rows)
27
+ create_reserved_instances(:mysql, :light, true, false, multi_az_rows)
28
+ no_multi_az_rows, multi_az_rows = get_reserved_rows(get_rows(tables[3]))
29
+ create_reserved_instances(:mysql, :medium, false, false, no_multi_az_rows)
30
+ create_reserved_instances(:mysql, :medium, true, false, multi_az_rows)
31
+ no_multi_az_rows, multi_az_rows = get_reserved_rows(get_rows(tables[4]))
32
+ create_reserved_instances(:mysql, :heavy, false, false, no_multi_az_rows)
33
+ create_reserved_instances(:mysql, :heavy, true, false, multi_az_rows)
34
+
35
+ # Oracle
36
+ create_ondemand_instances(:oracle_se1, :ondemand, false, false, get_rows(tables[5]))
37
+ create_ondemand_instances(:oracle_se1, :ondemand, true, false, get_rows(tables[6]))
38
+ create_ondemand_instances(:oracle_se1, :ondemand, false, true, get_rows(tables[7]))
39
+ create_ondemand_instances(:oracle_se1, :ondemand, true, true, get_rows(tables[8]))
40
+
41
+ row = 9
42
+ [false, true].each do |is_byol|
43
+ [:light, :medium, :heavy].each do |res_type|
44
+ no_multi_az_rows, multi_az_rows = get_reserved_rows(get_rows(tables[9]))
45
+ create_reserved_instances(:oracle_se1, res_type, false, is_byol, no_multi_az_rows)
46
+ create_reserved_instances(:oracle_se1, res_type, true, is_byol, multi_az_rows)
47
+ row += 1
48
+ end
49
+ end
50
+
51
+ # SQL Server
52
+ create_ondemand_instances(:sqlserver_ex, :ondemand, false, false, get_rows(tables[15]))
53
+ create_ondemand_instances(:sqlserver_web, :ondemand, false, false, get_rows(tables[16]))
54
+ create_ondemand_instances(:sqlserver_se, :ondemand, false, false, get_rows(tables[17]))
55
+ row = 18
56
+ [:light, :medium, :heavy].each do |restype|
57
+ [:sqlserver_ex, :sqlserver_web, :sqlserver_se].each do |db|
58
+ no_multi_az_rows, multi_az_rows = get_reserved_rows(get_rows(tables[row]))
59
+ create_reserved_instances(db, restype, false, false, no_multi_az_rows)
60
+ create_reserved_instances(db, restype, true, false, multi_az_rows)
61
+ row += 1
62
+ end
63
+ end
64
+
65
+ # Postgres
66
+ # Mysql
67
+ create_ondemand_instances(:postgresql, :ondemand, false, false, get_rows(tables[31]))
68
+ create_ondemand_instances(:postgresql, :ondemand, true, false, get_rows(tables[32]))
69
+ row = 33
70
+ [:light, :medium, :heavy].each do |restype|
71
+ no_multi_az_rows, multi_az_rows = get_reserved_rows(get_rows(tables[row]))
72
+ create_reserved_instances(:postgresql, restype, false, false, no_multi_az_rows)
73
+ create_reserved_instances(:postgresql, restype, true, false, multi_az_rows)
74
+ row += 1
75
+ end
76
+
77
+ end
78
+
79
+ # e.g. [["General Purpose - Previous Generation", "Price Per Hour"], ["m1.small", "$0.090"], ["m1.medium", "$0.185"]]
80
+ def create_ondemand_instances(db_type, res_type, is_multi_az, is_byol, rows)
81
+ @_regions.values.each do |region|
82
+ # Skip header row
83
+ rows.slice(1, rows.size).each do |row|
84
+ api_name = row[0]
85
+ instance_type = region.get_rds_instance_type(api_name)
86
+ if instance_type.nil?
87
+ api_name, name = RdsInstanceType.get_name(nil, row[0], false)
88
+ instance_type = region.add_or_update_rds_instance_type(api_name, name)
89
+ end
90
+ instance_type.update_pricing2(db_type, res_type, is_multi_az, is_byol, row[1])
91
+ end
92
+ end
93
+ end
94
+
95
+ # e.g. [[" ", "1 yr Term", "3 yr Term"], [" ", "Upfront", "Hourly", "Upfront", "Hourly"], ["m1.small", "$159", "$0.035", "$249", "$0.033"]]
96
+ def create_reserved_instances(db_type, res_type, is_multi_az, is_byol, rows)
97
+ @_regions.values.each do |region|
98
+ rows.each do |row|
99
+ api_name = row[0]
100
+ unless api_name.include?("db.")
101
+ $stderr.puts "Skipping row containing non-db type: #{api_name}"
102
+ next
103
+ end
104
+ instance_type = region.get_rds_instance_type(api_name)
105
+ if instance_type.nil?
106
+ api_name, name = RdsInstanceType.get_name(nil, row[0], true)
107
+ instance_type = region.add_or_update_rds_instance_type(api_name, name)
108
+ end
109
+ instance_type.update_pricing2(db_type, res_type, is_multi_az, is_byol, nil, row[1], row[3], row[2], row[4])
110
+ end
111
+ end
112
+ end
113
+
114
+ def get_reserved_rows(rows)
115
+ # Skip 2 header rows
116
+ new_rows = rows.slice(2, rows.size)
117
+ no_multi_az_rows = new_rows.slice(0, new_rows.size / 2)
118
+ multi_az_rows = new_rows.slice(new_rows.size / 2, new_rows.size / 2)
119
+ [no_multi_az_rows, multi_az_rows]
120
+ end
121
+
122
+ def get_rows(html_table)
123
+ rows = []
124
+ html_table.search(".//tr").each do |tr|
125
+ row = []
126
+ tr.search(".//td").each do |td|
127
+ row << td.inner_text.strip.sub("\n", " ").sub(" ", " ")
128
+ end
129
+ # Various <tR> elements contain labels which have only 1 <td> - except heavy multi-az ;)
130
+ next if row.size == 1 || row[0].include?("Multi-AZ Deployment")
131
+ rows << row unless row.empty?
132
+ end
133
+ rows
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,133 @@
1
+ module AwsPricing
2
+ class RdsPriceList < PriceList
3
+
4
+ def initialize
5
+ @_regions = {}
6
+ InstanceType.populate_lookups
7
+ get_rds_on_demand_instance_pricing
8
+ get_rds_reserved_instance_pricing
9
+ end
10
+
11
+ protected
12
+
13
+ @@DB_TYPE = [:mysql, :postgresql, :oracle, :sqlserver]
14
+ @@RES_TYPES = [:light, :medium, :heavy]
15
+
16
+ @@OD_DB_DEPLOY_TYPE = {
17
+ :mysql=> {:mysql=>["standard","multiAZ"]},
18
+ :postgresql=> {:postgresql=>["standard","multiAZ"]},
19
+ :oracle=> {:oracle_se1=>["li-standard","li-multiAZ","byol-standard","byol-multiAZ"], :oracle_se=>["byol-standard","byol-multiAZ"], :oracle_ee=>["byol-standard","byol-multiAZ"]},
20
+ :sqlserver=> {:sqlserver_ex=>["li-ex"], :sqlserver_web=>["li-web"], :sqlserver_se=>["li-se", "byol"], :sqlserver_ee=>["byol"]}
21
+ }
22
+
23
+
24
+ @@RESERVED_DB_DEPLOY_TYPE = {
25
+ :oracle=> {:oracle_se1=>["li","byol"], :oracle_se=>["byol"], :oracle_ee=>["byol"]},
26
+ :sqlserver=> {:sqlserver_ex=>["li-ex"], :sqlserver_web=>["li-web"], :sqlserver_se=>["li-se","byol"], :sqlserver_ee=>["byol"]}
27
+ }
28
+
29
+
30
+ def is_multi_az?(type)
31
+ return true if type.match("multiAZ")
32
+ false
33
+ end
34
+
35
+ def is_byol?(type)
36
+ return true if type.match("byol")
37
+ false
38
+ end
39
+
40
+ def get_rds_on_demand_instance_pricing
41
+ @@DB_TYPE.each do |db|
42
+ @@OD_DB_DEPLOY_TYPE[db].each {|db_type, db_instances|
43
+ db_instances.each do |dp_type|
44
+ #
45
+ # to find out the byol type
46
+ is_byol = is_byol? dp_type
47
+
48
+ if [:mysql, :postgresql, :oracle].include? db
49
+ fetch_on_demand_rds_instance_pricing(RDS_BASE_URL+"#{db}/pricing-#{dp_type}-deployments.min.js",:ondemand, db_type, is_byol)
50
+ elsif db == :sqlserver
51
+ fetch_on_demand_rds_instance_pricing(RDS_BASE_URL+"#{db}/sqlserver-#{dp_type}-ondemand.min.js",:ondemand, db_type, is_byol)
52
+ end
53
+ end
54
+ }
55
+ end
56
+ end
57
+
58
+ def get_rds_reserved_instance_pricing
59
+ @@DB_TYPE.each do |db|
60
+ if [:mysql, :postgresql].include? db
61
+ @@RES_TYPES.each do |res_type|
62
+ if db == :postgresql and res_type == :heavy
63
+ fetch_reserved_rds_instance_pricing(RDS_BASE_URL+"#{db}/pricing-#{res_type}-utilization-reserved-instances.min.js", res_type, db, false)
64
+ elsif db == :mysql
65
+ fetch_reserved_rds_instance_pricing(RDS_BASE_URL+"#{db}/pricing-#{res_type}-utilization-reserved-instances.min.js", res_type, db, false)
66
+ end
67
+ end
68
+ else
69
+ @@RESERVED_DB_DEPLOY_TYPE[db].each {|db_type, db_instance|
70
+ @@RES_TYPES.each do |res_type|
71
+ db_instance.each do |dp_type|
72
+ is_byol = is_byol? dp_type
73
+ if db == :oracle
74
+ fetch_reserved_rds_instance_pricing(RDS_BASE_URL+"#{db}/pricing-#{dp_type}-#{res_type}-utilization-reserved-instances.min.js", res_type, db_type, is_byol)
75
+ elsif db == :sqlserver
76
+ fetch_reserved_rds_instance_pricing(RDS_BASE_URL+"#{db}/sqlserver-#{dp_type}-#{res_type}-ri.min.js", res_type, db_type, is_byol)
77
+ end
78
+ end
79
+ end
80
+ }
81
+ end
82
+ end
83
+ end
84
+
85
+ def fetch_on_demand_rds_instance_pricing(url, type_of_rds_instance, db_type, is_byol)
86
+ res = PriceList.fetch_url(url)
87
+ res['config']['regions'].each do |reg|
88
+ region_name = reg['region']
89
+ region = find_or_create_region(region_name)
90
+ reg['types'].each do |type|
91
+ type['tiers'].each do |tier|
92
+ begin
93
+ #
94
+ # this is special case URL, it is oracle - multiAZ type of deployment but it doesn't have mutliAZ attributes in json.
95
+ if url == "http://aws.amazon.com/rds/pricing/oracle/pricing-li-multiAZ-deployments.min.js"
96
+ is_multi_az = true
97
+ else
98
+ is_multi_az = is_multi_az? type["name"]
99
+ end
100
+ api_name, name = RdsInstanceType.get_name(type["name"], tier["name"], type_of_rds_instance != :ondemand)
101
+
102
+ instance_type = region.add_or_update_rds_instance_type(api_name, name)
103
+ instance_type.update_pricing(db_type, type_of_rds_instance, tier, is_multi_az, is_byol)
104
+ rescue UnknownTypeError
105
+ $stderr.puts "WARNING: encountered #{$!.message}"
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
111
+
112
+ def fetch_reserved_rds_instance_pricing(url, type_of_rds_instance, db_type, is_byol)
113
+ res = PriceList.fetch_url(url)
114
+ res['config']['regions'].each do |reg|
115
+ region_name = reg['region']
116
+ region = find_or_create_region(region_name)
117
+ reg['instanceTypes'].each do |type|
118
+ type['tiers'].each do |tier|
119
+ begin
120
+ is_multi_az = is_multi_az? type["type"]
121
+ api_name, name = RdsInstanceType.get_name(type["type"], tier["size"], true)
122
+
123
+ instance_type = region.add_or_update_rds_instance_type(api_name, name)
124
+ instance_type.update_pricing(db_type, type_of_rds_instance, tier, is_multi_az, is_byol)
125
+ rescue UnknownTypeError
126
+ $stderr.puts "WARNING: encountered #{$!.message}"
127
+ end
128
+ end
129
+ end
130
+ end
131
+ end
132
+ end
133
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: amazon-pricing
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.40
4
+ version: 0.1.41
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joe Kinsella
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-07-10 00:00:00.000000000 Z
11
+ date: 2014-07-22 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: A Ruby library for retrieving pricing for Amazon Web Services
14
14
  email:
@@ -40,6 +40,10 @@ files:
40
40
  - lib/amazon-pricing/rds-instance-type.rb
41
41
  - lib/amazon-pricing/region.rb
42
42
  - lib/amazon-pricing/version.rb
43
+ - lib/aws-price-list.rb
44
+ - lib/ec2-price-list.rb
45
+ - lib/gov-cloud-price-list.rb
46
+ - lib/rds-price-list.rb
43
47
  - spec/instance_type_spec.rb
44
48
  - spec/price_list_spec.rb
45
49
  - spec/rds_pricing_spec.rb