apisonator 3.3.1 → 3.4.1
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/CHANGELOG.md +68 -0
- data/Gemfile.base +3 -3
- data/Gemfile.lock +17 -16
- data/Gemfile.on_prem.lock +17 -16
- data/lib/3scale/backend.rb +1 -0
- data/lib/3scale/backend/alert_limit.rb +9 -11
- data/lib/3scale/backend/alerts.rb +90 -48
- 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 +8 -8
- 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: 78b328c64420fa58f4480eb39b555856dd9a032ba78eed32f084767988cea59d
|
|
4
|
+
data.tar.gz: de454b45677bc1c133eeda34c8fb4ebfe56253c4b4de851f1d192652c5baf999
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: bf7613f456c9810217adfbdd5f345b86aa59d9abdccd44d308d846e7f271849d484601900348a4dcd4a16437d9e0376b7927e3675374a9be7a2af723c2820626
|
|
7
|
+
data.tar.gz: deb0823a0648f55bf24c24da6727afa4e62d2d5d92eeeee5545b9f6c8af38b2105bc8bb8caf3f7b28c187e020080b9b9f0b43721a42dfece2d6963d698a23e9a
|
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.1 - 2021-06-16
|
|
6
|
+
|
|
7
|
+
### Changed
|
|
8
|
+
|
|
9
|
+
- Introduced performance optimizations around alerts detection
|
|
10
|
+
([#287](https://github.com/3scale/apisonator/pull/287)).
|
|
11
|
+
|
|
12
|
+
## 3.4.0 - 2021-06-14
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
|
|
16
|
+
- New extension that list the keys of an application
|
|
17
|
+
([#284](https://github.com/3scale/apisonator/pull/284)).
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
|
|
21
|
+
- It is now possible to use OIDC in the auth and authrep endpoints
|
|
22
|
+
([#280](https://github.com/3scale/apisonator/pull/280)).
|
|
23
|
+
- Updated multi-json to 1.15.0
|
|
24
|
+
([#278](https://github.com/3scale/apisonator/pull/278)).
|
|
25
|
+
|
|
26
|
+
### Removed
|
|
27
|
+
|
|
28
|
+
- Deleted unused service attributes related with deleted end-users functionality
|
|
29
|
+
([#277](https://github.com/3scale/apisonator/pull/277)).
|
|
30
|
+
|
|
31
|
+
## 3.3.3 - 2021-03-09
|
|
32
|
+
|
|
33
|
+
### Changed
|
|
34
|
+
|
|
35
|
+
- Check if alerts can be raised before calculating utilization (perf
|
|
36
|
+
optimization) ([#275](https://github.com/3scale/apisonator/pull/275)).
|
|
37
|
+
|
|
38
|
+
### Removed
|
|
39
|
+
|
|
40
|
+
- Stop maintaining unused "current_max" key in Alerts
|
|
41
|
+
([#272](https://github.com/3scale/apisonator/pull/272)).
|
|
42
|
+
|
|
43
|
+
## 3.3.2 - 2021-02-23
|
|
44
|
+
|
|
45
|
+
### Fixed
|
|
46
|
+
|
|
47
|
+
- Fixed nil exception in `Aggregator.process`
|
|
48
|
+
([#269](https://github.com/3scale/apisonator/pull/269)).
|
|
49
|
+
|
|
50
|
+
### Changed
|
|
51
|
+
|
|
52
|
+
- Updated to Ruby 2.7 in Docker images
|
|
53
|
+
([#265](https://github.com/3scale/apisonator/pull/265)) and
|
|
54
|
+
([#266](https://github.com/3scale/apisonator/pull/266)).
|
|
55
|
+
- Updated pry to 0.14.0 and pry-doc to 1.1.0
|
|
56
|
+
([#267](https://github.com/3scale/apisonator/pull/267)).
|
|
57
|
+
- Updated Docker image to be based on RHEL UBI 8
|
|
58
|
+
([#268](https://github.com/3scale/apisonator/pull/268)).
|
|
59
|
+
|
|
60
|
+
### Removed
|
|
61
|
+
|
|
62
|
+
- Removed redundant prometheus config params
|
|
63
|
+
(`listener_prometheus_metrics.enabled` and `listener_prometheus_metrics.port`)
|
|
64
|
+
([#270](https://github.com/3scale/apisonator/pull/270)).
|
|
65
|
+
|
|
66
|
+
## 3.3.1.1 - 2021-02-12
|
|
67
|
+
|
|
68
|
+
### Changed
|
|
69
|
+
|
|
70
|
+
- Updated our Puma fork to v4.3.7
|
|
71
|
+
([#261](https://github.com/3scale/apisonator/pull/261)).
|
|
72
|
+
|
|
5
73
|
## 3.3.1 - 2021-02-11
|
|
6
74
|
|
|
7
75
|
### Fixed
|
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
|
|
|
@@ -46,7 +46,7 @@ group :development, :test do
|
|
|
46
46
|
end
|
|
47
47
|
|
|
48
48
|
# Default server by platform
|
|
49
|
-
gem 'puma', git: 'https://github.com/3scale/puma',
|
|
49
|
+
gem 'puma', git: 'https://github.com/3scale/puma', branch: '3scale-4.3.7'
|
|
50
50
|
# gems required by the runner
|
|
51
51
|
gem 'gli', '~> 2.16.1', require: nil
|
|
52
52
|
# Workers
|
data/Gemfile.lock
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
GIT
|
|
2
2
|
remote: https://github.com/3scale/puma
|
|
3
|
-
revision:
|
|
4
|
-
|
|
3
|
+
revision: c0601d08695839b8ffd0f380e91c3b91c1e8b754
|
|
4
|
+
branch: 3scale-4.3.7
|
|
5
5
|
specs:
|
|
6
|
-
puma (
|
|
6
|
+
puma (4.3.7)
|
|
7
|
+
nio4r (~> 2.0)
|
|
7
8
|
|
|
8
9
|
GIT
|
|
9
10
|
remote: https://github.com/3scale/redis-rb
|
|
@@ -35,7 +36,7 @@ GIT
|
|
|
35
36
|
PATH
|
|
36
37
|
remote: .
|
|
37
38
|
specs:
|
|
38
|
-
apisonator (3.
|
|
39
|
+
apisonator (3.4.1)
|
|
39
40
|
|
|
40
41
|
GEM
|
|
41
42
|
remote: https://rubygems.org/
|
|
@@ -95,7 +96,7 @@ GEM
|
|
|
95
96
|
chronic (0.10.2)
|
|
96
97
|
codeclimate-test-reporter (0.6.0)
|
|
97
98
|
simplecov (>= 0.7.1, < 1.0.0)
|
|
98
|
-
coderay (1.1.
|
|
99
|
+
coderay (1.1.3)
|
|
99
100
|
concurrent-ruby (1.1.6)
|
|
100
101
|
console (1.8.2)
|
|
101
102
|
daemons (1.2.4)
|
|
@@ -130,13 +131,13 @@ GEM
|
|
|
130
131
|
localhost (1.1.6)
|
|
131
132
|
mapping (1.1.1)
|
|
132
133
|
metaclass (0.0.4)
|
|
133
|
-
method_source (0.
|
|
134
|
+
method_source (1.0.0)
|
|
134
135
|
mini_portile2 (2.4.0)
|
|
135
136
|
minitest (5.14.1)
|
|
136
137
|
mocha (1.3.0)
|
|
137
138
|
metaclass (~> 0.0.1)
|
|
138
139
|
mono_logger (1.1.0)
|
|
139
|
-
multi_json (1.
|
|
140
|
+
multi_json (1.15.0)
|
|
140
141
|
mustache (1.0.5)
|
|
141
142
|
mustermann (1.0.2)
|
|
142
143
|
net-scp (1.2.1)
|
|
@@ -163,15 +164,15 @@ GEM
|
|
|
163
164
|
protocol-hpack (~> 1.4)
|
|
164
165
|
protocol-http (~> 0.15)
|
|
165
166
|
protocol-redis (0.5.0)
|
|
166
|
-
pry (0.
|
|
167
|
-
coderay (~> 1.1
|
|
168
|
-
method_source (~>
|
|
167
|
+
pry (0.14.0)
|
|
168
|
+
coderay (~> 1.1)
|
|
169
|
+
method_source (~> 1.0)
|
|
169
170
|
pry-byebug (3.5.1)
|
|
170
171
|
byebug (~> 9.1)
|
|
171
172
|
pry (~> 0.10)
|
|
172
|
-
pry-doc (
|
|
173
|
-
pry (~> 0.
|
|
174
|
-
yard (~> 0.9)
|
|
173
|
+
pry-doc (1.1.0)
|
|
174
|
+
pry (~> 0.11)
|
|
175
|
+
yard (~> 0.9.11)
|
|
175
176
|
rack (2.1.4)
|
|
176
177
|
rack-protection (2.0.3)
|
|
177
178
|
rack
|
|
@@ -259,7 +260,7 @@ GEM
|
|
|
259
260
|
prometheus-client (~> 1.0)
|
|
260
261
|
yabeda (~> 0.5)
|
|
261
262
|
yajl-ruby (1.3.1)
|
|
262
|
-
yard (0.9.
|
|
263
|
+
yard (0.9.26)
|
|
263
264
|
|
|
264
265
|
PLATFORMS
|
|
265
266
|
ruby
|
|
@@ -283,9 +284,9 @@ DEPENDENCIES
|
|
|
283
284
|
nokogiri (~> 1.10.8)
|
|
284
285
|
pg (= 0.20.0)
|
|
285
286
|
pkg-config (~> 1.1.7)
|
|
286
|
-
pry (~> 0.
|
|
287
|
+
pry (~> 0.14)
|
|
287
288
|
pry-byebug (~> 3.5.1)
|
|
288
|
-
pry-doc (~>
|
|
289
|
+
pry-doc (~> 1.1)
|
|
289
290
|
puma!
|
|
290
291
|
rack (~> 2.1.4)
|
|
291
292
|
rack-test (= 0.8.2)
|
data/Gemfile.on_prem.lock
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
GIT
|
|
2
2
|
remote: https://github.com/3scale/puma
|
|
3
|
-
revision:
|
|
4
|
-
|
|
3
|
+
revision: c0601d08695839b8ffd0f380e91c3b91c1e8b754
|
|
4
|
+
branch: 3scale-4.3.7
|
|
5
5
|
specs:
|
|
6
|
-
puma (
|
|
6
|
+
puma (4.3.7)
|
|
7
|
+
nio4r (~> 2.0)
|
|
7
8
|
|
|
8
9
|
GIT
|
|
9
10
|
remote: https://github.com/3scale/redis-rb
|
|
@@ -35,7 +36,7 @@ GIT
|
|
|
35
36
|
PATH
|
|
36
37
|
remote: .
|
|
37
38
|
specs:
|
|
38
|
-
apisonator (3.
|
|
39
|
+
apisonator (3.4.1)
|
|
39
40
|
|
|
40
41
|
GEM
|
|
41
42
|
remote: https://rubygems.org/
|
|
@@ -85,7 +86,7 @@ GEM
|
|
|
85
86
|
byebug (9.1.0)
|
|
86
87
|
codeclimate-test-reporter (0.6.0)
|
|
87
88
|
simplecov (>= 0.7.1, < 1.0.0)
|
|
88
|
-
coderay (1.1.
|
|
89
|
+
coderay (1.1.3)
|
|
89
90
|
concurrent-ruby (1.1.6)
|
|
90
91
|
console (1.8.2)
|
|
91
92
|
daemons (1.2.4)
|
|
@@ -119,13 +120,13 @@ GEM
|
|
|
119
120
|
localhost (1.1.6)
|
|
120
121
|
mapping (1.1.1)
|
|
121
122
|
metaclass (0.0.4)
|
|
122
|
-
method_source (0.
|
|
123
|
+
method_source (1.0.0)
|
|
123
124
|
mini_portile2 (2.4.0)
|
|
124
125
|
minitest (5.14.1)
|
|
125
126
|
mocha (1.3.0)
|
|
126
127
|
metaclass (~> 0.0.1)
|
|
127
128
|
mono_logger (1.1.0)
|
|
128
|
-
multi_json (1.
|
|
129
|
+
multi_json (1.15.0)
|
|
129
130
|
mustache (1.0.5)
|
|
130
131
|
mustermann (1.0.2)
|
|
131
132
|
net-scp (1.2.1)
|
|
@@ -151,15 +152,15 @@ GEM
|
|
|
151
152
|
protocol-hpack (~> 1.4)
|
|
152
153
|
protocol-http (~> 0.15)
|
|
153
154
|
protocol-redis (0.5.0)
|
|
154
|
-
pry (0.
|
|
155
|
-
coderay (~> 1.1
|
|
156
|
-
method_source (~>
|
|
155
|
+
pry (0.14.0)
|
|
156
|
+
coderay (~> 1.1)
|
|
157
|
+
method_source (~> 1.0)
|
|
157
158
|
pry-byebug (3.5.1)
|
|
158
159
|
byebug (~> 9.1)
|
|
159
160
|
pry (~> 0.10)
|
|
160
|
-
pry-doc (
|
|
161
|
-
pry (~> 0.
|
|
162
|
-
yard (~> 0.9)
|
|
161
|
+
pry-doc (1.1.0)
|
|
162
|
+
pry (~> 0.11)
|
|
163
|
+
yard (~> 0.9.11)
|
|
163
164
|
rack (2.1.4)
|
|
164
165
|
rack-protection (2.0.3)
|
|
165
166
|
rack
|
|
@@ -243,7 +244,7 @@ GEM
|
|
|
243
244
|
prometheus-client (~> 1.0)
|
|
244
245
|
yabeda (~> 0.5)
|
|
245
246
|
yajl-ruby (1.3.1)
|
|
246
|
-
yard (0.9.
|
|
247
|
+
yard (0.9.26)
|
|
247
248
|
|
|
248
249
|
PLATFORMS
|
|
249
250
|
ruby
|
|
@@ -264,9 +265,9 @@ DEPENDENCIES
|
|
|
264
265
|
mocha (~> 1.3)
|
|
265
266
|
nokogiri (~> 1.10.8)
|
|
266
267
|
pkg-config (~> 1.1.7)
|
|
267
|
-
pry (~> 0.
|
|
268
|
+
pry (~> 0.14)
|
|
268
269
|
pry-byebug (~> 3.5.1)
|
|
269
|
-
pry-doc (~>
|
|
270
|
+
pry-doc (~> 1.1)
|
|
270
271
|
puma!
|
|
271
272
|
rack (~> 2.1.4)
|
|
272
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,104 @@ 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
|
-
|
|
64
|
-
|
|
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
|
+
storage.setex(key_usage_already_checked(service_id, app_id), ttl, '1'.freeze)
|
|
84
|
+
Memoizer.clear(Memoizer.build_key(self, :need_to_check_all?, service_id, app_id))
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def self.invalidate(service_id, app_id)
|
|
88
|
+
storage.del(key_usage_already_checked(service_id, app_id))
|
|
65
89
|
end
|
|
66
90
|
|
|
67
|
-
|
|
91
|
+
def self.invalidate_for_service(service_id)
|
|
92
|
+
app_ids = []
|
|
93
|
+
cursor = 0
|
|
68
94
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
95
|
+
loop do
|
|
96
|
+
cursor, ids = storage.sscan(
|
|
97
|
+
Application.applications_set_key(service_id), cursor, count: SCAN_SLICE
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
app_ids += ids
|
|
101
|
+
|
|
102
|
+
break if cursor.to_i == 0
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
invalidate_batch(service_id, app_ids)
|
|
73
106
|
end
|
|
74
107
|
|
|
75
|
-
|
|
108
|
+
def self.invalidate_batch(service_id, app_ids)
|
|
109
|
+
app_ids.each_slice(PIPELINED_SLICE_SIZE) do |ids|
|
|
110
|
+
keys = ids.map { |app_id| key_usage_already_checked(service_id, app_id) }
|
|
111
|
+
storage.del(keys)
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
private_class_method :invalidate_batch
|
|
76
115
|
end
|
|
77
116
|
|
|
78
|
-
def
|
|
79
|
-
|
|
80
|
-
max_utilization_i = (max_utilization * 100.0).round
|
|
117
|
+
def can_raise_more_alerts?(service_id, app_id)
|
|
118
|
+
allowed_bins = allowed_set_for_service(service_id).sort
|
|
81
119
|
|
|
82
|
-
|
|
83
|
-
period_hour = Period::Boundary.hour_start(timestamp).to_compact_s
|
|
84
|
-
# UNIX timestamp for key expiration - add 1 day + 5 mins
|
|
85
|
-
expire_at = (beginning_of_day + 86700).to_i
|
|
120
|
+
return false if allowed_bins.empty?
|
|
86
121
|
|
|
87
|
-
|
|
122
|
+
# If the bin with the highest value has already been notified, there's
|
|
123
|
+
# no need to notify anything else.
|
|
124
|
+
not notified?(service_id, app_id, allowed_bins.last)
|
|
125
|
+
end
|
|
88
126
|
|
|
89
|
-
|
|
127
|
+
def update_utilization(service_id, app_id, utilization)
|
|
128
|
+
discrete = utilization_discrete(utilization.ratio)
|
|
129
|
+
|
|
130
|
+
keys = alert_keys(service_id, app_id, discrete)
|
|
131
|
+
|
|
132
|
+
already_alerted, allowed = storage.pipelined do
|
|
90
133
|
storage.get(keys[:already_notified])
|
|
91
134
|
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
135
|
end
|
|
100
136
|
|
|
101
137
|
if already_alerted.nil? && allowed && discrete.to_i > 0
|
|
102
|
-
next_id, _ = storage.pipelined do
|
|
138
|
+
next_id, _, _ = storage.pipelined do
|
|
103
139
|
storage.incr(keys[:current_id])
|
|
104
140
|
storage.setex(keys[:already_notified], ALERT_TTL, "1")
|
|
141
|
+
UsagesChecked.invalidate(service_id, app_id)
|
|
105
142
|
end
|
|
106
143
|
|
|
107
144
|
alert = { :id => next_id,
|
|
108
145
|
:utilization => discrete,
|
|
109
|
-
:max_utilization =>
|
|
146
|
+
:max_utilization => utilization.ratio,
|
|
110
147
|
:application_id => app_id,
|
|
111
148
|
:service_id => service_id,
|
|
112
|
-
:timestamp =>
|
|
113
|
-
:limit =>
|
|
149
|
+
:timestamp => Time.now.utc,
|
|
150
|
+
:limit => utilization.to_s }
|
|
114
151
|
|
|
115
152
|
Backend::EventStorage::store(:alert, alert)
|
|
116
153
|
end
|
|
@@ -124,10 +161,15 @@ module ThreeScale
|
|
|
124
161
|
end || FIRST_ALERT_BIN
|
|
125
162
|
end
|
|
126
163
|
|
|
127
|
-
def
|
|
128
|
-
|
|
129
|
-
|
|
164
|
+
def allowed_set_for_service(service_id)
|
|
165
|
+
storage.smembers(key_allowed_set(service_id)).map(&:to_i) # Redis returns strings always
|
|
166
|
+
end
|
|
167
|
+
memoize :allowed_set_for_service
|
|
168
|
+
|
|
169
|
+
def notified?(service_id, app_id, bin)
|
|
170
|
+
storage.get(key_already_notified(service_id, app_id, bin))
|
|
130
171
|
end
|
|
172
|
+
memoize :notified?
|
|
131
173
|
|
|
132
174
|
def storage
|
|
133
175
|
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.1</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>
|
|
@@ -709,7 +709,7 @@
|
|
|
709
709
|
</dependency>
|
|
710
710
|
<dependency>
|
|
711
711
|
<packageName>puma</packageName>
|
|
712
|
-
<version>
|
|
712
|
+
<version>4.3.7</version>
|
|
713
713
|
<licenses>
|
|
714
714
|
<license>
|
|
715
715
|
<name>New BSD</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.1
|
|
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
|