apisonator 2.100.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +317 -0
- data/Gemfile +11 -0
- data/Gemfile.base +65 -0
- data/Gemfile.lock +319 -0
- data/Gemfile.on_prem +1 -0
- data/Gemfile.on_prem.lock +297 -0
- data/LICENSE +202 -0
- data/NOTICE +15 -0
- data/README.md +230 -0
- data/Rakefile +287 -0
- data/apisonator.gemspec +47 -0
- data/app/api/api.rb +13 -0
- data/app/api/internal/alert_limits.rb +32 -0
- data/app/api/internal/application_keys.rb +49 -0
- data/app/api/internal/application_referrer_filters.rb +43 -0
- data/app/api/internal/applications.rb +77 -0
- data/app/api/internal/errors.rb +54 -0
- data/app/api/internal/events.rb +42 -0
- data/app/api/internal/internal.rb +104 -0
- data/app/api/internal/metrics.rb +40 -0
- data/app/api/internal/service_tokens.rb +46 -0
- data/app/api/internal/services.rb +58 -0
- data/app/api/internal/stats.rb +42 -0
- data/app/api/internal/usagelimits.rb +62 -0
- data/app/api/internal/utilization.rb +23 -0
- data/bin/3scale_backend +223 -0
- data/bin/3scale_backend_worker +26 -0
- data/config.ru +4 -0
- data/config/puma.rb +192 -0
- data/config/schedule.rb +9 -0
- data/ext/mkrf_conf.rb +64 -0
- data/lib/3scale/backend.rb +67 -0
- data/lib/3scale/backend/alert_limit.rb +56 -0
- data/lib/3scale/backend/alerts.rb +137 -0
- data/lib/3scale/backend/analytics/kinesis.rb +3 -0
- data/lib/3scale/backend/analytics/kinesis/adapter.rb +180 -0
- data/lib/3scale/backend/analytics/kinesis/exporter.rb +86 -0
- data/lib/3scale/backend/analytics/kinesis/job.rb +135 -0
- data/lib/3scale/backend/analytics/redshift.rb +3 -0
- data/lib/3scale/backend/analytics/redshift/adapter.rb +367 -0
- data/lib/3scale/backend/analytics/redshift/importer.rb +83 -0
- data/lib/3scale/backend/analytics/redshift/job.rb +33 -0
- data/lib/3scale/backend/application.rb +330 -0
- data/lib/3scale/backend/application_events.rb +76 -0
- data/lib/3scale/backend/background_job.rb +65 -0
- data/lib/3scale/backend/configurable.rb +20 -0
- data/lib/3scale/backend/configuration.rb +151 -0
- data/lib/3scale/backend/configuration/loader.rb +42 -0
- data/lib/3scale/backend/constants.rb +19 -0
- data/lib/3scale/backend/cors.rb +84 -0
- data/lib/3scale/backend/distributed_lock.rb +67 -0
- data/lib/3scale/backend/environment.rb +21 -0
- data/lib/3scale/backend/error_storage.rb +52 -0
- data/lib/3scale/backend/errors.rb +343 -0
- data/lib/3scale/backend/event_storage.rb +120 -0
- data/lib/3scale/backend/experiment.rb +84 -0
- data/lib/3scale/backend/extensions.rb +5 -0
- data/lib/3scale/backend/extensions/array.rb +19 -0
- data/lib/3scale/backend/extensions/hash.rb +26 -0
- data/lib/3scale/backend/extensions/nil_class.rb +13 -0
- data/lib/3scale/backend/extensions/redis.rb +44 -0
- data/lib/3scale/backend/extensions/string.rb +13 -0
- data/lib/3scale/backend/extensions/time.rb +110 -0
- data/lib/3scale/backend/failed_jobs_scheduler.rb +141 -0
- data/lib/3scale/backend/job_fetcher.rb +122 -0
- data/lib/3scale/backend/listener.rb +728 -0
- data/lib/3scale/backend/listener_metrics.rb +99 -0
- data/lib/3scale/backend/logging.rb +48 -0
- data/lib/3scale/backend/logging/external.rb +44 -0
- data/lib/3scale/backend/logging/external/impl.rb +93 -0
- data/lib/3scale/backend/logging/external/impl/airbrake.rb +66 -0
- data/lib/3scale/backend/logging/external/impl/bugsnag.rb +69 -0
- data/lib/3scale/backend/logging/external/impl/default.rb +18 -0
- data/lib/3scale/backend/logging/external/resque.rb +57 -0
- data/lib/3scale/backend/logging/logger.rb +18 -0
- data/lib/3scale/backend/logging/middleware.rb +62 -0
- data/lib/3scale/backend/logging/middleware/json_writer.rb +21 -0
- data/lib/3scale/backend/logging/middleware/text_writer.rb +60 -0
- data/lib/3scale/backend/logging/middleware/writer.rb +143 -0
- data/lib/3scale/backend/logging/worker.rb +107 -0
- data/lib/3scale/backend/manifest.rb +80 -0
- data/lib/3scale/backend/memoizer.rb +277 -0
- data/lib/3scale/backend/metric.rb +275 -0
- data/lib/3scale/backend/metric/collection.rb +91 -0
- data/lib/3scale/backend/oauth.rb +4 -0
- data/lib/3scale/backend/oauth/token.rb +26 -0
- data/lib/3scale/backend/oauth/token_key.rb +30 -0
- data/lib/3scale/backend/oauth/token_storage.rb +313 -0
- data/lib/3scale/backend/oauth/token_value.rb +25 -0
- data/lib/3scale/backend/period.rb +3 -0
- data/lib/3scale/backend/period/boundary.rb +107 -0
- data/lib/3scale/backend/period/cache.rb +28 -0
- data/lib/3scale/backend/period/period.rb +402 -0
- data/lib/3scale/backend/queue_storage.rb +16 -0
- data/lib/3scale/backend/rack.rb +49 -0
- data/lib/3scale/backend/rack/exception_catcher.rb +136 -0
- data/lib/3scale/backend/rack/internal_error_catcher.rb +23 -0
- data/lib/3scale/backend/rack/prometheus.rb +19 -0
- data/lib/3scale/backend/saas.rb +6 -0
- data/lib/3scale/backend/saas_analytics.rb +4 -0
- data/lib/3scale/backend/server.rb +30 -0
- data/lib/3scale/backend/server/falcon.rb +52 -0
- data/lib/3scale/backend/server/puma.rb +71 -0
- data/lib/3scale/backend/service.rb +317 -0
- data/lib/3scale/backend/service_token.rb +97 -0
- data/lib/3scale/backend/stats.rb +8 -0
- data/lib/3scale/backend/stats/aggregator.rb +170 -0
- data/lib/3scale/backend/stats/aggregators/base.rb +72 -0
- data/lib/3scale/backend/stats/aggregators/response_code.rb +58 -0
- data/lib/3scale/backend/stats/aggregators/usage.rb +34 -0
- data/lib/3scale/backend/stats/bucket_reader.rb +135 -0
- data/lib/3scale/backend/stats/bucket_storage.rb +108 -0
- data/lib/3scale/backend/stats/cleaner.rb +195 -0
- data/lib/3scale/backend/stats/codes_commons.rb +14 -0
- data/lib/3scale/backend/stats/delete_job_def.rb +60 -0
- data/lib/3scale/backend/stats/key_generator.rb +73 -0
- data/lib/3scale/backend/stats/keys.rb +104 -0
- data/lib/3scale/backend/stats/partition_eraser_job.rb +58 -0
- data/lib/3scale/backend/stats/partition_generator_job.rb +46 -0
- data/lib/3scale/backend/stats/period_commons.rb +34 -0
- data/lib/3scale/backend/stats/stats_parser.rb +141 -0
- data/lib/3scale/backend/stats/storage.rb +113 -0
- data/lib/3scale/backend/statsd.rb +14 -0
- data/lib/3scale/backend/storable.rb +35 -0
- data/lib/3scale/backend/storage.rb +40 -0
- data/lib/3scale/backend/storage_async.rb +4 -0
- data/lib/3scale/backend/storage_async/async_redis.rb +21 -0
- data/lib/3scale/backend/storage_async/client.rb +205 -0
- data/lib/3scale/backend/storage_async/pipeline.rb +79 -0
- data/lib/3scale/backend/storage_async/resque_extensions.rb +30 -0
- data/lib/3scale/backend/storage_helpers.rb +278 -0
- data/lib/3scale/backend/storage_key_helpers.rb +9 -0
- data/lib/3scale/backend/storage_sync.rb +43 -0
- data/lib/3scale/backend/transaction.rb +62 -0
- data/lib/3scale/backend/transactor.rb +177 -0
- data/lib/3scale/backend/transactor/limit_headers.rb +54 -0
- data/lib/3scale/backend/transactor/notify_batcher.rb +139 -0
- data/lib/3scale/backend/transactor/notify_job.rb +47 -0
- data/lib/3scale/backend/transactor/process_job.rb +33 -0
- data/lib/3scale/backend/transactor/report_job.rb +84 -0
- data/lib/3scale/backend/transactor/status.rb +236 -0
- data/lib/3scale/backend/transactor/usage_report.rb +182 -0
- data/lib/3scale/backend/usage.rb +63 -0
- data/lib/3scale/backend/usage_limit.rb +115 -0
- data/lib/3scale/backend/use_cases/provider_key_change_use_case.rb +60 -0
- data/lib/3scale/backend/util.rb +17 -0
- data/lib/3scale/backend/validators.rb +26 -0
- data/lib/3scale/backend/validators/base.rb +36 -0
- data/lib/3scale/backend/validators/key.rb +17 -0
- data/lib/3scale/backend/validators/limits.rb +57 -0
- data/lib/3scale/backend/validators/oauth_key.rb +15 -0
- data/lib/3scale/backend/validators/oauth_setting.rb +15 -0
- data/lib/3scale/backend/validators/redirect_uri.rb +33 -0
- data/lib/3scale/backend/validators/referrer.rb +60 -0
- data/lib/3scale/backend/validators/service_state.rb +15 -0
- data/lib/3scale/backend/validators/state.rb +15 -0
- data/lib/3scale/backend/version.rb +5 -0
- data/lib/3scale/backend/views/oauth_access_tokens.builder +14 -0
- data/lib/3scale/backend/views/oauth_app_id_by_token.builder +4 -0
- data/lib/3scale/backend/worker.rb +87 -0
- data/lib/3scale/backend/worker_async.rb +88 -0
- data/lib/3scale/backend/worker_metrics.rb +44 -0
- data/lib/3scale/backend/worker_sync.rb +32 -0
- data/lib/3scale/bundler_shim.rb +17 -0
- data/lib/3scale/prometheus_server.rb +10 -0
- data/lib/3scale/tasks/connectivity.rake +41 -0
- data/lib/3scale/tasks/helpers.rb +3 -0
- data/lib/3scale/tasks/helpers/environment.rb +23 -0
- data/lib/3scale/tasks/stats.rake +131 -0
- data/lib/3scale/tasks/swagger.rake +46 -0
- data/licenses.xml +1215 -0
- metadata +227 -0
@@ -0,0 +1,26 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require '3scale/backend'
|
3
|
+
require 'daemons'
|
4
|
+
|
5
|
+
if ARGV.delete '--version'
|
6
|
+
STDOUT.puts "3scale_backend_worker version #{ThreeScale::Backend::VERSION}"
|
7
|
+
exit 0
|
8
|
+
end
|
9
|
+
|
10
|
+
options = {
|
11
|
+
multiple: true,
|
12
|
+
dir_mode: :normal,
|
13
|
+
dir: '/var/run/3scale'
|
14
|
+
}
|
15
|
+
|
16
|
+
# make --no-daemonize an alias of --ontop
|
17
|
+
options[:ontop] = true if ARGV.delete '--no-daemonize'
|
18
|
+
|
19
|
+
if !File.writable? options[:dir]
|
20
|
+
require 'fileutils'
|
21
|
+
FileUtils.mkdir_p options[:dir]
|
22
|
+
end
|
23
|
+
|
24
|
+
Daemons.run_proc('3scale_backend_worker', options) do
|
25
|
+
ThreeScale::Backend::Worker.work
|
26
|
+
end
|
data/config.ru
ADDED
data/config/puma.rb
ADDED
@@ -0,0 +1,192 @@
|
|
1
|
+
#!/usr/bin/env puma
|
2
|
+
|
3
|
+
# The directory to operate out of.
|
4
|
+
#
|
5
|
+
# The default is the current directory.
|
6
|
+
#
|
7
|
+
# directory '/u/apps/lolcat'
|
8
|
+
|
9
|
+
# Use an object or block as the rack application. This allows the
|
10
|
+
# config file to be the application itself.
|
11
|
+
#
|
12
|
+
# app do |env|
|
13
|
+
# puts env
|
14
|
+
#
|
15
|
+
# body = 'Hello, World!'
|
16
|
+
#
|
17
|
+
# [200, { 'Content-Type' => 'text/plain', 'Content-Length' => body.length.to_s }, [body]]
|
18
|
+
# end
|
19
|
+
|
20
|
+
# Load "path" as a rackup file.
|
21
|
+
#
|
22
|
+
# The default is "config.ru".
|
23
|
+
#
|
24
|
+
# rackup '/u/apps/lolcat/config.ru'
|
25
|
+
rackup 'config.ru'
|
26
|
+
|
27
|
+
# Set the environment in which the rack's app will run. The value must be a string.
|
28
|
+
#
|
29
|
+
# The default is "development".
|
30
|
+
#
|
31
|
+
# environment 'production'
|
32
|
+
|
33
|
+
# Daemonize the server into the background. Highly suggest that
|
34
|
+
# this be combined with "pidfile" and "stdout_redirect".
|
35
|
+
#
|
36
|
+
# The default is "false".
|
37
|
+
#
|
38
|
+
# daemonize
|
39
|
+
# daemonize false
|
40
|
+
|
41
|
+
# Store the pid of the server in the file at "path".
|
42
|
+
#
|
43
|
+
# pidfile '/u/apps/lolcat/tmp/pids/puma.pid'
|
44
|
+
|
45
|
+
# Use "path" as the file to store the server info state. This is
|
46
|
+
# used by "pumactl" to query and control the server.
|
47
|
+
#
|
48
|
+
# state_path '/u/apps/lolcat/tmp/pids/puma.state'
|
49
|
+
|
50
|
+
# Redirect STDOUT and STDERR to files specified. The 3rd parameter
|
51
|
+
# ("append") specifies whether the output is appended, the default is
|
52
|
+
# "false".
|
53
|
+
#
|
54
|
+
# stdout_redirect '/u/apps/lolcat/log/stdout', '/u/apps/lolcat/log/stderr'
|
55
|
+
# stdout_redirect '/u/apps/lolcat/log/stdout', '/u/apps/lolcat/log/stderr', true
|
56
|
+
|
57
|
+
# Disable request logging.
|
58
|
+
#
|
59
|
+
# The default is "false".
|
60
|
+
#
|
61
|
+
quiet
|
62
|
+
|
63
|
+
# Configure "min" to be the minimum number of threads to use to answer
|
64
|
+
# requests and "max" the maximum.
|
65
|
+
#
|
66
|
+
# The default is "0, 16".
|
67
|
+
#
|
68
|
+
# threads 0, 16
|
69
|
+
|
70
|
+
# Bind the server to "url". "tcp://", "unix://" and "ssl://" are the only
|
71
|
+
# accepted protocols.
|
72
|
+
#
|
73
|
+
# The default is "tcp://0.0.0.0:9292".
|
74
|
+
#
|
75
|
+
# bind 'tcp://0.0.0.0:9292'
|
76
|
+
# bind 'unix:///var/run/puma.sock'
|
77
|
+
# bind 'unix:///var/run/puma.sock?umask=0111'
|
78
|
+
# bind 'ssl://127.0.0.1:9292?key=path_to_key&cert=path_to_cert'
|
79
|
+
|
80
|
+
# Instead of "bind 'ssl://127.0.0.1:9292?key=path_to_key&cert=path_to_cert'" you
|
81
|
+
# can also use the "ssl_bind" option.
|
82
|
+
#
|
83
|
+
# ssl_bind '127.0.0.1', '9292', { key: path_to_key, cert: path_to_cert }
|
84
|
+
|
85
|
+
# Code to run before doing a restart. This code should
|
86
|
+
# close log files, database connections, etc.
|
87
|
+
#
|
88
|
+
# This can be called multiple times to add code each time.
|
89
|
+
#
|
90
|
+
# on_restart do
|
91
|
+
# puts 'On restart...'
|
92
|
+
# end
|
93
|
+
|
94
|
+
# Command to use to restart puma. This should be just how to
|
95
|
+
# load puma itself (ie. 'ruby -Ilib bin/puma'), not the arguments
|
96
|
+
# to puma, as those are the same as the original process.
|
97
|
+
#
|
98
|
+
# restart_command '/u/app/lolcat/bin/restart_puma'
|
99
|
+
|
100
|
+
# === Cluster mode ===
|
101
|
+
|
102
|
+
# How many worker processes to run.
|
103
|
+
#
|
104
|
+
# The default is "0".
|
105
|
+
#
|
106
|
+
# workers 2
|
107
|
+
|
108
|
+
# Code to run when a worker boots to setup the process before booting
|
109
|
+
# the app.
|
110
|
+
#
|
111
|
+
# This can be called multiple times to add hooks.
|
112
|
+
#
|
113
|
+
# on_worker_boot do
|
114
|
+
# puts 'On worker boot...'
|
115
|
+
# end
|
116
|
+
on_worker_boot do |_idx|
|
117
|
+
require_relative '../lib/3scale/backend/version'
|
118
|
+
title = $0.dup
|
119
|
+
title << " [3scale_backend #{ThreeScale::Backend::VERSION}]"
|
120
|
+
if Process.respond_to? :setproctitle
|
121
|
+
Process.setproctitle title
|
122
|
+
else
|
123
|
+
$0 = title
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
# Code to run when a worker boots to setup the process after booting
|
128
|
+
# the app.
|
129
|
+
#
|
130
|
+
# This can be called multiple times to add hooks.
|
131
|
+
#
|
132
|
+
# after_worker_boot do
|
133
|
+
# puts 'After worker boot...'
|
134
|
+
# end
|
135
|
+
|
136
|
+
# Code to run when a worker shutdown.
|
137
|
+
#
|
138
|
+
#
|
139
|
+
# on_worker_shutdown do
|
140
|
+
# puts 'On worker shutdown...'
|
141
|
+
# end
|
142
|
+
|
143
|
+
# Allow workers to reload bundler context when master process is issued
|
144
|
+
# a USR1 signal. This allows proper reloading of gems while the master
|
145
|
+
# is preserved across a phased-restart. (incompatible with preload_app)
|
146
|
+
# (off by default)
|
147
|
+
|
148
|
+
prune_bundler
|
149
|
+
|
150
|
+
# Preload the application before starting the workers; this conflicts with
|
151
|
+
# phased restart feature. (off by default)
|
152
|
+
|
153
|
+
# preload_app!
|
154
|
+
|
155
|
+
# Additional text to display in process listing
|
156
|
+
#
|
157
|
+
# tag 'app name'
|
158
|
+
#
|
159
|
+
# If you do not specify a tag, Puma will infer it. If you do not want Puma
|
160
|
+
# to add a tag, use an empty string.
|
161
|
+
tag ''
|
162
|
+
|
163
|
+
# Verifies that all workers have checked in to the master process within
|
164
|
+
# the given timeout. If not the worker process will be restarted. Default
|
165
|
+
# value is 60 seconds.
|
166
|
+
#
|
167
|
+
# worker_timeout 60
|
168
|
+
|
169
|
+
# Change the default worker timeout for booting
|
170
|
+
#
|
171
|
+
# If unspecified, this defaults to the value of worker_timeout.
|
172
|
+
#
|
173
|
+
# worker_boot_timeout 60
|
174
|
+
|
175
|
+
# === Puma control rack application ===
|
176
|
+
|
177
|
+
# Start the puma control rack application on "url". This application can
|
178
|
+
# be communicated with to control the main server. Additionally, you can
|
179
|
+
# provide an authentication token, so all requests to the control server
|
180
|
+
# will need to include that token as a query parameter. This allows for
|
181
|
+
# simple authentication.
|
182
|
+
#
|
183
|
+
# Check out https://github.com/puma/puma/blob/master/lib/puma/app/status.rb
|
184
|
+
# to see what the app has available.
|
185
|
+
#
|
186
|
+
# activate_control_app 'unix:///var/run/pumactl.sock'
|
187
|
+
# activate_control_app 'unix:///var/run/pumactl.sock', { auth_token: '12345' }
|
188
|
+
# activate_control_app 'unix:///var/run/pumactl.sock', { no_token: true }
|
189
|
+
|
190
|
+
before_fork do
|
191
|
+
require_relative '../lib/3scale/prometheus_server'
|
192
|
+
end
|
data/config/schedule.rb
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
job_type :backend_rake, 'cd :path && /usr/local/bin/bundle exec rake2.4 :task --silent'
|
2
|
+
|
3
|
+
every 2.minutes do
|
4
|
+
backend_rake 'stats:kinesis:send', path: '/home/bender/backend'
|
5
|
+
end
|
6
|
+
|
7
|
+
every 1.hour do
|
8
|
+
backend_rake 'stats:redshift:import', path: '/home/bender/backend'
|
9
|
+
end
|
data/ext/mkrf_conf.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
# This extension is a hack to allow gem install to take Gemfile into account.
|
2
|
+
#
|
3
|
+
require 'rubygems'
|
4
|
+
require 'pathname'
|
5
|
+
|
6
|
+
BUNDLER_GEM = 'bundler'
|
7
|
+
|
8
|
+
def bundled_with(lockfile)
|
9
|
+
File.read(lockfile).
|
10
|
+
lines.each_cons(2).find do |f, _|
|
11
|
+
f == "BUNDLED WITH\n".freeze
|
12
|
+
end.last.strip
|
13
|
+
end
|
14
|
+
|
15
|
+
def bundler_requirements(version, reqtype = '=')
|
16
|
+
["#{reqtype} #{version}"]
|
17
|
+
end
|
18
|
+
|
19
|
+
def gem_install_bundler(requirements)
|
20
|
+
require 'rubygems/command'
|
21
|
+
require 'rubygems/commands/install_command'
|
22
|
+
begin
|
23
|
+
Gem::Command.build_args = ARGV
|
24
|
+
rescue NoMethodError
|
25
|
+
end
|
26
|
+
|
27
|
+
instcmd = Gem::Commands::InstallCommand.new
|
28
|
+
instcmd.handle_options ['-N', BUNDLER_GEM, '--version', *requirements]
|
29
|
+
begin
|
30
|
+
instcmd.execute
|
31
|
+
rescue Gem::SystemExitException => e
|
32
|
+
raise e unless e.exit_code.zero?
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def get_bundler(requirements)
|
37
|
+
Gem::Specification.find_by_name(BUNDLER_GEM, *requirements)
|
38
|
+
end
|
39
|
+
|
40
|
+
begin
|
41
|
+
extdir = Pathname.new(__FILE__).dirname.realpath
|
42
|
+
rootdir = File.expand_path('..', extdir)
|
43
|
+
gemfile = File.join rootdir, 'Gemfile'
|
44
|
+
bundled_with_version = bundled_with(gemfile + '.lock')
|
45
|
+
bundler_reqs = bundler_requirements bundled_with_version
|
46
|
+
gem_install_bundler bundler_reqs
|
47
|
+
bundler = get_bundler bundler_reqs
|
48
|
+
bundler_version = bundler.version
|
49
|
+
raise "installed bundler version #{bundler_version} must match required " \
|
50
|
+
"version #{bundled_with_version}" if bundled_with_version != bundler_version.version
|
51
|
+
bundle_bin = bundler.bin_file 'bundle'
|
52
|
+
IO.popen(%W{#{Gem.ruby} #{bundle_bin} install --without development test --gemfile=#{gemfile}}) do |io|
|
53
|
+
STDOUT.puts "Running bundler #{bundler_version} at #{bundle_bin} from #{Dir.pwd} with pid #{io.pid}"
|
54
|
+
io.each_line { |l| puts l }
|
55
|
+
end
|
56
|
+
raise "bundle install failed: #{$?.inspect}" unless $?.success?
|
57
|
+
# create dummy rakefile to indicate success
|
58
|
+
File.open(File.join(extdir, 'Rakefile'), 'w') do |f|
|
59
|
+
f.write("task :default\n")
|
60
|
+
end
|
61
|
+
rescue => e
|
62
|
+
STDERR.puts "Error: #{e.message} - #{e.class}"
|
63
|
+
exit 1
|
64
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# load the bundler shim
|
2
|
+
require_relative 'bundler_shim'
|
3
|
+
|
4
|
+
require 'builder'
|
5
|
+
require 'hiredis'
|
6
|
+
|
7
|
+
require 'redis'
|
8
|
+
require '3scale/backend/extensions/redis'
|
9
|
+
|
10
|
+
require 'resque'
|
11
|
+
require 'securerandom'
|
12
|
+
require 'sinatra/base'
|
13
|
+
require 'time'
|
14
|
+
require 'yajl'
|
15
|
+
require 'yaml'
|
16
|
+
require 'digest/md5'
|
17
|
+
|
18
|
+
# Require here the classes needed for configuring Backend
|
19
|
+
require '3scale/backend/environment'
|
20
|
+
require '3scale/backend/version'
|
21
|
+
require '3scale/backend/constants'
|
22
|
+
require '3scale/backend/configuration'
|
23
|
+
require '3scale/backend/util'
|
24
|
+
require '3scale/backend/manifest'
|
25
|
+
require '3scale/backend/logging'
|
26
|
+
|
27
|
+
# A lot of classes depend on the required modules above, so don't place them
|
28
|
+
# above this point.
|
29
|
+
require '3scale/backend/logging/middleware'
|
30
|
+
require '3scale/backend/period'
|
31
|
+
require '3scale/backend/storage_helpers'
|
32
|
+
require '3scale/backend/storage_key_helpers'
|
33
|
+
require '3scale/backend/storable'
|
34
|
+
require '3scale/backend/usage'
|
35
|
+
require '3scale/backend/rack'
|
36
|
+
require '3scale/backend/extensions'
|
37
|
+
require '3scale/backend/background_job'
|
38
|
+
require '3scale/backend/storage'
|
39
|
+
require '3scale/backend/oauth'
|
40
|
+
require '3scale/backend/memoizer'
|
41
|
+
require '3scale/backend/application'
|
42
|
+
require '3scale/backend/error_storage'
|
43
|
+
require '3scale/backend/metric'
|
44
|
+
require '3scale/backend/service'
|
45
|
+
require '3scale/backend/queue_storage'
|
46
|
+
require '3scale/backend/errors'
|
47
|
+
require '3scale/backend/stats'
|
48
|
+
require '3scale/backend/usage_limit'
|
49
|
+
require '3scale/backend/alerts'
|
50
|
+
require '3scale/backend/event_storage'
|
51
|
+
require '3scale/backend/worker'
|
52
|
+
require '3scale/backend/service_token'
|
53
|
+
require '3scale/backend/distributed_lock'
|
54
|
+
require '3scale/backend/failed_jobs_scheduler'
|
55
|
+
require '3scale/backend/transactor'
|
56
|
+
require '3scale/backend/saas'
|
57
|
+
require '3scale/backend/listener'
|
58
|
+
|
59
|
+
Resque.redis = ThreeScale::Backend::QueueStorage.connection(
|
60
|
+
ThreeScale::Backend.environment,
|
61
|
+
ThreeScale::Backend.configuration,
|
62
|
+
)
|
63
|
+
|
64
|
+
# Need to monkey-patch Resque when using async
|
65
|
+
if ThreeScale::Backend.configuration.redis.async
|
66
|
+
Resque.extend ThreeScale::Backend::StorageAsync::ResqueExtensions
|
67
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module ThreeScale
|
2
|
+
module Backend
|
3
|
+
class AlertLimit
|
4
|
+
module KeyHelpers
|
5
|
+
def key(service_id)
|
6
|
+
"alerts/service_id:#{service_id}/allowed_set"
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
include KeyHelpers
|
11
|
+
extend KeyHelpers
|
12
|
+
|
13
|
+
include Storable
|
14
|
+
|
15
|
+
attr_accessor :service_id, :value
|
16
|
+
|
17
|
+
def save
|
18
|
+
storage.sadd(key(service_id), value.to_i) if valid?
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_hash
|
22
|
+
{
|
23
|
+
service_id: service_id,
|
24
|
+
value: value.to_i,
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.load_all(service_id)
|
29
|
+
values = storage.smembers(key(service_id))
|
30
|
+
values.map do |value|
|
31
|
+
new(service_id: service_id, value: value.to_i)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.save(service_id, value)
|
36
|
+
alert_limit = new(service_id: service_id, value: value)
|
37
|
+
alert_limit if alert_limit.save
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.delete(service_id, value)
|
41
|
+
storage.srem(key(service_id), value.to_i) if valid_value?(value)
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.valid_value?(value)
|
45
|
+
val = value.to_i
|
46
|
+
Alerts::ALERT_BINS.include?(val) && val.to_s == value.to_s
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def valid?
|
52
|
+
self.class.valid_value?(value)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
module ThreeScale
|
2
|
+
module Backend
|
3
|
+
module Alerts
|
4
|
+
module KeyHelpers
|
5
|
+
private
|
6
|
+
|
7
|
+
# The compacted hour in the params refers to the
|
8
|
+
# TimeHacks.to_compact_s method.
|
9
|
+
def alert_keys(service_id, app_id, discrete_utilization, compacted_hour_start)
|
10
|
+
{
|
11
|
+
already_notified: key_already_notified(service_id, app_id, discrete_utilization),
|
12
|
+
allowed: key_allowed_set(service_id),
|
13
|
+
current_max: key_current_max(service_id, app_id, compacted_hour_start),
|
14
|
+
current_id: key_current_id
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
def key_prefix(service_id, app_id = nil)
|
19
|
+
prefix = "alerts/service_id:#{service_id}/"
|
20
|
+
prefix << "app_id:#{app_id}/" if app_id
|
21
|
+
prefix
|
22
|
+
end
|
23
|
+
|
24
|
+
def key_already_notified(service_id, app_id, discrete_utilization)
|
25
|
+
prefix = key_prefix(service_id, app_id)
|
26
|
+
"#{prefix}#{discrete_utilization}/already_notified"
|
27
|
+
end
|
28
|
+
|
29
|
+
def key_allowed_set(service_id)
|
30
|
+
prefix = key_prefix(service_id)
|
31
|
+
"#{prefix}allowed_set"
|
32
|
+
end
|
33
|
+
|
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
|
+
def key_current_id
|
40
|
+
'alerts/current_id'.freeze
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
extend self
|
45
|
+
extend KeyHelpers
|
46
|
+
|
47
|
+
ALERT_TTL = 24*3600 # 1 day (only one message per day)
|
48
|
+
## zero must be here and sorted, yes or yes
|
49
|
+
ALERT_BINS = [0, 50, 80, 90, 100, 120, 150, 200, 300].freeze
|
50
|
+
FIRST_ALERT_BIN = ALERT_BINS.first
|
51
|
+
RALERT_BINS = ALERT_BINS.reverse.freeze
|
52
|
+
|
53
|
+
def utilization(app_usage_reports)
|
54
|
+
max_utilization = -1.0
|
55
|
+
max_record = nil
|
56
|
+
max = proc do |item|
|
57
|
+
if item.max_value > 0
|
58
|
+
utilization = item.current_value / item.max_value.to_f
|
59
|
+
|
60
|
+
if utilization > max_utilization
|
61
|
+
max_record = item
|
62
|
+
max_utilization = utilization
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
app_usage_reports.each(&max)
|
68
|
+
|
69
|
+
if max_utilization == -1
|
70
|
+
## case that all the limits have max_value==0
|
71
|
+
max_utilization = 0
|
72
|
+
max_record = app_usage_reports.first
|
73
|
+
end
|
74
|
+
|
75
|
+
[max_utilization, max_record]
|
76
|
+
end
|
77
|
+
|
78
|
+
def update_utilization(service_id, app_id, max_utilization, max_record, timestamp)
|
79
|
+
discrete = utilization_discrete(max_utilization)
|
80
|
+
max_utilization_i = (max_utilization * 100.0).round
|
81
|
+
|
82
|
+
beginning_of_day = Period::Boundary.day_start(timestamp)
|
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
|
86
|
+
|
87
|
+
keys = alert_keys(service_id, app_id, discrete, period_hour)
|
88
|
+
|
89
|
+
already_alerted, allowed, current_max, _ = storage.pipelined do
|
90
|
+
storage.get(keys[:already_notified])
|
91
|
+
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
|
+
end
|
100
|
+
|
101
|
+
if already_alerted.nil? && allowed && discrete.to_i > 0
|
102
|
+
next_id, _ = storage.pipelined do
|
103
|
+
storage.incr(keys[:current_id])
|
104
|
+
storage.setex(keys[:already_notified], ALERT_TTL, "1")
|
105
|
+
end
|
106
|
+
|
107
|
+
alert = { :id => next_id,
|
108
|
+
:utilization => discrete,
|
109
|
+
:max_utilization => max_utilization,
|
110
|
+
:application_id => app_id,
|
111
|
+
:service_id => service_id,
|
112
|
+
:timestamp => timestamp,
|
113
|
+
:limit => formatted_limit(max_record) }
|
114
|
+
|
115
|
+
Backend::EventStorage::store(:alert, alert)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def utilization_discrete(utilization)
|
120
|
+
u = utilization * 100.0
|
121
|
+
# reverse search
|
122
|
+
RALERT_BINS.find do |b|
|
123
|
+
u >= b
|
124
|
+
end || FIRST_ALERT_BIN
|
125
|
+
end
|
126
|
+
|
127
|
+
def formatted_limit(record)
|
128
|
+
"#{record.metric_name} per #{record.period}: "\
|
129
|
+
"#{record.current_value}/#{record.max_value}"
|
130
|
+
end
|
131
|
+
|
132
|
+
def storage
|
133
|
+
Storage.instance
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|