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