##// END OF EJS Templates
metrics: remove bootstrap timing, as its not usefull at all....
super-admin -
r4813:5072ed70 default
parent child Browse files
Show More
@@ -1,800 +1,794 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2020 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21 import os
22 22 import sys
23 23 import logging
24 24 import collections
25 25 import tempfile
26 26 import time
27 27
28 28 from paste.gzipper import make_gzip_middleware
29 29 import pyramid.events
30 30 from pyramid.wsgi import wsgiapp
31 31 from pyramid.authorization import ACLAuthorizationPolicy
32 32 from pyramid.config import Configurator
33 33 from pyramid.settings import asbool, aslist
34 34 from pyramid.httpexceptions import (
35 35 HTTPException, HTTPError, HTTPInternalServerError, HTTPFound, HTTPNotFound)
36 36 from pyramid.renderers import render_to_response
37 37
38 38 from rhodecode.model import meta
39 39 from rhodecode.config import patches
40 40 from rhodecode.config import utils as config_utils
41 41 from rhodecode.config.environment import load_pyramid_environment
42 42
43 43 import rhodecode.events
44 44 from rhodecode.lib.middleware.vcs import VCSMiddleware
45 45 from rhodecode.lib.request import Request
46 46 from rhodecode.lib.vcs import VCSCommunicationError
47 47 from rhodecode.lib.exceptions import VCSServerUnavailable
48 48 from rhodecode.lib.middleware.appenlight import wrap_in_appenlight_if_enabled
49 49 from rhodecode.lib.middleware.https_fixup import HttpsFixup
50 50 from rhodecode.lib.plugins.utils import register_rhodecode_plugin
51 51 from rhodecode.lib.utils2 import aslist as rhodecode_aslist, AttributeDict
52 52 from rhodecode.lib.exc_tracking import store_exception
53 53 from rhodecode.subscribers import (
54 54 scan_repositories_if_enabled, write_js_routes_if_enabled,
55 55 write_metadata_if_needed, write_usage_data)
56 56 from rhodecode.lib.statsd_client import StatsdClient
57 57
58 58 log = logging.getLogger(__name__)
59 59
60 60
61 61 def is_http_error(response):
62 62 # error which should have traceback
63 63 return response.status_code > 499
64 64
65 65
66 66 def should_load_all():
67 67 """
68 68 Returns if all application components should be loaded. In some cases it's
69 69 desired to skip apps loading for faster shell script execution
70 70 """
71 71 ssh_cmd = os.environ.get('RC_CMD_SSH_WRAPPER')
72 72 if ssh_cmd:
73 73 return False
74 74
75 75 return True
76 76
77 77
78 78 def make_pyramid_app(global_config, **settings):
79 79 """
80 80 Constructs the WSGI application based on Pyramid.
81 81
82 82 Specials:
83 83
84 84 * The application can also be integrated like a plugin via the call to
85 85 `includeme`. This is accompanied with the other utility functions which
86 86 are called. Changing this should be done with great care to not break
87 87 cases when these fragments are assembled from another place.
88 88
89 89 """
90 90
91 91 # Allows to use format style "{ENV_NAME}" placeholders in the configuration. It
92 92 # will be replaced by the value of the environment variable "NAME" in this case.
93 93 start_time = time.time()
94 94 log.info('Pyramid app config starting')
95 95
96 96 # init and bootstrap StatsdClient
97 97 StatsdClient.setup(settings)
98 98
99 99 debug = asbool(global_config.get('debug'))
100 100 if debug:
101 101 enable_debug()
102 102
103 103 environ = {'ENV_{}'.format(key): value for key, value in os.environ.items()}
104 104
105 105 global_config = _substitute_values(global_config, environ)
106 106 settings = _substitute_values(settings, environ)
107 107
108 108 sanitize_settings_and_apply_defaults(global_config, settings)
109 109
110 110 config = Configurator(settings=settings)
111 111 # Init our statsd at very start
112 112 config.registry.statsd = StatsdClient.statsd
113 113
114 114 # Apply compatibility patches
115 115 patches.inspect_getargspec()
116 116
117 117 load_pyramid_environment(global_config, settings)
118 118
119 119 # Static file view comes first
120 120 includeme_first(config)
121 121
122 122 includeme(config)
123 123
124 124 pyramid_app = config.make_wsgi_app()
125 125 pyramid_app = wrap_app_in_wsgi_middlewares(pyramid_app, config)
126 126 pyramid_app.config = config
127 127
128 128 config.configure_celery(global_config['__file__'])
129 129
130 130 # creating the app uses a connection - return it after we are done
131 131 meta.Session.remove()
132 statsd = StatsdClient.statsd
133 132
134 133 total_time = time.time() - start_time
135 134 log.info('Pyramid app `%s` created and configured in %.2fs',
136 135 pyramid_app.func_name, total_time)
137 if statsd:
138 elapsed_time_ms = round(1000.0 * total_time) # use ms only rounded time
139 statsd.timing('rhodecode_app_bootstrap_timing', elapsed_time_ms, tags=[
140 "pyramid_app:{}".format(pyramid_app.func_name)
141 ], use_decimals=False)
142 136 return pyramid_app
143 137
144 138
145 139 def not_found_view(request):
146 140 """
147 141 This creates the view which should be registered as not-found-view to
148 142 pyramid.
149 143 """
150 144
151 145 if not getattr(request, 'vcs_call', None):
152 146 # handle like regular case with our error_handler
153 147 return error_handler(HTTPNotFound(), request)
154 148
155 149 # handle not found view as a vcs call
156 150 settings = request.registry.settings
157 151 ae_client = getattr(request, 'ae_client', None)
158 152 vcs_app = VCSMiddleware(
159 153 HTTPNotFound(), request.registry, settings,
160 154 appenlight_client=ae_client)
161 155
162 156 return wsgiapp(vcs_app)(None, request)
163 157
164 158
165 159 def error_handler(exception, request):
166 160 import rhodecode
167 161 from rhodecode.lib import helpers
168 162 from rhodecode.lib.utils2 import str2bool
169 163
170 164 rhodecode_title = rhodecode.CONFIG.get('rhodecode_title') or 'RhodeCode'
171 165
172 166 base_response = HTTPInternalServerError()
173 167 # prefer original exception for the response since it may have headers set
174 168 if isinstance(exception, HTTPException):
175 169 base_response = exception
176 170 elif isinstance(exception, VCSCommunicationError):
177 171 base_response = VCSServerUnavailable()
178 172
179 173 if is_http_error(base_response):
180 174 log.exception(
181 175 'error occurred handling this request for path: %s', request.path)
182 176
183 177 error_explanation = base_response.explanation or str(base_response)
184 178 if base_response.status_code == 404:
185 179 error_explanation += " Optionally you don't have permission to access this page."
186 180 c = AttributeDict()
187 181 c.error_message = base_response.status
188 182 c.error_explanation = error_explanation
189 183 c.visual = AttributeDict()
190 184
191 185 c.visual.rhodecode_support_url = (
192 186 request.registry.settings.get('rhodecode_support_url') or
193 187 request.route_url('rhodecode_support')
194 188 )
195 189 c.redirect_time = 0
196 190 c.rhodecode_name = rhodecode_title
197 191 if not c.rhodecode_name:
198 192 c.rhodecode_name = 'Rhodecode'
199 193
200 194 c.causes = []
201 195 if is_http_error(base_response):
202 196 c.causes.append('Server is overloaded.')
203 197 c.causes.append('Server database connection is lost.')
204 198 c.causes.append('Server expected unhandled error.')
205 199
206 200 if hasattr(base_response, 'causes'):
207 201 c.causes = base_response.causes
208 202
209 203 c.messages = helpers.flash.pop_messages(request=request)
210 204
211 205 exc_info = sys.exc_info()
212 206 c.exception_id = id(exc_info)
213 207 c.show_exception_id = isinstance(base_response, VCSServerUnavailable) \
214 208 or base_response.status_code > 499
215 209 c.exception_id_url = request.route_url(
216 210 'admin_settings_exception_tracker_show', exception_id=c.exception_id)
217 211
218 212 if c.show_exception_id:
219 213 store_exception(c.exception_id, exc_info)
220 214 c.exception_debug = str2bool(rhodecode.CONFIG.get('debug'))
221 215 c.exception_config_ini = rhodecode.CONFIG.get('__file__')
222 216
223 217 response = render_to_response(
224 218 '/errors/error_document.mako', {'c': c, 'h': helpers}, request=request,
225 219 response=base_response)
226 220
227 221 statsd = request.registry.statsd
228 222 if statsd and base_response.status_code > 499:
229 223 exc_type = "{}.{}".format(exception.__class__.__module__, exception.__class__.__name__)
230 224 statsd.incr('rhodecode_exception_total',
231 225 tags=["exc_source:web",
232 226 "http_code:{}".format(base_response.status_code),
233 227 "type:{}".format(exc_type)])
234 228
235 229 return response
236 230
237 231
238 232 def includeme_first(config):
239 233 # redirect automatic browser favicon.ico requests to correct place
240 234 def favicon_redirect(context, request):
241 235 return HTTPFound(
242 236 request.static_path('rhodecode:public/images/favicon.ico'))
243 237
244 238 config.add_view(favicon_redirect, route_name='favicon')
245 239 config.add_route('favicon', '/favicon.ico')
246 240
247 241 def robots_redirect(context, request):
248 242 return HTTPFound(
249 243 request.static_path('rhodecode:public/robots.txt'))
250 244
251 245 config.add_view(robots_redirect, route_name='robots')
252 246 config.add_route('robots', '/robots.txt')
253 247
254 248 config.add_static_view(
255 249 '_static/deform', 'deform:static')
256 250 config.add_static_view(
257 251 '_static/rhodecode', path='rhodecode:public', cache_max_age=3600 * 24)
258 252
259 253
260 254 def includeme(config, auth_resources=None):
261 255 from rhodecode.lib.celerylib.loader import configure_celery
262 256 log.debug('Initializing main includeme from %s', os.path.basename(__file__))
263 257 settings = config.registry.settings
264 258 config.set_request_factory(Request)
265 259
266 260 # plugin information
267 261 config.registry.rhodecode_plugins = collections.OrderedDict()
268 262
269 263 config.add_directive(
270 264 'register_rhodecode_plugin', register_rhodecode_plugin)
271 265
272 266 config.add_directive('configure_celery', configure_celery)
273 267
274 268 if asbool(settings.get('appenlight', 'false')):
275 269 config.include('appenlight_client.ext.pyramid_tween')
276 270
277 271 load_all = should_load_all()
278 272
279 273 # Includes which are required. The application would fail without them.
280 274 config.include('pyramid_mako')
281 275 config.include('rhodecode.lib.rc_beaker')
282 276 config.include('rhodecode.lib.rc_cache')
283 277 config.include('rhodecode.apps._base.navigation')
284 278 config.include('rhodecode.apps._base.subscribers')
285 279 config.include('rhodecode.tweens')
286 280 config.include('rhodecode.authentication')
287 281
288 282 if load_all:
289 283 ce_auth_resources = [
290 284 'rhodecode.authentication.plugins.auth_crowd',
291 285 'rhodecode.authentication.plugins.auth_headers',
292 286 'rhodecode.authentication.plugins.auth_jasig_cas',
293 287 'rhodecode.authentication.plugins.auth_ldap',
294 288 'rhodecode.authentication.plugins.auth_pam',
295 289 'rhodecode.authentication.plugins.auth_rhodecode',
296 290 'rhodecode.authentication.plugins.auth_token',
297 291 ]
298 292
299 293 # load CE authentication plugins
300 294
301 295 if auth_resources:
302 296 ce_auth_resources.extend(auth_resources)
303 297
304 298 for resource in ce_auth_resources:
305 299 config.include(resource)
306 300
307 301 # Auto discover authentication plugins and include their configuration.
308 302 if asbool(settings.get('auth_plugin.import_legacy_plugins', 'true')):
309 303 from rhodecode.authentication import discover_legacy_plugins
310 304 discover_legacy_plugins(config)
311 305
312 306 # apps
313 307 if load_all:
314 308 config.include('rhodecode.api')
315 309 config.include('rhodecode.apps._base')
316 310 config.include('rhodecode.apps.hovercards')
317 311 config.include('rhodecode.apps.ops')
318 312 config.include('rhodecode.apps.channelstream')
319 313 config.include('rhodecode.apps.file_store')
320 314 config.include('rhodecode.apps.admin')
321 315 config.include('rhodecode.apps.login')
322 316 config.include('rhodecode.apps.home')
323 317 config.include('rhodecode.apps.journal')
324 318
325 319 config.include('rhodecode.apps.repository')
326 320 config.include('rhodecode.apps.repo_group')
327 321 config.include('rhodecode.apps.user_group')
328 322 config.include('rhodecode.apps.search')
329 323 config.include('rhodecode.apps.user_profile')
330 324 config.include('rhodecode.apps.user_group_profile')
331 325 config.include('rhodecode.apps.my_account')
332 326 config.include('rhodecode.apps.gist')
333 327
334 328 config.include('rhodecode.apps.svn_support')
335 329 config.include('rhodecode.apps.ssh_support')
336 330 config.include('rhodecode.apps.debug_style')
337 331
338 332 if load_all:
339 333 config.include('rhodecode.integrations')
340 334
341 335 config.add_route('rhodecode_support', 'https://rhodecode.com/help/', static=True)
342 336 config.add_translation_dirs('rhodecode:i18n/')
343 337 settings['default_locale_name'] = settings.get('lang', 'en')
344 338
345 339 # Add subscribers.
346 340 if load_all:
347 341 config.add_subscriber(scan_repositories_if_enabled,
348 342 pyramid.events.ApplicationCreated)
349 343 config.add_subscriber(write_metadata_if_needed,
350 344 pyramid.events.ApplicationCreated)
351 345 config.add_subscriber(write_usage_data,
352 346 pyramid.events.ApplicationCreated)
353 347 config.add_subscriber(write_js_routes_if_enabled,
354 348 pyramid.events.ApplicationCreated)
355 349
356 350 # request custom methods
357 351 config.add_request_method(
358 352 'rhodecode.lib.partial_renderer.get_partial_renderer',
359 353 'get_partial_renderer')
360 354
361 355 config.add_request_method(
362 356 'rhodecode.lib.request_counter.get_request_counter',
363 357 'request_count')
364 358
365 359 # Set the authorization policy.
366 360 authz_policy = ACLAuthorizationPolicy()
367 361 config.set_authorization_policy(authz_policy)
368 362
369 363 # Set the default renderer for HTML templates to mako.
370 364 config.add_mako_renderer('.html')
371 365
372 366 config.add_renderer(
373 367 name='json_ext',
374 368 factory='rhodecode.lib.ext_json_renderer.pyramid_ext_json')
375 369
376 370 config.add_renderer(
377 371 name='string_html',
378 372 factory='rhodecode.lib.string_renderer.html')
379 373
380 374 # include RhodeCode plugins
381 375 includes = aslist(settings.get('rhodecode.includes', []))
382 376 for inc in includes:
383 377 config.include(inc)
384 378
385 379 # custom not found view, if our pyramid app doesn't know how to handle
386 380 # the request pass it to potential VCS handling ap
387 381 config.add_notfound_view(not_found_view)
388 382 if not settings.get('debugtoolbar.enabled', False):
389 383 # disabled debugtoolbar handle all exceptions via the error_handlers
390 384 config.add_view(error_handler, context=Exception)
391 385
392 386 # all errors including 403/404/50X
393 387 config.add_view(error_handler, context=HTTPError)
394 388
395 389
396 390 def wrap_app_in_wsgi_middlewares(pyramid_app, config):
397 391 """
398 392 Apply outer WSGI middlewares around the application.
399 393 """
400 394 registry = config.registry
401 395 settings = registry.settings
402 396
403 397 # enable https redirects based on HTTP_X_URL_SCHEME set by proxy
404 398 pyramid_app = HttpsFixup(pyramid_app, settings)
405 399
406 400 pyramid_app, _ae_client = wrap_in_appenlight_if_enabled(
407 401 pyramid_app, settings)
408 402 registry.ae_client = _ae_client
409 403
410 404 if settings['gzip_responses']:
411 405 pyramid_app = make_gzip_middleware(
412 406 pyramid_app, settings, compress_level=1)
413 407
414 408 # this should be the outer most middleware in the wsgi stack since
415 409 # middleware like Routes make database calls
416 410 def pyramid_app_with_cleanup(environ, start_response):
417 411 try:
418 412 return pyramid_app(environ, start_response)
419 413 finally:
420 414 # Dispose current database session and rollback uncommitted
421 415 # transactions.
422 416 meta.Session.remove()
423 417
424 418 # In a single threaded mode server, on non sqlite db we should have
425 419 # '0 Current Checked out connections' at the end of a request,
426 420 # if not, then something, somewhere is leaving a connection open
427 421 pool = meta.Base.metadata.bind.engine.pool
428 422 log.debug('sa pool status: %s', pool.status())
429 423 log.debug('Request processing finalized')
430 424
431 425 return pyramid_app_with_cleanup
432 426
433 427
434 428 def sanitize_settings_and_apply_defaults(global_config, settings):
435 429 """
436 430 Applies settings defaults and does all type conversion.
437 431
438 432 We would move all settings parsing and preparation into this place, so that
439 433 we have only one place left which deals with this part. The remaining parts
440 434 of the application would start to rely fully on well prepared settings.
441 435
442 436 This piece would later be split up per topic to avoid a big fat monster
443 437 function.
444 438 """
445 439
446 440 settings.setdefault('rhodecode.edition', 'Community Edition')
447 441 settings.setdefault('rhodecode.edition_id', 'CE')
448 442
449 443 if 'mako.default_filters' not in settings:
450 444 # set custom default filters if we don't have it defined
451 445 settings['mako.imports'] = 'from rhodecode.lib.base import h_filter'
452 446 settings['mako.default_filters'] = 'h_filter'
453 447
454 448 if 'mako.directories' not in settings:
455 449 mako_directories = settings.setdefault('mako.directories', [
456 450 # Base templates of the original application
457 451 'rhodecode:templates',
458 452 ])
459 453 log.debug(
460 454 "Using the following Mako template directories: %s",
461 455 mako_directories)
462 456
463 457 # NOTE(marcink): fix redis requirement for schema of connection since 3.X
464 458 if 'beaker.session.type' in settings and settings['beaker.session.type'] == 'ext:redis':
465 459 raw_url = settings['beaker.session.url']
466 460 if not raw_url.startswith(('redis://', 'rediss://', 'unix://')):
467 461 settings['beaker.session.url'] = 'redis://' + raw_url
468 462
469 463 # Default includes, possible to change as a user
470 464 pyramid_includes = settings.setdefault('pyramid.includes', [])
471 465 log.debug(
472 466 "Using the following pyramid.includes: %s",
473 467 pyramid_includes)
474 468
475 469 # TODO: johbo: Re-think this, usually the call to config.include
476 470 # should allow to pass in a prefix.
477 471 settings.setdefault('rhodecode.api.url', '/_admin/api')
478 472 settings.setdefault('__file__', global_config.get('__file__'))
479 473
480 474 # Sanitize generic settings.
481 475 _list_setting(settings, 'default_encoding', 'UTF-8')
482 476 _bool_setting(settings, 'is_test', 'false')
483 477 _bool_setting(settings, 'gzip_responses', 'false')
484 478
485 479 # Call split out functions that sanitize settings for each topic.
486 480 _sanitize_appenlight_settings(settings)
487 481 _sanitize_vcs_settings(settings)
488 482 _sanitize_cache_settings(settings)
489 483
490 484 # configure instance id
491 485 config_utils.set_instance_id(settings)
492 486
493 487 return settings
494 488
495 489
496 490 def enable_debug():
497 491 """
498 492 Helper to enable debug on running instance
499 493 :return:
500 494 """
501 495 import tempfile
502 496 import textwrap
503 497 import logging.config
504 498
505 499 ini_template = textwrap.dedent("""
506 500 #####################################
507 501 ### DEBUG LOGGING CONFIGURATION ####
508 502 #####################################
509 503 [loggers]
510 504 keys = root, sqlalchemy, beaker, celery, rhodecode, ssh_wrapper
511 505
512 506 [handlers]
513 507 keys = console, console_sql
514 508
515 509 [formatters]
516 510 keys = generic, color_formatter, color_formatter_sql
517 511
518 512 #############
519 513 ## LOGGERS ##
520 514 #############
521 515 [logger_root]
522 516 level = NOTSET
523 517 handlers = console
524 518
525 519 [logger_sqlalchemy]
526 520 level = INFO
527 521 handlers = console_sql
528 522 qualname = sqlalchemy.engine
529 523 propagate = 0
530 524
531 525 [logger_beaker]
532 526 level = DEBUG
533 527 handlers =
534 528 qualname = beaker.container
535 529 propagate = 1
536 530
537 531 [logger_rhodecode]
538 532 level = DEBUG
539 533 handlers =
540 534 qualname = rhodecode
541 535 propagate = 1
542 536
543 537 [logger_ssh_wrapper]
544 538 level = DEBUG
545 539 handlers =
546 540 qualname = ssh_wrapper
547 541 propagate = 1
548 542
549 543 [logger_celery]
550 544 level = DEBUG
551 545 handlers =
552 546 qualname = celery
553 547
554 548
555 549 ##############
556 550 ## HANDLERS ##
557 551 ##############
558 552
559 553 [handler_console]
560 554 class = StreamHandler
561 555 args = (sys.stderr, )
562 556 level = DEBUG
563 557 formatter = color_formatter
564 558
565 559 [handler_console_sql]
566 560 # "level = DEBUG" logs SQL queries and results.
567 561 # "level = INFO" logs SQL queries.
568 562 # "level = WARN" logs neither. (Recommended for production systems.)
569 563 class = StreamHandler
570 564 args = (sys.stderr, )
571 565 level = WARN
572 566 formatter = color_formatter_sql
573 567
574 568 ################
575 569 ## FORMATTERS ##
576 570 ################
577 571
578 572 [formatter_generic]
579 573 class = rhodecode.lib.logging_formatter.ExceptionAwareFormatter
580 574 format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s | %(req_id)s
581 575 datefmt = %Y-%m-%d %H:%M:%S
582 576
583 577 [formatter_color_formatter]
584 578 class = rhodecode.lib.logging_formatter.ColorRequestTrackingFormatter
585 579 format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s | %(req_id)s
586 580 datefmt = %Y-%m-%d %H:%M:%S
587 581
588 582 [formatter_color_formatter_sql]
589 583 class = rhodecode.lib.logging_formatter.ColorFormatterSql
590 584 format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s
591 585 datefmt = %Y-%m-%d %H:%M:%S
592 586 """)
593 587
594 588 with tempfile.NamedTemporaryFile(prefix='rc_debug_logging_', suffix='.ini',
595 589 delete=False) as f:
596 590 log.info('Saved Temporary DEBUG config at %s', f.name)
597 591 f.write(ini_template)
598 592
599 593 logging.config.fileConfig(f.name)
600 594 log.debug('DEBUG MODE ON')
601 595 os.remove(f.name)
602 596
603 597
604 598 def _sanitize_appenlight_settings(settings):
605 599 _bool_setting(settings, 'appenlight', 'false')
606 600
607 601
608 602 def _sanitize_vcs_settings(settings):
609 603 """
610 604 Applies settings defaults and does type conversion for all VCS related
611 605 settings.
612 606 """
613 607 _string_setting(settings, 'vcs.svn.compatible_version', '')
614 608 _string_setting(settings, 'vcs.hooks.protocol', 'http')
615 609 _string_setting(settings, 'vcs.hooks.host', '127.0.0.1')
616 610 _string_setting(settings, 'vcs.scm_app_implementation', 'http')
617 611 _string_setting(settings, 'vcs.server', '')
618 612 _string_setting(settings, 'vcs.server.protocol', 'http')
619 613 _bool_setting(settings, 'startup.import_repos', 'false')
620 614 _bool_setting(settings, 'vcs.hooks.direct_calls', 'false')
621 615 _bool_setting(settings, 'vcs.server.enable', 'true')
622 616 _bool_setting(settings, 'vcs.start_server', 'false')
623 617 _list_setting(settings, 'vcs.backends', 'hg, git, svn')
624 618 _int_setting(settings, 'vcs.connection_timeout', 3600)
625 619
626 620 # Support legacy values of vcs.scm_app_implementation. Legacy
627 621 # configurations may use 'rhodecode.lib.middleware.utils.scm_app_http', or
628 622 # disabled since 4.13 'vcsserver.scm_app' which is now mapped to 'http'.
629 623 scm_app_impl = settings['vcs.scm_app_implementation']
630 624 if scm_app_impl in ['rhodecode.lib.middleware.utils.scm_app_http', 'vcsserver.scm_app']:
631 625 settings['vcs.scm_app_implementation'] = 'http'
632 626
633 627
634 628 def _sanitize_cache_settings(settings):
635 629 temp_store = tempfile.gettempdir()
636 630 default_cache_dir = os.path.join(temp_store, 'rc_cache')
637 631
638 632 # save default, cache dir, and use it for all backends later.
639 633 default_cache_dir = _string_setting(
640 634 settings,
641 635 'cache_dir',
642 636 default_cache_dir, lower=False, default_when_empty=True)
643 637
644 638 # ensure we have our dir created
645 639 if not os.path.isdir(default_cache_dir):
646 640 os.makedirs(default_cache_dir, mode=0o755)
647 641
648 642 # exception store cache
649 643 _string_setting(
650 644 settings,
651 645 'exception_tracker.store_path',
652 646 temp_store, lower=False, default_when_empty=True)
653 647 _bool_setting(
654 648 settings,
655 649 'exception_tracker.send_email',
656 650 'false')
657 651 _string_setting(
658 652 settings,
659 653 'exception_tracker.email_prefix',
660 654 '[RHODECODE ERROR]', lower=False, default_when_empty=True)
661 655
662 656 # cache_perms
663 657 _string_setting(
664 658 settings,
665 659 'rc_cache.cache_perms.backend',
666 660 'dogpile.cache.rc.file_namespace', lower=False)
667 661 _int_setting(
668 662 settings,
669 663 'rc_cache.cache_perms.expiration_time',
670 664 60)
671 665 _string_setting(
672 666 settings,
673 667 'rc_cache.cache_perms.arguments.filename',
674 668 os.path.join(default_cache_dir, 'rc_cache_1'), lower=False)
675 669
676 670 # cache_repo
677 671 _string_setting(
678 672 settings,
679 673 'rc_cache.cache_repo.backend',
680 674 'dogpile.cache.rc.file_namespace', lower=False)
681 675 _int_setting(
682 676 settings,
683 677 'rc_cache.cache_repo.expiration_time',
684 678 60)
685 679 _string_setting(
686 680 settings,
687 681 'rc_cache.cache_repo.arguments.filename',
688 682 os.path.join(default_cache_dir, 'rc_cache_2'), lower=False)
689 683
690 684 # cache_license
691 685 _string_setting(
692 686 settings,
693 687 'rc_cache.cache_license.backend',
694 688 'dogpile.cache.rc.file_namespace', lower=False)
695 689 _int_setting(
696 690 settings,
697 691 'rc_cache.cache_license.expiration_time',
698 692 5*60)
699 693 _string_setting(
700 694 settings,
701 695 'rc_cache.cache_license.arguments.filename',
702 696 os.path.join(default_cache_dir, 'rc_cache_3'), lower=False)
703 697
704 698 # cache_repo_longterm memory, 96H
705 699 _string_setting(
706 700 settings,
707 701 'rc_cache.cache_repo_longterm.backend',
708 702 'dogpile.cache.rc.memory_lru', lower=False)
709 703 _int_setting(
710 704 settings,
711 705 'rc_cache.cache_repo_longterm.expiration_time',
712 706 345600)
713 707 _int_setting(
714 708 settings,
715 709 'rc_cache.cache_repo_longterm.max_size',
716 710 10000)
717 711
718 712 # sql_cache_short
719 713 _string_setting(
720 714 settings,
721 715 'rc_cache.sql_cache_short.backend',
722 716 'dogpile.cache.rc.memory_lru', lower=False)
723 717 _int_setting(
724 718 settings,
725 719 'rc_cache.sql_cache_short.expiration_time',
726 720 30)
727 721 _int_setting(
728 722 settings,
729 723 'rc_cache.sql_cache_short.max_size',
730 724 10000)
731 725
732 726
733 727 def _int_setting(settings, name, default):
734 728 settings[name] = int(settings.get(name, default))
735 729 return settings[name]
736 730
737 731
738 732 def _bool_setting(settings, name, default):
739 733 input_val = settings.get(name, default)
740 734 if isinstance(input_val, unicode):
741 735 input_val = input_val.encode('utf8')
742 736 settings[name] = asbool(input_val)
743 737 return settings[name]
744 738
745 739
746 740 def _list_setting(settings, name, default):
747 741 raw_value = settings.get(name, default)
748 742
749 743 old_separator = ','
750 744 if old_separator in raw_value:
751 745 # If we get a comma separated list, pass it to our own function.
752 746 settings[name] = rhodecode_aslist(raw_value, sep=old_separator)
753 747 else:
754 748 # Otherwise we assume it uses pyramids space/newline separation.
755 749 settings[name] = aslist(raw_value)
756 750 return settings[name]
757 751
758 752
759 753 def _string_setting(settings, name, default, lower=True, default_when_empty=False):
760 754 value = settings.get(name, default)
761 755
762 756 if default_when_empty and not value:
763 757 # use default value when value is empty
764 758 value = default
765 759
766 760 if lower:
767 761 value = value.lower()
768 762 settings[name] = value
769 763 return settings[name]
770 764
771 765
772 766 def _substitute_values(mapping, substitutions):
773 767 result = {}
774 768
775 769 try:
776 770 for key, value in mapping.items():
777 771 # initialize without substitution first
778 772 result[key] = value
779 773
780 774 # Note: Cannot use regular replacements, since they would clash
781 775 # with the implementation of ConfigParser. Using "format" instead.
782 776 try:
783 777 result[key] = value.format(**substitutions)
784 778 except KeyError as e:
785 779 env_var = '{}'.format(e.args[0])
786 780
787 781 msg = 'Failed to substitute: `{key}={{{var}}}` with environment entry. ' \
788 782 'Make sure your environment has {var} set, or remove this ' \
789 783 'variable from config file'.format(key=key, var=env_var)
790 784
791 785 if env_var.startswith('ENV_'):
792 786 raise ValueError(msg)
793 787 else:
794 788 log.warning(msg)
795 789
796 790 except ValueError as e:
797 791 log.warning('Failed to substitute ENV variable: %s', e)
798 792 result = mapping
799 793
800 794 return result
General Comments 0
You need to be logged in to leave comments. Login now