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.
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