apisonator 2.100.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (173) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +317 -0
  3. data/Gemfile +11 -0
  4. data/Gemfile.base +65 -0
  5. data/Gemfile.lock +319 -0
  6. data/Gemfile.on_prem +1 -0
  7. data/Gemfile.on_prem.lock +297 -0
  8. data/LICENSE +202 -0
  9. data/NOTICE +15 -0
  10. data/README.md +230 -0
  11. data/Rakefile +287 -0
  12. data/apisonator.gemspec +47 -0
  13. data/app/api/api.rb +13 -0
  14. data/app/api/internal/alert_limits.rb +32 -0
  15. data/app/api/internal/application_keys.rb +49 -0
  16. data/app/api/internal/application_referrer_filters.rb +43 -0
  17. data/app/api/internal/applications.rb +77 -0
  18. data/app/api/internal/errors.rb +54 -0
  19. data/app/api/internal/events.rb +42 -0
  20. data/app/api/internal/internal.rb +104 -0
  21. data/app/api/internal/metrics.rb +40 -0
  22. data/app/api/internal/service_tokens.rb +46 -0
  23. data/app/api/internal/services.rb +58 -0
  24. data/app/api/internal/stats.rb +42 -0
  25. data/app/api/internal/usagelimits.rb +62 -0
  26. data/app/api/internal/utilization.rb +23 -0
  27. data/bin/3scale_backend +223 -0
  28. data/bin/3scale_backend_worker +26 -0
  29. data/config.ru +4 -0
  30. data/config/puma.rb +192 -0
  31. data/config/schedule.rb +9 -0
  32. data/ext/mkrf_conf.rb +64 -0
  33. data/lib/3scale/backend.rb +67 -0
  34. data/lib/3scale/backend/alert_limit.rb +56 -0
  35. data/lib/3scale/backend/alerts.rb +137 -0
  36. data/lib/3scale/backend/analytics/kinesis.rb +3 -0
  37. data/lib/3scale/backend/analytics/kinesis/adapter.rb +180 -0
  38. data/lib/3scale/backend/analytics/kinesis/exporter.rb +86 -0
  39. data/lib/3scale/backend/analytics/kinesis/job.rb +135 -0
  40. data/lib/3scale/backend/analytics/redshift.rb +3 -0
  41. data/lib/3scale/backend/analytics/redshift/adapter.rb +367 -0
  42. data/lib/3scale/backend/analytics/redshift/importer.rb +83 -0
  43. data/lib/3scale/backend/analytics/redshift/job.rb +33 -0
  44. data/lib/3scale/backend/application.rb +330 -0
  45. data/lib/3scale/backend/application_events.rb +76 -0
  46. data/lib/3scale/backend/background_job.rb +65 -0
  47. data/lib/3scale/backend/configurable.rb +20 -0
  48. data/lib/3scale/backend/configuration.rb +151 -0
  49. data/lib/3scale/backend/configuration/loader.rb +42 -0
  50. data/lib/3scale/backend/constants.rb +19 -0
  51. data/lib/3scale/backend/cors.rb +84 -0
  52. data/lib/3scale/backend/distributed_lock.rb +67 -0
  53. data/lib/3scale/backend/environment.rb +21 -0
  54. data/lib/3scale/backend/error_storage.rb +52 -0
  55. data/lib/3scale/backend/errors.rb +343 -0
  56. data/lib/3scale/backend/event_storage.rb +120 -0
  57. data/lib/3scale/backend/experiment.rb +84 -0
  58. data/lib/3scale/backend/extensions.rb +5 -0
  59. data/lib/3scale/backend/extensions/array.rb +19 -0
  60. data/lib/3scale/backend/extensions/hash.rb +26 -0
  61. data/lib/3scale/backend/extensions/nil_class.rb +13 -0
  62. data/lib/3scale/backend/extensions/redis.rb +44 -0
  63. data/lib/3scale/backend/extensions/string.rb +13 -0
  64. data/lib/3scale/backend/extensions/time.rb +110 -0
  65. data/lib/3scale/backend/failed_jobs_scheduler.rb +141 -0
  66. data/lib/3scale/backend/job_fetcher.rb +122 -0
  67. data/lib/3scale/backend/listener.rb +728 -0
  68. data/lib/3scale/backend/listener_metrics.rb +99 -0
  69. data/lib/3scale/backend/logging.rb +48 -0
  70. data/lib/3scale/backend/logging/external.rb +44 -0
  71. data/lib/3scale/backend/logging/external/impl.rb +93 -0
  72. data/lib/3scale/backend/logging/external/impl/airbrake.rb +66 -0
  73. data/lib/3scale/backend/logging/external/impl/bugsnag.rb +69 -0
  74. data/lib/3scale/backend/logging/external/impl/default.rb +18 -0
  75. data/lib/3scale/backend/logging/external/resque.rb +57 -0
  76. data/lib/3scale/backend/logging/logger.rb +18 -0
  77. data/lib/3scale/backend/logging/middleware.rb +62 -0
  78. data/lib/3scale/backend/logging/middleware/json_writer.rb +21 -0
  79. data/lib/3scale/backend/logging/middleware/text_writer.rb +60 -0
  80. data/lib/3scale/backend/logging/middleware/writer.rb +143 -0
  81. data/lib/3scale/backend/logging/worker.rb +107 -0
  82. data/lib/3scale/backend/manifest.rb +80 -0
  83. data/lib/3scale/backend/memoizer.rb +277 -0
  84. data/lib/3scale/backend/metric.rb +275 -0
  85. data/lib/3scale/backend/metric/collection.rb +91 -0
  86. data/lib/3scale/backend/oauth.rb +4 -0
  87. data/lib/3scale/backend/oauth/token.rb +26 -0
  88. data/lib/3scale/backend/oauth/token_key.rb +30 -0
  89. data/lib/3scale/backend/oauth/token_storage.rb +313 -0
  90. data/lib/3scale/backend/oauth/token_value.rb +25 -0
  91. data/lib/3scale/backend/period.rb +3 -0
  92. data/lib/3scale/backend/period/boundary.rb +107 -0
  93. data/lib/3scale/backend/period/cache.rb +28 -0
  94. data/lib/3scale/backend/period/period.rb +402 -0
  95. data/lib/3scale/backend/queue_storage.rb +16 -0
  96. data/lib/3scale/backend/rack.rb +49 -0
  97. data/lib/3scale/backend/rack/exception_catcher.rb +136 -0
  98. data/lib/3scale/backend/rack/internal_error_catcher.rb +23 -0
  99. data/lib/3scale/backend/rack/prometheus.rb +19 -0
  100. data/lib/3scale/backend/saas.rb +6 -0
  101. data/lib/3scale/backend/saas_analytics.rb +4 -0
  102. data/lib/3scale/backend/server.rb +30 -0
  103. data/lib/3scale/backend/server/falcon.rb +52 -0
  104. data/lib/3scale/backend/server/puma.rb +71 -0
  105. data/lib/3scale/backend/service.rb +317 -0
  106. data/lib/3scale/backend/service_token.rb +97 -0
  107. data/lib/3scale/backend/stats.rb +8 -0
  108. data/lib/3scale/backend/stats/aggregator.rb +170 -0
  109. data/lib/3scale/backend/stats/aggregators/base.rb +72 -0
  110. data/lib/3scale/backend/stats/aggregators/response_code.rb +58 -0
  111. data/lib/3scale/backend/stats/aggregators/usage.rb +34 -0
  112. data/lib/3scale/backend/stats/bucket_reader.rb +135 -0
  113. data/lib/3scale/backend/stats/bucket_storage.rb +108 -0
  114. data/lib/3scale/backend/stats/cleaner.rb +195 -0
  115. data/lib/3scale/backend/stats/codes_commons.rb +14 -0
  116. data/lib/3scale/backend/stats/delete_job_def.rb +60 -0
  117. data/lib/3scale/backend/stats/key_generator.rb +73 -0
  118. data/lib/3scale/backend/stats/keys.rb +104 -0
  119. data/lib/3scale/backend/stats/partition_eraser_job.rb +58 -0
  120. data/lib/3scale/backend/stats/partition_generator_job.rb +46 -0
  121. data/lib/3scale/backend/stats/period_commons.rb +34 -0
  122. data/lib/3scale/backend/stats/stats_parser.rb +141 -0
  123. data/lib/3scale/backend/stats/storage.rb +113 -0
  124. data/lib/3scale/backend/statsd.rb +14 -0
  125. data/lib/3scale/backend/storable.rb +35 -0
  126. data/lib/3scale/backend/storage.rb +40 -0
  127. data/lib/3scale/backend/storage_async.rb +4 -0
  128. data/lib/3scale/backend/storage_async/async_redis.rb +21 -0
  129. data/lib/3scale/backend/storage_async/client.rb +205 -0
  130. data/lib/3scale/backend/storage_async/pipeline.rb +79 -0
  131. data/lib/3scale/backend/storage_async/resque_extensions.rb +30 -0
  132. data/lib/3scale/backend/storage_helpers.rb +278 -0
  133. data/lib/3scale/backend/storage_key_helpers.rb +9 -0
  134. data/lib/3scale/backend/storage_sync.rb +43 -0
  135. data/lib/3scale/backend/transaction.rb +62 -0
  136. data/lib/3scale/backend/transactor.rb +177 -0
  137. data/lib/3scale/backend/transactor/limit_headers.rb +54 -0
  138. data/lib/3scale/backend/transactor/notify_batcher.rb +139 -0
  139. data/lib/3scale/backend/transactor/notify_job.rb +47 -0
  140. data/lib/3scale/backend/transactor/process_job.rb +33 -0
  141. data/lib/3scale/backend/transactor/report_job.rb +84 -0
  142. data/lib/3scale/backend/transactor/status.rb +236 -0
  143. data/lib/3scale/backend/transactor/usage_report.rb +182 -0
  144. data/lib/3scale/backend/usage.rb +63 -0
  145. data/lib/3scale/backend/usage_limit.rb +115 -0
  146. data/lib/3scale/backend/use_cases/provider_key_change_use_case.rb +60 -0
  147. data/lib/3scale/backend/util.rb +17 -0
  148. data/lib/3scale/backend/validators.rb +26 -0
  149. data/lib/3scale/backend/validators/base.rb +36 -0
  150. data/lib/3scale/backend/validators/key.rb +17 -0
  151. data/lib/3scale/backend/validators/limits.rb +57 -0
  152. data/lib/3scale/backend/validators/oauth_key.rb +15 -0
  153. data/lib/3scale/backend/validators/oauth_setting.rb +15 -0
  154. data/lib/3scale/backend/validators/redirect_uri.rb +33 -0
  155. data/lib/3scale/backend/validators/referrer.rb +60 -0
  156. data/lib/3scale/backend/validators/service_state.rb +15 -0
  157. data/lib/3scale/backend/validators/state.rb +15 -0
  158. data/lib/3scale/backend/version.rb +5 -0
  159. data/lib/3scale/backend/views/oauth_access_tokens.builder +14 -0
  160. data/lib/3scale/backend/views/oauth_app_id_by_token.builder +4 -0
  161. data/lib/3scale/backend/worker.rb +87 -0
  162. data/lib/3scale/backend/worker_async.rb +88 -0
  163. data/lib/3scale/backend/worker_metrics.rb +44 -0
  164. data/lib/3scale/backend/worker_sync.rb +32 -0
  165. data/lib/3scale/bundler_shim.rb +17 -0
  166. data/lib/3scale/prometheus_server.rb +10 -0
  167. data/lib/3scale/tasks/connectivity.rake +41 -0
  168. data/lib/3scale/tasks/helpers.rb +3 -0
  169. data/lib/3scale/tasks/helpers/environment.rb +23 -0
  170. data/lib/3scale/tasks/stats.rake +131 -0
  171. data/lib/3scale/tasks/swagger.rake +46 -0
  172. data/licenses.xml +1215 -0
  173. 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
@@ -0,0 +1,4 @@
1
+ require_relative 'lib/3scale/bundler_shim'
2
+ require '3scale/backend/rack'
3
+
4
+ ThreeScale::Backend::Rack.run self
@@ -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
@@ -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
@@ -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