apisonator 2.100.0
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 +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
|