amazon-pricing 0.1.9 → 0.1.10
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.
- data/Rakefile +75 -7
- data/amazon-pricing.gemspec +1 -1
- data/lib/amazon-pricing.rb +147 -27
- data/lib/amazon-pricing/category-type.rb +154 -0
- data/lib/amazon-pricing/database-type.rb +13 -0
- data/lib/amazon-pricing/ec2-instance-type.rb +79 -0
- data/lib/amazon-pricing/instance-type.rb +61 -91
- data/lib/amazon-pricing/operating-system.rb +1 -144
- data/lib/amazon-pricing/rds-instance-type.rb +89 -0
- data/lib/amazon-pricing/region.rb +33 -9
- data/lib/amazon-pricing/version.rb +1 -1
- data/spec/rds-amazon-pricing-spec.rb +34 -0
- data/test/test-ec2-instance-types.rb +16 -16
- metadata +7 -1
data/Rakefile
CHANGED
@@ -3,7 +3,7 @@ require 'rake/testtask'
|
|
3
3
|
|
4
4
|
$: << File.expand_path(File.dirname(__FILE__), 'lib')
|
5
5
|
|
6
|
-
require 'amazon-pricing
|
6
|
+
require File.join('amazon-pricing','version')
|
7
7
|
|
8
8
|
Rake::TestTask.new(:test) do |test|
|
9
9
|
test.libs << 'lib' << 'test'
|
@@ -32,10 +32,10 @@ task :test do
|
|
32
32
|
end
|
33
33
|
|
34
34
|
desc "Prints current EC2 pricing in CSV format"
|
35
|
-
task :
|
36
|
-
require '
|
37
|
-
pricing = AwsPricing::
|
38
|
-
line = "Region,Instance Type,API Name,Memory (MB),Disk (
|
35
|
+
task :print_ec2_price_list do
|
36
|
+
require 'amazon-pricing'
|
37
|
+
pricing = AwsPricing::Ec2PriceList.new
|
38
|
+
line = "Region,Instance Type,API Name,Memory (MB),Disk (GB),Compute Units,Virtual Cores,Disk Type,OD Linux PPH,OD Windows PPH,OD RHEL PPH,OD SLES PPH,OD MsWinSQL PPH,OD MsWinSQLWeb PPH,"
|
39
39
|
[:year1, :year3].each do |term|
|
40
40
|
[:light, :medium, :heavy].each do |res_type|
|
41
41
|
[:linux, :mswin, :rhel, :sles, :mswinSQL, :mswinSQLWeb].each do |os|
|
@@ -45,8 +45,8 @@ task :print_price_list do
|
|
45
45
|
end
|
46
46
|
puts line.chop
|
47
47
|
pricing.regions.each do |region|
|
48
|
-
region.
|
49
|
-
line = "#{region.name},#{t.name},#{t.api_name},#{t.memory_in_mb},#{t.
|
48
|
+
region.ec2_instance_types.each do |t|
|
49
|
+
line = "#{region.name},#{t.name},#{t.api_name},#{t.memory_in_mb},#{t.disk_in_gb},#{t.compute_units},#{t.virtual_cores},#{t.disk_type},"
|
50
50
|
[:linux, :mswin, :rhel, :sles, :mswinSQL, :mswinSQLWeb].each do |os|
|
51
51
|
line += "#{t.price_per_hour(os, :ondemand)},"
|
52
52
|
end
|
@@ -62,4 +62,72 @@ task :print_price_list do
|
|
62
62
|
end
|
63
63
|
end
|
64
64
|
|
65
|
+
|
66
|
+
desc "Prints current RDS pricing in CSV format"
|
67
|
+
task :print_rds_price_list do
|
68
|
+
require 'amazon-pricing'
|
69
|
+
pricing = AwsPricing::RdsPriceList.new
|
70
|
+
|
71
|
+
line = "Region,Instance Type,API Name,Memory (MB),Disk (GB),Compute Units,Virtual Cores,Disk Type,"
|
72
|
+
|
73
|
+
|
74
|
+
[:mysql, :oracle, :oracle_byol, :sqlserver, :sqlserver_express, :sqlserver_web, :sqlserver_byol].each do |db|
|
75
|
+
if [:mysql, :oracle, :oracle_byol].include? db
|
76
|
+
[:standard,:multiAZ].each do |deploy_type|
|
77
|
+
line += "OD #{db} #{deploy_type} PPH,"
|
78
|
+
end
|
79
|
+
else
|
80
|
+
line += "OD #{db} PPH,"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
|
85
|
+
[:year1, :year3].each do |term|
|
86
|
+
[:light, :medium, :heavy].each do |res_type|
|
87
|
+
[:mysql, :oracle, :oracle_byol, :sqlserver, :sqlserver_express, :sqlserver_web, :sqlserver_byol].each do |db|
|
88
|
+
if [:mysql, :oracle, :oracle_byol].include? db
|
89
|
+
[:standard,:multiAZ].each do |deploy_type|
|
90
|
+
line += "#{term} #{res_type} #{deploy_type} #{db} Prepay,#{term} #{res_type} #{deploy_type} #{db} PPH,"
|
91
|
+
end
|
92
|
+
else
|
93
|
+
line += "#{term} #{res_type} #{db} Prepay,#{term} #{res_type} #{db} PPH,"
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
|
100
|
+
puts line.chop
|
101
|
+
|
102
|
+
pricing.regions.each do |region|
|
103
|
+
region.rds_instance_types.each do |t|
|
104
|
+
line = "#{region.name},#{t.name},#{t.api_name},#{t.memory_in_mb},#{t.disk_in_gb},#{t.compute_units},#{t.virtual_cores},#{t.disk_type},"
|
105
|
+
[:mysql, :oracle, :oracle_byol, :sqlserver, :sqlserver_express, :sqlserver_web, :sqlserver_byol].each do |db|
|
106
|
+
if [:mysql, :oracle, :oracle_byol].include? db
|
107
|
+
[:standard,:multiAZ].each do |deploy_type|
|
108
|
+
line += "#{t.price_per_hour(db, :ondemand, nil, deploy_type == :multiAZ)},"
|
109
|
+
end
|
110
|
+
else
|
111
|
+
line += "#{t.price_per_hour(db, :ondemand, nil, false)},"
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
[:year1, :year3].each do |term|
|
116
|
+
[:light, :medium, :heavy].each do |res_type|
|
117
|
+
[:mysql, :oracle, :oracle_byol, :sqlserver, :sqlserver_express, :sqlserver_web, :sqlserver_byol].each do |db|
|
118
|
+
if [:mysql, :oracle, :oracle_byol].include? db
|
119
|
+
[:standard,:multiAZ].each do |deploy_type|
|
120
|
+
line += "#{t.prepay(db, res_type, term, deploy_type == :multiAZ)},#{t.price_per_hour(db, res_type, term, deploy_type == :multiAZ)},"
|
121
|
+
end
|
122
|
+
else
|
123
|
+
line += "#{t.prepay(db, res_type, term, false)},#{t.price_per_hour(db, res_type, term, false)},"
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
puts line.chop
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
65
133
|
task :default => [:test]
|
data/amazon-pricing.gemspec
CHANGED
data/lib/amazon-pricing.rb
CHANGED
@@ -18,16 +18,9 @@ module AwsPricing
|
|
18
18
|
# Upon instantiating a PriceList object, all the corresponding pricing
|
19
19
|
# information will be retrieved from Amazon via currently undocumented
|
20
20
|
# json APIs.
|
21
|
-
|
21
|
+
class PriceList
|
22
22
|
attr_accessor :regions
|
23
23
|
|
24
|
-
def initialize
|
25
|
-
@_regions = {}
|
26
|
-
get_ec2_on_demand_instance_pricing
|
27
|
-
get_ec2_reserved_instance_pricing
|
28
|
-
fetch_ec2_ebs_pricing
|
29
|
-
end
|
30
|
-
|
31
24
|
def get_region(name)
|
32
25
|
@_regions[@@Region_Lookup[name] || name]
|
33
26
|
end
|
@@ -42,6 +35,12 @@ module AwsPricing
|
|
42
35
|
region.get_instance_type(api_name)
|
43
36
|
end
|
44
37
|
|
38
|
+
def fetch_url(url)
|
39
|
+
uri = URI.parse(url)
|
40
|
+
page = Net::HTTP.get_response(uri)
|
41
|
+
JSON.parse(page.body)
|
42
|
+
end
|
43
|
+
|
45
44
|
protected
|
46
45
|
|
47
46
|
attr_accessor :_regions
|
@@ -59,6 +58,33 @@ module AwsPricing
|
|
59
58
|
region
|
60
59
|
end
|
61
60
|
|
61
|
+
EC2_BASE_URL = "http://aws.amazon.com/ec2/pricing/"
|
62
|
+
RDS_BASE_URL = "http://aws.amazon.com/rds/pricing/"
|
63
|
+
|
64
|
+
# Lookup allows us to map to AWS API region names
|
65
|
+
@@Region_Lookup = {
|
66
|
+
'us-east-1' => 'us-east',
|
67
|
+
'us-west-1' => 'us-west',
|
68
|
+
'us-west-2' => 'us-west-2',
|
69
|
+
'eu-west-1' => 'eu-ireland',
|
70
|
+
'ap-southeast-1' => 'apac-sin',
|
71
|
+
'ap-southeast-2' => 'apac-syd',
|
72
|
+
'ap-northeast-1' => 'apac-tokyo',
|
73
|
+
'sa-east-1' => 'sa-east-1'
|
74
|
+
}
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
class Ec2PriceList < PriceList
|
80
|
+
|
81
|
+
def initialize
|
82
|
+
@_regions = {}
|
83
|
+
get_ec2_on_demand_instance_pricing
|
84
|
+
get_ec2_reserved_instance_pricing
|
85
|
+
fetch_ec2_ebs_pricing
|
86
|
+
end
|
87
|
+
|
62
88
|
protected
|
63
89
|
|
64
90
|
@@OS_TYPES = [:linux, :mswin, :rhel, :sles, :mswinSQL, :mswinSQLWeb]
|
@@ -90,9 +116,9 @@ module AwsPricing
|
|
90
116
|
# e.g. size = {"size"=>"xl", "valueColumns"=>[{"name"=>"mswinSQL", "prices"=>{"USD"=>"2.427"}}]}
|
91
117
|
type['sizes'].each do |size|
|
92
118
|
begin
|
93
|
-
api_name, name =
|
94
|
-
|
95
|
-
region.
|
119
|
+
api_name, name = Ec2InstanceType.get_name(type["type"], size["size"], type_of_instance != :ondemand)
|
120
|
+
|
121
|
+
region.add_or_update_ec2_instance_type(api_name, name, operating_system, type_of_instance, size)
|
96
122
|
rescue UnknownTypeError
|
97
123
|
$stderr.puts "WARNING: encountered #{$!.message}"
|
98
124
|
end
|
@@ -109,24 +135,118 @@ module AwsPricing
|
|
109
135
|
end
|
110
136
|
end
|
111
137
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
138
|
+
end
|
139
|
+
|
140
|
+
|
141
|
+
|
142
|
+
class RdsPriceList < PriceList
|
143
|
+
|
144
|
+
def initialize
|
145
|
+
@_regions = {}
|
146
|
+
get_rds_on_demand_instance_pricing
|
147
|
+
get_rds_reserved_instance_pricing
|
116
148
|
end
|
117
149
|
|
118
|
-
|
150
|
+
protected
|
119
151
|
|
120
|
-
|
121
|
-
@@
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
152
|
+
@@DB_TYPE = [:mysql, :oracle, :sqlserver]
|
153
|
+
@@RES_TYPES = [:light, :medium, :heavy]
|
154
|
+
|
155
|
+
@@OD_DB_DEPLOY_TYPE = {
|
156
|
+
:mysql=> {:mysql=>["standard","multiAZ"]},
|
157
|
+
:oracle=> {:oracle=>["li-standard","li-multiAZ"], :oracle_byol=>["byol-standard","byol-multiAZ"]},
|
158
|
+
:sqlserver=> {:sqlserver=>["li-se"], :sqlserver_express=>["li-ex"], :sqlserver_web=>["li-web"], :sqlserver_byol=>["byol"]}
|
159
|
+
}
|
160
|
+
|
161
|
+
|
162
|
+
@@RESERVED_DB_DEPLOY_TYPE = {
|
163
|
+
:oracle=> {:oracle=>"li", :oracle_byol=>"byol"},
|
164
|
+
:sqlserver=> {:sqlserver=>"li-se", :sqlserver_express=>"li-ex", :sqlserver_web=>"li-web", :sqlserver_byol=>"byol"}
|
165
|
+
}
|
166
|
+
|
167
|
+
|
168
|
+
def is_multi_az?(type)
|
169
|
+
return true if type.match("multiAZ")
|
170
|
+
false
|
171
|
+
end
|
172
|
+
|
173
|
+
def get_rds_on_demand_instance_pricing
|
174
|
+
@@DB_TYPE.each do |db|
|
175
|
+
@@OD_DB_DEPLOY_TYPE[db].each {|db_type, db_instances|
|
176
|
+
db_instances.each do |dp_type|
|
177
|
+
if db == :mysql or db == :oracle
|
178
|
+
fetch_on_demand_rds_instance_pricing(RDS_BASE_URL+"#{db}/pricing-#{dp_type}-deployments.json",:ondemand, db_type)
|
179
|
+
elsif db == :sqlserver
|
180
|
+
fetch_on_demand_rds_instance_pricing(RDS_BASE_URL+"#{db}/sqlserver-#{dp_type}-ondemand.json",:ondemand, db_type)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
}
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
def get_rds_reserved_instance_pricing
|
188
|
+
@@DB_TYPE.each do |db|
|
189
|
+
if db == :mysql
|
190
|
+
@@RES_TYPES.each do |res_type|
|
191
|
+
fetch_reserved_rds_instance_pricing(RDS_BASE_URL+"#{db}/pricing-#{res_type}-utilization-reserved-instances.json", res_type, db)
|
192
|
+
end
|
193
|
+
else
|
194
|
+
@@RESERVED_DB_DEPLOY_TYPE[db].each {|db_type, db_instance|
|
195
|
+
@@RES_TYPES.each do |res_type|
|
196
|
+
fetch_reserved_rds_instance_pricing(RDS_BASE_URL+"#{db}/pricing-#{db_instance}-#{res_type}-utilization-reserved-instances.json", res_type, db_type) if db == :oracle
|
197
|
+
fetch_reserved_rds_instance_pricing(RDS_BASE_URL+"#{db}/sqlserver-#{db_instance}-#{res_type}-ri.json", res_type, db_type) if db == :sqlserver
|
198
|
+
end
|
199
|
+
}
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
def fetch_on_demand_rds_instance_pricing(url, type_of_rds_instance, db_type)
|
205
|
+
res = fetch_url(url)
|
206
|
+
res['config']['regions'].each do |reg|
|
207
|
+
region_name = reg['region']
|
208
|
+
region = find_or_create_region(region_name)
|
209
|
+
reg['types'].each do |type|
|
210
|
+
type['tiers'].each do |tier|
|
211
|
+
begin
|
212
|
+
#
|
213
|
+
# this is special case URL, it is oracle - multiAZ type of deployment but it doesn't have mutliAZ attributes in json.
|
214
|
+
if url == "http://aws.amazon.com/rds/pricing/oracle/pricing-li-multiAZ-deployments.json"
|
215
|
+
isMultiAz = true
|
216
|
+
else
|
217
|
+
isMultiAz = is_multi_az? type["name"]
|
218
|
+
end
|
219
|
+
api_name, name = RdsInstanceType.get_name(type["name"], tier["name"], type_of_rds_instance != :ondemand)
|
220
|
+
|
221
|
+
region.add_or_update_rds_instance_type(api_name, name, db_type, type_of_rds_instance, tier, isMultiAz)
|
222
|
+
rescue UnknownTypeError
|
223
|
+
$stderr.puts "WARNING: encountered #{$!.message}"
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
def fetch_reserved_rds_instance_pricing(url, type_of_rds_instance, db_type)
|
231
|
+
res = fetch_url(url)
|
232
|
+
res['config']['regions'].each do |reg|
|
233
|
+
region_name = reg['region']
|
234
|
+
region = find_or_create_region(region_name)
|
235
|
+
reg['instanceTypes'].each do |type|
|
236
|
+
type['tiers'].each do |tier|
|
237
|
+
begin
|
238
|
+
isMultiAz = is_multi_az? type["type"]
|
239
|
+
api_name, name = RdsInstanceType.get_name(type["type"], tier["size"], true)
|
240
|
+
|
241
|
+
region.add_or_update_rds_instance_type(api_name, name, db_type, type_of_rds_instance, tier, isMultiAz)
|
242
|
+
rescue UnknownTypeError
|
243
|
+
$stderr.puts "WARNING: encountered #{$!.message}"
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end
|
247
|
+
end
|
248
|
+
end
|
131
249
|
end
|
250
|
+
|
251
|
+
|
132
252
|
end
|
@@ -0,0 +1,154 @@
|
|
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
|
+
class CategoryType
|
13
|
+
attr_accessor :instance_type, :name,
|
14
|
+
:ondemand_price_per_hour, :light_price_per_hour_1_year, :medium_price_per_hour_1_year, :heavy_price_per_hour_1_year,
|
15
|
+
:light_price_per_hour_3_year, :medium_price_per_hour_3_year, :heavy_price_per_hour_3_year,
|
16
|
+
:light_prepay_1_year, :light_prepay_3_year, :medium_prepay_1_year, :medium_prepay_3_year, :heavy_prepay_1_year, :heavy_prepay_3_year
|
17
|
+
|
18
|
+
|
19
|
+
def initialize(instance_type, name)
|
20
|
+
@instance_type = instance_type
|
21
|
+
@name = name
|
22
|
+
end
|
23
|
+
|
24
|
+
# Returns whether an instance_type is available.
|
25
|
+
# type_of_instance = :ondemand, :light, :medium, :heavy
|
26
|
+
def available?(type_of_instance = :ondemand)
|
27
|
+
not price_per_hour(type_of_instance).nil?
|
28
|
+
end
|
29
|
+
|
30
|
+
# type_of_instance = :ondemand, :light, :medium, :heavy
|
31
|
+
# term = :year_1, :year_3, nil
|
32
|
+
def prepay(type_of_instance = :ondemand, term = nil)
|
33
|
+
case type_of_instance
|
34
|
+
when :ondemand
|
35
|
+
0
|
36
|
+
when :light
|
37
|
+
if term == :year1
|
38
|
+
@light_prepay_1_year
|
39
|
+
elsif term == :year3
|
40
|
+
@light_prepay_3_year
|
41
|
+
end
|
42
|
+
when :medium
|
43
|
+
if term == :year1
|
44
|
+
@medium_prepay_1_year
|
45
|
+
elsif term == :year3
|
46
|
+
@medium_prepay_3_year
|
47
|
+
end
|
48
|
+
when :heavy
|
49
|
+
if term == :year1
|
50
|
+
@heavy_prepay_1_year
|
51
|
+
elsif term == :year3
|
52
|
+
@heavy_prepay_3_year
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# type_of_instance = :ondemand, :light, :medium, :heavy
|
58
|
+
# term = :year_1, :year_3, nil
|
59
|
+
def set_prepay(type_of_instance, term, price)
|
60
|
+
case type_of_instance
|
61
|
+
when :light
|
62
|
+
if term == :year1
|
63
|
+
@light_prepay_1_year = price
|
64
|
+
elsif term == :year3
|
65
|
+
@light_prepay_3_year = price
|
66
|
+
end
|
67
|
+
when :medium
|
68
|
+
if term == :year1
|
69
|
+
@medium_prepay_1_year = price
|
70
|
+
elsif term == :year3
|
71
|
+
@medium_prepay_3_year = price
|
72
|
+
end
|
73
|
+
when :heavy
|
74
|
+
if term == :year1
|
75
|
+
@heavy_prepay_1_year = price
|
76
|
+
elsif term == :year3
|
77
|
+
@heavy_prepay_3_year = price
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# type_of_instance = :ondemand, :light, :medium, :heavy
|
83
|
+
# term = :year_1, :year_3, nil
|
84
|
+
def price_per_hour(type_of_instance = :ondemand, term = nil)
|
85
|
+
case type_of_instance
|
86
|
+
when :ondemand
|
87
|
+
@ondemand_price_per_hour
|
88
|
+
when :light
|
89
|
+
if term == :year1
|
90
|
+
@light_price_per_hour_1_year
|
91
|
+
elsif term == :year3
|
92
|
+
@light_price_per_hour_3_year
|
93
|
+
end
|
94
|
+
when :medium
|
95
|
+
if term == :year1
|
96
|
+
@medium_price_per_hour_1_year
|
97
|
+
elsif term == :year3
|
98
|
+
@medium_price_per_hour_3_year
|
99
|
+
end
|
100
|
+
when :heavy
|
101
|
+
if term == :year1
|
102
|
+
@heavy_price_per_hour_1_year
|
103
|
+
elsif term == :year3
|
104
|
+
@heavy_price_per_hour_3_year
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# type_of_instance = :ondemand, :light, :medium, :heavy
|
110
|
+
# term = :year_1, :year_3, nil
|
111
|
+
def set_price_per_hour(type_of_instance, term, price_per_hour)
|
112
|
+
case type_of_instance
|
113
|
+
when :ondemand
|
114
|
+
@ondemand_price_per_hour = price_per_hour
|
115
|
+
when :light
|
116
|
+
if term == :year1
|
117
|
+
@light_price_per_hour_1_year = price_per_hour
|
118
|
+
elsif term == :year3
|
119
|
+
@light_price_per_hour_3_year = price_per_hour
|
120
|
+
end
|
121
|
+
when :medium
|
122
|
+
if term == :year1
|
123
|
+
@medium_price_per_hour_1_year = price_per_hour
|
124
|
+
elsif term == :year3
|
125
|
+
@medium_price_per_hour_3_year = price_per_hour
|
126
|
+
end
|
127
|
+
when :heavy
|
128
|
+
if term == :year1
|
129
|
+
@heavy_price_per_hour_1_year = price_per_hour
|
130
|
+
elsif term == :year3
|
131
|
+
@heavy_price_per_hour_3_year = price_per_hour
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
# type_of_instance = :ondemand, :light, :medium, :heavy
|
137
|
+
# term = :year_1, :year_3, nil
|
138
|
+
def get_breakeven_month(type_of_instance, term)
|
139
|
+
# Some regions and types do not have reserved available
|
140
|
+
ondemand_pph = price_per_hour(:ondemand)
|
141
|
+
reserved_pph = price_per_hour(type_of_instance, term)
|
142
|
+
return nil if ondemand_pph.nil? || reserved_pph.nil?
|
143
|
+
|
144
|
+
on_demand = 0
|
145
|
+
reserved = prepay(type_of_instance, term)
|
146
|
+
for i in 1..36 do
|
147
|
+
on_demand += ondemand_pph * 24 * 30.4
|
148
|
+
reserved += reserved_pph * 24 * 30.4
|
149
|
+
return i if reserved < on_demand
|
150
|
+
end
|
151
|
+
nil
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
@@ -0,0 +1,13 @@
|
|
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
|
+
class DatabaseType < CategoryType
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'amazon-pricing/instance-type'
|
2
|
+
module AwsPricing
|
3
|
+
class Ec2InstanceType < InstanceType
|
4
|
+
|
5
|
+
# Returns whether an instance_type is available.
|
6
|
+
# operating_system = :linux, :mswin, :rhel, :sles, :mswinSQL, :mswinSQLWeb
|
7
|
+
# type_of_instance = :ondemand, :light, :medium, :heavy
|
8
|
+
def available?(type_of_instance = :ondemand, operating_system = :linux)
|
9
|
+
os = get_category_type(operating_system)
|
10
|
+
return false if os.nil?
|
11
|
+
os.available?(type_of_instance)
|
12
|
+
end
|
13
|
+
|
14
|
+
# operating_system = :linux, :mswin, :rhel, :sles, :mswinSQL, :mswinSQLWeb
|
15
|
+
# type_of_instance = :ondemand, :light, :medium, :heavy
|
16
|
+
def update_pricing(operating_system, type_of_instance, json)
|
17
|
+
os = get_category_type(operating_system)
|
18
|
+
if os.nil?
|
19
|
+
os = OperatingSystem.new(self, operating_system)
|
20
|
+
@category_types[operating_system] = os
|
21
|
+
end
|
22
|
+
|
23
|
+
if type_of_instance == :ondemand
|
24
|
+
# e.g. {"size"=>"sm", "valueColumns"=>[{"name"=>"linux", "prices"=>{"USD"=>"0.060"}}]}
|
25
|
+
values = Ec2InstanceType::get_values(json, operating_system)
|
26
|
+
price = coerce_price(values[operating_system.to_s])
|
27
|
+
os.set_price_per_hour(type_of_instance, nil, price)
|
28
|
+
else
|
29
|
+
json['valueColumns'].each do |val|
|
30
|
+
price = coerce_price(val['prices']['USD'])
|
31
|
+
|
32
|
+
case val["name"]
|
33
|
+
when "yrTerm1"
|
34
|
+
os.set_prepay(type_of_instance, :year1, price)
|
35
|
+
when "yrTerm3"
|
36
|
+
os.set_prepay(type_of_instance, :year3, price)
|
37
|
+
when "yrTerm1Hourly"
|
38
|
+
os.set_price_per_hour(type_of_instance, :year1, price)
|
39
|
+
when "yrTerm3Hourly"
|
40
|
+
os.set_price_per_hour(type_of_instance, :year3, price)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# Maintained for backward compatibility reasons
|
47
|
+
def operating_systems
|
48
|
+
category_types
|
49
|
+
end
|
50
|
+
|
51
|
+
protected
|
52
|
+
# Returns [api_name, name]
|
53
|
+
def self.get_name(instance_type, api_name, is_reserved = false)
|
54
|
+
# Let's handle new instances more gracefully
|
55
|
+
unless @@Memory_Lookup.has_key? api_name
|
56
|
+
raise UnknownTypeError, "Unknown instance type #{instance_type} #{api_name}", caller
|
57
|
+
end
|
58
|
+
|
59
|
+
name = @@Name_Lookup[api_name]
|
60
|
+
|
61
|
+
[api_name, name]
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
@@Name_Lookup = {
|
66
|
+
'm1.small' => 'Standard Small', 'm1.medium' => 'Standard Medium', 'm1.large' => 'Standard Large', 'm1.xlarge' => 'Standard Extra Large',
|
67
|
+
'm2.xlarge' => 'Hi-Memory Extra Large', 'm2.2xlarge' => 'Hi-Memory Double Extra Large', 'm2.4xlarge' => 'Hi-Memory Quadruple Extra Large',
|
68
|
+
'm3.xlarge' => 'M3 Extra Large Instance', 'm3.2xlarge' => 'M3 Double Extra Large Instance',
|
69
|
+
'c1.medium' => 'High-CPU Medium', 'c1.xlarge' => 'High-CPU Extra Large',
|
70
|
+
'hi1.4xlarge' => 'High I/O Quadruple Extra Large',
|
71
|
+
'cg1.4xlarge' => 'Cluster GPU Quadruple Extra Large',
|
72
|
+
'cc1.4xlarge' => 'Cluster Compute Quadruple Extra Large', 'cc2.8xlarge' => 'Cluster Compute Eight Extra Large',
|
73
|
+
't1.micro' => 'Micro',
|
74
|
+
'cr1.8xlarge' => 'High-Memory Cluster Eight Extra Large',
|
75
|
+
'hs1.8xlarge' => 'High-Storage Eight Extra Large',
|
76
|
+
'g2.2xlarge' => 'Cluster GPU Double Extra Large',
|
77
|
+
}
|
78
|
+
end
|
79
|
+
end
|
@@ -19,93 +19,62 @@ module AwsPricing
|
|
19
19
|
# $0.48/hour for Windows.
|
20
20
|
#
|
21
21
|
class InstanceType
|
22
|
-
attr_accessor :name, :api_name, :memory_in_mb, :
|
23
|
-
|
24
|
-
# Initializes and InstanceType object given a region, the internal
|
25
|
-
# type (e.g. stdODI) and the json for the specific instance. The json is
|
26
|
-
# based on the current undocumented AWS pricing API.
|
22
|
+
attr_accessor :name, :api_name, :memory_in_mb, :platform, :compute_units, :virtual_cores, :disk_type, :disk_in_gb
|
23
|
+
|
27
24
|
def initialize(region, api_name, name)
|
28
|
-
@
|
25
|
+
@category_types = {}
|
29
26
|
|
30
27
|
@region = region
|
31
28
|
@name = name
|
32
29
|
@api_name = api_name
|
33
30
|
|
34
31
|
@memory_in_mb = @@Memory_Lookup[@api_name]
|
35
|
-
@
|
32
|
+
@disk_in_gb = @@Disk_Lookup[@api_name]
|
36
33
|
@platform = @@Platform_Lookup[@api_name]
|
37
34
|
@compute_units = @@Compute_Units_Lookup[@api_name]
|
38
35
|
@virtual_cores = @@Virtual_Cores_Lookup[@api_name]
|
36
|
+
@disk_type = @@Disk_Type_Lookup[@api_name]
|
39
37
|
end
|
40
38
|
|
41
|
-
|
42
|
-
|
39
|
+
# Keep this in for backwards compatibility within current major version of gem
|
40
|
+
def disk_in_mb
|
41
|
+
@disk_in_gb * 1000
|
43
42
|
end
|
44
43
|
|
45
|
-
def
|
46
|
-
@
|
44
|
+
def memory_in_gb
|
45
|
+
@memory_in_mb / 1000
|
47
46
|
end
|
48
47
|
|
49
|
-
|
50
|
-
|
51
|
-
# type_of_instance = :ondemand, :light, :medium, :heavy
|
52
|
-
def available?(type_of_instance = :ondemand, operating_system = :linux)
|
53
|
-
os = get_operating_system(operating_system)
|
54
|
-
return false if os.nil?
|
55
|
-
os.available?(type_of_instance)
|
48
|
+
def category_types
|
49
|
+
@category_types.values
|
56
50
|
end
|
57
51
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
52
|
+
def get_category_type(name, multiAz = false)
|
53
|
+
if multiAz
|
54
|
+
db = @category_types["#{name}_multiAz"]
|
55
|
+
else
|
56
|
+
db = @category_types[name]
|
57
|
+
end
|
63
58
|
end
|
64
59
|
|
65
60
|
# type_of_instance = :ondemand, :light, :medium, :heavy
|
66
61
|
# term = :year_1, :year_3, nil
|
67
|
-
def
|
68
|
-
|
69
|
-
|
62
|
+
def price_per_hour(category_type, type_of_instance, term = nil, isMultiAz = false)
|
63
|
+
cat = get_category_type(category_type, isMultiAz)
|
64
|
+
cat.price_per_hour(type_of_instance, term) unless cat.nil?
|
70
65
|
end
|
71
66
|
|
72
|
-
# operating_system = :linux, :mswin, :rhel, :sles, :mswinSQL, :mswinSQLWeb
|
73
67
|
# type_of_instance = :ondemand, :light, :medium, :heavy
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
@operating_systems[operating_system] = os
|
79
|
-
end
|
80
|
-
|
81
|
-
if type_of_instance == :ondemand
|
82
|
-
# e.g. {"size"=>"sm", "valueColumns"=>[{"name"=>"linux", "prices"=>{"USD"=>"0.060"}}]}
|
83
|
-
values = InstanceType::get_values(json)
|
84
|
-
price = coerce_price(values[operating_system.to_s])
|
85
|
-
|
86
|
-
os.set_price_per_hour(type_of_instance, nil, price)
|
87
|
-
else
|
88
|
-
json['valueColumns'].each do |val|
|
89
|
-
price = coerce_price(val['prices']['USD'])
|
90
|
-
|
91
|
-
case val["name"]
|
92
|
-
when "yrTerm1"
|
93
|
-
os.set_prepay(type_of_instance, :year1, price)
|
94
|
-
when "yrTerm3"
|
95
|
-
os.set_prepay(type_of_instance, :year3, price)
|
96
|
-
when "yrTerm1Hourly"
|
97
|
-
os.set_price_per_hour(type_of_instance, :year1, price)
|
98
|
-
when "yrTerm3Hourly"
|
99
|
-
os.set_price_per_hour(type_of_instance, :year3, price)
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|
68
|
+
# term = :year_1, :year_3, nil
|
69
|
+
def prepay(category_type, type_of_instance, term = nil, isMultiAz = false)
|
70
|
+
cat = get_category_type(category_type, isMultiAz)
|
71
|
+
cat.prepay(type_of_instance, term) unless cat.nil?
|
103
72
|
end
|
104
73
|
|
105
74
|
# type_of_instance = :ondemand, :light, :medium, :heavy
|
106
75
|
# term = :year_1, :year_3, nil
|
107
|
-
def get_breakeven_month(
|
108
|
-
os =
|
76
|
+
def get_breakeven_month(category_types, type_of_instance, term)
|
77
|
+
os = get_category_type(category_types)
|
109
78
|
os.get_breakeven_month(type_of_instance, term)
|
110
79
|
end
|
111
80
|
|
@@ -113,46 +82,21 @@ module AwsPricing
|
|
113
82
|
|
114
83
|
def coerce_price(price)
|
115
84
|
return nil if price.nil? || price == "N/A"
|
116
|
-
price.to_f
|
117
|
-
end
|
118
|
-
|
119
|
-
#attr_accessor :size, :instance_type
|
120
|
-
|
121
|
-
# Returns [api_name, name]
|
122
|
-
def self.get_name(instance_type, api_name, is_reserved = false)
|
123
|
-
# Let's handle new instances more gracefully
|
124
|
-
unless @@Memory_Lookup.has_key? api_name
|
125
|
-
raise UnknownTypeError, "Unknown instance type #{instance_type} #{api_name}", caller
|
126
|
-
end
|
127
|
-
|
128
|
-
name = @@Name_Lookup[api_name]
|
129
|
-
|
130
|
-
[api_name, name]
|
85
|
+
price.gsub(",","").to_f
|
131
86
|
end
|
132
87
|
|
133
|
-
|
134
|
-
def self.get_values(json)
|
135
|
-
# e.g. json = {"size"=>"xl", "valueColumns"=>[{"name"=>"mswinSQL", "prices"=>{"USD"=>"2.427"}}]}
|
88
|
+
def self.get_values(json, category_type)
|
136
89
|
values = {}
|
137
|
-
json['valueColumns'].
|
138
|
-
|
90
|
+
unless json['valueColumns'].nil?
|
91
|
+
json['valueColumns'].each do |val|
|
92
|
+
values[val['name']] = val['prices']['USD']
|
93
|
+
end
|
94
|
+
else
|
95
|
+
values[category_type.to_s] = json['prices']['USD']
|
139
96
|
end
|
140
97
|
values
|
141
98
|
end
|
142
99
|
|
143
|
-
@@Name_Lookup = {
|
144
|
-
'm1.small' => 'Standard Small', 'm1.medium' => 'Standard Medium', 'm1.large' => 'Standard Large', 'm1.xlarge' => 'Standard Extra Large',
|
145
|
-
'm2.xlarge' => 'Hi-Memory Extra Large', 'm2.2xlarge' => 'Hi-Memory Double Extra Large', 'm2.4xlarge' => 'Hi-Memory Quadruple Extra Large',
|
146
|
-
'm3.xlarge' => 'M3 Extra Large Instance', 'm3.2xlarge' => 'M3 Double Extra Large Instance',
|
147
|
-
'c1.medium' => 'High-CPU Medium', 'c1.xlarge' => 'High-CPU Extra Large',
|
148
|
-
'hi1.4xlarge' => 'High I/O Quadruple Extra Large',
|
149
|
-
'cg1.4xlarge' => 'Cluster GPU Quadruple Extra Large',
|
150
|
-
'cc1.4xlarge' => 'Cluster Compute Quadruple Extra Large', 'cc2.8xlarge' => 'Cluster Compute Eight Extra Large',
|
151
|
-
't1.micro' => 'Micro',
|
152
|
-
'cr1.8xlarge' => 'High-Memory Cluster Eight Extra Large',
|
153
|
-
'hs1.8xlarge' => 'High-Storage Eight Extra Large',
|
154
|
-
'g2.2xlarge' => 'Cluster GPU Double Extra Large',
|
155
|
-
}
|
156
100
|
@@Memory_Lookup = {
|
157
101
|
'm1.small' => 1700, 'm1.medium' => 3750, 'm1.large' => 7500, 'm1.xlarge' => 15000,
|
158
102
|
'm2.xlarge' => 17100, 'm2.2xlarge' => 34200, 'm2.4xlarge' => 68400,
|
@@ -166,6 +110,8 @@ module AwsPricing
|
|
166
110
|
'cr1.8xlarge' => 244000,
|
167
111
|
'hs1.8xlarge' => 117000,
|
168
112
|
'g2.2xlarge' => 15000,
|
113
|
+
'db.m1.small' => 1700, 'db.m1.medium' => 3750, 'db.m1.large' => 7500, 'db.m1.xlarge' => 15000,
|
114
|
+
'db.m2.xlarge' => 17100, 'db.m2.2xlarge' => 34200, 'db.m2.4xlarge' => 68400, 'db.m2.8xlarge' => 136800
|
169
115
|
}
|
170
116
|
@@Disk_Lookup = {
|
171
117
|
'm1.small' => 160, 'm1.medium' => 410, 'm1.large' =>850, 'm1.xlarge' => 1690,
|
@@ -180,6 +126,8 @@ module AwsPricing
|
|
180
126
|
'cr1.8xlarge' => 240,
|
181
127
|
'hs1.8xlarge' => 48000,
|
182
128
|
'g2.2xlarge' => 60,
|
129
|
+
'db.m1.small' => 160, 'db.m1.medium' => 410, 'db.m1.large' =>850, 'db.m1.xlarge' => 1690,
|
130
|
+
'db.m2.xlarge' => 420, 'db.m2.2xlarge' => 850, 'db.m2.4xlarge' => 1690, 'db.m2.8xlarge' => 0
|
183
131
|
}
|
184
132
|
@@Platform_Lookup = {
|
185
133
|
'm1.small' => 32, 'm1.medium' => 32, 'm1.large' => 64, 'm1.xlarge' => 64,
|
@@ -194,6 +142,8 @@ module AwsPricing
|
|
194
142
|
'cr1.8xlarge' => 64,
|
195
143
|
'hs1.8xlarge' => 64,
|
196
144
|
'g2.2xlarge' => 64,
|
145
|
+
'db.m1.small' => 32, 'db.m1.medium' => 32, 'db.m1.large' => 64, 'db.m1.xlarge' => 64,
|
146
|
+
'db.m2.xlarge' => 64, 'db.m2.2xlarge' => 64, 'db.m2.4xlarge' => 64, 'db.m2.8xlarge' => 64
|
197
147
|
}
|
198
148
|
@@Compute_Units_Lookup = {
|
199
149
|
'm1.small' => 1, 'm1.medium' => 2, 'm1.large' => 4, 'm1.xlarge' => 8,
|
@@ -208,6 +158,8 @@ module AwsPricing
|
|
208
158
|
'hs1.8xlarge' => 35,
|
209
159
|
'g2.2xlarge' => 26,
|
210
160
|
'unknown' => 0,
|
161
|
+
'db.m1.small' => 1, 'db.m1.medium' => 2, 'db.m1.large' => 4, 'db.m1.xlarge' => 8,
|
162
|
+
'db.m2.xlarge' => 6, 'db.m2.2xlarge' => 13, 'db.m2.4xlarge' => 26, 'db.m2.8xlarge' => 52
|
211
163
|
}
|
212
164
|
@@Virtual_Cores_Lookup = {
|
213
165
|
'm1.small' => 1, 'm1.medium' => 1, 'm1.large' => 2, 'm1.xlarge' => 4,
|
@@ -222,6 +174,24 @@ module AwsPricing
|
|
222
174
|
'hs1.8xlarge' => 16,
|
223
175
|
'g2.2xlarge' => 8,
|
224
176
|
'unknown' => 0,
|
177
|
+
'db.m1.small' => 1, 'db.m1.medium' => 1, 'db.m1.large' => 2, 'db.m1.xlarge' => 4,
|
178
|
+
'db.m2.xlarge' => 2, 'db.m2.2xlarge' => 4, 'db.m2.4xlarge' => 8, 'db.m2.8xlarge' => 16
|
179
|
+
}
|
180
|
+
@@Disk_Type_Lookup = {
|
181
|
+
'm1.small' => :ephemeral, 'm1.medium' => :ephemeral, 'm1.large' => :ephemeral, 'm1.xlarge' => :ephemeral,
|
182
|
+
'm2.xlarge' => :ephemeral, 'm2.2xlarge' => :ephemeral, 'm2.4xlarge' => :ephemeral,
|
183
|
+
'm3.xlarge' => :ephemeral, 'm3.2xlarge' => :ephemeral,
|
184
|
+
'c1.medium' => :ephemeral, 'c1.xlarge' => :ephemeral,
|
185
|
+
'hi1.4xlarge' => :ssd,
|
186
|
+
'cg1.4xlarge' => :ephemeral,
|
187
|
+
'cc1.4xlarge' => :ephemeral, 'cc2.8xlarge' => :ephemeral,
|
188
|
+
't1.micro' => :ebs,
|
189
|
+
'cr1.8xlarge' => :ssd,
|
190
|
+
'hs1.8xlarge' => :ephemeral,
|
191
|
+
'g2.2xlarge' => :ssd,
|
192
|
+
'unknown' => :ephemeral,
|
193
|
+
'db.m1.small' => :ephemeral, 'db.m1.medium' => :ephemeral, 'db.m1.large' => :ephemeral, 'db.m1.xlarge' => :ephemeral,
|
194
|
+
'db.m2.xlarge' => :ephemeral, 'db.m2.2xlarge' => :ephemeral, 'db.m2.4xlarge' => :ephemeral, 'db.m2.8xlarge' => :ephemeral
|
225
195
|
}
|
226
196
|
end
|
227
197
|
|
@@ -8,149 +8,6 @@
|
|
8
8
|
# Home:: http://github.com/CloudHealth/amazon-pricing
|
9
9
|
#++
|
10
10
|
module AwsPricing
|
11
|
-
|
12
|
-
class OperatingSystem
|
13
|
-
attr_accessor :instance_type, :name,
|
14
|
-
:ondemand_price_per_hour, :light_price_per_hour_1_year, :medium_price_per_hour_1_year, :heavy_price_per_hour_1_year,
|
15
|
-
:light_price_per_hour_3_year, :medium_price_per_hour_3_year, :heavy_price_per_hour_3_year,
|
16
|
-
:light_prepay_1_year, :light_prepay_3_year, :medium_prepay_1_year, :medium_prepay_3_year, :heavy_prepay_1_year, :heavy_prepay_3_year
|
17
|
-
|
18
|
-
|
19
|
-
def initialize(instance_type, name)
|
20
|
-
@instance_type = instance_type
|
21
|
-
@name = name
|
22
|
-
end
|
23
|
-
|
24
|
-
# Returns whether an instance_type is available.
|
25
|
-
# type_of_instance = :ondemand, :light, :medium, :heavy
|
26
|
-
def available?(type_of_instance = :ondemand)
|
27
|
-
not price_per_hour(type_of_instance).nil?
|
28
|
-
end
|
29
|
-
|
30
|
-
# type_of_instance = :ondemand, :light, :medium, :heavy
|
31
|
-
# term = :year_1, :year_3, nil
|
32
|
-
def prepay(type_of_instance = :ondemand, term = nil)
|
33
|
-
case type_of_instance
|
34
|
-
when :ondemand
|
35
|
-
0
|
36
|
-
when :light
|
37
|
-
if term == :year1
|
38
|
-
@light_prepay_1_year
|
39
|
-
elsif term == :year3
|
40
|
-
@light_prepay_3_year
|
41
|
-
end
|
42
|
-
when :medium
|
43
|
-
if term == :year1
|
44
|
-
@medium_prepay_1_year
|
45
|
-
elsif term == :year3
|
46
|
-
@medium_prepay_3_year
|
47
|
-
end
|
48
|
-
when :heavy
|
49
|
-
if term == :year1
|
50
|
-
@heavy_prepay_1_year
|
51
|
-
elsif term == :year3
|
52
|
-
@heavy_prepay_3_year
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
# type_of_instance = :ondemand, :light, :medium, :heavy
|
58
|
-
# term = :year_1, :year_3, nil
|
59
|
-
def set_prepay(type_of_instance, term, price)
|
60
|
-
case type_of_instance
|
61
|
-
when :light
|
62
|
-
if term == :year1
|
63
|
-
@light_prepay_1_year = price
|
64
|
-
elsif term == :year3
|
65
|
-
@light_prepay_3_year = price
|
66
|
-
end
|
67
|
-
when :medium
|
68
|
-
if term == :year1
|
69
|
-
@medium_prepay_1_year = price
|
70
|
-
elsif term == :year3
|
71
|
-
@medium_prepay_3_year = price
|
72
|
-
end
|
73
|
-
when :heavy
|
74
|
-
if term == :year1
|
75
|
-
@heavy_prepay_1_year = price
|
76
|
-
elsif term == :year3
|
77
|
-
@heavy_prepay_3_year = price
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
# type_of_instance = :ondemand, :light, :medium, :heavy
|
83
|
-
# term = :year_1, :year_3, nil
|
84
|
-
def price_per_hour(type_of_instance = :ondemand, term = nil)
|
85
|
-
case type_of_instance
|
86
|
-
when :ondemand
|
87
|
-
@ondemand_price_per_hour
|
88
|
-
when :light
|
89
|
-
if term == :year1
|
90
|
-
@light_price_per_hour_1_year
|
91
|
-
elsif term == :year3
|
92
|
-
@light_price_per_hour_3_year
|
93
|
-
end
|
94
|
-
when :medium
|
95
|
-
if term == :year1
|
96
|
-
@medium_price_per_hour_1_year
|
97
|
-
elsif term == :year3
|
98
|
-
@medium_price_per_hour_3_year
|
99
|
-
end
|
100
|
-
when :heavy
|
101
|
-
if term == :year1
|
102
|
-
@heavy_price_per_hour_1_year
|
103
|
-
elsif term == :year3
|
104
|
-
@heavy_price_per_hour_3_year
|
105
|
-
end
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
# type_of_instance = :ondemand, :light, :medium, :heavy
|
110
|
-
# term = :year_1, :year_3, nil
|
111
|
-
def set_price_per_hour(type_of_instance, term, price_per_hour)
|
112
|
-
case type_of_instance
|
113
|
-
when :ondemand
|
114
|
-
@ondemand_price_per_hour = price_per_hour
|
115
|
-
when :light
|
116
|
-
if term == :year1
|
117
|
-
@light_price_per_hour_1_year = price_per_hour
|
118
|
-
elsif term == :year3
|
119
|
-
@light_price_per_hour_3_year = price_per_hour
|
120
|
-
end
|
121
|
-
when :medium
|
122
|
-
if term == :year1
|
123
|
-
@medium_price_per_hour_1_year = price_per_hour
|
124
|
-
elsif term == :year3
|
125
|
-
@medium_price_per_hour_3_year = price_per_hour
|
126
|
-
end
|
127
|
-
when :heavy
|
128
|
-
if term == :year1
|
129
|
-
@heavy_price_per_hour_1_year = price_per_hour
|
130
|
-
elsif term == :year3
|
131
|
-
@heavy_price_per_hour_3_year = price_per_hour
|
132
|
-
end
|
133
|
-
end
|
134
|
-
end
|
135
|
-
|
136
|
-
# type_of_instance = :ondemand, :light, :medium, :heavy
|
137
|
-
# term = :year_1, :year_3, nil
|
138
|
-
def get_breakeven_month(type_of_instance, term)
|
139
|
-
# Some regions and types do not have reserved available
|
140
|
-
ondemand_pph = price_per_hour(:ondemand)
|
141
|
-
reserved_pph = price_per_hour(type_of_instance, term)
|
142
|
-
return nil if ondemand_pph.nil? || reserved_pph.nil?
|
143
|
-
|
144
|
-
on_demand = 0
|
145
|
-
reserved = prepay(type_of_instance, term)
|
146
|
-
for i in 1..36 do
|
147
|
-
on_demand += ondemand_pph * 24 * 30.4
|
148
|
-
reserved += reserved_pph * 24 * 30.4
|
149
|
-
return i if reserved < on_demand
|
150
|
-
end
|
151
|
-
nil
|
152
|
-
end
|
153
|
-
|
11
|
+
class OperatingSystem < CategoryType
|
154
12
|
end
|
155
|
-
|
156
13
|
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'amazon-pricing/instance-type'
|
2
|
+
module AwsPricing
|
3
|
+
class RdsInstanceType < InstanceType
|
4
|
+
# database_type = :mysql, :oracle, :sqlserver
|
5
|
+
# type_of_instance = :ondemand, :light, :medium, :heavy
|
6
|
+
def update_pricing(database_type, type_of_instance, json, isMultiAz)
|
7
|
+
db = get_category_type(database_type, isMultiAz)
|
8
|
+
if db.nil?
|
9
|
+
db = DatabaseType.new(self, database_type)
|
10
|
+
if isMultiAz
|
11
|
+
@category_types["#{database_type}_multiAz"] = db
|
12
|
+
else
|
13
|
+
@category_types[database_type] = db
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
if type_of_instance == :ondemand
|
18
|
+
values = RdsInstanceType::get_values(json, database_type)
|
19
|
+
price = coerce_price(values[database_type.to_s])
|
20
|
+
db.set_price_per_hour(type_of_instance, nil, price)
|
21
|
+
else
|
22
|
+
json['valueColumns'].each do |val|
|
23
|
+
price = coerce_price(val['prices']['USD'])
|
24
|
+
|
25
|
+
case val["name"]
|
26
|
+
when "yrTerm1"
|
27
|
+
db.set_prepay(type_of_instance, :year1, price)
|
28
|
+
when "yrTerm3"
|
29
|
+
db.set_prepay(type_of_instance, :year3, price)
|
30
|
+
when "yrTerm1Hourly"
|
31
|
+
db.set_price_per_hour(type_of_instance, :year1, price)
|
32
|
+
when "yrTerm3Hourly"
|
33
|
+
db.set_price_per_hour(type_of_instance, :year3, price)
|
34
|
+
when "yearTerm1Hourly"
|
35
|
+
db.set_price_per_hour(type_of_instance, :year1, price)
|
36
|
+
when "yearTerm3Hourly"
|
37
|
+
db.set_price_per_hour(type_of_instance, :year3, price)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
protected
|
44
|
+
|
45
|
+
# Returns [api_name, name]
|
46
|
+
def self.get_name(instance_type, size, is_reserved = false)
|
47
|
+
lookup = @@Api_Name_Lookup
|
48
|
+
lookup = @@Api_Name_Lookup_Reserved if is_reserved
|
49
|
+
|
50
|
+
# Let's handle new instances more gracefully
|
51
|
+
unless lookup.has_key? instance_type
|
52
|
+
raise UnknownTypeError, "Unknown instance type #{instance_type}", caller
|
53
|
+
else
|
54
|
+
api_name = lookup[instance_type][size]
|
55
|
+
end
|
56
|
+
|
57
|
+
lookup = @@Name_Lookup
|
58
|
+
lookup = @@Name_Lookup_Reserved if is_reserved
|
59
|
+
name = lookup[instance_type][size]
|
60
|
+
|
61
|
+
[api_name, name]
|
62
|
+
end
|
63
|
+
|
64
|
+
@@Api_Name_Lookup = {
|
65
|
+
'udbInstClass' => {'uDBInst'=>'db.t1.micro'},
|
66
|
+
'dbInstClass'=> {'uDBInst' => 'db.t1.micro', 'smDBInst' => 'db.m1.small', 'medDBInst' => 'db.m1.medium', 'lgDBInst' => 'db.m1.large', 'xlDBInst' => 'db.m1.xlarge'},
|
67
|
+
'hiMemDBInstClass'=> {'xlDBInst' => 'db.m2.xlarge', 'xxlDBInst' => 'db.m2.2xlarge', 'xxxxDBInst' => 'db.m2.4xlarge'},
|
68
|
+
'clusterHiMemDB' => {'xxxxxxxxl' => 'db.m2.8xlarge'},
|
69
|
+
'multiAZDBInstClass'=> {'uDBInst' => 'db.t1.micro', 'smDBInst' => 'db.m1.small', 'medDBInst' => 'db.m1.medium', 'lgDBInst' => 'db.m1.large', 'xlDBInst' => 'db.m1.xlarge'},
|
70
|
+
'multiAZHiMemInstClass'=> {'xlDBInst' => 'db.m2.xlarge', 'xxlDBInst' => 'db.m2.2xlarge', 'xxxxDBInst' => 'db.m2.4xlarge'},
|
71
|
+
}
|
72
|
+
@@Name_Lookup = {
|
73
|
+
'udbInstClass' => {'uDBInst'=>'Standard Micro'},
|
74
|
+
'dbInstClass'=> {'uDBInst' => 'Standard Micro', 'smDBInst' => 'Standard Small', 'medDBInst' => 'Standard Medium', 'lgDBInst' => 'Standard Large', 'xlDBInst' => 'Standard Extra Large'},
|
75
|
+
'hiMemDBInstClass'=> {'xlDBInst' => 'Standard High-Memory Extra Large', 'xxlDBInst' => 'Standard High-Memory Double Extra Large', 'xxxxDBInst' => 'Standard High-Memory Quadruple Extra Large'},
|
76
|
+
'clusterHiMemDB' => {'xxxxxxxxl' => 'Standard High-Memory Cluster Eight Extra Large'},
|
77
|
+
'multiAZDBInstClass'=> {'uDBInst' => 'Multi-AZ Micro', 'smDBInst' => 'Multi-AZ Small', 'medDBInst' => 'Multi-AZ Medium', 'lgDBInst' => 'Multi-AZ Large', 'xlDBInst' => 'Multi-AZ Extra Large'},
|
78
|
+
'multiAZHiMemInstClass'=> {'xlDBInst' => 'Multi-AZ High-Memory Extra Large', 'xxlDBInst' => 'Multi-AZ High-Memory Double Extra Large', 'xxxxDBInst' => 'Multi-AZ High-Memory Quadruple Extra Large'},
|
79
|
+
}
|
80
|
+
@@Api_Name_Lookup_Reserved = {
|
81
|
+
'stdDeployRes' => {'u' => 'db.t1.micro', 'micro' => 'db.t1.micro', 'sm' => 'db.m1.small', 'med' => 'db.m1.medium', 'lg' => 'db.m1.large', 'xl' => 'db.m1.xlarge', 'xlHiMem' => 'db.m2.xlarge', 'xxlHiMem' => 'db.m2.2xlarge', 'xxxxlHiMem' => 'db.m2.4xlarge', 'xxxxxxxxl' => 'db.m2.8xlarge'},
|
82
|
+
'multiAZdeployRes' => {'u' => 'db.t1.micro', 'micro' => 'db.t1.micro', 'sm' => 'db.m1.small', 'med' => 'db.m1.medium', 'lg' => 'db.m1.large', 'xl' => 'db.m1.xlarge', 'xlHiMem' => 'db.m2.xlarge', 'xxlHiMem' => 'db.m2.2xlarge', 'xxxxlHiMem' => 'db.m2.4xlarge', 'xxxxxxxxl' => 'db.m2.8xlarge'},
|
83
|
+
}
|
84
|
+
@@Name_Lookup_Reserved = {
|
85
|
+
'stdDeployRes' => {'u' => 'Standard Micro', 'micro' => 'Standard Micro', 'sm' => 'Standard Small', 'med' => 'Standard Medium', 'lg' => 'Standard Large', 'xl' => 'Standard Extra Large', 'xlHiMem' => 'Standard Extra Large High-Memory', 'xxlHiMem' => 'Standard Double Extra Large High-Memory', 'xxxxlHiMem' => 'Standard Quadruple Extra Large High-Memory', 'xxxxxxxxl' => 'Standard Eight Extra Large'} ,
|
86
|
+
'multiAZdeployRes' => {'u' => 'Multi-AZ Micro', 'micro' => 'Multi-AZ Micro', 'sm' => 'Multi-AZ Small', 'med' => 'Multi-AZ Medium', 'lg' => 'Multi-AZ Large', 'xl' => 'Multi-AZ Extra Large', 'xlHiMem' => 'Multi-AZ Extra Large High-Memory', 'xxlHiMem' => 'Multi-AZ Double Extra Large High-Memory', 'xxxxlHiMem' => 'Multi-AZ Quadruple Extra Large High-Memory', 'xxxxxxxxl' => 'Multi-AZ Eight Extra Large'},
|
87
|
+
}
|
88
|
+
end
|
89
|
+
end
|
@@ -19,35 +19,59 @@ module AwsPricing
|
|
19
19
|
|
20
20
|
def initialize(name)
|
21
21
|
@name = name
|
22
|
-
@
|
22
|
+
@ec2_instance_types = {}
|
23
|
+
@rds_instance_types = {}
|
23
24
|
end
|
24
25
|
|
25
|
-
def
|
26
|
-
@
|
26
|
+
def ec2_instance_types
|
27
|
+
@ec2_instance_types.values
|
28
|
+
end
|
29
|
+
|
30
|
+
def rds_instance_types
|
31
|
+
@rds_instance_types.values
|
27
32
|
end
|
28
33
|
|
29
34
|
# Returns whether an instance_type is available.
|
30
35
|
# operating_system = :linux, :mswin, :rhel, :sles, :mswinSQL, :mswinSQLWeb
|
31
36
|
# type_of_instance = :ondemand, :light, :medium, :heavy
|
32
37
|
def instance_type_available?(api_name, type_of_instance = :ondemand, operating_system = :linux)
|
33
|
-
instance = @
|
38
|
+
instance = @ec2_instance_types[api_name]
|
34
39
|
return false if instance.nil?
|
35
40
|
instance.available?(type_of_instance, operating_system)
|
36
41
|
end
|
37
42
|
|
38
43
|
# type_of_instance = :ondemand, :light, :medium, :heavy
|
39
|
-
def
|
40
|
-
current =
|
44
|
+
def add_or_update_ec2_instance_type(api_name, name, operating_system, type_of_instance, json)
|
45
|
+
current = get_ec2_instance_type(api_name)
|
41
46
|
if current.nil?
|
42
|
-
current =
|
43
|
-
@
|
47
|
+
current = Ec2InstanceType.new(self, api_name, name)
|
48
|
+
@ec2_instance_types[api_name] = current
|
44
49
|
end
|
45
50
|
current.update_pricing(operating_system, type_of_instance, json)
|
46
51
|
current
|
47
52
|
end
|
48
53
|
|
54
|
+
def add_or_update_rds_instance_type(api_name, name, db_type, type_of_instance, json, isMultiAz)
|
55
|
+
current = get_rds_instance_type(api_name)
|
56
|
+
if current.nil?
|
57
|
+
current = RdsInstanceType.new(self, api_name, name)
|
58
|
+
@rds_instance_types[api_name] = current
|
59
|
+
end
|
60
|
+
current.update_pricing(db_type, type_of_instance, json, isMultiAz)
|
61
|
+
current
|
62
|
+
end
|
63
|
+
|
64
|
+
# Maintained for backward compatibility reasons (retrieves EC2 instance type)
|
49
65
|
def get_instance_type(api_name)
|
50
|
-
|
66
|
+
get_ec2_instance_type(api_name)
|
67
|
+
end
|
68
|
+
|
69
|
+
def get_ec2_instance_type(api_name)
|
70
|
+
@ec2_instance_types[api_name]
|
71
|
+
end
|
72
|
+
|
73
|
+
def get_rds_instance_type(api_name)
|
74
|
+
@rds_instance_types[api_name]
|
51
75
|
end
|
52
76
|
|
53
77
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'amazon-pricing'
|
2
|
+
|
3
|
+
describe AwsPricing::RdsPriceList do
|
4
|
+
|
5
|
+
before do
|
6
|
+
@region_name = ['us-east', 'us-west', 'us-west-2', 'eu-ireland', 'apac-sin', 'apac-syd', 'apac-tokyo', 'sa-east-1']
|
7
|
+
@db_types = [:mysql, :oracle, :oracle_byol, :sqlserver, :sqlserver_express, :sqlserver_web, :sqlserver_byol]
|
8
|
+
end
|
9
|
+
|
10
|
+
describe 'new' do
|
11
|
+
it 'RdsPriceList.new should return the valid response' do
|
12
|
+
result = AwsPricing::RdsPriceList.new
|
13
|
+
result.regions.each do |region|
|
14
|
+
# response should have valid region
|
15
|
+
expect(@region_name).to include(region.name)
|
16
|
+
# Result have valid db name
|
17
|
+
expect(@db_types).to include(region.rds_instance_types.first.category_types.first.name)
|
18
|
+
# values should not be nil
|
19
|
+
region.rds_instance_types.first.category_types.first.ondemand_price_per_hour.should_not be_nil
|
20
|
+
region.rds_instance_types.first.category_types.first.light_price_per_hour_1_year.should_not be_nil
|
21
|
+
region.rds_instance_types.first.category_types.first.medium_price_per_hour_1_year.should_not be_nil
|
22
|
+
region.rds_instance_types.first.category_types.first.heavy_price_per_hour_1_year.should_not be_nil
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe '::get_api_name' do
|
28
|
+
it "raises an UnknownTypeError on an unexpected instance type" do
|
29
|
+
expect {
|
30
|
+
AwsPricing::InstanceType::get_name 'QuantumODI', 'huge'
|
31
|
+
}.to raise_error(AwsPricing::UnknownTypeError)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -16,17 +16,17 @@ require 'test/unit'
|
|
16
16
|
|
17
17
|
class TestEc2InstanceTypes < Test::Unit::TestCase
|
18
18
|
def test_cc8xlarge_issue
|
19
|
-
pricing = AwsPricing::
|
19
|
+
pricing = AwsPricing::Ec2PriceList.new
|
20
20
|
obj = pricing.get_instance_type('us-east', 'cc2.8xlarge')
|
21
21
|
assert obj.api_name == 'cc2.8xlarge'
|
22
22
|
end
|
23
23
|
|
24
24
|
def test_name_lookup
|
25
|
-
pricing = AwsPricing::
|
25
|
+
pricing = AwsPricing::Ec2PriceList.new
|
26
26
|
pricing.regions.each do |region|
|
27
27
|
assert_not_nil region.name
|
28
28
|
|
29
|
-
region.
|
29
|
+
region.ec2_instance_types.each do |instance|
|
30
30
|
assert_not_nil(instance.api_name)
|
31
31
|
assert_not_nil(instance.name)
|
32
32
|
end
|
@@ -43,15 +43,15 @@ class TestEc2InstanceTypes < Test::Unit::TestCase
|
|
43
43
|
|
44
44
|
def test_available
|
45
45
|
# Validate instance types in specific regions are available
|
46
|
-
pricing = AwsPricing::
|
46
|
+
pricing = AwsPricing::Ec2PriceList.new
|
47
47
|
region = pricing.get_region('us-east')
|
48
48
|
assert region.instance_type_available?('m1.large')
|
49
49
|
end
|
50
50
|
|
51
51
|
def test_fetch_all_breakeven_months
|
52
|
-
pricing = AwsPricing::
|
52
|
+
pricing = AwsPricing::Ec2PriceList.new
|
53
53
|
pricing.regions.each do |region|
|
54
|
-
region.
|
54
|
+
region.ec2_instance_types.each do |instance|
|
55
55
|
instance.operating_systems.each do |os|
|
56
56
|
[:light, :medium, :heavy].each do |res_type|
|
57
57
|
next if not instance.available?(res_type)
|
@@ -64,30 +64,30 @@ class TestEc2InstanceTypes < Test::Unit::TestCase
|
|
64
64
|
end
|
65
65
|
|
66
66
|
def test_breakeven_month
|
67
|
-
pricing = AwsPricing::
|
67
|
+
pricing = AwsPricing::Ec2PriceList.new
|
68
68
|
region = pricing.get_region('us-east')
|
69
|
-
instance = region.
|
69
|
+
instance = region.get_ec2_instance_type('m1.large')
|
70
70
|
bem = instance.get_breakeven_month(:linux, :heavy, :year1)
|
71
71
|
assert bem == 6
|
72
72
|
end
|
73
73
|
|
74
74
|
def test_memory
|
75
75
|
# Validate instance types in specific regions are available
|
76
|
-
pricing = AwsPricing::
|
76
|
+
pricing = AwsPricing::Ec2PriceList.new
|
77
77
|
region = pricing.get_region('us-east')
|
78
|
-
instance = region.
|
78
|
+
instance = region.get_ec2_instance_type('m1.large')
|
79
79
|
assert instance.memory_in_mb == 7500
|
80
80
|
end
|
81
81
|
|
82
82
|
def test_non_standard_region_name
|
83
|
-
pricing = AwsPricing::
|
83
|
+
pricing = AwsPricing::Ec2PriceList.new
|
84
84
|
region = pricing.get_region('eu-west-1')
|
85
|
-
instance = region.
|
85
|
+
instance = region.get_ec2_instance_type('m1.large')
|
86
86
|
assert instance.memory_in_mb == 7500
|
87
87
|
end
|
88
88
|
|
89
89
|
def test_ebs
|
90
|
-
pricing = AwsPricing::
|
90
|
+
pricing = AwsPricing::Ec2PriceList.new
|
91
91
|
region = pricing.get_region('us-east')
|
92
92
|
assert region.ebs_price.standard_per_gb == 0.10
|
93
93
|
assert region.ebs_price.standard_per_million_io == 0.10
|
@@ -97,7 +97,7 @@ class TestEc2InstanceTypes < Test::Unit::TestCase
|
|
97
97
|
end
|
98
98
|
|
99
99
|
def test_ebs_not_null
|
100
|
-
pricing = AwsPricing::
|
100
|
+
pricing = AwsPricing::Ec2PriceList.new
|
101
101
|
pricing.regions.each do |region|
|
102
102
|
# Everyone should have standard pricing
|
103
103
|
assert_not_nil region.ebs_price.standard_per_gb
|
@@ -107,9 +107,9 @@ class TestEc2InstanceTypes < Test::Unit::TestCase
|
|
107
107
|
end
|
108
108
|
|
109
109
|
def test_virtual_cores
|
110
|
-
pricing = AwsPricing::
|
110
|
+
pricing = AwsPricing::Ec2PriceList.new
|
111
111
|
region = pricing.get_region('us-east')
|
112
|
-
instance = region.
|
112
|
+
instance = region.get_ec2_instance_type('m1.large')
|
113
113
|
assert instance.virtual_cores == 2
|
114
114
|
end
|
115
115
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: amazon-pricing
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.10
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -27,13 +27,18 @@ files:
|
|
27
27
|
- Rakefile
|
28
28
|
- amazon-pricing.gemspec
|
29
29
|
- lib/amazon-pricing.rb
|
30
|
+
- lib/amazon-pricing/category-type.rb
|
31
|
+
- lib/amazon-pricing/database-type.rb
|
30
32
|
- lib/amazon-pricing/ebs-price.rb
|
33
|
+
- lib/amazon-pricing/ec2-instance-type.rb
|
31
34
|
- lib/amazon-pricing/instance-type.rb
|
32
35
|
- lib/amazon-pricing/operating-system.rb
|
36
|
+
- lib/amazon-pricing/rds-instance-type.rb
|
33
37
|
- lib/amazon-pricing/region.rb
|
34
38
|
- lib/amazon-pricing/version.rb
|
35
39
|
- spec/instance_type_spec.rb
|
36
40
|
- spec/price_list_spec.rb
|
41
|
+
- spec/rds-amazon-pricing-spec.rb
|
37
42
|
- test/helper.rb
|
38
43
|
- test/test-ec2-instance-types.rb
|
39
44
|
homepage: http://github.com/CloudHealth/amazon-pricing
|
@@ -69,6 +74,7 @@ summary: Amazon Web Services Pricing Ruby gem
|
|
69
74
|
test_files:
|
70
75
|
- spec/instance_type_spec.rb
|
71
76
|
- spec/price_list_spec.rb
|
77
|
+
- spec/rds-amazon-pricing-spec.rb
|
72
78
|
- test/helper.rb
|
73
79
|
- test/test-ec2-instance-types.rb
|
74
80
|
has_rdoc:
|