apisonator 3.3.1.1 → 3.4.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +68 -0
- data/Gemfile.base +2 -2
- data/Gemfile.lock +13 -13
- data/Gemfile.on_prem.lock +13 -13
- data/lib/3scale/backend.rb +1 -0
- data/lib/3scale/backend/alert_limit.rb +9 -11
- data/lib/3scale/backend/alerts.rb +94 -47
- data/lib/3scale/backend/configuration.rb +0 -1
- data/lib/3scale/backend/constants.rb +2 -0
- data/lib/3scale/backend/rack.rb +4 -1
- data/lib/3scale/backend/service.rb +3 -35
- data/lib/3scale/backend/stats/aggregator.rb +30 -24
- data/lib/3scale/backend/stats/cleaner.rb +0 -6
- data/lib/3scale/backend/transactor.rb +17 -26
- data/lib/3scale/backend/transactor/status.rb +27 -9
- data/lib/3scale/backend/transactor/usage_report.rb +1 -1
- data/lib/3scale/backend/usage.rb +10 -3
- data/lib/3scale/backend/utilization.rb +83 -0
- data/lib/3scale/backend/validators.rb +7 -0
- data/lib/3scale/backend/validators/oauth_setting.rb +1 -1
- data/lib/3scale/backend/version.rb +1 -1
- data/lib/3scale/prometheus_server.rb +1 -1
- data/licenses.xml +7 -7
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 356ca549dce065646329337096b0c3233ea3be1fdf599b135c144f5c887e5754
|
4
|
+
data.tar.gz: 04af4be3b14ce0299bbefc968349e7f063222d9a61d10557a4ffade0a5c683db
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 850c97fc6f5835da57e1918881aa2f4ce0e086fb550c2bda024b98c9e1e62b829aadb1f0b45dd7b690aa0bd5b5cfb712de1d4914f39eab8caa5107e28c48f600
|
7
|
+
data.tar.gz: 0d45268818cd98bf0c8684fe1340544e230c85fdef7d05b4f37d0c1db4d963d21fc2f50455bf1226619276ec6402c3be3af9ee755b783f8ee5d2ec5c300b8e66
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,74 @@
|
|
2
2
|
|
3
3
|
Notable changes to Apisonator will be tracked in this document.
|
4
4
|
|
5
|
+
## 3.4.2 - 2021-06-17
|
6
|
+
|
7
|
+
### Fixed
|
8
|
+
|
9
|
+
- Fixed exception raised when TTL = 0 in `UsagesChecked.mark_all_checked`
|
10
|
+
([#290](https://github.com/3scale/apisonator/pull/290)).
|
11
|
+
|
12
|
+
## 3.4.1 - 2021-06-16
|
13
|
+
|
14
|
+
### Changed
|
15
|
+
|
16
|
+
- Introduced performance optimizations around alerts detection
|
17
|
+
([#287](https://github.com/3scale/apisonator/pull/287)).
|
18
|
+
|
19
|
+
## 3.4.0 - 2021-06-14
|
20
|
+
|
21
|
+
### Added
|
22
|
+
|
23
|
+
- New extension that list the keys of an application
|
24
|
+
([#284](https://github.com/3scale/apisonator/pull/284)).
|
25
|
+
|
26
|
+
### Changed
|
27
|
+
|
28
|
+
- It is now possible to use OIDC in the auth and authrep endpoints
|
29
|
+
([#280](https://github.com/3scale/apisonator/pull/280)).
|
30
|
+
- Updated multi-json to 1.15.0
|
31
|
+
([#278](https://github.com/3scale/apisonator/pull/278)).
|
32
|
+
|
33
|
+
### Removed
|
34
|
+
|
35
|
+
- Deleted unused service attributes related with deleted end-users functionality
|
36
|
+
([#277](https://github.com/3scale/apisonator/pull/277)).
|
37
|
+
|
38
|
+
## 3.3.3 - 2021-03-09
|
39
|
+
|
40
|
+
### Changed
|
41
|
+
|
42
|
+
- Check if alerts can be raised before calculating utilization (perf
|
43
|
+
optimization) ([#275](https://github.com/3scale/apisonator/pull/275)).
|
44
|
+
|
45
|
+
### Removed
|
46
|
+
|
47
|
+
- Stop maintaining unused "current_max" key in Alerts
|
48
|
+
([#272](https://github.com/3scale/apisonator/pull/272)).
|
49
|
+
|
50
|
+
## 3.3.2 - 2021-02-23
|
51
|
+
|
52
|
+
### Fixed
|
53
|
+
|
54
|
+
- Fixed nil exception in `Aggregator.process`
|
55
|
+
([#269](https://github.com/3scale/apisonator/pull/269)).
|
56
|
+
|
57
|
+
### Changed
|
58
|
+
|
59
|
+
- Updated to Ruby 2.7 in Docker images
|
60
|
+
([#265](https://github.com/3scale/apisonator/pull/265)) and
|
61
|
+
([#266](https://github.com/3scale/apisonator/pull/266)).
|
62
|
+
- Updated pry to 0.14.0 and pry-doc to 1.1.0
|
63
|
+
([#267](https://github.com/3scale/apisonator/pull/267)).
|
64
|
+
- Updated Docker image to be based on RHEL UBI 8
|
65
|
+
([#268](https://github.com/3scale/apisonator/pull/268)).
|
66
|
+
|
67
|
+
### Removed
|
68
|
+
|
69
|
+
- Removed redundant prometheus config params
|
70
|
+
(`listener_prometheus_metrics.enabled` and `listener_prometheus_metrics.port`)
|
71
|
+
([#270](https://github.com/3scale/apisonator/pull/270)).
|
72
|
+
|
5
73
|
## 3.3.1.1 - 2021-02-12
|
6
74
|
|
7
75
|
### Changed
|
data/Gemfile.base
CHANGED
@@ -36,8 +36,8 @@ end
|
|
36
36
|
group :development do
|
37
37
|
gem 'sshkit'
|
38
38
|
gem 'source2swagger', git: 'https://github.com/3scale/source2swagger', branch: 'backend'
|
39
|
-
gem 'pry', '~> 0.
|
40
|
-
gem 'pry-doc', '~>
|
39
|
+
gem 'pry', '~> 0.14'
|
40
|
+
gem 'pry-doc', '~> 1.1'
|
41
41
|
gem 'license_finder', '~> 5'
|
42
42
|
end
|
43
43
|
|
data/Gemfile.lock
CHANGED
@@ -36,7 +36,7 @@ GIT
|
|
36
36
|
PATH
|
37
37
|
remote: .
|
38
38
|
specs:
|
39
|
-
apisonator (3.
|
39
|
+
apisonator (3.4.2)
|
40
40
|
|
41
41
|
GEM
|
42
42
|
remote: https://rubygems.org/
|
@@ -96,7 +96,7 @@ GEM
|
|
96
96
|
chronic (0.10.2)
|
97
97
|
codeclimate-test-reporter (0.6.0)
|
98
98
|
simplecov (>= 0.7.1, < 1.0.0)
|
99
|
-
coderay (1.1.
|
99
|
+
coderay (1.1.3)
|
100
100
|
concurrent-ruby (1.1.6)
|
101
101
|
console (1.8.2)
|
102
102
|
daemons (1.2.4)
|
@@ -131,13 +131,13 @@ GEM
|
|
131
131
|
localhost (1.1.6)
|
132
132
|
mapping (1.1.1)
|
133
133
|
metaclass (0.0.4)
|
134
|
-
method_source (0.
|
134
|
+
method_source (1.0.0)
|
135
135
|
mini_portile2 (2.4.0)
|
136
136
|
minitest (5.14.1)
|
137
137
|
mocha (1.3.0)
|
138
138
|
metaclass (~> 0.0.1)
|
139
139
|
mono_logger (1.1.0)
|
140
|
-
multi_json (1.
|
140
|
+
multi_json (1.15.0)
|
141
141
|
mustache (1.0.5)
|
142
142
|
mustermann (1.0.2)
|
143
143
|
net-scp (1.2.1)
|
@@ -164,15 +164,15 @@ GEM
|
|
164
164
|
protocol-hpack (~> 1.4)
|
165
165
|
protocol-http (~> 0.15)
|
166
166
|
protocol-redis (0.5.0)
|
167
|
-
pry (0.
|
168
|
-
coderay (~> 1.1
|
169
|
-
method_source (~>
|
167
|
+
pry (0.14.0)
|
168
|
+
coderay (~> 1.1)
|
169
|
+
method_source (~> 1.0)
|
170
170
|
pry-byebug (3.5.1)
|
171
171
|
byebug (~> 9.1)
|
172
172
|
pry (~> 0.10)
|
173
|
-
pry-doc (
|
174
|
-
pry (~> 0.
|
175
|
-
yard (~> 0.9)
|
173
|
+
pry-doc (1.1.0)
|
174
|
+
pry (~> 0.11)
|
175
|
+
yard (~> 0.9.11)
|
176
176
|
rack (2.1.4)
|
177
177
|
rack-protection (2.0.3)
|
178
178
|
rack
|
@@ -260,7 +260,7 @@ GEM
|
|
260
260
|
prometheus-client (~> 1.0)
|
261
261
|
yabeda (~> 0.5)
|
262
262
|
yajl-ruby (1.3.1)
|
263
|
-
yard (0.9.
|
263
|
+
yard (0.9.26)
|
264
264
|
|
265
265
|
PLATFORMS
|
266
266
|
ruby
|
@@ -284,9 +284,9 @@ DEPENDENCIES
|
|
284
284
|
nokogiri (~> 1.10.8)
|
285
285
|
pg (= 0.20.0)
|
286
286
|
pkg-config (~> 1.1.7)
|
287
|
-
pry (~> 0.
|
287
|
+
pry (~> 0.14)
|
288
288
|
pry-byebug (~> 3.5.1)
|
289
|
-
pry-doc (~>
|
289
|
+
pry-doc (~> 1.1)
|
290
290
|
puma!
|
291
291
|
rack (~> 2.1.4)
|
292
292
|
rack-test (= 0.8.2)
|
data/Gemfile.on_prem.lock
CHANGED
@@ -36,7 +36,7 @@ GIT
|
|
36
36
|
PATH
|
37
37
|
remote: .
|
38
38
|
specs:
|
39
|
-
apisonator (3.
|
39
|
+
apisonator (3.4.2)
|
40
40
|
|
41
41
|
GEM
|
42
42
|
remote: https://rubygems.org/
|
@@ -86,7 +86,7 @@ GEM
|
|
86
86
|
byebug (9.1.0)
|
87
87
|
codeclimate-test-reporter (0.6.0)
|
88
88
|
simplecov (>= 0.7.1, < 1.0.0)
|
89
|
-
coderay (1.1.
|
89
|
+
coderay (1.1.3)
|
90
90
|
concurrent-ruby (1.1.6)
|
91
91
|
console (1.8.2)
|
92
92
|
daemons (1.2.4)
|
@@ -120,13 +120,13 @@ GEM
|
|
120
120
|
localhost (1.1.6)
|
121
121
|
mapping (1.1.1)
|
122
122
|
metaclass (0.0.4)
|
123
|
-
method_source (0.
|
123
|
+
method_source (1.0.0)
|
124
124
|
mini_portile2 (2.4.0)
|
125
125
|
minitest (5.14.1)
|
126
126
|
mocha (1.3.0)
|
127
127
|
metaclass (~> 0.0.1)
|
128
128
|
mono_logger (1.1.0)
|
129
|
-
multi_json (1.
|
129
|
+
multi_json (1.15.0)
|
130
130
|
mustache (1.0.5)
|
131
131
|
mustermann (1.0.2)
|
132
132
|
net-scp (1.2.1)
|
@@ -152,15 +152,15 @@ GEM
|
|
152
152
|
protocol-hpack (~> 1.4)
|
153
153
|
protocol-http (~> 0.15)
|
154
154
|
protocol-redis (0.5.0)
|
155
|
-
pry (0.
|
156
|
-
coderay (~> 1.1
|
157
|
-
method_source (~>
|
155
|
+
pry (0.14.0)
|
156
|
+
coderay (~> 1.1)
|
157
|
+
method_source (~> 1.0)
|
158
158
|
pry-byebug (3.5.1)
|
159
159
|
byebug (~> 9.1)
|
160
160
|
pry (~> 0.10)
|
161
|
-
pry-doc (
|
162
|
-
pry (~> 0.
|
163
|
-
yard (~> 0.9)
|
161
|
+
pry-doc (1.1.0)
|
162
|
+
pry (~> 0.11)
|
163
|
+
yard (~> 0.9.11)
|
164
164
|
rack (2.1.4)
|
165
165
|
rack-protection (2.0.3)
|
166
166
|
rack
|
@@ -244,7 +244,7 @@ GEM
|
|
244
244
|
prometheus-client (~> 1.0)
|
245
245
|
yabeda (~> 0.5)
|
246
246
|
yajl-ruby (1.3.1)
|
247
|
-
yard (0.9.
|
247
|
+
yard (0.9.26)
|
248
248
|
|
249
249
|
PLATFORMS
|
250
250
|
ruby
|
@@ -265,9 +265,9 @@ DEPENDENCIES
|
|
265
265
|
mocha (~> 1.3)
|
266
266
|
nokogiri (~> 1.10.8)
|
267
267
|
pkg-config (~> 1.1.7)
|
268
|
-
pry (~> 0.
|
268
|
+
pry (~> 0.14)
|
269
269
|
pry-byebug (~> 3.5.1)
|
270
|
-
pry-doc (~>
|
270
|
+
pry-doc (~> 1.1)
|
271
271
|
puma!
|
272
272
|
rack (~> 2.1.4)
|
273
273
|
rack-test (= 0.8.2)
|
data/lib/3scale/backend.rb
CHANGED
@@ -44,6 +44,7 @@ require '3scale/backend/queue_storage'
|
|
44
44
|
require '3scale/backend/errors'
|
45
45
|
require '3scale/backend/stats'
|
46
46
|
require '3scale/backend/usage_limit'
|
47
|
+
require '3scale/backend/utilization'
|
47
48
|
require '3scale/backend/alerts'
|
48
49
|
require '3scale/backend/event_storage'
|
49
50
|
require '3scale/backend/worker'
|
@@ -1,21 +1,19 @@
|
|
1
1
|
module ThreeScale
|
2
2
|
module Backend
|
3
3
|
class AlertLimit
|
4
|
-
|
5
|
-
|
6
|
-
"alerts/service_id:#{service_id}/allowed_set"
|
7
|
-
end
|
8
|
-
end
|
9
|
-
|
10
|
-
include KeyHelpers
|
11
|
-
extend KeyHelpers
|
4
|
+
include Alerts::KeyHelpers
|
5
|
+
extend Alerts::KeyHelpers
|
12
6
|
|
13
7
|
include Storable
|
14
8
|
|
15
9
|
attr_accessor :service_id, :value
|
16
10
|
|
17
11
|
def save
|
18
|
-
|
12
|
+
if valid?
|
13
|
+
res = storage.sadd(key_allowed_set(service_id), value.to_i)
|
14
|
+
Alerts::UsagesChecked.invalidate_for_service(service_id)
|
15
|
+
res
|
16
|
+
end
|
19
17
|
end
|
20
18
|
|
21
19
|
def to_hash
|
@@ -26,7 +24,7 @@ module ThreeScale
|
|
26
24
|
end
|
27
25
|
|
28
26
|
def self.load_all(service_id)
|
29
|
-
values = storage.smembers(
|
27
|
+
values = storage.smembers(key_allowed_set(service_id))
|
30
28
|
values.map do |value|
|
31
29
|
new(service_id: service_id, value: value.to_i)
|
32
30
|
end
|
@@ -38,7 +36,7 @@ module ThreeScale
|
|
38
36
|
end
|
39
37
|
|
40
38
|
def self.delete(service_id, value)
|
41
|
-
storage.srem(
|
39
|
+
storage.srem(key_allowed_set(service_id), value.to_i) if valid_value?(value)
|
42
40
|
end
|
43
41
|
|
44
42
|
def self.valid_value?(value)
|
@@ -6,11 +6,10 @@ module ThreeScale
|
|
6
6
|
|
7
7
|
# The compacted hour in the params refers to the
|
8
8
|
# TimeHacks.to_compact_s method.
|
9
|
-
def alert_keys(service_id, app_id, discrete_utilization
|
9
|
+
def alert_keys(service_id, app_id, discrete_utilization)
|
10
10
|
{
|
11
11
|
already_notified: key_already_notified(service_id, app_id, discrete_utilization),
|
12
12
|
allowed: key_allowed_set(service_id),
|
13
|
-
current_max: key_current_max(service_id, app_id, compacted_hour_start),
|
14
13
|
current_id: key_current_id
|
15
14
|
}
|
16
15
|
end
|
@@ -31,18 +30,19 @@ module ThreeScale
|
|
31
30
|
"#{prefix}allowed_set"
|
32
31
|
end
|
33
32
|
|
34
|
-
def key_current_max(service_id, app_id, compacted_hour_start)
|
35
|
-
prefix = key_prefix(service_id, app_id)
|
36
|
-
"#{prefix}#{compacted_hour_start}/current_max"
|
37
|
-
end
|
38
|
-
|
39
33
|
def key_current_id
|
40
34
|
'alerts/current_id'.freeze
|
41
35
|
end
|
36
|
+
|
37
|
+
def key_usage_already_checked(service_id, app_id)
|
38
|
+
prefix = key_prefix(service_id, app_id)
|
39
|
+
"#{prefix}usage_already_checked"
|
40
|
+
end
|
42
41
|
end
|
43
42
|
|
44
43
|
extend self
|
45
44
|
extend KeyHelpers
|
45
|
+
include Memoizer::Decorator
|
46
46
|
|
47
47
|
ALERT_TTL = 24*3600 # 1 day (only one message per day)
|
48
48
|
## zero must be here and sorted, yes or yes
|
@@ -50,67 +50,109 @@ module ThreeScale
|
|
50
50
|
FIRST_ALERT_BIN = ALERT_BINS.first
|
51
51
|
RALERT_BINS = ALERT_BINS.reverse.freeze
|
52
52
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
53
|
+
# This class is useful to reduce the amount of information that we need to
|
54
|
+
# fetch from Redis to determine whether an alert should be raised.
|
55
|
+
# In summary, alerts are raised at the application level and we need to
|
56
|
+
# wait for 24h before raising a new one for the same level (ALERTS_BIN
|
57
|
+
# above).
|
58
|
+
#
|
59
|
+
# This class allows us to check all the usage limits once and then not
|
60
|
+
# check all of them again (just the ones in the report job) until:
|
61
|
+
# 1) A specific alert has expired (24h passed since it was triggered).
|
62
|
+
# 2) A new alert bin is enabled for the service.
|
63
|
+
class UsagesChecked
|
64
|
+
extend KeyHelpers
|
65
|
+
extend StorageHelpers
|
66
|
+
include Memoizer::Decorator
|
67
|
+
|
68
|
+
def self.need_to_check_all?(service_id, app_id)
|
69
|
+
!storage.exists(key_usage_already_checked(service_id, app_id))
|
70
|
+
end
|
71
|
+
memoize :need_to_check_all?
|
72
|
+
|
73
|
+
def self.mark_all_checked(service_id, app_id)
|
74
|
+
ttl = ALERT_BINS.map do |bin|
|
75
|
+
ttl = storage.ttl(key_already_notified(service_id, app_id, bin))
|
76
|
+
|
77
|
+
# Redis returns -2 if key does not exist, and -1 if it exists without
|
78
|
+
# a TTL (we know this should not happen for the alert bins).
|
79
|
+
# In those cases we should just set the TTL to the max (ALERT_TTL).
|
80
|
+
ttl >= 0 ? ttl : ALERT_TTL
|
81
|
+
end.min
|
82
|
+
|
83
|
+
# Setex fails when ttl = 0. Also, if it's 0, we don't need to mark it
|
84
|
+
# as checked, because the "already_notified" key for the bin is just
|
85
|
+
# about to expire, so we'll need to check all the usages.
|
86
|
+
if ttl > 0
|
87
|
+
storage.setex(key_usage_already_checked(service_id, app_id), ttl, '1'.freeze)
|
88
|
+
Memoizer.clear(Memoizer.build_key(self, :need_to_check_all?, service_id, app_id))
|
64
89
|
end
|
65
90
|
end
|
66
91
|
|
67
|
-
|
92
|
+
def self.invalidate(service_id, app_id)
|
93
|
+
storage.del(key_usage_already_checked(service_id, app_id))
|
94
|
+
end
|
95
|
+
|
96
|
+
def self.invalidate_for_service(service_id)
|
97
|
+
app_ids = []
|
98
|
+
cursor = 0
|
99
|
+
|
100
|
+
loop do
|
101
|
+
cursor, ids = storage.sscan(
|
102
|
+
Application.applications_set_key(service_id), cursor, count: SCAN_SLICE
|
103
|
+
)
|
104
|
+
|
105
|
+
app_ids += ids
|
68
106
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
107
|
+
break if cursor.to_i == 0
|
108
|
+
end
|
109
|
+
|
110
|
+
invalidate_batch(service_id, app_ids)
|
73
111
|
end
|
74
112
|
|
75
|
-
|
113
|
+
def self.invalidate_batch(service_id, app_ids)
|
114
|
+
app_ids.each_slice(PIPELINED_SLICE_SIZE) do |ids|
|
115
|
+
keys = ids.map { |app_id| key_usage_already_checked(service_id, app_id) }
|
116
|
+
storage.del(keys)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
private_class_method :invalidate_batch
|
76
120
|
end
|
77
121
|
|
78
|
-
def
|
79
|
-
|
80
|
-
|
122
|
+
def can_raise_more_alerts?(service_id, app_id)
|
123
|
+
allowed_bins = allowed_set_for_service(service_id).sort
|
124
|
+
|
125
|
+
return false if allowed_bins.empty?
|
81
126
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
127
|
+
# If the bin with the highest value has already been notified, there's
|
128
|
+
# no need to notify anything else.
|
129
|
+
not notified?(service_id, app_id, allowed_bins.last)
|
130
|
+
end
|
86
131
|
|
87
|
-
|
132
|
+
def update_utilization(service_id, app_id, utilization)
|
133
|
+
discrete = utilization_discrete(utilization.ratio)
|
88
134
|
|
89
|
-
|
135
|
+
keys = alert_keys(service_id, app_id, discrete)
|
136
|
+
|
137
|
+
already_alerted, allowed = storage.pipelined do
|
90
138
|
storage.get(keys[:already_notified])
|
91
139
|
storage.sismember(keys[:allowed], discrete)
|
92
|
-
storage.get(keys[:current_max])
|
93
|
-
storage.expireat(keys[:current_max], expire_at)
|
94
|
-
end
|
95
|
-
|
96
|
-
## update the status of utilization
|
97
|
-
if max_utilization_i > current_max.to_i
|
98
|
-
storage.set(keys[:current_max], max_utilization_i)
|
99
140
|
end
|
100
141
|
|
101
142
|
if already_alerted.nil? && allowed && discrete.to_i > 0
|
102
|
-
next_id, _ = storage.pipelined do
|
143
|
+
next_id, _, _ = storage.pipelined do
|
103
144
|
storage.incr(keys[:current_id])
|
104
145
|
storage.setex(keys[:already_notified], ALERT_TTL, "1")
|
146
|
+
UsagesChecked.invalidate(service_id, app_id)
|
105
147
|
end
|
106
148
|
|
107
149
|
alert = { :id => next_id,
|
108
150
|
:utilization => discrete,
|
109
|
-
:max_utilization =>
|
151
|
+
:max_utilization => utilization.ratio,
|
110
152
|
:application_id => app_id,
|
111
153
|
:service_id => service_id,
|
112
|
-
:timestamp =>
|
113
|
-
:limit =>
|
154
|
+
:timestamp => Time.now.utc,
|
155
|
+
:limit => utilization.to_s }
|
114
156
|
|
115
157
|
Backend::EventStorage::store(:alert, alert)
|
116
158
|
end
|
@@ -124,10 +166,15 @@ module ThreeScale
|
|
124
166
|
end || FIRST_ALERT_BIN
|
125
167
|
end
|
126
168
|
|
127
|
-
def
|
128
|
-
|
129
|
-
|
169
|
+
def allowed_set_for_service(service_id)
|
170
|
+
storage.smembers(key_allowed_set(service_id)).map(&:to_i) # Redis returns strings always
|
171
|
+
end
|
172
|
+
memoize :allowed_set_for_service
|
173
|
+
|
174
|
+
def notified?(service_id, app_id, bin)
|
175
|
+
storage.get(key_already_notified(service_id, app_id, bin))
|
130
176
|
end
|
177
|
+
memoize :notified?
|
131
178
|
|
132
179
|
def storage
|
133
180
|
Storage.instance
|
@@ -58,7 +58,6 @@ module ThreeScale
|
|
58
58
|
config.add_section(:internal_api, :user, :password)
|
59
59
|
config.add_section(:master, :metrics)
|
60
60
|
config.add_section(:worker_prometheus_metrics, :enabled, :port)
|
61
|
-
config.add_section(:listener_prometheus_metrics, :enabled, :port)
|
62
61
|
|
63
62
|
config.add_section(
|
64
63
|
:async_worker,
|
data/lib/3scale/backend/rack.rb
CHANGED
@@ -17,7 +17,10 @@ module ThreeScale
|
|
17
17
|
|
18
18
|
Backend::Logging::External.setup_rack self
|
19
19
|
|
20
|
-
|
20
|
+
# Notice that this cannot be specified via config, it needs to be an
|
21
|
+
# ENV because the metric server is started in Puma/Falcon
|
22
|
+
# "before_fork" and the configuration is not loaded at that point.
|
23
|
+
if ENV['CONFIG_LISTENER_PROMETHEUS_METRICS_ENABLED'].to_s.downcase.freeze == 'true'.freeze
|
21
24
|
use Rack::Prometheus
|
22
25
|
end
|
23
26
|
|
@@ -4,16 +4,12 @@ module ThreeScale
|
|
4
4
|
include Storable
|
5
5
|
|
6
6
|
# list of attributes to be fetched from storage
|
7
|
-
ATTRIBUTES = %i[state referrer_filters_required backend_version
|
8
|
-
user_registration_required default_user_plan_id
|
9
|
-
default_user_plan_name provider_key].freeze
|
7
|
+
ATTRIBUTES = %i[state referrer_filters_required backend_version provider_key].freeze
|
10
8
|
private_constant :ATTRIBUTES
|
11
9
|
|
12
10
|
attr_reader :state
|
13
|
-
attr_accessor :provider_key, :id, :backend_version
|
14
|
-
|
15
|
-
attr_writer :referrer_filters_required, :user_registration_required,
|
16
|
-
:default_service
|
11
|
+
attr_accessor :provider_key, :id, :backend_version
|
12
|
+
attr_writer :referrer_filters_required, :default_service
|
17
13
|
|
18
14
|
class << self
|
19
15
|
include Memoizer::Decorator
|
@@ -104,8 +100,6 @@ module ThreeScale
|
|
104
100
|
memoize :list
|
105
101
|
|
106
102
|
def save!(attributes = {})
|
107
|
-
massage_set_user_registration_required attributes
|
108
|
-
|
109
103
|
new(attributes).save!
|
110
104
|
end
|
111
105
|
|
@@ -139,26 +133,10 @@ module ThreeScale
|
|
139
133
|
def massage_service_attrs(service_attrs)
|
140
134
|
service_attrs[:referrer_filters_required] =
|
141
135
|
service_attrs[:referrer_filters_required].to_i > 0
|
142
|
-
service_attrs[:user_registration_required] =
|
143
|
-
massage_get_user_registration_required(
|
144
|
-
service_attrs[:user_registration_required])
|
145
136
|
|
146
137
|
service_attrs
|
147
138
|
end
|
148
139
|
|
149
|
-
# nil => true, 1 => true, '1' => true, 0 => false, '0' => false
|
150
|
-
def massage_get_user_registration_required(value)
|
151
|
-
value.nil? ? true : value.to_i > 0
|
152
|
-
end
|
153
|
-
|
154
|
-
def massage_set_user_registration_required(attributes)
|
155
|
-
if attributes[:user_registration_required].nil?
|
156
|
-
val = storage.get(storage_key(attributes[:id], :user_registration_required))
|
157
|
-
attributes[:user_registration_required] =
|
158
|
-
(!val.nil? && val.to_i == 0) ? false : true
|
159
|
-
end
|
160
|
-
end
|
161
|
-
|
162
140
|
def get_attr(id, attribute)
|
163
141
|
storage.get(storage_key(id, attribute))
|
164
142
|
end
|
@@ -195,10 +173,6 @@ module ThreeScale
|
|
195
173
|
@referrer_filters_required
|
196
174
|
end
|
197
175
|
|
198
|
-
def user_registration_required?
|
199
|
-
@user_registration_required
|
200
|
-
end
|
201
|
-
|
202
176
|
def save!
|
203
177
|
set_as_default_if_needed
|
204
178
|
persist
|
@@ -227,9 +201,6 @@ module ThreeScale
|
|
227
201
|
provider_key: provider_key,
|
228
202
|
backend_version: backend_version,
|
229
203
|
referrer_filters_required: referrer_filters_required?,
|
230
|
-
user_registration_required: user_registration_required?,
|
231
|
-
default_user_plan_id: default_user_plan_id,
|
232
|
-
default_user_plan_name: default_user_plan_name,
|
233
204
|
default_service: default_service?
|
234
205
|
}
|
235
206
|
end
|
@@ -294,9 +265,6 @@ module ThreeScale
|
|
294
265
|
|
295
266
|
def persist_attributes
|
296
267
|
persist_attribute :referrer_filters_required, referrer_filters_required? ? 1 : 0
|
297
|
-
persist_attribute :user_registration_required, user_registration_required? ? 1 : 0
|
298
|
-
persist_attribute :default_user_plan_id, default_user_plan_id, true
|
299
|
-
persist_attribute :default_user_plan_name, default_user_plan_name, true
|
300
268
|
persist_attribute :backend_version, backend_version, true
|
301
269
|
persist_attribute :provider_key, provider_key
|
302
270
|
persist_attribute :state, state.to_s if state
|
@@ -59,7 +59,7 @@ module ThreeScale
|
|
59
59
|
touched_apps = aggregate(transactions, current_bucket)
|
60
60
|
|
61
61
|
ApplicationEvents.generate(touched_apps.values)
|
62
|
-
update_alerts(
|
62
|
+
update_alerts(transactions)
|
63
63
|
begin
|
64
64
|
ApplicationEvents.ping
|
65
65
|
rescue ApplicationEvents::PingFailed => e
|
@@ -137,29 +137,35 @@ module ThreeScale
|
|
137
137
|
logger.info(MAX_BUCKETS_CREATED_MSG)
|
138
138
|
end
|
139
139
|
|
140
|
-
def update_alerts(
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
140
|
+
def update_alerts(transactions)
|
141
|
+
transactions.group_by { |tx| tx.application_id }.each do |app_id, txs|
|
142
|
+
service_id = txs.first.service_id # All the txs of an app belong to the same service
|
143
|
+
|
144
|
+
# Finding the max utilization can be costly because it involves
|
145
|
+
# loading usage limits and current usages. That's why before that,
|
146
|
+
# we check if there are any alerts that can be raised.
|
147
|
+
next unless Alerts.can_raise_more_alerts?(service_id, app_id)
|
148
|
+
|
149
|
+
begin
|
150
|
+
max_utilization = if Alerts::UsagesChecked.need_to_check_all?(service_id, app_id)
|
151
|
+
Utilization.max_in_all_metrics(service_id, app_id).tap do
|
152
|
+
Alerts::UsagesChecked.mark_all_checked(service_id, app_id)
|
153
|
+
end
|
154
|
+
else
|
155
|
+
# metrics_ids here includes the metrics
|
156
|
+
# explicitly reported plus their parents in
|
157
|
+
# the hierarchy.
|
158
|
+
metric_ids = txs.map { |tx| tx.usage.keys }.flatten.uniq
|
159
|
+
Utilization.max_in_metrics(service_id, app_id, metric_ids)
|
160
|
+
end
|
161
|
+
rescue ApplicationNotFound
|
162
|
+
# The app could have been deleted at some point since the job
|
163
|
+
# was enqueued. No need to update alerts in that case.
|
164
|
+
next
|
165
|
+
end
|
166
|
+
|
167
|
+
if max_utilization && max_utilization.ratio > 0
|
168
|
+
Alerts.update_utilization(service_id, app_id, max_utilization)
|
163
169
|
end
|
164
170
|
end
|
165
171
|
end
|
@@ -36,12 +36,6 @@ module ThreeScale
|
|
36
36
|
KEY_SERVICES_TO_DELETE = 'set_with_services_marked_for_deletion'.freeze
|
37
37
|
private_constant :KEY_SERVICES_TO_DELETE
|
38
38
|
|
39
|
-
SLEEP_BETWEEN_SCANS = 0.01 # In seconds
|
40
|
-
private_constant :SLEEP_BETWEEN_SCANS
|
41
|
-
|
42
|
-
SCAN_SLICE = 500
|
43
|
-
private_constant :SCAN_SLICE
|
44
|
-
|
45
39
|
STATS_KEY_PREFIX = 'stats/'.freeze
|
46
40
|
private_constant :STATS_KEY_PREFIX
|
47
41
|
|
@@ -61,6 +61,8 @@ module ThreeScale
|
|
61
61
|
|
62
62
|
def validate(oauth, provider_key, report_usage, params, request_info)
|
63
63
|
service = Service.load_with_provider_key!(params[:service_id], provider_key)
|
64
|
+
oidc_service = !oauth && service.backend_version == 'oauth'.freeze
|
65
|
+
|
64
66
|
# service_id cannot be taken from params since it might be missing there
|
65
67
|
service_id = service.id
|
66
68
|
|
@@ -70,12 +72,18 @@ module ThreeScale
|
|
70
72
|
# significant.
|
71
73
|
params[:app_id] = nil if app_id && app_id.empty?
|
72
74
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
75
|
+
# While OIDC without an app_id makes little sense, we would break existing
|
76
|
+
# behaviour when calling non oauth_auth*.xml endpoints if we returned an
|
77
|
+
# error here, so only do this for oauth_auth*.xml endpoints.
|
78
|
+
raise ApplicationNotFound.new nil if oauth && app_id.nil?
|
79
|
+
|
80
|
+
validators = if oidc_service
|
81
|
+
Validators::OIDC_VALIDATORS
|
82
|
+
elsif oauth
|
83
|
+
Validators::OAUTH_VALIDATORS
|
84
|
+
else
|
85
|
+
Validators::VALIDATORS
|
86
|
+
end
|
79
87
|
|
80
88
|
params[:user_key] = nil if params[:user_key] && params[:user_key].empty?
|
81
89
|
application = Application.load_by_id_or_user_key!(service_id,
|
@@ -98,8 +106,9 @@ module ThreeScale
|
|
98
106
|
# hierarchy parameter adds information in the response needed
|
99
107
|
# to derive which limits affect directly or indirectly the
|
100
108
|
# metrics for which authorization is requested.
|
101
|
-
hierarchy: extensions[:hierarchy] == '1',
|
102
|
-
flat_usage: extensions[:flat_usage] == '1'
|
109
|
+
hierarchy: extensions[:hierarchy] == '1'.freeze,
|
110
|
+
flat_usage: extensions[:flat_usage] == '1'.freeze,
|
111
|
+
list_app_keys: extensions[:list_app_keys] == '1'.freeze
|
103
112
|
}
|
104
113
|
|
105
114
|
application.load_metric_names
|
@@ -108,24 +117,6 @@ module ThreeScale
|
|
108
117
|
apply_validators(validators, status_attrs, params)
|
109
118
|
end
|
110
119
|
|
111
|
-
def get_token_ids(token, service_id, app_id)
|
112
|
-
begin
|
113
|
-
token_aid = OAuth::Token::Storage.get_credentials(token, service_id)
|
114
|
-
rescue AccessTokenInvalid => e
|
115
|
-
# Yep, well, er. Someone specified that it is OK to have an
|
116
|
-
# invalid token if an app_id is specified. Somehow passing in
|
117
|
-
# a user_key is still not enough, though...
|
118
|
-
raise e if app_id.nil?
|
119
|
-
end
|
120
|
-
|
121
|
-
# We only take the token ids into account if we had no parameter ids
|
122
|
-
if app_id.nil?
|
123
|
-
app_id = token_aid
|
124
|
-
end
|
125
|
-
|
126
|
-
app_id
|
127
|
-
end
|
128
|
-
|
129
120
|
def do_authorize(method, provider_key, params, context_info)
|
130
121
|
notify_authorize(provider_key)
|
131
122
|
validate(method == :oauth_authorize, provider_key, false, params, context_info[:request])
|
@@ -8,17 +8,23 @@ module ThreeScale
|
|
8
8
|
# We only use 'redirect_uri' if a request sent such a param. See #397.
|
9
9
|
REDIRECT_URI_FIELD = 'redirect_url'.freeze
|
10
10
|
private_constant :REDIRECT_URI_FIELD
|
11
|
+
# Maximum number of keys to list when using the list_app_keys extension
|
12
|
+
# At the time of writing System/Porta has a limit of 5 different app_keys
|
13
|
+
# at any given moment, but this could change anytime.
|
14
|
+
LIST_APP_KEYS_MAX = 256
|
15
|
+
private_constant :LIST_APP_KEYS_MAX
|
11
16
|
|
12
17
|
def initialize(attributes)
|
13
|
-
@service_id
|
14
|
-
@application
|
15
|
-
@oauth
|
16
|
-
@usage
|
17
|
-
@predicted_usage
|
18
|
-
@values
|
19
|
-
@timestamp
|
20
|
-
@hierarchy_ext
|
21
|
-
@flat_usage_ext
|
18
|
+
@service_id = attributes[:service_id]
|
19
|
+
@application = attributes[:application]
|
20
|
+
@oauth = attributes[:oauth]
|
21
|
+
@usage = attributes[:usage]
|
22
|
+
@predicted_usage = attributes[:predicted_usage]
|
23
|
+
@values = filter_values(attributes[:values] || {})
|
24
|
+
@timestamp = attributes[:timestamp] || Time.now.getutc
|
25
|
+
@hierarchy_ext = attributes[:hierarchy]
|
26
|
+
@flat_usage_ext = attributes[:flat_usage]
|
27
|
+
@list_app_keys_ext = attributes[:list_app_keys]
|
22
28
|
|
23
29
|
raise 'service_id not specified' if @service_id.nil?
|
24
30
|
raise ':application is required' if @application.nil?
|
@@ -106,6 +112,7 @@ module ThreeScale
|
|
106
112
|
add_plan_section(xml, 'plan'.freeze, plan_name)
|
107
113
|
add_reports_section(xml, application_usage_reports)
|
108
114
|
hierarchy_reports.concat application_usage_reports if hierarchy_reports
|
115
|
+
add_app_keys_section xml if @list_app_keys_ext
|
109
116
|
end
|
110
117
|
|
111
118
|
if hierarchy_reports
|
@@ -161,6 +168,17 @@ module ThreeScale
|
|
161
168
|
xml << '</hierarchy>'.freeze
|
162
169
|
end
|
163
170
|
|
171
|
+
def add_app_keys_section(xml)
|
172
|
+
xml << '<app_keys app="'.freeze
|
173
|
+
xml << @application.id << '" svc="'.freeze
|
174
|
+
xml << @service_id << '">'.freeze
|
175
|
+
@application.keys.take(LIST_APP_KEYS_MAX).each do |key|
|
176
|
+
xml << '<key id="'.freeze
|
177
|
+
xml << key << '"/>'.freeze
|
178
|
+
end
|
179
|
+
xml << '</app_keys>'.freeze
|
180
|
+
end
|
181
|
+
|
164
182
|
# helper to iterate over reports and get relevant hierarchy info
|
165
183
|
def with_report_and_hierarchy(reports)
|
166
184
|
reports.each do |ur|
|
data/lib/3scale/backend/usage.rb
CHANGED
@@ -3,12 +3,19 @@ module ThreeScale
|
|
3
3
|
class Usage
|
4
4
|
class << self
|
5
5
|
def application_usage(application, timestamp)
|
6
|
-
usage(application, timestamp) do |metric_id, instance_period|
|
6
|
+
usage(application.usage_limits, timestamp) do |metric_id, instance_period|
|
7
7
|
Stats::Keys.application_usage_value_key(
|
8
8
|
application.service_id, application.id, metric_id, instance_period)
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
12
|
+
def application_usage_for_limits(application, timestamp, usage_limits)
|
13
|
+
usage(usage_limits, timestamp) do |metric_id, instance_period|
|
14
|
+
Stats::Keys.application_usage_value_key(
|
15
|
+
application.service_id, application.id, metric_id, instance_period)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
12
19
|
def is_set?(usage_str)
|
13
20
|
usage_str && usage_str[0] == '#'.freeze
|
14
21
|
end
|
@@ -25,7 +32,7 @@ module ThreeScale
|
|
25
32
|
|
26
33
|
private
|
27
34
|
|
28
|
-
def usage(
|
35
|
+
def usage(usage_limits, timestamp)
|
29
36
|
# The timestamp does not change, so we can generate all the
|
30
37
|
# instantiated periods just once.
|
31
38
|
# This is important. Without this, the code can generate many instance
|
@@ -33,7 +40,7 @@ module ThreeScale
|
|
33
40
|
# time.
|
34
41
|
instance_periods = Period::instance_periods_for_ts(timestamp)
|
35
42
|
|
36
|
-
pairs = metric_period_pairs
|
43
|
+
pairs = metric_period_pairs usage_limits
|
37
44
|
return {} if pairs.empty?
|
38
45
|
|
39
46
|
keys = pairs.map do |(metric_id, period)|
|
@@ -0,0 +1,83 @@
|
|
1
|
+
module ThreeScale
|
2
|
+
module Backend
|
3
|
+
class Utilization
|
4
|
+
include Comparable
|
5
|
+
|
6
|
+
attr_reader :metric_id, :period, :max_value, :current_value
|
7
|
+
|
8
|
+
def initialize(limit, current_value)
|
9
|
+
@metric_id = limit.metric_id
|
10
|
+
@period = limit.period
|
11
|
+
@max_value = limit.value
|
12
|
+
@current_value = current_value
|
13
|
+
@encoded = encoded(limit, current_value)
|
14
|
+
end
|
15
|
+
|
16
|
+
def ratio
|
17
|
+
return 0 if max_value == 0 # Disabled metric
|
18
|
+
current_value/max_value.to_f
|
19
|
+
end
|
20
|
+
|
21
|
+
# Returns in the format needed by the Alerts class.
|
22
|
+
def to_s
|
23
|
+
@encoded
|
24
|
+
end
|
25
|
+
|
26
|
+
def <=>(other)
|
27
|
+
# Consider "disabled" the lowest ones
|
28
|
+
if ratio == 0 && other.ratio == 0
|
29
|
+
return max_value <=> other.max_value
|
30
|
+
end
|
31
|
+
|
32
|
+
ratio <=> other.ratio
|
33
|
+
end
|
34
|
+
|
35
|
+
# Note: this can return nil
|
36
|
+
def self.max_in_all_metrics(service_id, app_id)
|
37
|
+
application = Backend::Application.load!(service_id, app_id)
|
38
|
+
|
39
|
+
usage = Usage.application_usage(application, Time.now.getutc)
|
40
|
+
|
41
|
+
status = Transactor::Status.new(service_id: service_id,
|
42
|
+
application: application,
|
43
|
+
values: usage)
|
44
|
+
|
45
|
+
# Preloads all the metric names to avoid fetching them one by one when
|
46
|
+
# generating the usage reports
|
47
|
+
application.load_metric_names
|
48
|
+
|
49
|
+
max = status.application_usage_reports.map do |usage_report|
|
50
|
+
Utilization.new(usage_report.usage_limit, usage_report.current_value)
|
51
|
+
end.max
|
52
|
+
|
53
|
+
# Avoid returning a utilization for disabled metrics
|
54
|
+
max && max.max_value > 0 ? max : nil
|
55
|
+
end
|
56
|
+
|
57
|
+
# Note: this can return nil
|
58
|
+
def self.max_in_metrics(service_id, app_id, metric_ids)
|
59
|
+
application = Backend::Application.load!(service_id, app_id)
|
60
|
+
|
61
|
+
limits = UsageLimit.load_for_affecting_metrics(
|
62
|
+
service_id, application.plan_id, metric_ids
|
63
|
+
)
|
64
|
+
|
65
|
+
usage = Usage.application_usage_for_limits(application, Time.now.getutc, limits)
|
66
|
+
|
67
|
+
max = limits.map do |limit|
|
68
|
+
Utilization.new(limit, usage[limit.period][limit.metric_id])
|
69
|
+
end.max
|
70
|
+
|
71
|
+
# Avoid returning a utilization for disabled metrics
|
72
|
+
max && max.max_value > 0 ? max : nil
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
|
77
|
+
def encoded(limit, current_value)
|
78
|
+
metric_name = Metric.load_name(limit.service_id, limit.metric_id)
|
79
|
+
"#{metric_name} per #{limit.period}: #{current_value}/#{limit.value}"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -21,6 +21,13 @@ module ThreeScale
|
|
21
21
|
OAUTH_VALIDATORS = ([Validators::OauthSetting,
|
22
22
|
Validators::OauthKey,
|
23
23
|
Validators::RedirectURI] + COMMON_VALIDATORS).freeze
|
24
|
+
|
25
|
+
# OIDC specific validators will only check app keys when app_key is given.
|
26
|
+
#
|
27
|
+
# No need to add OauthSetting, since we need to check that to tell
|
28
|
+
# OIDC apart from the rest when calling authrep.xml (note lack of
|
29
|
+
# the oauth_ prefix).
|
30
|
+
OIDC_VALIDATORS = ([Validators::OauthKey] + COMMON_VALIDATORS).freeze
|
24
31
|
end
|
25
32
|
end
|
26
33
|
end
|
@@ -4,7 +4,7 @@
|
|
4
4
|
require_relative '../3scale/backend/listener_metrics'
|
5
5
|
|
6
6
|
# Config is not loaded at this point, so read ENV instead.
|
7
|
-
if ENV['CONFIG_LISTENER_PROMETHEUS_METRICS_ENABLED'].to_s == 'true'
|
7
|
+
if ENV['CONFIG_LISTENER_PROMETHEUS_METRICS_ENABLED'].to_s.downcase.freeze == 'true'.freeze
|
8
8
|
prometheus_port = ENV['CONFIG_LISTENER_PROMETHEUS_METRICS_PORT']
|
9
9
|
ThreeScale::Backend::ListenerMetrics.start_metrics_server(prometheus_port)
|
10
10
|
end
|
data/licenses.xml
CHANGED
@@ -23,7 +23,7 @@
|
|
23
23
|
</dependency>
|
24
24
|
<dependency>
|
25
25
|
<packageName>apisonator</packageName>
|
26
|
-
<version>3.
|
26
|
+
<version>3.4.2</version>
|
27
27
|
<licenses>
|
28
28
|
<license>
|
29
29
|
<name>Apache 2.0</name>
|
@@ -233,7 +233,7 @@
|
|
233
233
|
</dependency>
|
234
234
|
<dependency>
|
235
235
|
<packageName>coderay</packageName>
|
236
|
-
<version>1.1.
|
236
|
+
<version>1.1.3</version>
|
237
237
|
<licenses>
|
238
238
|
<license>
|
239
239
|
<name>MIT</name>
|
@@ -421,7 +421,7 @@
|
|
421
421
|
</dependency>
|
422
422
|
<dependency>
|
423
423
|
<packageName>method_source</packageName>
|
424
|
-
<version>0.
|
424
|
+
<version>1.0.0</version>
|
425
425
|
<licenses>
|
426
426
|
<license>
|
427
427
|
<name>MIT</name>
|
@@ -475,7 +475,7 @@
|
|
475
475
|
</dependency>
|
476
476
|
<dependency>
|
477
477
|
<packageName>multi_json</packageName>
|
478
|
-
<version>1.
|
478
|
+
<version>1.15.0</version>
|
479
479
|
<licenses>
|
480
480
|
<license>
|
481
481
|
<name>MIT</name>
|
@@ -679,7 +679,7 @@
|
|
679
679
|
</dependency>
|
680
680
|
<dependency>
|
681
681
|
<packageName>pry</packageName>
|
682
|
-
<version>0.
|
682
|
+
<version>0.14.0</version>
|
683
683
|
<licenses>
|
684
684
|
<license>
|
685
685
|
<name>MIT</name>
|
@@ -699,7 +699,7 @@
|
|
699
699
|
</dependency>
|
700
700
|
<dependency>
|
701
701
|
<packageName>pry-doc</packageName>
|
702
|
-
<version>
|
702
|
+
<version>1.1.0</version>
|
703
703
|
<licenses>
|
704
704
|
<license>
|
705
705
|
<name>MIT</name>
|
@@ -1143,7 +1143,7 @@
|
|
1143
1143
|
</dependency>
|
1144
1144
|
<dependency>
|
1145
1145
|
<packageName>yard</packageName>
|
1146
|
-
<version>0.9.
|
1146
|
+
<version>0.9.26</version>
|
1147
1147
|
<licenses>
|
1148
1148
|
<license>
|
1149
1149
|
<name>MIT</name>
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: apisonator
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.4.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Adam Ciganek
|
@@ -16,7 +16,7 @@ authors:
|
|
16
16
|
autorequire:
|
17
17
|
bindir: bin
|
18
18
|
cert_chain: []
|
19
|
-
date: 2021-
|
19
|
+
date: 2021-06-17 00:00:00.000000000 Z
|
20
20
|
dependencies: []
|
21
21
|
description: This gem provides a daemon that handles authorization and reporting of
|
22
22
|
web services managed by 3scale.
|
@@ -164,6 +164,7 @@ files:
|
|
164
164
|
- lib/3scale/backend/usage_limit.rb
|
165
165
|
- lib/3scale/backend/use_cases/provider_key_change_use_case.rb
|
166
166
|
- lib/3scale/backend/util.rb
|
167
|
+
- lib/3scale/backend/utilization.rb
|
167
168
|
- lib/3scale/backend/validators.rb
|
168
169
|
- lib/3scale/backend/validators/base.rb
|
169
170
|
- lib/3scale/backend/validators/key.rb
|
@@ -207,8 +208,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
207
208
|
- !ruby/object:Gem::Version
|
208
209
|
version: 1.3.7
|
209
210
|
requirements: []
|
210
|
-
|
211
|
-
rubygems_version: 2.7.8
|
211
|
+
rubygems_version: 3.2.10
|
212
212
|
signing_key:
|
213
213
|
specification_version: 4
|
214
214
|
summary: 3scale web service management system backend
|