joyent-cloud-pricing 1.0.9 → 1.0.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.
- checksums.yaml +4 -4
- data/README.md +48 -15
- data/config/commit_pricing.yml.example +6 -0
- data/config/{legacy_prices.yml → joyent_pricing_unpublished.yml} +11 -0
- data/lib/pricing.rb +1 -1
- data/lib/pricing/analyzer.rb +10 -0
- data/lib/pricing/commit.rb +7 -3
- data/lib/pricing/configuration.rb +4 -0
- data/lib/pricing/report.txt.erb +66 -0
- data/lib/pricing/reporter.rb +69 -99
- data/lib/pricing/version.rb +1 -1
- data/spec/fixtures/commit.yml +4 -0
- data/spec/fixtures/commit_noreserve.yml +6 -0
- data/spec/pricing/analyzer_spec.rb +9 -3
- data/spec/pricing/commit_spec.rb +32 -11
- data/spec/pricing/reporter_spec.rb +12 -4
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ffe763f26373c4c9dd19d269cabb8d34be18204b
|
4
|
+
data.tar.gz: e1454babed191bb8e3ddd4f3a6d0f768396a5c76
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8ee3d92c075e5bd7bd352b59b6e16bf1e6fcd57b5312888b9ae8d802d63bd206138ae8c36c8a95226c56546bae3fd4125fbab1e75d16d53c3a13a207ef0007fb
|
7
|
+
data.tar.gz: a37d969d4682497eb6380875b9fa7380190145b1d6b3946de4b15d1885f638e2b416c3f51647a47c4a6480058d4d692d223c40cbaac4ca088e56182fdf3859fe
|
data/README.md
CHANGED
@@ -54,15 +54,16 @@ Or install it yourself as:
|
|
54
54
|
|
55
55
|
Most recent pricing structure is stored in the YAML file under ```config/joyent_pricing.yml```.
|
56
56
|
|
57
|
-
To update this file, run provided rake
|
57
|
+
To update this file using prices published on Joyent's website, run the provided rake
|
58
|
+
task, and if YAML file changed, please feel free to submit a pull request.
|
58
59
|
|
59
60
|
```ruby
|
60
61
|
rake joyent:pricing:update
|
61
62
|
```
|
62
63
|
|
63
|
-
|
64
|
+
### Full Pricing
|
64
65
|
|
65
|
-
Full price is stored in the configuration instance.
|
66
|
+
Full price is stored in the configuration instance and is read from YAML file.
|
66
67
|
|
67
68
|
```ruby
|
68
69
|
c = Joyent::Cloud::Pricing::Configuration.instance
|
@@ -74,7 +75,7 @@ f.name
|
|
74
75
|
# => "g3-highmemory-34.25-kvm"
|
75
76
|
```
|
76
77
|
|
77
|
-
|
78
|
+
### Analysis of Commit Pricing
|
78
79
|
|
79
80
|
> DISCLAIMER: please note that prices specified in this sample commit configuration
|
80
81
|
> are completely arbitrary and have no relationship to any actual discounts issued by Joyent, Inc.
|
@@ -126,7 +127,30 @@ analyzer.monthly_overages_price # => monthly $$ for instances in excess of res
|
|
126
127
|
analyzer.over_reserved_zone_list # => list of zones in reserve, but not in reality
|
127
128
|
```
|
128
129
|
|
129
|
-
|
130
|
+
### Custom Pricing
|
131
|
+
|
132
|
+
If you have some zones with flavors that are either old, or created specifically for you,
|
133
|
+
they may not be known to this library. If they are known to you, you can use the reserve
|
134
|
+
pricing YAML file, and add a 'custom' section to it to define prices (and other attributes)
|
135
|
+
for any of the custom flavors, as follows (note that the 'reserved' section is not required).
|
136
|
+
|
137
|
+
```yaml
|
138
|
+
defaults: &defaults
|
139
|
+
years: 1
|
140
|
+
|
141
|
+
custom:
|
142
|
+
:flavor-just-for-me:
|
143
|
+
:cost: 1.22
|
144
|
+
:disk: 800
|
145
|
+
:ram: 96
|
146
|
+
:cpus: 32
|
147
|
+
|
148
|
+
```
|
149
|
+
|
150
|
+
The structure is the same as in the main file ```joyent_pricing.yml```, and the contents will
|
151
|
+
simply be merged on top of Joyent's standard pricing, so you can even overwrite existing flavors.
|
152
|
+
|
153
|
+
### Reporter
|
130
154
|
|
131
155
|
This module is used by ```knife joyent server price``` plugin to calculate pricing with and without
|
132
156
|
reserve discounts.
|
@@ -144,23 +168,28 @@ puts reporter.render
|
|
144
168
|
Example output with commit pricing used:
|
145
169
|
|
146
170
|
```
|
171
|
+
Joyent Pricing Calculator: https://github.com/kigster/joyent-cloud-pricing
|
172
|
+
.................................................................
|
147
173
|
ZONE COUNTS:
|
148
174
|
Total # of zones 33
|
149
175
|
Total # of reserved zones 27
|
150
|
-
Total # of reserved but absent
|
176
|
+
Total # of reserved but absent flavors 6
|
177
|
+
4 x g3-highmemory-68.375-smartos
|
178
|
+
2 x g3-highcpu-7-smartos
|
179
|
+
.................................................................
|
151
180
|
|
152
181
|
Resources in use: Reserved On-Demand Total
|
153
182
|
CPUs 384 118 494
|
154
183
|
RAM 828G 140G 907G
|
155
184
|
DISK 23T 5T 27T
|
156
|
-
.................................................................
|
157
185
|
|
158
186
|
MONTHLY COSTS:
|
159
187
|
List of on-demand flavors by price (in excess of reserve)
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
188
|
+
|
189
|
+
2 x g3-highcpu-32-smartos-cc $3,339.36
|
190
|
+
2 x g3-highcpu-16-smartos $1,670.40
|
191
|
+
2 x g3-highcpu-7-smartos $731.52
|
192
|
+
1 x g3-standard-30-smartos $691.20
|
164
193
|
___________
|
165
194
|
On demand monthly $6,432.48
|
166
195
|
Zones under reserve pricing $8,720.00
|
@@ -181,14 +210,18 @@ YEARLY RESERVE SAVINGS:
|
|
181
210
|
.................................................................
|
182
211
|
```
|
183
212
|
|
184
|
-
|
213
|
+
### Color
|
214
|
+
|
215
|
+
You can turn off color output by setting ```NO_COLOR``` environment variable.
|
216
|
+
|
217
|
+
### Usage with knife joyent
|
185
218
|
|
186
|
-
This gem is integrated
|
219
|
+
This gem is integrated into [knife-joyent](https://github.com/joyent/knife-joyent) gem.
|
187
220
|
|
188
|
-
Use it as follows:
|
221
|
+
Use it with ```knife joyent``` as follows:
|
189
222
|
|
190
223
|
```
|
191
|
-
knife joyent server pricing -z -r config/my-reserve-config.yml
|
224
|
+
knife joyent server pricing -z -r config/my-reserve-config.yml [ --no-color ]
|
192
225
|
```
|
193
226
|
|
194
227
|
## Contributing
|
@@ -1,8 +1,19 @@
|
|
1
1
|
:g3-standard-8-smartos:
|
2
2
|
:cost: 0.26
|
3
|
+
:ram: 8.0
|
4
|
+
:cpus: 4.0
|
5
|
+
:disk: 738
|
3
6
|
:g3-highcpu-8-smartos:
|
4
7
|
:cost: 0.58
|
8
|
+
:ram: 8.0
|
9
|
+
:cpus: 8.0
|
10
|
+
:disk: 738
|
5
11
|
:g3-standard-0.5-smartos:
|
6
12
|
:cost: 0.016
|
13
|
+
:ram: 0.5
|
14
|
+
:cpus: 0.5
|
7
15
|
:g3-highmemory-96-smartos:
|
8
16
|
:cost: 2.451
|
17
|
+
:ram: 7.5
|
18
|
+
:cpus: 32.0
|
19
|
+
:disk: 3100
|
data/lib/pricing.rb
CHANGED
@@ -6,7 +6,7 @@ module Joyent
|
|
6
6
|
module Pricing
|
7
7
|
|
8
8
|
PRICING_FILENAME = File.expand_path('../../config/joyent_pricing.yml', __FILE__)
|
9
|
-
LEGACY_FILENAME = File.expand_path('../../config/
|
9
|
+
LEGACY_FILENAME = File.expand_path('../../config/joyent_pricing_unpublished.yml', __FILE__)
|
10
10
|
COMMIT_FILENAME = 'config/commit_pricing.yml'
|
11
11
|
JOYENT_URL = 'http://www.joyent.com/products/compute-service/pricing'
|
12
12
|
HOURS_PER_MONTH = 720
|
data/lib/pricing/analyzer.rb
CHANGED
@@ -31,10 +31,20 @@ module Joyent::Cloud::Pricing
|
|
31
31
|
h
|
32
32
|
end
|
33
33
|
|
34
|
+
def unknown_zone_total
|
35
|
+
count_for_all(unknown_zone_counts) do |flavor|
|
36
|
+
1
|
37
|
+
end.to_i
|
38
|
+
end
|
39
|
+
|
34
40
|
def have_unknown_zones?
|
35
41
|
unknown_zone_counts.size > 0
|
36
42
|
end
|
37
43
|
|
44
|
+
def have_excess_zones?
|
45
|
+
excess_zone_counts.size > 0
|
46
|
+
end
|
47
|
+
|
38
48
|
def have_over_reserved_zones?
|
39
49
|
over_reserved_zone_counts.size > 0
|
40
50
|
end
|
data/lib/pricing/commit.rb
CHANGED
@@ -5,19 +5,23 @@ module Joyent::Cloud::Pricing
|
|
5
5
|
class Commit
|
6
6
|
class << self
|
7
7
|
def from_yaml(filename = COMMIT_FILENAME)
|
8
|
-
|
8
|
+
hash = YAML.load(File.read(filename))
|
9
|
+
new(hash['reserved'] || {}, hash['custom'])
|
9
10
|
end
|
10
11
|
end
|
11
12
|
|
12
13
|
# map of image names to prices
|
13
|
-
attr_accessor :reserves
|
14
|
+
attr_accessor :reserves, :custom
|
14
15
|
|
15
|
-
def initialize(hash = {})
|
16
|
+
def initialize(hash = {}, custom = nil)
|
16
17
|
@config = hash.symbolize_keys
|
17
18
|
self.reserves = {}
|
18
19
|
@config.each_pair do |flavor, config|
|
19
20
|
self.reserves[flavor] = Reserve.new(flavor, config)
|
20
21
|
end
|
22
|
+
if custom
|
23
|
+
Joyent::Cloud::Pricing::Configuration.instance.merge(custom)
|
24
|
+
end
|
21
25
|
end
|
22
26
|
|
23
27
|
def reserve_for flavor
|
@@ -0,0 +1,66 @@
|
|
1
|
+
<%- separator = ('.' * 65).cyan -%>
|
2
|
+
Joyent Pricing Calculator: https://github.com/kigster/joyent-cloud-pricing
|
3
|
+
<%= separator %>
|
4
|
+
<%- if have_unknown_zones? -%>
|
5
|
+
<%= "WARNING!".red %>: Some 'flavors' in your list were not recognized, and
|
6
|
+
were excluded from calculations. You could add them to the "custom"
|
7
|
+
section of your reserve pricing file, and specify their cost.
|
8
|
+
|
9
|
+
Total # of zones with unknown flavors: <%= sprintf("%20d", unknown_zone_total).red %>
|
10
|
+
List of unknown flavors below:
|
11
|
+
|
12
|
+
<%= unknown_zones_for_print.red %>
|
13
|
+
<%= separator %>
|
14
|
+
|
15
|
+
<%- end -%>
|
16
|
+
ZONE COUNTS:
|
17
|
+
Total # of zones <%= sprintf("%20d", zones_in_use.size).cyan %>
|
18
|
+
<%- if have_commit_pricing? -%>
|
19
|
+
Total # of reserved zones <%= sprintf("%20d", commit.total_zones).green %>
|
20
|
+
<%- if have_over_reserved_zones? -%>
|
21
|
+
Total # of reserved but absent flavors <%= value = sprintf("%20d", over_reserved_zone_counts.size || 0); value == "0" ? value.blue : value.red %>
|
22
|
+
<%= over_reserved_zones_for_print.magenta %>
|
23
|
+
<%- end -%>
|
24
|
+
<%- end -%>
|
25
|
+
<%= separator %>
|
26
|
+
|
27
|
+
Resources in use:<%= sprintf('%14s %15s %15s', 'Reserved', 'On-Demand', 'Total') %>
|
28
|
+
CPUs <%= props = zone_props_to_string(:cpus, 16); props[0].green + props[1].yellow + props[2].cyan %>
|
29
|
+
RAM <%= props = zone_props_to_string(:ram, 15, 'G'); props[0].green + props[1].yellow + props[2].cyan %>
|
30
|
+
DISK <%= props = zone_props_to_string(:disk, 15, 'T', 1024); props[0].green + props[1].yellow + props[2].cyan %>
|
31
|
+
<%= separator %>
|
32
|
+
|
33
|
+
MONTHLY COSTS:
|
34
|
+
<%- if print_zone_list -%>
|
35
|
+
List of on-demand flavors by price <%= have_commit_pricing? ? "(in excess of reserve)" : "" %>
|
36
|
+
|
37
|
+
<%= excess_zones_for_print %>
|
38
|
+
<%= "___________".yellow %>
|
39
|
+
<%- end -%>
|
40
|
+
On demand monthly <%= format_price(monthly_overages_price, 20).yellow %>
|
41
|
+
<%- if have_commit_pricing? -%>
|
42
|
+
Zones under reserve pricing <%= format_price(commit.monthly_price, 20).green %>
|
43
|
+
<%- end -%>
|
44
|
+
<%- if have_commit_pricing? -%>
|
45
|
+
<%= "___________".cyan %>
|
46
|
+
Total <%= format_price(monthly_total_price, 20).cyan %>
|
47
|
+
<%- end -%>
|
48
|
+
<%= separator %>
|
49
|
+
|
50
|
+
YEARLY COSTS:
|
51
|
+
<%- if have_commit_pricing? -%>
|
52
|
+
On demand yearly <%= format_price(yearly_overages_price, 20).yellow %>
|
53
|
+
Reserve prepay one time fee <%= format_price(commit.upfront_price, 20).green %>
|
54
|
+
Reserve sum of all monthly fees <%= format_price(commit.monthly_price * 12, 20).green %>
|
55
|
+
<%= "___________".cyan %>
|
56
|
+
Total <%= format_price(yearly_total, 20).cyan %>
|
57
|
+
<%- else -%>
|
58
|
+
On demand yearly <%= format_price(yearly_full_price, 20).cyan %>
|
59
|
+
<%- end -%>
|
60
|
+
<%- if have_commit_pricing? -%>
|
61
|
+
|
62
|
+
YEARLY RESERVE SAVINGS:
|
63
|
+
Savings due to reserved pricing <%= format_price(yearly_savings, 20).green %>
|
64
|
+
Savings % <%= sprintf("%19d", yearly_savings_percent).green + '%'.green %>
|
65
|
+
<%- end -%>
|
66
|
+
<%= separator %>
|
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, :print_zone_list
|
8
|
+
attr_accessor :commit, :zones_in_use, :analyzer, :formatter, :print_zone_list, :template
|
9
9
|
|
10
10
|
def initialize(commit = COMMIT, zones_in_use = [])
|
11
11
|
@commit = case commit
|
@@ -20,130 +20,100 @@ module Joyent::Cloud::Pricing
|
|
20
20
|
end
|
21
21
|
|
22
22
|
@zones_in_use = zones_in_use
|
23
|
-
@analyzer
|
23
|
+
@analyzer = Joyent::Cloud::Pricing::Analyzer.new(@commit, @zones_in_use)
|
24
24
|
@formatter = Joyent::Cloud::Pricing::Formatter.new(pricing.config)
|
25
25
|
@print_zone_list = true
|
26
|
+
@template = File.read(File.expand_path('../report.txt.erb', __FILE__))
|
26
27
|
end
|
27
28
|
|
28
|
-
def render
|
29
|
+
def render(options = {})
|
30
|
+
disable_color if (options && options[:disable_color]) || ENV['NO_COLOR']
|
29
31
|
@r = self
|
30
|
-
|
31
|
-
ERB.new(REPORT_ASCII, 0, '-').result(binding)
|
32
|
+
ERB.new(template, 0, '-').result(binding)
|
32
33
|
end
|
33
34
|
|
34
|
-
def
|
35
|
-
|
35
|
+
def pricing
|
36
|
+
Joyent::Cloud::Pricing::Configuration.instance
|
36
37
|
end
|
37
38
|
|
38
|
-
|
39
|
-
|
39
|
+
# Various formatting helpers follow below
|
40
|
+
# Note that we delegate to analyzer for majority of calls.
|
41
|
+
# Sorry about that method_missing :(
|
42
|
+
|
43
|
+
def method_missing(method, *args, &block)
|
44
|
+
if @analyzer.respond_to?(method)
|
45
|
+
@analyzer.send(method, *args, &block)
|
46
|
+
else
|
47
|
+
super
|
48
|
+
end
|
40
49
|
end
|
41
50
|
|
42
|
-
def
|
43
|
-
|
51
|
+
def format_price *args
|
52
|
+
@formatter.format_price *args
|
44
53
|
end
|
45
54
|
|
46
|
-
def
|
47
|
-
|
48
|
-
map{|flavor, count| [ flavor, count, pricing.monthly(flavor) * count ]}.
|
49
|
-
sort{|x,y| y[2] <=> x[2]}
|
50
|
-
zones
|
55
|
+
def have_commit_pricing?
|
56
|
+
commit.reserves.size > 0
|
51
57
|
end
|
52
58
|
|
53
|
-
def
|
54
|
-
|
55
|
-
flavor, count, monthly = tuple
|
56
|
-
sprintf(" %2d x %-36s %20s",
|
57
|
-
count, flavor, formatter.format_price(monthly, 20).yellow)
|
58
|
-
end.join("\n")
|
59
|
+
def excess_zones_for_print
|
60
|
+
zones_for_print(zone_counts_to_list(analyzer.excess_zone_counts), :yellow)
|
59
61
|
end
|
60
62
|
|
61
|
-
def
|
62
|
-
|
63
|
-
[ props[:reserved], props[:unreserved], props[:total] ].map do |value|
|
64
|
-
sprintf("%#{width}d#{suffix}", value / divide_by)
|
65
|
-
end
|
63
|
+
def over_reserved_zones_for_print
|
64
|
+
zones_for_print(analyzer.over_reserved_zone_counts)
|
66
65
|
end
|
67
66
|
|
68
|
-
def
|
69
|
-
analyzer.unknown_zone_counts.keys
|
67
|
+
def unknown_zones_for_print
|
68
|
+
zone_list_for_print(analyzer.unknown_zone_counts.keys)
|
70
69
|
end
|
71
70
|
|
72
|
-
def
|
73
|
-
|
71
|
+
def zones_for_print(zone_list, color = nil)
|
72
|
+
zone_list.map do |tuple|
|
73
|
+
flavor, count, monthly = tuple
|
74
|
+
price = formatter.format_price(monthly, 16)
|
75
|
+
price = price.send(color) if color
|
76
|
+
sprintf(" %2d x %-36s %16s", count, flavor, price)
|
77
|
+
end.join("\n")
|
74
78
|
end
|
75
79
|
|
76
80
|
def zone_list_for_print(list, format = ' %-40s')
|
77
|
-
list.map{|k| sprintf(format, k) }.join("\n")
|
81
|
+
list.map { |k| sprintf(format, k) }.join("\n")
|
78
82
|
end
|
79
83
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
were excluded from calculations. Add them to legacy_prices.yml.
|
87
|
-
|
88
|
-
List of flavors with unknown properties:
|
89
|
-
Total # of unrecognized flavor zones <%= sprintf("%20d", @r.analyzer.unknown_zone_counts.keys.size).red %>
|
90
|
-
<%= @r.zone_list_for_print(@r.unknown_flavor_zone_list).red %>
|
91
|
-
<%= SEPARATOR %>
|
92
|
-
|
93
|
-
<%- end -%>
|
94
|
-
ZONE COUNTS:
|
95
|
-
Total # of zones <%= sprintf("%20d", @r.zones).cyan %>
|
96
|
-
<%- if @r.reserve? -%>
|
97
|
-
Total # of reserved zones <%= sprintf("%20d", @r.commit.total_zones).green %>
|
98
|
-
<%- if @r.analyzer.have_over_reserved_zones? -%>
|
99
|
-
Total # of reserved but absent zones <%= value = sprintf("%20d", @r.analyzer.over_reserved_zone_counts.size || 0); value == "0" ? value.blue : value.red %>
|
100
|
-
<%= @r.zone_list_for_print(@r.over_reserved_zone_list).red %>
|
101
|
-
<%- end -%>
|
102
|
-
<%- end -%>
|
103
|
-
<%= SEPARATOR %>
|
104
|
-
|
105
|
-
Resources in use:<%= sprintf('%14s %15s %15s', 'Reserved', 'On-Demand', 'Total') %>
|
106
|
-
CPUs <%= props = @r.zone_props_to_string(:cpus, 16); props[0].green + props[1].yellow + props[2].cyan %>
|
107
|
-
RAM <%= props = @r.zone_props_to_string(:ram, 15, 'G'); props[0].green + props[1].yellow + props[2].cyan %>
|
108
|
-
DISK <%= props = @r.zone_props_to_string(:disk, 15, 'T', 1024); props[0].green + props[1].yellow + props[2].cyan %>
|
109
|
-
<%= SEPARATOR %>
|
110
|
-
|
111
|
-
MONTHLY COSTS:
|
112
|
-
<%- if @r.print_zone_list -%>
|
113
|
-
List of on-demand flavors by price <%= @r.reserve? ? "(in excess of reserve)" : "" %>
|
114
|
-
<%= @r.excess_zone_list %>
|
115
|
-
<%= "___________".yellow %>
|
116
|
-
<%- end -%>
|
117
|
-
On demand monthly <%= @f.format_price(@r.analyzer.monthly_overages_price, 20).yellow %>
|
118
|
-
<%- if @r.reserve? -%>
|
119
|
-
Zones under reserve pricing <%= @f.format_price(@r.commit.monthly_price, 20).green %>
|
120
|
-
<%- end -%>
|
121
|
-
<%- if @r.reserve? -%>
|
122
|
-
<%= "___________".cyan %>
|
123
|
-
Total <%= @f.format_price(@r.analyzer.monthly_total_price, 20).cyan %>
|
124
|
-
<%- end -%>
|
125
|
-
<%= SEPARATOR %>
|
126
|
-
|
127
|
-
YEARLY COSTS:
|
128
|
-
<%- if @r.reserve? -%>
|
129
|
-
On demand yearly <%= @f.format_price(@r.analyzer.yearly_overages_price, 20).yellow %>
|
130
|
-
Reserve prepay one time fee <%= @f.format_price(@r.commit.upfront_price, 20).green %>
|
131
|
-
Reserve sum of all monthly fees <%= @f.format_price(@r.commit.monthly_price * 12, 20).green %>
|
132
|
-
<%= "___________".cyan %>
|
133
|
-
Total <%= @f.format_price(@r.analyzer.yearly_total, 20).cyan %>
|
134
|
-
<%- else -%>
|
135
|
-
On demand yearly <%= @f.format_price(@r.analyzer.yearly_full_price, 20).cyan %>
|
136
|
-
<%- end -%>
|
137
|
-
<%- if @r.reserve? -%>
|
138
|
-
|
139
|
-
YEARLY RESERVE SAVINGS:
|
140
|
-
Savings due to reserved pricing <%= @f.format_price(@r.analyzer.yearly_savings, 20).green %>
|
141
|
-
Savings % <%= sprintf("%19d", @r.analyzer.yearly_savings_percent).green + '%'.green %>
|
142
|
-
<%- end -%>
|
143
|
-
<%= SEPARATOR %>
|
144
|
-
|
145
|
-
ASCII
|
84
|
+
def zone_counts_to_list zone_count_hash
|
85
|
+
zones = zone_count_hash.each_pair.
|
86
|
+
map { |flavor, count| [flavor, count, pricing.monthly(flavor) * count] }.
|
87
|
+
sort { |x, y| y[2] <=> x[2] }
|
88
|
+
zones
|
89
|
+
end
|
146
90
|
|
147
|
-
|
91
|
+
def zone_props_to_string(prop_type, width, suffix = '', divide_by = 1)
|
92
|
+
props = analyzer.send(prop_type)
|
93
|
+
[props[:reserved], props[:unreserved], props[:total]].map do |value|
|
94
|
+
sprintf("%#{width}d#{suffix}", value / divide_by)
|
95
|
+
end
|
96
|
+
end
|
148
97
|
|
98
|
+
private
|
99
|
+
|
100
|
+
def disable_color
|
101
|
+
String.instance_eval do
|
102
|
+
%w(
|
103
|
+
black
|
104
|
+
red
|
105
|
+
green
|
106
|
+
yellow
|
107
|
+
blue
|
108
|
+
magenta
|
109
|
+
cyan
|
110
|
+
white
|
111
|
+
).each do |color|
|
112
|
+
define_method(color) do
|
113
|
+
self
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
149
119
|
end
|
data/lib/pricing/version.rb
CHANGED
data/spec/fixtures/commit.yml
CHANGED
@@ -37,6 +37,8 @@ describe 'Joyent::Cloud::Pricing::Analyzer' do
|
|
37
37
|
g3-highmemory-17.125-smartos
|
38
38
|
g3-highmemory-17.125-smartos
|
39
39
|
some-unknown-flavor
|
40
|
+
some-other-unknown-flavor
|
41
|
+
some-other-unknown-flavor
|
40
42
|
)
|
41
43
|
|
42
44
|
let(:flavors) { FLAVORS }
|
@@ -57,7 +59,8 @@ describe 'Joyent::Cloud::Pricing::Analyzer' do
|
|
57
59
|
:'g3-highio-60.5-smartos' => 4,
|
58
60
|
:'g3-highmemory-17.125-smartos' => 12,
|
59
61
|
:'g3-standard-30-smartos' => 1,
|
60
|
-
:'some-unknown-flavor' => 1
|
62
|
+
:'some-unknown-flavor' => 1,
|
63
|
+
:'some-other-unknown-flavor' => 2
|
61
64
|
})
|
62
65
|
end
|
63
66
|
|
@@ -78,7 +81,8 @@ describe 'Joyent::Cloud::Pricing::Analyzer' do
|
|
78
81
|
:'g3-highcpu-32-smartos-cc' => 2,
|
79
82
|
:'g3-highcpu-7-smartos' => 2,
|
80
83
|
:'g3-standard-30-smartos' => 1,
|
81
|
-
:'some-unknown-flavor' => 1
|
84
|
+
:'some-unknown-flavor' => 1,
|
85
|
+
:'some-other-unknown-flavor' => 2
|
82
86
|
})
|
83
87
|
end
|
84
88
|
|
@@ -103,7 +107,9 @@ describe 'Joyent::Cloud::Pricing::Analyzer' do
|
|
103
107
|
|
104
108
|
context 'for unknown instances' do
|
105
109
|
it 'should return some-unknown-flavor' do
|
106
|
-
expect(analyzer.unknown_zone_counts).to eql({ :'some-unknown-flavor' => 1
|
110
|
+
expect(analyzer.unknown_zone_counts).to eql({ :'some-unknown-flavor' => 1,
|
111
|
+
:'some-other-unknown-flavor' => 2 })
|
112
|
+
expect(analyzer.unknown_zone_total).to eql(3)
|
107
113
|
end
|
108
114
|
end
|
109
115
|
|
data/spec/pricing/commit_spec.rb
CHANGED
@@ -1,22 +1,43 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe 'Joyent::Cloud::Pricing::Commit' do
|
4
|
-
let(:commit) { Joyent::Cloud::Pricing::Commit.from_yaml 'spec/fixtures/commit.yml' }
|
5
4
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
'g3-highio-60.5-smartos' => {prepay: 1800.0, monthly: 600.0, years: 1, quantity: 5}
|
10
|
-
} }
|
5
|
+
context 'when some reserve pricing is defined' do
|
6
|
+
let(:commit) { Joyent::Cloud::Pricing::Commit.from_yaml 'spec/fixtures/commit.yml' }
|
7
|
+
let(:config) { Joyent::Cloud::Pricing::Configuration.instance }
|
11
8
|
|
12
|
-
|
13
|
-
|
14
|
-
|
9
|
+
let(:expected_commit) { {
|
10
|
+
'g3-highcpu-32-smartos-cc' => {prepay: 8000.0, monthly: 500.0, years: 1, quantity: 10},
|
11
|
+
'g3-highmemory-17.125-smartos' => {prepay: 800.0, monthly: 60.0, years: 1, quantity: 12},
|
12
|
+
'g3-highio-60.5-smartos' => {prepay: 1800.0, monthly: 600.0, years: 1, quantity: 5}
|
13
|
+
} }
|
14
|
+
|
15
|
+
it 'should correctly load commit from the file' do
|
16
|
+
expected_commit.keys.each do |flavor|
|
17
|
+
expect(expected_commit[flavor]).to eql(commit.reserve_for(flavor).to_hash)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
it '#monthly_price' do
|
22
|
+
expect(commit.monthly_price).to eql(8720.0)
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should have different custom pricing' do
|
26
|
+
expect(commit.reserves.keys.size).to eql(3)
|
27
|
+
expect(config.config[:'some-instance'][:cost]).to eql(2.451)
|
15
28
|
end
|
16
29
|
end
|
17
30
|
|
18
|
-
|
19
|
-
|
31
|
+
context 'when no reserve but custom pricing is available' do
|
32
|
+
let(:commit) { Joyent::Cloud::Pricing::Commit.from_yaml 'spec/fixtures/commit_noreserve.yml' }
|
33
|
+
let(:config) { Joyent::Cloud::Pricing::Configuration.instance }
|
34
|
+
let(:custom_flavor) { :'some-fake-flavor-again' }
|
35
|
+
it 'should load properly and add custom to config' do
|
36
|
+
|
37
|
+
expect(commit.reserves).to be_empty
|
38
|
+
expect(config.config[custom_flavor.to_sym][:cost]).to eql(5.1)
|
39
|
+
config.config.delete(custom_flavor.to_sym)
|
40
|
+
end
|
20
41
|
end
|
21
42
|
|
22
43
|
end
|
@@ -55,17 +55,25 @@ describe 'Joyent::Cloud::Pricing::Reporter' do
|
|
55
55
|
end
|
56
56
|
|
57
57
|
context '#render' do
|
58
|
-
|
59
|
-
|
60
|
-
|
58
|
+
context 'with existing commit pricing' do
|
59
|
+
it 'should propertly render an ERB template' do
|
60
|
+
output = reporter.render
|
61
|
+
STDOUT.puts output if ENV['DEBUG_REPORTER']
|
62
|
+
expect(output).to_not be_nil
|
63
|
+
expect(output).to include('MONTHLY COSTS')
|
64
|
+
expect(output).to include('YEARLY RESERVE SAVINGS')
|
65
|
+
end
|
61
66
|
end
|
62
67
|
|
63
|
-
context '
|
68
|
+
context 'without any commit configuration' do
|
64
69
|
let(:commit) { Joyent::Cloud::Pricing::Commit.new }
|
65
70
|
it 'should still properly render an ERB template' do
|
66
71
|
expect(commit.reserves.size).to eql(0)
|
67
72
|
output = reporter.render
|
73
|
+
STDOUT.puts output if ENV['DEBUG_REPORTER']
|
68
74
|
expect(output).to_not be_nil
|
75
|
+
expect(output).to_not include('YEARLY RESERVE SAVINGS')
|
76
|
+
expect(output).to include('some-fake-flavor-without-pricing')
|
69
77
|
end
|
70
78
|
end
|
71
79
|
|
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.10
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Konstantin Gredeskoul
|
@@ -126,7 +126,7 @@ files:
|
|
126
126
|
- Rakefile
|
127
127
|
- config/commit_pricing.yml.example
|
128
128
|
- config/joyent_pricing.yml
|
129
|
-
- config/
|
129
|
+
- config/joyent_pricing_unpublished.yml
|
130
130
|
- joyent-cloud-pricing.gemspec
|
131
131
|
- lib/pricing.rb
|
132
132
|
- lib/pricing/analyzer.rb
|
@@ -135,6 +135,7 @@ files:
|
|
135
135
|
- lib/pricing/flavor.rb
|
136
136
|
- lib/pricing/formatter.rb
|
137
137
|
- lib/pricing/helpers.rb
|
138
|
+
- lib/pricing/report.txt.erb
|
138
139
|
- lib/pricing/reporter.rb
|
139
140
|
- lib/pricing/reserve.rb
|
140
141
|
- lib/pricing/scraper.rb
|
@@ -142,6 +143,7 @@ files:
|
|
142
143
|
- lib/pricing/version.rb
|
143
144
|
- lib/tasks/update.rake
|
144
145
|
- spec/fixtures/commit.yml
|
146
|
+
- spec/fixtures/commit_noreserve.yml
|
145
147
|
- spec/fixtures/pricing.yml
|
146
148
|
- spec/pricing/analyzer_spec.rb
|
147
149
|
- spec/pricing/commit_spec.rb
|
@@ -178,6 +180,7 @@ summary: Tools for calculating monthly and yearly price of infrastructure hosted
|
|
178
180
|
Joyent Public Cloud.
|
179
181
|
test_files:
|
180
182
|
- spec/fixtures/commit.yml
|
183
|
+
- spec/fixtures/commit_noreserve.yml
|
181
184
|
- spec/fixtures/pricing.yml
|
182
185
|
- spec/pricing/analyzer_spec.rb
|
183
186
|
- spec/pricing/commit_spec.rb
|