joyent-cloud-pricing 1.0.3 → 1.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +19 -3
- data/config/joyent_pricing.yml +309 -45
- data/config/legacy_prices.yml +6 -3
- data/joyent-cloud-pricing.gemspec +6 -6
- data/lib/pricing.rb +10 -9
- data/lib/pricing/analyzer.rb +32 -10
- data/lib/pricing/commit.rb +6 -0
- data/lib/pricing/configuration.rb +13 -4
- data/lib/pricing/flavor.rb +25 -0
- data/lib/pricing/formatter.rb +1 -1
- data/lib/pricing/reporter.rb +36 -21
- data/lib/pricing/scraper.rb +13 -8
- data/lib/pricing/version.rb +1 -1
- data/spec/fixtures/pricing.yml +10 -4
- data/spec/pricing/analyzer_spec.rb +98 -0
- data/spec/pricing/configuration_spec.rb +22 -11
- data/spec/pricing/formatter_spec.rb +20 -19
- data/spec/pricing/reporter_spec.rb +6 -6
- data/spec/pricing/scraper_spec.rb +14 -6
- metadata +4 -3
- data/spec/pricing/analyze_spec.rb +0 -82
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: af9e7e7a7f24831b00088ee284035a3ab1c5d385
|
4
|
+
data.tar.gz: f7de3d3f2c71529d6a5a9a8fc64fa2ac2f6a0e03
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: de8614e7801059dd5ee1f9886a05c4a1ae750857c26215197a5a7ea3da276556037762415ede75f9cf7652bc8d822eb53b7816217bade8a1b3320a70eac2b786
|
7
|
+
data.tar.gz: ee977c931ab860210802396ef2f920169e7610808b9bde394c0eb6d13c724c17716eb99faef8287488c753689c51590d3646b90c21bebd5266f3855e7eb5e9b0
|
data/README.md
CHANGED
@@ -70,8 +70,11 @@ Joyent::Cloud::Pricing::Configuration.instance["g3-standard-48-smartos"]
|
|
70
70
|
|
71
71
|
## Analysis of Commit Pricing
|
72
72
|
|
73
|
+
_DISCLAIMER_: please note that prices specified in this sample commit configuration
|
74
|
+
are completely arbitrary and have no relationship to any actual discounts issued by Joyent, Inc.
|
75
|
+
|
73
76
|
Reserve pricing is meant to be defined by a YAML file, outside of the gem folder,
|
74
|
-
somewhere on the file system. File looks like this
|
77
|
+
somewhere on the file system. File looks like this.
|
75
78
|
|
76
79
|
```yaml
|
77
80
|
defaults: &defaults
|
@@ -123,8 +126,15 @@ This module is used by ```knife joyent server price``` plugin to calculate prici
|
|
123
126
|
reserve discounts.
|
124
127
|
|
125
128
|
```ruby
|
126
|
-
current_zone_list = %w(
|
127
|
-
|
129
|
+
current_zone_list = %w(
|
130
|
+
g3-highcpu-8-smartos
|
131
|
+
g3-highcpu-8-smartos
|
132
|
+
# ....
|
133
|
+
)
|
134
|
+
|
135
|
+
reporter = Joyent::Cloud::Pricing::Reporter.new(
|
136
|
+
'config/reserve-commit.yml',
|
137
|
+
current_zone_list)
|
128
138
|
|
129
139
|
puts reporter.render
|
130
140
|
```
|
@@ -175,6 +185,12 @@ YEARLY COSTS:
|
|
175
185
|
4. Push to the branch (`git push origin my-new-feature`)
|
176
186
|
5. Create new Pull Request
|
177
187
|
|
188
|
+
## Disclaimer
|
189
|
+
|
190
|
+
This gem is provided as a convenience tool in understanding and comparing cloud pricing. No warranties,
|
191
|
+
explicit or implied, are made in relation to correctness or accuracy of the calculations provided by this
|
192
|
+
library. Use at your own risk.
|
193
|
+
|
178
194
|
## Author
|
179
195
|
|
180
196
|
Konstantin Gredeskoul, [@kig on twitter](http://twitter.com/kig), [@kigster on github](http://github.com/kigster)
|
data/config/joyent_pricing.yml
CHANGED
@@ -1,47 +1,311 @@
|
|
1
1
|
---
|
2
|
-
:date: '2014-03-
|
2
|
+
:date: '2014-03-30 00:02:20 -0700'
|
3
3
|
:pricing:
|
4
|
-
:g3-standard-0.625-smartos:
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
:g3-standard-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
:g3-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
:g3-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
:g3-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
:g3-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
:g3-
|
47
|
-
|
4
|
+
:g3-standard-0.625-smartos:
|
5
|
+
:name: g3-standard-0.625-smartos
|
6
|
+
:os: SmartOS
|
7
|
+
:cost: 0.02
|
8
|
+
:cpus: 0.15
|
9
|
+
:disk: 20
|
10
|
+
:ram: 0.625
|
11
|
+
:g3-standard-1.75-smartos:
|
12
|
+
:name: g3-standard-1.75-smartos
|
13
|
+
:os: SmartOS
|
14
|
+
:cost: 0.056
|
15
|
+
:cpus: 1.0
|
16
|
+
:disk: 56
|
17
|
+
:ram: 1.75
|
18
|
+
:g3-standard-3.75-smartos:
|
19
|
+
:name: g3-standard-3.75-smartos
|
20
|
+
:os: SmartOS
|
21
|
+
:cost: 0.12
|
22
|
+
:cpus: 1.0
|
23
|
+
:disk: 123
|
24
|
+
:ram: 3.75
|
25
|
+
:g3-standard-7.5-smartos:
|
26
|
+
:name: g3-standard-7.5-smartos
|
27
|
+
:os: SmartOS
|
28
|
+
:cost: 0.24
|
29
|
+
:cpus: 2.0
|
30
|
+
:disk: 738
|
31
|
+
:ram: 7.5
|
32
|
+
:g3-standard-15-smartos:
|
33
|
+
:name: g3-standard-15-smartos
|
34
|
+
:os: SmartOS
|
35
|
+
:cost: 0.48
|
36
|
+
:cpus: 4.0
|
37
|
+
:disk: 1467
|
38
|
+
:ram: 15.0
|
39
|
+
:g3-standard-30-smartos:
|
40
|
+
:name: g3-standard-30-smartos
|
41
|
+
:os: SmartOS
|
42
|
+
:cost: 0.96
|
43
|
+
:cpus: 8.0
|
44
|
+
:disk: 1683
|
45
|
+
:ram: 30.0
|
46
|
+
:g3-standard-48-smartos:
|
47
|
+
:name: g3-standard-48-smartos
|
48
|
+
:os: SmartOS
|
49
|
+
:cost: 1.536
|
50
|
+
:cpus: 12.0
|
51
|
+
:disk: 1683
|
52
|
+
:ram: 48.0
|
53
|
+
:g3-standard-64-smartos:
|
54
|
+
:name: g3-standard-64-smartos
|
55
|
+
:os: SmartOS
|
56
|
+
:cost: 2.048
|
57
|
+
:cpus: 16.0
|
58
|
+
:disk: 2100
|
59
|
+
:ram: 64.0
|
60
|
+
:g3-standard-80-smartos:
|
61
|
+
:name: g3-standard-80-smartos
|
62
|
+
:os: SmartOS
|
63
|
+
:cost: 2.56
|
64
|
+
:cpus: 20.0
|
65
|
+
:disk: 2625
|
66
|
+
:ram: 80.0
|
67
|
+
:g3-standard-96-smartos:
|
68
|
+
:name: g3-standard-96-smartos
|
69
|
+
:os: SmartOS
|
70
|
+
:cost: 3.072
|
71
|
+
:cpus: 24.0
|
72
|
+
:disk: 3150
|
73
|
+
:ram: 96.0
|
74
|
+
:g3-standard-128-smartos-cc:
|
75
|
+
:name: g3-standard-128-smartos-cc
|
76
|
+
:os: SmartOS
|
77
|
+
:cost: 4.096
|
78
|
+
:cpus: 32.0
|
79
|
+
:disk: 4200
|
80
|
+
:ram: 128.0
|
81
|
+
:g3-highmemory-17.125-smartos:
|
82
|
+
:name: g3-highmemory-17.125-smartos
|
83
|
+
:os: SmartOS
|
84
|
+
:cost: 0.409
|
85
|
+
:cpus: 2.0
|
86
|
+
:disk: 420
|
87
|
+
:ram: 17.125
|
88
|
+
:g3-highmemory-34.25-smartos:
|
89
|
+
:name: g3-highmemory-34.25-smartos
|
90
|
+
:os: SmartOS
|
91
|
+
:cost: 0.817
|
92
|
+
:cpus: 4.0
|
93
|
+
:disk: 843
|
94
|
+
:ram: 34.25
|
95
|
+
:g3-highmemory-68.375-smartos:
|
96
|
+
:name: g3-highmemory-68.375-smartos
|
97
|
+
:os: SmartOS
|
98
|
+
:cost: 1.63
|
99
|
+
:cpus: 8.0
|
100
|
+
:disk: 1122
|
101
|
+
:ram: 68.375
|
102
|
+
:g3-highmemory-144-smartos:
|
103
|
+
:name: g3-highmemory-144-smartos
|
104
|
+
:os: SmartOS
|
105
|
+
:cost: 3.433
|
106
|
+
:cpus: 18.0
|
107
|
+
:disk: 2363
|
108
|
+
:ram: 144.0
|
109
|
+
:g3-highmemory-256-smartos-cc:
|
110
|
+
:name: g3-highmemory-256-smartos-cc
|
111
|
+
:os: SmartOS
|
112
|
+
:cost: 6.102
|
113
|
+
:cpus: 32.0
|
114
|
+
:disk: 4200
|
115
|
+
:ram: 256.0
|
116
|
+
:g3-highcpu-1.75-smartos:
|
117
|
+
:name: g3-highcpu-1.75-smartos
|
118
|
+
:os: SmartOS
|
119
|
+
:cost: 0.127
|
120
|
+
:cpus: 2.0
|
121
|
+
:disk: 75
|
122
|
+
:ram: 1.75
|
123
|
+
:g3-highcpu-7-smartos:
|
124
|
+
:name: g3-highcpu-7-smartos
|
125
|
+
:os: SmartOS
|
126
|
+
:cost: 0.508
|
127
|
+
:cpus: 7.0
|
128
|
+
:disk: 262
|
129
|
+
:ram: 7.0
|
130
|
+
:g3-highcpu-16-smartos:
|
131
|
+
:name: g3-highcpu-16-smartos
|
132
|
+
:os: SmartOS
|
133
|
+
:cost: 1.16
|
134
|
+
:cpus: 16.0
|
135
|
+
:disk: 600
|
136
|
+
:ram: 16.0
|
137
|
+
:g3-highcpu-24-smartos:
|
138
|
+
:name: g3-highcpu-24-smartos
|
139
|
+
:os: SmartOS
|
140
|
+
:cost: 1.739
|
141
|
+
:cpus: 24.0
|
142
|
+
:disk: 900
|
143
|
+
:ram: 24.0
|
144
|
+
:g3-highcpu-32-smartos-cc:
|
145
|
+
:name: g3-highcpu-32-smartos-cc
|
146
|
+
:os: SmartOS
|
147
|
+
:cost: 2.319
|
148
|
+
:cpus: 32.0
|
149
|
+
:disk: 1200
|
150
|
+
:ram: 32.0
|
151
|
+
:g3-highio-15-smartos:
|
152
|
+
:name: g3-highio-15-smartos
|
153
|
+
:os: SmartOS
|
154
|
+
:cost: 0.76
|
155
|
+
:cpus: 2.0
|
156
|
+
:disk: 360
|
157
|
+
:ram: 15.0
|
158
|
+
:g3-highio-30-smartos:
|
159
|
+
:name: g3-highio-30-smartos
|
160
|
+
:os: SmartOS
|
161
|
+
:cost: 1.52
|
162
|
+
:cpus: 4.0
|
163
|
+
:disk: 725
|
164
|
+
:ram: 30.0
|
165
|
+
:g3-highio-60.5-smartos:
|
166
|
+
:name: g3-highio-60.5-smartos
|
167
|
+
:os: SmartOS
|
168
|
+
:cost: 3.067
|
169
|
+
:cpus: 8.0
|
170
|
+
:disk: 1452
|
171
|
+
:ram: 60.5
|
172
|
+
:g3-highio-128-smartos:
|
173
|
+
:name: g3-highio-128-smartos
|
174
|
+
:os: SmartOS
|
175
|
+
:cost: 6.488
|
176
|
+
:cpus: 16.0
|
177
|
+
:disk: 3072
|
178
|
+
:ram: 128.0
|
179
|
+
:g3-highio-256-smartos-cc:
|
180
|
+
:name: g3-highio-256-smartos-cc
|
181
|
+
:os: SmartOS
|
182
|
+
:cost: 12.976
|
183
|
+
:cpus: 32.0
|
184
|
+
:disk: 6144
|
185
|
+
:ram: 256.0
|
186
|
+
:g3-highstorage-32-smartos:
|
187
|
+
:name: g3-highstorage-32-smartos
|
188
|
+
:os: SmartOS
|
189
|
+
:cost: 0.863
|
190
|
+
:cpus: 8.0
|
191
|
+
:disk: 7680
|
192
|
+
:ram: 32.0
|
193
|
+
:g3-highstorage-64-smartos:
|
194
|
+
:name: g3-highstorage-64-smartos
|
195
|
+
:os: SmartOS
|
196
|
+
:cost: 1.726
|
197
|
+
:cpus: 16.0
|
198
|
+
:disk: 15360
|
199
|
+
:ram: 64.0
|
200
|
+
:g3-highstorage-128-smartos-cc:
|
201
|
+
:name: g3-highstorage-128-smartos-cc
|
202
|
+
:os: SmartOS
|
203
|
+
:cost: 3.451
|
204
|
+
:cpus: 32.0
|
205
|
+
:disk: 30720
|
206
|
+
:ram: 128.0
|
207
|
+
:g3-standard-0.625-kvm:
|
208
|
+
:name: g3-standard-0.625-kvm
|
209
|
+
:os: Linux
|
210
|
+
:cost: 0.02
|
211
|
+
:cpus: 0.15
|
212
|
+
:disk: 20
|
213
|
+
:ram: 0.625
|
214
|
+
:g3-standard-1.75-kvm:
|
215
|
+
:name: g3-standard-1.75-kvm
|
216
|
+
:os: Linux
|
217
|
+
:cost: 0.056
|
218
|
+
:cpus: 1.0
|
219
|
+
:disk: 56
|
220
|
+
:ram: 1.75
|
221
|
+
:g3-standard-3.75-kvm:
|
222
|
+
:name: g3-standard-3.75-kvm
|
223
|
+
:os: Linux
|
224
|
+
:cost: 0.12
|
225
|
+
:cpus: 1.0
|
226
|
+
:disk: 123
|
227
|
+
:ram: 3.75
|
228
|
+
:g3-standard-7.5-kvm:
|
229
|
+
:name: g3-standard-7.5-kvm
|
230
|
+
:os: Linux
|
231
|
+
:cost: 0.24
|
232
|
+
:cpus: 2.0
|
233
|
+
:disk: 738
|
234
|
+
:ram: 7.5
|
235
|
+
:g3-standard-15-kvm:
|
236
|
+
:name: g3-standard-15-kvm
|
237
|
+
:os: Linux
|
238
|
+
:cost: 0.48
|
239
|
+
:cpus: 4.0
|
240
|
+
:disk: 1467
|
241
|
+
:ram: 15.0
|
242
|
+
:g3-standard-30-kvm:
|
243
|
+
:name: g3-standard-30-kvm
|
244
|
+
:os: Linux
|
245
|
+
:cost: 0.96
|
246
|
+
:cpus: 8.0
|
247
|
+
:disk: 1683
|
248
|
+
:ram: 30.0
|
249
|
+
:g3-highmemory-17.125-kvm:
|
250
|
+
:name: g3-highmemory-17.125-kvm
|
251
|
+
:os: Linux
|
252
|
+
:cost: 0.409
|
253
|
+
:cpus: 2.0
|
254
|
+
:disk: 420
|
255
|
+
:ram: 17.125
|
256
|
+
:g3-highmemory-34.25-kvm:
|
257
|
+
:name: g3-highmemory-34.25-kvm
|
258
|
+
:os: Linux
|
259
|
+
:cost: 0.817
|
260
|
+
:cpus: 4.0
|
261
|
+
:disk: 843
|
262
|
+
:ram: 34.25
|
263
|
+
:g3-highmemory-68.375-kvm:
|
264
|
+
:name: g3-highmemory-68.375-kvm
|
265
|
+
:os: Linux
|
266
|
+
:cost: 1.63
|
267
|
+
:cpus: 8.0
|
268
|
+
:disk: 1122
|
269
|
+
:ram: 68.375
|
270
|
+
:g3-highcpu-1.75-kvm:
|
271
|
+
:name: g3-highcpu-1.75-kvm
|
272
|
+
:os: Linux
|
273
|
+
:cost: 0.127
|
274
|
+
:cpus: 2.0
|
275
|
+
:disk: 75
|
276
|
+
:ram: 1.75
|
277
|
+
:g3-highcpu-7-kvm:
|
278
|
+
:name: g3-highcpu-7-kvm
|
279
|
+
:os: Linux
|
280
|
+
:cost: 0.508
|
281
|
+
:cpus: 7.0
|
282
|
+
:disk: 262
|
283
|
+
:ram: 7.0
|
284
|
+
:g3-highio-15-kvm:
|
285
|
+
:name: g3-highio-15-kvm
|
286
|
+
:os: Linux
|
287
|
+
:cost: 0.76
|
288
|
+
:cpus: 2.0
|
289
|
+
:disk: 360
|
290
|
+
:ram: 15.0
|
291
|
+
:g3-highio-30-kvm:
|
292
|
+
:name: g3-highio-30-kvm
|
293
|
+
:os: Linux
|
294
|
+
:cost: 1.52
|
295
|
+
:cpus: 4.0
|
296
|
+
:disk: 725
|
297
|
+
:ram: 30.0
|
298
|
+
:g3-highio-60.5-kvm:
|
299
|
+
:name: g3-highio-60.5-kvm
|
300
|
+
:os: Linux
|
301
|
+
:cost: 3.067
|
302
|
+
:cpus: 8.0
|
303
|
+
:disk: 1452
|
304
|
+
:ram: 60.5
|
305
|
+
:g3-highstorage-32-kvm:
|
306
|
+
:name: g3-highstorage-32-kvm
|
307
|
+
:os: Linux
|
308
|
+
:cost: 0.863
|
309
|
+
:cpus: 8.0
|
310
|
+
:disk: 7680
|
311
|
+
:ram: 32.0
|
data/config/legacy_prices.yml
CHANGED
@@ -4,20 +4,20 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
require 'pricing/version'
|
5
5
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
|
-
spec.name =
|
7
|
+
spec.name = 'joyent-cloud-pricing'
|
8
8
|
spec.version = Joyent::Cloud::Pricing::VERSION
|
9
|
-
spec.authors = [
|
10
|
-
spec.email = [
|
9
|
+
spec.authors = ['Konstantin Gredeskoul']
|
10
|
+
spec.email = ['kigster@gmail.com']
|
11
11
|
spec.summary = %q{Tools for calculating monthly and yearly price of infrastructure hosted on Joyent Public Cloud.}
|
12
12
|
spec.description = %q{Various set of tools and helpers to calculate infrastructure footprint and cost on Joyent Cloud. Supports commit discounts.}
|
13
|
-
spec.homepage =
|
14
|
-
spec.license =
|
13
|
+
spec.homepage = 'https://github.com/kigster/joyent-cloud-pricing'
|
14
|
+
spec.license = 'MIT'
|
15
15
|
|
16
16
|
spec.files = `git ls-files -z`.split("\x0")
|
17
17
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
19
|
|
20
|
-
spec.require_paths = [
|
20
|
+
spec.require_paths = ['lib']
|
21
21
|
|
22
22
|
spec.add_dependency 'nokogiri'
|
23
23
|
spec.add_dependency 'colored'
|
data/lib/pricing.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require 'pricing/version'
|
2
|
+
require 'pricing/symbolize_keys'
|
3
3
|
|
4
4
|
module Joyent
|
5
5
|
module Cloud
|
@@ -15,10 +15,11 @@ module Joyent
|
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
|
-
require
|
19
|
-
require
|
20
|
-
require
|
21
|
-
require
|
22
|
-
require
|
23
|
-
require
|
24
|
-
require
|
18
|
+
require 'pricing/flavor'
|
19
|
+
require 'pricing/helpers'
|
20
|
+
require 'pricing/configuration'
|
21
|
+
require 'pricing/scraper'
|
22
|
+
require 'pricing/formatter'
|
23
|
+
require 'pricing/commit'
|
24
|
+
require 'pricing/analyzer'
|
25
|
+
require 'pricing/reporter'
|
data/lib/pricing/analyzer.rb
CHANGED
@@ -3,35 +3,35 @@ require_relative 'commit'
|
|
3
3
|
module Joyent::Cloud::Pricing
|
4
4
|
class Analyzer
|
5
5
|
|
6
|
-
attr_accessor :commit, :
|
6
|
+
attr_accessor :commit, :zone_counts
|
7
7
|
|
8
8
|
def initialize(commit, flavors = [])
|
9
9
|
@commit = commit
|
10
|
-
@
|
10
|
+
@zone_counts = count_dupes(flavors).symbolize_keys
|
11
11
|
end
|
12
12
|
|
13
13
|
# Zones that are not on commit
|
14
|
-
def
|
14
|
+
def excess_zone_counts
|
15
15
|
h = {}
|
16
|
-
|
16
|
+
zone_counts.each_pair { |flavor, count| diff = count - quantity_for(flavor); h[flavor] = diff if diff > 0 }
|
17
17
|
h
|
18
18
|
end
|
19
19
|
|
20
20
|
# Zones that are committed, but do not exist
|
21
|
-
def
|
21
|
+
def over_reserved_zone_counts
|
22
22
|
h = {}
|
23
|
-
|
23
|
+
zone_counts.each_pair { |flavor, count| diff = count - quantity_for(flavor); h[flavor] = -diff if diff < 0 }
|
24
24
|
h
|
25
25
|
end
|
26
26
|
|
27
27
|
# Non-discounted full price
|
28
28
|
def monthly_full_price
|
29
|
-
monthly_full_price_for(
|
29
|
+
monthly_full_price_for(zone_counts)
|
30
30
|
end
|
31
31
|
|
32
32
|
# Excess zones cost this much
|
33
33
|
def monthly_overages_price
|
34
|
-
monthly_full_price_for(
|
34
|
+
monthly_full_price_for(excess_zone_counts)
|
35
35
|
end
|
36
36
|
|
37
37
|
# Monthly for all of the commits
|
@@ -49,7 +49,7 @@ module Joyent::Cloud::Pricing
|
|
49
49
|
end
|
50
50
|
|
51
51
|
def monthly_full_price_for zones
|
52
|
-
|
52
|
+
count_for_all zones do |flavor|
|
53
53
|
pricing.monthly(flavor)
|
54
54
|
end
|
55
55
|
end
|
@@ -74,9 +74,31 @@ module Joyent::Cloud::Pricing
|
|
74
74
|
100 * (yearly_full_price - yearly_total) / yearly_full_price
|
75
75
|
end
|
76
76
|
|
77
|
+
def cpus
|
78
|
+
count_props(:cpus)
|
79
|
+
end
|
80
|
+
|
81
|
+
def ram
|
82
|
+
count_props(:ram)
|
83
|
+
end
|
84
|
+
|
85
|
+
def disk
|
86
|
+
count_props(:disk)
|
87
|
+
end
|
88
|
+
|
77
89
|
private
|
78
90
|
|
79
|
-
def
|
91
|
+
def count_props(operation)
|
92
|
+
results = [ zone_counts, excess_zone_counts, commit.flavor_counts ].map do |list|
|
93
|
+
count_for_all list do |flavor|
|
94
|
+
pricing.flavor(flavor).send(operation)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
{ total: results[0], unreserved: results[1], reserved: results[2] }
|
98
|
+
end
|
99
|
+
|
100
|
+
|
101
|
+
def count_for_all zones, &block
|
80
102
|
zones.keys.inject(0) do |sum, flavor|
|
81
103
|
sum += zones[flavor] * yield(flavor); sum
|
82
104
|
end.round(2)
|
data/lib/pricing/commit.rb
CHANGED
@@ -44,6 +44,12 @@ module Joyent::Cloud::Pricing
|
|
44
44
|
reserves.empty? ? 0 : reserves.values.first.years
|
45
45
|
end
|
46
46
|
|
47
|
+
def flavor_counts
|
48
|
+
zone_list = {}
|
49
|
+
reserves.keys.each{|zone| zone_list[zone] = reserves[zone].quantity}
|
50
|
+
zone_list
|
51
|
+
end
|
52
|
+
|
47
53
|
private
|
48
54
|
|
49
55
|
def sum_of
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'yaml'
|
2
2
|
require_relative 'helpers'
|
3
|
+
require_relative 'flavor'
|
3
4
|
|
4
5
|
module Joyent::Cloud::Pricing
|
5
6
|
class Configuration
|
@@ -39,12 +40,20 @@ module Joyent::Cloud::Pricing
|
|
39
40
|
@config = hash.symbolize_keys
|
40
41
|
end
|
41
42
|
|
42
|
-
def
|
43
|
-
|
43
|
+
def cost(flavor)
|
44
|
+
f = config[flavor.to_sym]
|
45
|
+
f.nil? ? nil : f[:cost]
|
44
46
|
end
|
45
47
|
|
46
|
-
def
|
47
|
-
f =
|
48
|
+
def flavor(flavor)
|
49
|
+
f = config[flavor.to_sym]
|
50
|
+
return nil if f.nil?
|
51
|
+
f.delete(:name) # name is saved in YAML, but it's not in Flavor class hash attributes
|
52
|
+
Flavor.new(flavor, f)
|
53
|
+
end
|
54
|
+
|
55
|
+
def monthly(flavor)
|
56
|
+
f = self.cost(flavor)
|
48
57
|
if f.nil?
|
49
58
|
STDERR.puts "WARNING: can't find flavor #{flavor}, assuming 0"
|
50
59
|
0
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Joyent::Cloud::Pricing
|
2
|
+
class Flavor
|
3
|
+
attr_accessor :name, :os, :cost, :ram, :cpus, :disk
|
4
|
+
|
5
|
+
def initialize(name, os: os, cost: cost, ram: ram, cpus: cpus, disk: disk)
|
6
|
+
@name = name
|
7
|
+
@os = os
|
8
|
+
@cost = (cost == 'N/A') ? nil : cost.to_f
|
9
|
+
@cpus = cpus.to_f
|
10
|
+
@disk = disk.to_i
|
11
|
+
@ram = ram.to_f
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_h
|
15
|
+
{
|
16
|
+
name: name,
|
17
|
+
os: os,
|
18
|
+
cost: cost,
|
19
|
+
cpus: cpus,
|
20
|
+
disk: disk,
|
21
|
+
ram: ram
|
22
|
+
}
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/pricing/formatter.rb
CHANGED
data/lib/pricing/reporter.rb
CHANGED
@@ -5,7 +5,7 @@ require 'colored'
|
|
5
5
|
module Joyent::Cloud::Pricing
|
6
6
|
class Reporter
|
7
7
|
|
8
|
-
attr_accessor :commit, :zones_in_use, :analyzer, :formatter
|
8
|
+
attr_accessor :commit, :zones_in_use, :analyzer, :formatter, :print_zone_list
|
9
9
|
|
10
10
|
def initialize(commit = COMMIT, zones_in_use = [])
|
11
11
|
@commit = case commit
|
@@ -20,8 +20,9 @@ module Joyent::Cloud::Pricing
|
|
20
20
|
end
|
21
21
|
|
22
22
|
@zones_in_use = zones_in_use
|
23
|
-
@analyzer = Analyzer.new(@commit, @zones_in_use)
|
24
|
-
@formatter = Formatter.new(pricing.config)
|
23
|
+
@analyzer = Joyent::Cloud::Pricing::Analyzer.new(@commit, @zones_in_use)
|
24
|
+
@formatter = Joyent::Cloud::Pricing::Formatter.new(pricing.config)
|
25
|
+
@print_zone_list = true
|
25
26
|
end
|
26
27
|
|
27
28
|
def render
|
@@ -39,11 +40,11 @@ module Joyent::Cloud::Pricing
|
|
39
40
|
end
|
40
41
|
|
41
42
|
def pricing
|
42
|
-
Configuration.instance
|
43
|
+
Joyent::Cloud::Pricing::Configuration.instance
|
43
44
|
end
|
44
45
|
|
45
46
|
def excess_zones
|
46
|
-
zones = analyzer.
|
47
|
+
zones = analyzer.excess_zone_counts.each_pair.map{|flavor, count| [ flavor, count, pricing.monthly(flavor) * count ]}.sort{|x,y| y[2] <=> x[2]}
|
47
48
|
zones
|
48
49
|
end
|
49
50
|
|
@@ -55,30 +56,39 @@ module Joyent::Cloud::Pricing
|
|
55
56
|
end.join("\n")
|
56
57
|
end
|
57
58
|
|
59
|
+
def zone_props_to_string(prop_type, width, suffix = '', divide_by = 1)
|
60
|
+
props = analyzer.send(prop_type)
|
61
|
+
[ props[:reserved], props[:unreserved], props[:total] ].map do |value|
|
62
|
+
sprintf("%#{width}d#{suffix}", value / divide_by)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
58
66
|
SEPARATOR = ('.' * 65).cyan
|
67
|
+
PROPS_FORMAT= '%20d %20d %20d'
|
59
68
|
REPORT_ASCII = <<ASCII
|
60
69
|
|
61
70
|
ZONE COUNTS:
|
62
71
|
Total # of zones <%= sprintf("%20d", @r.zones).cyan %>
|
63
72
|
<%- if @r.reserve? -%>
|
64
73
|
Total # of reserved zones <%= sprintf("%20d", @r.commit.total_zones).green %>
|
65
|
-
Total # of reserved but absent zones <%= value = sprintf("%20d", @r.analyzer.
|
66
|
-
Reserve Pricing Term/Duration (years) <%= sprintf("%20d", @r.commit.years || 0).blue %>
|
67
|
-
<%= SEPARATOR %>
|
68
|
-
|
69
|
-
RESERVE UPFRONT COST:
|
70
|
-
Reserve Pricing Upfront Payments <%= @f.format_price(@r.commit.upfront_price, 20).green %>
|
74
|
+
Total # of reserved but absent zones <%= value = sprintf("%20d", @r.analyzer.over_reserved_zone_counts.size || 0); value == "0" ? value.blue : value.red %>
|
71
75
|
<%- end -%>
|
76
|
+
|
77
|
+
Resources in use:<%= sprintf('%14s %15s %15s', 'Reserved', 'On-Demand', 'Total') %>
|
78
|
+
CPUs <%= props = @r.zone_props_to_string(:cpus, 16); props[0].green + props[1].yellow + props[2].cyan %>
|
79
|
+
RAM <%= props = @r.zone_props_to_string(:ram, 15, 'G'); props[0].green + props[1].yellow + props[2].cyan %>
|
80
|
+
DISK <%= props = @r.zone_props_to_string(:disk, 15, 'T', 1024); props[0].green + props[1].yellow + props[2].cyan %>
|
72
81
|
<%= SEPARATOR %>
|
73
82
|
|
74
83
|
MONTHLY COSTS:
|
75
|
-
|
84
|
+
<%- if @r.print_zone_list -%>
|
85
|
+
List of on-demand flavors by price <%= @r.reserve? ? "(in excess of reserve)" : "" %>
|
76
86
|
<%= @r.excess_zone_list %>
|
77
87
|
<%= "___________".yellow %>
|
78
|
-
|
79
|
-
|
88
|
+
<%- end -%>
|
89
|
+
On demand monthly <%= @f.format_price(@r.analyzer.monthly_overages_price, 20).yellow %>
|
80
90
|
<%- if @r.reserve? -%>
|
81
|
-
Zones
|
91
|
+
Zones under reserve pricing <%= @f.format_price(@r.commit.monthly_price, 20).green %>
|
82
92
|
<%- end -%>
|
83
93
|
<%- if @r.reserve? -%>
|
84
94
|
<%= "___________".cyan %>
|
@@ -88,16 +98,21 @@ MONTHLY COSTS:
|
|
88
98
|
|
89
99
|
YEARLY COSTS:
|
90
100
|
<%- if @r.reserve? -%>
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
Reserve Yearly <%= @f.format_price(@r.commit.yearly_price, 20).green %>
|
95
|
-
On Demand Yearly <%= @f.format_price(@r.analyzer.yearly_overages_price, 20).yellow %>
|
101
|
+
On demand yearly <%= @f.format_price(@r.analyzer.yearly_overages_price, 20).yellow %>
|
102
|
+
Commit prepay one time fee <%= @f.format_price(@r.commit.upfront_price, 20).green %>
|
103
|
+
Reserve yearly <%= @f.format_price(@r.commit.yearly_price, 20).green %>
|
96
104
|
<%= "___________".cyan %>
|
97
105
|
Total <%= @f.format_price(@r.analyzer.yearly_total, 20).cyan %>
|
98
106
|
<%- else -%>
|
99
|
-
On
|
107
|
+
On demand yearly <%= @f.format_price(@r.analyzer.yearly_full_price, 20).cyan %>
|
100
108
|
<%- end -%>
|
109
|
+
<%- if @r.reserve? -%>
|
110
|
+
|
111
|
+
YEARLY RESERVE SAVINGS:
|
112
|
+
Savings due to reserved pricing <%= @f.format_price(@r.analyzer.yearly_savings, 20).green %>
|
113
|
+
Savings % <%= sprintf("%19d", @r.analyzer.yearly_savings_percent).green + '%'.green %>
|
114
|
+
<%- end -%>
|
115
|
+
<%= SEPARATOR %>
|
101
116
|
|
102
117
|
ASCII
|
103
118
|
|
data/lib/pricing/scraper.rb
CHANGED
@@ -12,15 +12,14 @@ module Joyent::Cloud::Pricing
|
|
12
12
|
end
|
13
13
|
|
14
14
|
class Parser < Struct.new(:doc)
|
15
|
-
class PriceTuple < Struct.new(:os, :cost, :flavor); end
|
16
15
|
|
17
16
|
def result
|
18
17
|
config = Hash.new
|
19
|
-
self.doc.css(
|
20
|
-
|
21
|
-
next if
|
22
|
-
next if
|
23
|
-
config[
|
18
|
+
self.doc.css('ul.full-specs').each do |ul|
|
19
|
+
flavor = extract_price(ul)
|
20
|
+
next if flavor.cost.nil?
|
21
|
+
next if flavor.name =~ /kvm/ && flavor.os !~ /linux/i
|
22
|
+
config[flavor.name]= flavor.to_h
|
24
23
|
end
|
25
24
|
config
|
26
25
|
end
|
@@ -30,8 +29,14 @@ module Joyent::Cloud::Pricing
|
|
30
29
|
def extract_price(ul)
|
31
30
|
lis = ul.css("span").map(&:content)
|
32
31
|
# grab last two <li> elements in each <ul class="full-spec"> block
|
33
|
-
#
|
34
|
-
|
32
|
+
# and first few for cpu/ram/disk
|
33
|
+
# note: this obviously depends on Joyent website markup and is subject to break.
|
34
|
+
Flavor.new(lis[-1], # flavor
|
35
|
+
os: lis[-3],
|
36
|
+
cost: lis[-2].gsub(/^\$/, ''),
|
37
|
+
ram: lis[0],
|
38
|
+
cpus: lis[1],
|
39
|
+
disk: lis[2])
|
35
40
|
end
|
36
41
|
end
|
37
42
|
end
|
data/lib/pricing/version.rb
CHANGED
data/spec/fixtures/pricing.yml
CHANGED
@@ -1,7 +1,13 @@
|
|
1
1
|
---
|
2
2
|
:date: '2014-03-23 21:51:04 -0700'
|
3
3
|
:pricing:
|
4
|
-
g3-standard-0.625-smartos:
|
5
|
-
|
6
|
-
g3-standard-
|
7
|
-
|
4
|
+
g3-standard-0.625-smartos:
|
5
|
+
:cost: 0.02
|
6
|
+
g3-standard-30-kvm:
|
7
|
+
:cost: 0.96
|
8
|
+
g3-standard-48-smartos:
|
9
|
+
:cost: 1.536
|
10
|
+
:ram: 12
|
11
|
+
:cpus: 16.0
|
12
|
+
g3-standard-64-smartos:
|
13
|
+
:cost: 2.048
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Joyent::Cloud::Pricing::Analyzer' do
|
4
|
+
|
5
|
+
let(:flavors) { %w(
|
6
|
+
g3-highcpu-16-smartos
|
7
|
+
g3-highcpu-16-smartos
|
8
|
+
g3-standard-30-smartos
|
9
|
+
g3-highcpu-32-smartos-cc
|
10
|
+
g3-highcpu-32-smartos-cc
|
11
|
+
g3-highcpu-32-smartos-cc
|
12
|
+
g3-highcpu-32-smartos-cc
|
13
|
+
g3-highcpu-32-smartos-cc
|
14
|
+
g3-highcpu-32-smartos-cc
|
15
|
+
g3-highcpu-32-smartos-cc
|
16
|
+
g3-highcpu-32-smartos-cc
|
17
|
+
g3-highcpu-32-smartos-cc
|
18
|
+
g3-highcpu-32-smartos-cc
|
19
|
+
g3-highcpu-32-smartos-cc
|
20
|
+
g3-highcpu-32-smartos-cc
|
21
|
+
g3-highcpu-7-smartos
|
22
|
+
g3-highcpu-7-smartos
|
23
|
+
g3-highio-60.5-smartos
|
24
|
+
g3-highio-60.5-smartos
|
25
|
+
g3-highio-60.5-smartos
|
26
|
+
g3-highio-60.5-smartos
|
27
|
+
g3-highmemory-17.125-smartos
|
28
|
+
g3-highmemory-17.125-smartos
|
29
|
+
g3-highmemory-17.125-smartos
|
30
|
+
g3-highmemory-17.125-smartos
|
31
|
+
g3-highmemory-17.125-smartos
|
32
|
+
g3-highmemory-17.125-smartos
|
33
|
+
g3-highmemory-17.125-smartos
|
34
|
+
g3-highmemory-17.125-smartos
|
35
|
+
g3-highmemory-17.125-smartos
|
36
|
+
g3-highmemory-17.125-smartos
|
37
|
+
g3-highmemory-17.125-smartos
|
38
|
+
g3-highmemory-17.125-smartos
|
39
|
+
) }
|
40
|
+
let(:commit) { Joyent::Cloud::Pricing::Commit.from_yaml 'spec/fixtures/commit.yml' }
|
41
|
+
let(:analyzer) { Joyent::Cloud::Pricing::Analyzer.new(commit, flavors) }
|
42
|
+
|
43
|
+
# need to have pricing so that it reloads from real price TODO: fix this
|
44
|
+
before do
|
45
|
+
Joyent::Cloud::Pricing::Configuration.from_yaml
|
46
|
+
end
|
47
|
+
|
48
|
+
it '#initialize' do
|
49
|
+
expect(analyzer.zone_counts).to_not be_empty
|
50
|
+
expect(analyzer.zone_counts).to eql (
|
51
|
+
{:'g3-highcpu-16-smartos' => 2,
|
52
|
+
:'g3-highcpu-32-smartos-cc' => 12,
|
53
|
+
:'g3-highcpu-7-smartos' => 2,
|
54
|
+
:'g3-highio-60.5-smartos' => 4,
|
55
|
+
:'g3-highmemory-17.125-smartos' => 12,
|
56
|
+
:'g3-standard-30-smartos' => 1
|
57
|
+
})
|
58
|
+
end
|
59
|
+
|
60
|
+
context 'monthly prices' do
|
61
|
+
it '#monthly_full_price' do
|
62
|
+
expect(analyzer.monthly_full_price).to eql(35496.0)
|
63
|
+
end
|
64
|
+
|
65
|
+
it '#monthly_overages_price' do
|
66
|
+
expect(analyzer.monthly_overages_price).to eql(6432.48)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
context 'zone frequency counts' do
|
71
|
+
it '#excess_zone_counts' do
|
72
|
+
expect(analyzer.excess_zone_counts).to eql(
|
73
|
+
{:'g3-highcpu-16-smartos' => 2,
|
74
|
+
:'g3-highcpu-32-smartos-cc' => 2,
|
75
|
+
:'g3-highcpu-7-smartos' => 2,
|
76
|
+
:'g3-standard-30-smartos' => 1
|
77
|
+
})
|
78
|
+
end
|
79
|
+
|
80
|
+
it '#over_reserved_zone_counts' do
|
81
|
+
expect(analyzer.over_reserved_zone_counts).to eql({:'g3-highio-60.5-smartos' => 1})
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
context 'reserved and unreserved totals for flavor properties' do
|
86
|
+
it '#cpus' do
|
87
|
+
expect(analyzer.cpus).to eql({total: 494.0, reserved: 384.0, unreserved: 118.0})
|
88
|
+
end
|
89
|
+
|
90
|
+
it '#ram' do
|
91
|
+
expect(analyzer.ram).to eql({total: 907.5, unreserved: 140.0, reserved: 828.0})
|
92
|
+
end
|
93
|
+
|
94
|
+
it '#disk' do
|
95
|
+
expect(analyzer.disk).to eql({total: 28655.0, unreserved: 5807.0, reserved: 24300.0})
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -2,28 +2,28 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe 'Joyent::Cloud::Pricing::Configuration' do
|
4
4
|
expected_prices = {
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
5
|
+
'g3-standard-48-smartos' => 1.536,
|
6
|
+
'g3-standard-0.625-smartos' => 0.02,
|
7
|
+
'g3-standard-30-kvm' => 0.960,
|
8
|
+
'g3-standard-8-smartos' => 0.26,
|
9
|
+
'g3-highcpu-8-smartos' => 0.58,
|
10
|
+
'g3-standard-0.5-smartos' => 0.016
|
11
11
|
}
|
12
12
|
|
13
13
|
let(:config) {
|
14
14
|
Joyent::Cloud::Pricing::Configuration.from_yaml 'spec/fixtures/pricing.yml'
|
15
15
|
}
|
16
16
|
|
17
|
-
context
|
17
|
+
context '#from_yaml' do
|
18
18
|
expected_prices.keys.each do |flavor|
|
19
19
|
it "should load pricing for #{flavor}" do
|
20
|
-
expect(config
|
20
|
+
expect(config.cost(flavor)).to eql(expected_prices[flavor])
|
21
21
|
end
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
25
|
-
context
|
26
|
-
it
|
25
|
+
context '#instance' do
|
26
|
+
it 'should be able to create new instance, but remember the last once' do
|
27
27
|
c1 = Joyent::Cloud::Pricing::Configuration.from_yaml 'spec/fixtures/pricing.yml'
|
28
28
|
c2 = Joyent::Cloud::Pricing::Configuration.from_yaml 'spec/fixtures/pricing.yml'
|
29
29
|
|
@@ -31,8 +31,19 @@ describe 'Joyent::Cloud::Pricing::Configuration' do
|
|
31
31
|
expect(Joyent::Cloud::Pricing::Configuration.instance).not_to eql(c1)
|
32
32
|
end
|
33
33
|
|
34
|
-
it
|
34
|
+
it 'should have instance set' do
|
35
35
|
expect(Joyent::Cloud::Pricing::Configuration.instance).not_to be_nil
|
36
36
|
end
|
37
37
|
end
|
38
|
+
|
39
|
+
context '#flavor' do
|
40
|
+
it 'should properly instantiate Flavor instance from hash' do
|
41
|
+
flavor = config.flavor 'g3-standard-48-smartos'
|
42
|
+
expect(flavor.class).to eql(Joyent::Cloud::Pricing::Flavor)
|
43
|
+
|
44
|
+
expect(flavor.ram).to eql(12.0)
|
45
|
+
expect(flavor.cpus).to eql(16.0)
|
46
|
+
expect(flavor.cost).to eql(1.536)
|
47
|
+
end
|
48
|
+
end
|
38
49
|
end
|
@@ -2,34 +2,35 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe' Joyent::Cloud::Pricing::Formatter' do
|
4
4
|
|
5
|
-
let(:config) {
|
6
|
-
|
7
|
-
|
5
|
+
let(:config) { Joyent::Cloud::Pricing::Configuration.new(
|
6
|
+
{'g3-standard-48-smartos' => {cost: 1.536},
|
7
|
+
'g3-standard-0.625-smartos' => {cost: 0.02},
|
8
|
+
'g3-standard-30-kvm' => {cost: 0.960} }) }
|
8
9
|
|
9
10
|
let(:formatter) { Joyent::Cloud::Pricing::Formatter.new(config) }
|
10
11
|
|
11
|
-
context
|
12
|
-
it
|
13
|
-
expect(formatter.format_monthly_price
|
14
|
-
expect(formatter.format_monthly_price
|
12
|
+
context '#format_monthly_price' do
|
13
|
+
it 'should return properly formatted monthly price' do
|
14
|
+
expect(formatter.format_monthly_price 'g3-standard-0.625-smartos').to eql('$14.40')
|
15
|
+
expect(formatter.format_monthly_price 'g3-standard-30-kvm').to eql('$691.20')
|
15
16
|
end
|
16
17
|
end
|
17
|
-
context
|
18
|
-
it
|
19
|
-
expect(formatter.format_monthly_price
|
18
|
+
context '#monthly_formatted_price_for_flavor' do
|
19
|
+
it 'should return properly formatted monthly price' do
|
20
|
+
expect(formatter.format_monthly_price 'g3-standard-48-smartos', 10).to eql(' $1,105.92')
|
20
21
|
end
|
21
|
-
it
|
22
|
-
expect(formatter.format_monthly_price
|
22
|
+
it 'should return blank when no match was found' do
|
23
|
+
expect(formatter.format_monthly_price 'asdfkasdfasdlfkjasl;dkjf').to eql('')
|
23
24
|
end
|
24
25
|
end
|
25
|
-
context
|
26
|
-
it
|
27
|
-
expect(formatter.format_price 24566.34, 10).to eql(
|
28
|
-
expect(formatter.format_price 4566.34, 10).to eql(
|
26
|
+
context '#format_price' do
|
27
|
+
it 'should return properly formatted price' do
|
28
|
+
expect(formatter.format_price 24566.34, 10).to eql('$24,566.34')
|
29
|
+
expect(formatter.format_price 4566.34, 10).to eql(' $4,566.34')
|
29
30
|
end
|
30
|
-
it
|
31
|
-
expect(formatter.format_price 0, 10).to eql(
|
32
|
-
expect(formatter.format_price nil, 10).to eql(
|
31
|
+
it 'should return blank string of given width for 0 or nil' do
|
32
|
+
expect(formatter.format_price 0, 10).to eql(' ')
|
33
|
+
expect(formatter.format_price nil, 10).to eql(' ')
|
33
34
|
end
|
34
35
|
end
|
35
36
|
end
|
@@ -44,23 +44,23 @@ describe 'Joyent::Cloud::Pricing::Reporter' do
|
|
44
44
|
Joyent::Cloud::Pricing::Configuration.instance(true)
|
45
45
|
end
|
46
46
|
|
47
|
-
context
|
48
|
-
it
|
47
|
+
context '#initialize' do
|
48
|
+
it 'should not be empty when created' do
|
49
49
|
expect(reporter).to_not be_nil
|
50
50
|
expect(reporter.analyzer).to_not be_nil
|
51
51
|
expect(reporter.zones_in_use.size).to eql(flavors.size)
|
52
52
|
end
|
53
53
|
end
|
54
54
|
|
55
|
-
context
|
56
|
-
it
|
55
|
+
context '#render' do
|
56
|
+
it 'should propertly render an ERB template' do
|
57
57
|
output = reporter.render
|
58
58
|
expect(output).to_not be_nil
|
59
59
|
end
|
60
60
|
|
61
|
-
context
|
61
|
+
context 'blank commit configuration' do
|
62
62
|
let(:commit) { Joyent::Cloud::Pricing::Commit.new }
|
63
|
-
it
|
63
|
+
it 'should still properly render an ERB template' do
|
64
64
|
expect(commit.reserves.size).to eql(0)
|
65
65
|
output = reporter.render
|
66
66
|
expect(output).to_not be_nil
|
@@ -1,21 +1,29 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe 'Joyent::Cloud::Pricing::Scraper' do
|
4
|
-
context
|
4
|
+
context 'scraping from URL'
|
5
5
|
let(:scraper) { Joyent::Cloud::Pricing::Scraper.new }
|
6
6
|
|
7
|
-
let(:prices) { {
|
8
|
-
|
9
|
-
|
7
|
+
let(:prices) { {'g3-standard-48-smartos' => 1.536,
|
8
|
+
'g3-standard-0.625-smartos' => 0.02,
|
9
|
+
'g3-standard-30-kvm' => 0.960
|
10
|
+
} }
|
11
|
+
|
12
|
+
let(:cpus) { {'g3-standard-48-smartos' => 12.0,
|
13
|
+
'g3-standard-0.625-smartos' => 0.15,
|
14
|
+
'g3-standard-30-kvm' => 8.0
|
10
15
|
} }
|
11
16
|
|
12
17
|
before do
|
13
18
|
@config = scraper.scrape
|
14
19
|
end
|
15
20
|
|
16
|
-
it
|
21
|
+
it 'should load pricing configuration hash from Joyent Website' do
|
17
22
|
prices.keys.each do |flavor|
|
18
|
-
expect(@config[flavor]).to eql(prices[flavor])
|
23
|
+
expect(@config[flavor][:cost]).to eql(prices[flavor])
|
24
|
+
end
|
25
|
+
cpus.keys.each do |flavor|
|
26
|
+
expect(@config[flavor][:cpus]).to eql(cpus[flavor])
|
19
27
|
end
|
20
28
|
end
|
21
29
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: joyent-cloud-pricing
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Konstantin Gredeskoul
|
@@ -117,6 +117,7 @@ files:
|
|
117
117
|
- lib/pricing/analyzer.rb
|
118
118
|
- lib/pricing/commit.rb
|
119
119
|
- lib/pricing/configuration.rb
|
120
|
+
- lib/pricing/flavor.rb
|
120
121
|
- lib/pricing/formatter.rb
|
121
122
|
- lib/pricing/helpers.rb
|
122
123
|
- lib/pricing/reporter.rb
|
@@ -127,7 +128,7 @@ files:
|
|
127
128
|
- lib/tasks/update.rake
|
128
129
|
- spec/fixtures/commit.yml
|
129
130
|
- spec/fixtures/pricing.yml
|
130
|
-
- spec/pricing/
|
131
|
+
- spec/pricing/analyzer_spec.rb
|
131
132
|
- spec/pricing/commit_spec.rb
|
132
133
|
- spec/pricing/configuration_spec.rb
|
133
134
|
- spec/pricing/formatter_spec.rb
|
@@ -163,7 +164,7 @@ summary: Tools for calculating monthly and yearly price of infrastructure hosted
|
|
163
164
|
test_files:
|
164
165
|
- spec/fixtures/commit.yml
|
165
166
|
- spec/fixtures/pricing.yml
|
166
|
-
- spec/pricing/
|
167
|
+
- spec/pricing/analyzer_spec.rb
|
167
168
|
- spec/pricing/commit_spec.rb
|
168
169
|
- spec/pricing/configuration_spec.rb
|
169
170
|
- spec/pricing/formatter_spec.rb
|
@@ -1,82 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe 'Joyent::Cloud::Pricing::Analyze' do
|
4
|
-
|
5
|
-
let(:flavors) { %w(
|
6
|
-
g3-highcpu-16-smartos
|
7
|
-
g3-highcpu-16-smartos
|
8
|
-
g3-standard-30-smartos
|
9
|
-
g3-highcpu-32-smartos-cc
|
10
|
-
g3-highcpu-32-smartos-cc
|
11
|
-
g3-highcpu-32-smartos-cc
|
12
|
-
g3-highcpu-32-smartos-cc
|
13
|
-
g3-highcpu-32-smartos-cc
|
14
|
-
g3-highcpu-32-smartos-cc
|
15
|
-
g3-highcpu-32-smartos-cc
|
16
|
-
g3-highcpu-32-smartos-cc
|
17
|
-
g3-highcpu-32-smartos-cc
|
18
|
-
g3-highcpu-32-smartos-cc
|
19
|
-
g3-highcpu-32-smartos-cc
|
20
|
-
g3-highcpu-32-smartos-cc
|
21
|
-
g3-highcpu-7-smartos
|
22
|
-
g3-highcpu-7-smartos
|
23
|
-
g3-highio-60.5-smartos
|
24
|
-
g3-highio-60.5-smartos
|
25
|
-
g3-highio-60.5-smartos
|
26
|
-
g3-highio-60.5-smartos
|
27
|
-
g3-highmemory-17.125-smartos
|
28
|
-
g3-highmemory-17.125-smartos
|
29
|
-
g3-highmemory-17.125-smartos
|
30
|
-
g3-highmemory-17.125-smartos
|
31
|
-
g3-highmemory-17.125-smartos
|
32
|
-
g3-highmemory-17.125-smartos
|
33
|
-
g3-highmemory-17.125-smartos
|
34
|
-
g3-highmemory-17.125-smartos
|
35
|
-
g3-highmemory-17.125-smartos
|
36
|
-
g3-highmemory-17.125-smartos
|
37
|
-
g3-highmemory-17.125-smartos
|
38
|
-
g3-highmemory-17.125-smartos
|
39
|
-
) }
|
40
|
-
let(:commit) { Joyent::Cloud::Pricing::Commit.from_yaml 'spec/fixtures/commit.yml' }
|
41
|
-
let(:analyzer) { Joyent::Cloud::Pricing::Analyzer.new(commit, flavors) }
|
42
|
-
|
43
|
-
# need to have pricing so that it reloads from real price TODO: fix this
|
44
|
-
before do
|
45
|
-
Joyent::Cloud::Pricing::Configuration.from_yaml
|
46
|
-
end
|
47
|
-
|
48
|
-
it '#initialize' do
|
49
|
-
expect(analyzer.zone_list).to_not be_empty
|
50
|
-
expect(analyzer.zone_list).to eql (
|
51
|
-
{:"g3-highcpu-16-smartos" => 2,
|
52
|
-
:"g3-highcpu-32-smartos-cc" => 12,
|
53
|
-
:"g3-highcpu-7-smartos" => 2,
|
54
|
-
:"g3-highio-60.5-smartos" => 4,
|
55
|
-
:"g3-highmemory-17.125-smartos" => 12,
|
56
|
-
:"g3-standard-30-smartos" => 1
|
57
|
-
})
|
58
|
-
end
|
59
|
-
|
60
|
-
it '#monthly_full_price' do
|
61
|
-
expect(analyzer.monthly_full_price).to eql(35496.0)
|
62
|
-
end
|
63
|
-
|
64
|
-
it '#excess_zone_list' do
|
65
|
-
expect(analyzer.excess_zone_list).to eql(
|
66
|
-
{:"g3-highcpu-16-smartos" => 2,
|
67
|
-
:"g3-highcpu-32-smartos-cc" => 2,
|
68
|
-
:"g3-highcpu-7-smartos" => 2,
|
69
|
-
:"g3-standard-30-smartos" => 1
|
70
|
-
})
|
71
|
-
end
|
72
|
-
|
73
|
-
it '#monthly_overages_price' do
|
74
|
-
expect(analyzer.monthly_overages_price).to eql( 6432.48 )
|
75
|
-
end
|
76
|
-
|
77
|
-
it '#over_reserved_zone_list' do
|
78
|
-
expect(analyzer.over_reserved_zone_list).to eql( {:"g3-highio-60.5-smartos" => 1 })
|
79
|
-
end
|
80
|
-
|
81
|
-
|
82
|
-
end
|