amazon-pricing 0.1.40 → 0.1.41

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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