##// END OF EJS Templates
config: major update for the code to make it be almost fully controllable via env for new docker based installer.
super-admin -
r4823:59ec40ea default
parent child Browse files
Show More
@@ -0,0 +1,98 b''
1 ; #####################
2 ; LOGGING CONFIGURATION
3 ; #####################
4 [loggers]
5 keys = root, sqlalchemy, beaker, celery, rhodecode, ssh_wrapper
6
7 [handlers]
8 keys = console, console_sql
9
10 [formatters]
11 keys = generic, json, color_formatter, color_formatter_sql
12
13 ; #######
14 ; LOGGERS
15 ; #######
16 [logger_root]
17 level = NOTSET
18 handlers = console
19
20 [logger_sqlalchemy]
21 level = $RC_LOGGING_LEVEL
22 handlers = console_sql
23 qualname = sqlalchemy.engine
24 propagate = 0
25
26 [logger_beaker]
27 level = $RC_LOGGING_LEVEL
28 handlers =
29 qualname = beaker.container
30 propagate = 1
31
32 [logger_rhodecode]
33 level = $RC_LOGGING_LEVEL
34 handlers =
35 qualname = rhodecode
36 propagate = 1
37
38 [logger_ssh_wrapper]
39 level = $RC_LOGGING_LEVEL
40 handlers =
41 qualname = ssh_wrapper
42 propagate = 1
43
44 [logger_celery]
45 level = $RC_LOGGING_LEVEL
46 handlers =
47 qualname = celery
48
49
50 ; ########
51 ; HANDLERS
52 ; ########
53
54 [handler_console]
55 class = StreamHandler
56 args = (sys.stderr, )
57 level = $RC_LOGGING_LEVEL
58 ; To enable JSON formatted logs replace generic with json
59 ; This allows sending properly formatted logs to grafana loki or elasticsearch
60 #formatter = json
61 #formatter = generic
62 formatter = $RC_LOGGING_FORMATTER
63
64 [handler_console_sql]
65 ; "level = DEBUG" logs SQL queries and results.
66 ; "level = INFO" logs SQL queries.
67 ; "level = WARN" logs neither. (Recommended for production systems.)
68 class = StreamHandler
69 args = (sys.stderr, )
70 level = WARN
71 ; To enable JSON formatted logs replace generic with json
72 ; This allows sending properly formatted logs to grafana loki or elasticsearch
73 #formatter = json
74 #formatter = generic
75 formatter = $RC_LOGGING_FORMATTER
76
77 ; ##########
78 ; FORMATTERS
79 ; ##########
80
81 [formatter_generic]
82 class = rhodecode.lib.logging_formatter.ExceptionAwareFormatter
83 format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s
84 datefmt = %Y-%m-%d %H:%M:%S
85
86 [formatter_color_formatter]
87 class = rhodecode.lib.logging_formatter.ColorFormatter
88 format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s
89 datefmt = %Y-%m-%d %H:%M:%S
90
91 [formatter_color_formatter_sql]
92 class = rhodecode.lib.logging_formatter.ColorFormatterSql
93 format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s
94 datefmt = %Y-%m-%d %H:%M:%S
95
96 [formatter_json]
97 format = %(message)s
98 class = rhodecode.lib._vendor.jsonlogger.JsonFormatter No newline at end of file
@@ -0,0 +1,182 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2010-2020 RhodeCode GmbH
4 #
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
21 import os
22 import textwrap
23 import string
24 import functools
25 import logging
26 import tempfile
27 import logging.config
28 log = logging.getLogger(__name__)
29
30
31 def str2bool(_str):
32 """
33 returns True/False value from given string, it tries to translate the
34 string into boolean
35
36 :param _str: string value to translate into boolean
37 :rtype: boolean
38 :returns: boolean from given string
39 """
40 if _str is None:
41 return False
42 if _str in (True, False):
43 return _str
44 _str = str(_str).strip().lower()
45 return _str in ('t', 'true', 'y', 'yes', 'on', '1')
46
47
48 def aslist(obj, sep=None, strip=True):
49 """
50 Returns given string separated by sep as list
51
52 :param obj:
53 :param sep:
54 :param strip:
55 """
56 if isinstance(obj, (basestring,)):
57 if obj in ['', ""]:
58 return []
59
60 lst = obj.split(sep)
61 if strip:
62 lst = [v.strip() for v in lst]
63 return lst
64 elif isinstance(obj, (list, tuple)):
65 return obj
66 elif obj is None:
67 return []
68 else:
69 return [obj]
70
71
72 class SettingsMaker(object):
73
74 def __init__(self, app_settings):
75 self.settings = app_settings
76
77 @classmethod
78 def _bool_func(cls, input_val):
79 if isinstance(input_val, unicode):
80 input_val = input_val.encode('utf8')
81 return str2bool(input_val)
82
83 @classmethod
84 def _int_func(cls, input_val):
85 return int(input_val)
86
87 @classmethod
88 def _list_func(cls, input_val, sep=','):
89 return aslist(input_val, sep=sep)
90
91 @classmethod
92 def _string_func(cls, input_val, lower=True):
93 if lower:
94 input_val = input_val.lower()
95 return input_val
96
97 @classmethod
98 def _float_func(cls, input_val):
99 return float(input_val)
100
101 @classmethod
102 def _dir_func(cls, input_val, ensure_dir=False, mode=0o755):
103
104 # ensure we have our dir created
105 if not os.path.isdir(input_val) and ensure_dir:
106 os.makedirs(input_val, mode=mode)
107
108 if not os.path.isdir(input_val):
109 raise Exception('Dir at {} does not exist'.format(input_val))
110 return input_val
111
112 @classmethod
113 def _file_path_func(cls, input_val, ensure_dir=False, mode=0o755):
114 dirname = os.path.dirname(input_val)
115 cls._dir_func(dirname, ensure_dir=ensure_dir)
116 return input_val
117
118 @classmethod
119 def _key_transformator(cls, key):
120 return "{}_{}".format('RC'.upper(), key.upper().replace('.', '_').replace('-', '_'))
121
122 def enable_logging(self, logging_conf=None, level='INFO', formatter='generic'):
123 """
124 Helper to enable debug on running instance
125 :return:
126 """
127
128 if not str2bool(self.settings.get('logging.autoconfigure')):
129 log.info('logging configuration based on main .ini file')
130 return
131
132 if logging_conf is None:
133 logging_conf = self.settings.get('logging.logging_conf_file') or ''
134
135 if not os.path.isfile(logging_conf):
136 log.error('Unable to setup logging based on %s, file does not exist...', logging_conf)
137 return
138
139 with open(logging_conf, 'rb') as f:
140 ini_template = textwrap.dedent(f.read())
141 ini_template = string.Template(ini_template).safe_substitute(
142 RC_LOGGING_LEVEL=os.environ.get('RC_LOGGING_LEVEL', '') or level,
143 RC_LOGGING_FORMATTER=os.environ.get('RC_LOGGING_FORMATTER', '') or formatter
144 )
145
146 with tempfile.NamedTemporaryFile(prefix='rc_logging_', suffix='.ini', delete=False) as f:
147 log.info('Saved Temporary LOGGING config at %s', f.name)
148 f.write(ini_template)
149
150 logging.config.fileConfig(f.name)
151 os.remove(f.name)
152
153 def make_setting(self, key, default, lower=False, default_when_empty=False, parser=None):
154
155 input_val = self.settings.get(key, default)
156
157 if default_when_empty and not input_val:
158 # use default value when value is set in the config but it is empty
159 input_val = default
160
161 parser_func = {
162 'bool': self._bool_func,
163 'int': self._int_func,
164 'list': self._list_func,
165 'list:newline': functools.partial(self._list_func, sep='/n'),
166 'list:spacesep': functools.partial(self._list_func, sep=' '),
167 'string': functools.partial(self._string_func, lower=lower),
168 'dir': self._dir_func,
169 'dir:ensured': functools.partial(self._dir_func, ensure_dir=True),
170 'file': self._file_path_func,
171 'file:ensured': functools.partial(self._file_path_func, ensure_dir=True),
172 None: lambda i: i
173 }[parser]
174
175 # now maybe we have this KEY in env, search and use the value with higher priority.
176 transformed_key = self._key_transformator(key)
177 envvar_value = os.environ.get(transformed_key)
178 if envvar_value:
179 log.debug('using `%s` key instead of `%s` key for config', transformed_key, key)
180 input_val = envvar_value
181 self.settings[key] = parser_func(input_val)
182 return self.settings[key]
@@ -30,12 +30,12 b' worker_tmp_dir = None'
30 30 tmp_upload_dir = None
31 31
32 32 # Custom log format
33 access_log_format = (
34 '%(t)s %(p)s INFO [GNCRN] %(h)-15s rqt:%(L)s %(s)s %(b)-6s "%(m)s:%(U)s %(q)s" usr:%(u)s "%(f)s" "%(a)s"')
33 #access_log_format = (
34 # '%(t)s %(p)s INFO [GNCRN] %(h)-15s rqt:%(L)s %(s)s %(b)-6s "%(m)s:%(U)s %(q)s" usr:%(u)s "%(f)s" "%(a)s"')
35 35
36 36 # loki format for easier parsing in grafana
37 #access_log_format = (
38 # 'time="%(t)s" pid=%(p)s level="INFO" type="[GNCRN]" ip="%(h)-15s" rqt="%(L)s" response_code="%(s)s" response_bytes="%(b)-6s" uri="%(m)s:%(U)s %(q)s" user=":%(u)s" user_agent="%(a)s"')
37 access_log_format = (
38 'time="%(t)s" pid=%(p)s level="INFO" type="[GNCRN]" ip="%(h)-15s" rqt="%(L)s" response_code="%(s)s" response_bytes="%(b)-6s" uri="%(m)s:%(U)s %(q)s" user=":%(u)s" user_agent="%(a)s"')
39 39
40 40 # self adjust workers based on CPU count
41 41 # workers = get_workers()
@@ -97,9 +97,12 b' def post_fork(server, worker):'
97 97 if conf.has_option(section, 'memory_usage_recovery_threshold'):
98 98 _memory_usage_recovery_threshold = conf.getfloat(section, 'memory_usage_recovery_threshold')
99 99
100 worker._memory_max_usage = _memory_max_usage
101 worker._memory_usage_check_interval = _memory_usage_check_interval
102 worker._memory_usage_recovery_threshold = _memory_usage_recovery_threshold
100 worker._memory_max_usage = int(os.environ.get('RC_GUNICORN_MEMORY_MAX_USAGE', '')
101 or _memory_max_usage)
102 worker._memory_usage_check_interval = int(os.environ.get('RC_GUNICORN_MEMORY_USAGE_CHECK_INTERVAL', '')
103 or _memory_usage_check_interval)
104 worker._memory_usage_recovery_threshold = float(os.environ.get('RC_GUNICORN_MEMORY_USAGE_RECOVERY_THRESHOLD', '')
105 or _memory_usage_recovery_threshold)
103 106
104 107 # register memory last check time, with some random offset so we don't recycle all
105 108 # at once
@@ -124,10 +124,6 b' use = egg:PasteDeploy#prefix'
124 124 prefix = /
125 125
126 126 [app:main]
127 ; The %(here)s variable will be replaced with the absolute path of parent directory
128 ; of this file
129 ; In addition ENVIRONMENT variables usage is possible, e.g
130 ; sqlalchemy.db1.url = {ENV_RC_DB_URL}
131 127
132 128 use = egg:rhodecode-enterprise-ce
133 129
@@ -330,6 +326,9 b' file_store.storage_path = %(here)s/data/'
330 326
331 327 use_celery = false
332 328
329 ; path to store schedule database
330 #celerybeat-schedule.path =
331
333 332 ; connection url to the message broker (default redis)
334 333 celery.broker_url = redis://localhost:6379/8
335 334
@@ -575,6 +574,9 b' vcs.connection_timeout = 3600'
575 574 ; Legacy available options are: pre-1.4-compatible, pre-1.5-compatible, pre-1.6-compatible, pre-1.8-compatible, pre-1.9-compatible
576 575 #vcs.svn.compatible_version = 1.8
577 576
577 ; Cache flag to cache vcsserver remote calls locally
578 ; It uses cache_region `cache_repo`
579 vcs.methods.cache = true
578 580
579 581 ; ####################################################
580 582 ; Subversion proxy support (mod_dav_svn)
@@ -657,55 +659,55 b' ssh.enable_ui_key_generator = true'
657 659 ; http://appenlight.rhodecode.com for details how to obtain an account
658 660
659 661 ; Appenlight integration enabled
660 appenlight = false
662 #appenlight = false
661 663
662 appenlight.server_url = https://api.appenlight.com
663 appenlight.api_key = YOUR_API_KEY
664 #appenlight.server_url = https://api.appenlight.com
665 #appenlight.api_key = YOUR_API_KEY
664 666 #appenlight.transport_config = https://api.appenlight.com?threaded=1&timeout=5
665 667
666 668 ; used for JS client
667 appenlight.api_public_key = YOUR_API_PUBLIC_KEY
669 #appenlight.api_public_key = YOUR_API_PUBLIC_KEY
668 670
669 671 ; TWEAK AMOUNT OF INFO SENT HERE
670 672
671 673 ; enables 404 error logging (default False)
672 appenlight.report_404 = false
674 #appenlight.report_404 = false
673 675
674 676 ; time in seconds after request is considered being slow (default 1)
675 appenlight.slow_request_time = 1
677 #appenlight.slow_request_time = 1
676 678
677 679 ; record slow requests in application
678 680 ; (needs to be enabled for slow datastore recording and time tracking)
679 appenlight.slow_requests = true
681 #appenlight.slow_requests = true
680 682
681 683 ; enable hooking to application loggers
682 appenlight.logging = true
684 #appenlight.logging = true
683 685
684 686 ; minimum log level for log capture
685 appenlight.logging.level = WARNING
687 #ppenlight.logging.level = WARNING
686 688
687 689 ; send logs only from erroneous/slow requests
688 690 ; (saves API quota for intensive logging)
689 appenlight.logging_on_error = false
691 #appenlight.logging_on_error = false
690 692
691 693 ; list of additional keywords that should be grabbed from environ object
692 694 ; can be string with comma separated list of words in lowercase
693 695 ; (by default client will always send following info:
694 696 ; 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that
695 697 ; start with HTTP* this list be extended with additional keywords here
696 appenlight.environ_keys_whitelist =
698 #appenlight.environ_keys_whitelist =
697 699
698 700 ; list of keywords that should be blanked from request object
699 701 ; can be string with comma separated list of words in lowercase
700 702 ; (by default client will always blank keys that contain following words
701 703 ; 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'
702 704 ; this list be extended with additional keywords set here
703 appenlight.request_keys_blacklist =
705 #appenlight.request_keys_blacklist =
704 706
705 707 ; list of namespaces that should be ignores when gathering log entries
706 708 ; can be string with comma separated list of namespaces
707 709 ; (by default the client ignores own entries: appenlight_client.client)
708 appenlight.log_namespace_blacklist =
710 #appenlight.log_namespace_blacklist =
709 711
710 712 ; Statsd client config, this is used to send metrics to statsd
711 713 ; We recommend setting statsd_exported and scrape them using Promethues
@@ -716,6 +718,13 b' appenlight.log_namespace_blacklist ='
716 718 #statsd.statsd_ipv6 = false
717 719
718 720
721 ; configure logging automatically at server startup set to false
722 ; to use the below custom logging config.
723 #logging.autoconfigure = true
724
725 ; specify your own custom logging config file to configure logging
726 #logging.logging_conf_file = /path/to/custom_logging.ini
727
719 728 ; Dummy marker to add new entries after.
720 729 ; Add any custom entries below. Please don't remove this marker.
721 730 custom.conf = 1
@@ -19,19 +19,20 b''
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20 import os
21 21 from rhodecode.apps.file_store import config_keys
22 from rhodecode.config.middleware import _bool_setting, _string_setting
22 from rhodecode.config.settings_maker import SettingsMaker
23 23
24 24
25 25 def _sanitize_settings_and_apply_defaults(settings):
26 26 """
27 27 Set defaults, convert to python types and validate settings.
28 28 """
29 _bool_setting(settings, config_keys.enabled, 'true')
29 settings_maker = SettingsMaker(settings)
30 30
31 _string_setting(settings, config_keys.backend, 'local')
31 settings_maker.make_setting(config_keys.enabled, True, parser='bool')
32 settings_maker.make_setting(config_keys.backend, 'local')
32 33
33 34 default_store = os.path.join(os.path.dirname(settings['__file__']), 'upload_store')
34 _string_setting(settings, config_keys.store_path, default_store)
35 settings_maker.make_setting(config_keys.store_path, default_store)
35 36
36 37
37 38 def includeme(config):
@@ -24,7 +24,7 b' from . import config_keys'
24 24 from .events import SshKeyFileChangeEvent
25 25 from .subscribers import generate_ssh_authorized_keys_file_subscriber
26 26
27 from rhodecode.config.middleware import _bool_setting, _string_setting
27 from rhodecode.config.settings_maker import SettingsMaker
28 28
29 29 log = logging.getLogger(__name__)
30 30
@@ -33,28 +33,20 b' def _sanitize_settings_and_apply_default'
33 33 """
34 34 Set defaults, convert to python types and validate settings.
35 35 """
36 _bool_setting(settings, config_keys.generate_authorized_keyfile, 'false')
37 _bool_setting(settings, config_keys.wrapper_allow_shell, 'false')
38 _bool_setting(settings, config_keys.enable_debug_logging, 'false')
39 _bool_setting(settings, config_keys.ssh_key_generator_enabled, 'true')
36 settings_maker = SettingsMaker(settings)
37
38 settings_maker.make_setting(config_keys.generate_authorized_keyfile, False, parser='bool')
39 settings_maker.make_setting(config_keys.wrapper_allow_shell, False, parser='bool')
40 settings_maker.make_setting(config_keys.enable_debug_logging, False, parser='bool')
41 settings_maker.make_setting(config_keys.ssh_key_generator_enabled, True, parser='bool')
40 42
41 _string_setting(settings, config_keys.authorized_keys_file_path,
42 '~/.ssh/authorized_keys_rhodecode',
43 lower=False)
44 _string_setting(settings, config_keys.wrapper_cmd, '',
45 lower=False)
46 _string_setting(settings, config_keys.authorized_keys_line_ssh_opts, '',
47 lower=False)
43 settings_maker.make_setting(config_keys.authorized_keys_file_path, '~/.ssh/authorized_keys_rhodecode')
44 settings_maker.make_setting(config_keys.wrapper_cmd, '')
45 settings_maker.make_setting(config_keys.authorized_keys_line_ssh_opts, '')
48 46
49 _string_setting(settings, config_keys.ssh_hg_bin,
50 '~/.rccontrol/vcsserver-1/profile/bin/hg',
51 lower=False)
52 _string_setting(settings, config_keys.ssh_git_bin,
53 '~/.rccontrol/vcsserver-1/profile/bin/git',
54 lower=False)
55 _string_setting(settings, config_keys.ssh_svn_bin,
56 '~/.rccontrol/vcsserver-1/profile/bin/svnserve',
57 lower=False)
47 settings_maker.make_setting(config_keys.ssh_hg_bin, '~/.rccontrol/vcsserver-1/profile/bin/hg')
48 settings_maker.make_setting(config_keys.ssh_git_bin, '~/.rccontrol/vcsserver-1/profile/bin/git')
49 settings_maker.make_setting(config_keys.ssh_svn_bin, '~/.rccontrol/vcsserver-1/profile/bin/svnserve')
58 50
59 51
60 52 def includeme(config):
@@ -19,15 +19,13 b''
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20 import os
21 21 import logging
22 import shlex
23 22 from pyramid import compat
24 23
25 24 # Do not use `from rhodecode import events` here, it will be overridden by the
26 25 # events module in this package due to pythons import mechanism.
27 26 from rhodecode.events import RepoGroupEvent
28 27 from rhodecode.subscribers import AsyncSubprocessSubscriber
29 from rhodecode.config.middleware import (
30 _bool_setting, _string_setting, _int_setting)
28 from rhodecode.config.settings_maker import SettingsMaker
31 29
32 30 from .events import ModDavSvnConfigChange
33 31 from .subscribers import generate_config_subscriber
@@ -41,13 +39,14 b' def _sanitize_settings_and_apply_default'
41 39 """
42 40 Set defaults, convert to python types and validate settings.
43 41 """
44 _bool_setting(settings, config_keys.generate_config, 'false')
45 _bool_setting(settings, config_keys.list_parent_path, 'true')
46 _int_setting(settings, config_keys.reload_timeout, 10)
47 _string_setting(settings, config_keys.config_file_path, '', lower=False)
48 _string_setting(settings, config_keys.location_root, '/', lower=False)
49 _string_setting(settings, config_keys.reload_command, '', lower=False)
50 _string_setting(settings, config_keys.template, '', lower=False)
42 settings_maker = SettingsMaker(settings)
43 settings_maker.make_setting(config_keys.generate_config, False, parser='bool')
44 settings_maker.make_setting(config_keys.list_parent_path, True, parser='bool')
45 settings_maker.make_setting(config_keys.reload_timeout, 10, parser='bool')
46 settings_maker.make_setting(config_keys.config_file_path, '')
47 settings_maker.make_setting(config_keys.location_root, '/')
48 settings_maker.make_setting(config_keys.reload_command, '')
49 settings_maker.make_setting(config_keys.template, '')
51 50
52 51 # Convert negative timeout values to zero.
53 52 if settings[config_keys.reload_timeout] < 0:
@@ -85,38 +85,3 b' def load_pyramid_environment(global_conf'
85 85
86 86 if vcs_server_enabled:
87 87 connect_vcs(vcs_server_uri, utils.get_vcs_server_protocol(settings))
88
89
90 def get_rc_env_settings(prefix='ENV_{}'):
91 return {'ENV_{}'.format(key): value for key, value in os.environ.items()}
92
93
94 def substitute_values(mapping, substitutions):
95 result = {}
96
97 try:
98 for key, value in mapping.items():
99 # initialize without substitution first
100 result[key] = value
101
102 # Note: Cannot use regular replacements, since they would clash
103 # with the implementation of ConfigParser. Using "format" instead.
104 try:
105 result[key] = value.format(**substitutions)
106 except KeyError as e:
107 env_var = '{}'.format(e.args[0])
108
109 msg = 'Failed to substitute: `{key}={{{var}}}` with environment entry. ' \
110 'Make sure your environment has {var} set, or remove this ' \
111 'variable from config file'.format(key=key, var=env_var)
112
113 if env_var.startswith('ENV_'):
114 raise ValueError(msg)
115 else:
116 log.warning(msg)
117
118 except ValueError as e:
119 log.warning('Failed to substitute ENV variable: %s', e)
120 result = mapping
121
122 return result No newline at end of file
@@ -20,10 +20,10 b''
20 20
21 21 import os
22 22 import sys
23 import logging
24 23 import collections
25 24 import tempfile
26 25 import time
26 import logging.config
27 27
28 28 from paste.gzipper import make_gzip_middleware
29 29 import pyramid.events
@@ -38,7 +38,8 b' from pyramid.renderers import render_to_'
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 from rhodecode.config.environment import load_pyramid_environment, substitute_values, get_rc_env_settings
41 from rhodecode.config.settings_maker import SettingsMaker
42 from rhodecode.config.environment import load_pyramid_environment
42 43
43 44 import rhodecode.events
44 45 from rhodecode.lib.middleware.vcs import VCSMiddleware
@@ -48,7 +49,7 b' from rhodecode.lib.exceptions import VCS'
48 49 from rhodecode.lib.middleware.appenlight import wrap_in_appenlight_if_enabled
49 50 from rhodecode.lib.middleware.https_fixup import HttpsFixup
50 51 from rhodecode.lib.plugins.utils import register_rhodecode_plugin
51 from rhodecode.lib.utils2 import aslist as rhodecode_aslist, AttributeDict
52 from rhodecode.lib.utils2 import AttributeDict
52 53 from rhodecode.lib.exc_tracking import store_exception
53 54 from rhodecode.subscribers import (
54 55 scan_repositories_if_enabled, write_js_routes_if_enabled,
@@ -87,24 +88,14 b' def make_pyramid_app(global_config, **se'
87 88 cases when these fragments are assembled from another place.
88 89
89 90 """
90
91 # Allows to use format style "{ENV_NAME}" placeholders in the configuration. It
92 # will be replaced by the value of the environment variable "NAME" in this case.
93 91 start_time = time.time()
94 92 log.info('Pyramid app config starting')
95 93
96 global_config = substitute_values(global_config, get_rc_env_settings())
97 settings = substitute_values(settings, get_rc_env_settings())
94 sanitize_settings_and_apply_defaults(global_config, settings)
98 95
99 96 # init and bootstrap StatsdClient
100 97 StatsdClient.setup(settings)
101 98
102 debug = asbool(global_config.get('debug'))
103 if debug:
104 enable_debug()
105
106 sanitize_settings_and_apply_defaults(global_config, settings)
107
108 99 config = Configurator(settings=settings)
109 100 # Init our statsd at very start
110 101 config.registry.statsd = StatsdClient.statsd
@@ -123,17 +114,62 b' def make_pyramid_app(global_config, **se'
123 114 pyramid_app = wrap_app_in_wsgi_middlewares(pyramid_app, config)
124 115 pyramid_app.config = config
125 116
126 config.configure_celery(global_config['__file__'])
117 celery_settings = get_celery_config(settings)
118 config.configure_celery(celery_settings)
127 119
128 120 # creating the app uses a connection - return it after we are done
129 121 meta.Session.remove()
130 122
131 123 total_time = time.time() - start_time
132 124 log.info('Pyramid app `%s` created and configured in %.2fs',
133 pyramid_app.func_name, total_time)
125 getattr(pyramid_app, 'func_name', 'pyramid_app'), total_time)
134 126 return pyramid_app
135 127
136 128
129 def get_celery_config(settings):
130 """
131 Converts basic ini configuration into celery 4.X options
132 """
133
134 def key_converter(key_name):
135 pref = 'celery.'
136 if key_name.startswith(pref):
137 return key_name[len(pref):].replace('.', '_').lower()
138
139 def type_converter(parsed_key, value):
140 # cast to int
141 if value.isdigit():
142 return int(value)
143
144 # cast to bool
145 if value.lower() in ['true', 'false', 'True', 'False']:
146 return value.lower() == 'true'
147 return value
148
149 celery_config = {}
150 for k, v in settings.items():
151 pref = 'celery.'
152 if k.startswith(pref):
153 celery_config[key_converter(k)] = type_converter(key_converter(k), v)
154
155 # TODO:rethink if we want to support celerybeat based file config, probably NOT
156 # beat_config = {}
157 # for section in parser.sections():
158 # if section.startswith('celerybeat:'):
159 # name = section.split(':', 1)[1]
160 # beat_config[name] = get_beat_config(parser, section)
161
162 # final compose of settings
163 celery_settings = {}
164
165 if celery_config:
166 celery_settings.update(celery_config)
167 # if beat_config:
168 # celery_settings.update({'beat_schedule': beat_config})
169
170 return celery_settings
171
172
137 173 def not_found_view(request):
138 174 """
139 175 This creates the view which should be registered as not-found-view to
@@ -263,7 +299,7 b' def includeme(config, auth_resources=Non'
263 299
264 300 config.add_directive('configure_celery', configure_celery)
265 301
266 if asbool(settings.get('appenlight', 'false')):
302 if settings.get('appenlight', False):
267 303 config.include('appenlight_client.ext.pyramid_tween')
268 304
269 305 load_all = should_load_all()
@@ -435,8 +471,28 b' def sanitize_settings_and_apply_defaults'
435 471 function.
436 472 """
437 473
438 settings.setdefault('rhodecode.edition', 'Community Edition')
439 settings.setdefault('rhodecode.edition_id', 'CE')
474 global_settings_maker = SettingsMaker(global_config)
475 global_settings_maker.make_setting('debug', default=False, parser='bool')
476 debug_enabled = asbool(global_config.get('debug'))
477
478 settings_maker = SettingsMaker(settings)
479
480 settings_maker.make_setting(
481 'logging.autoconfigure',
482 default=True,
483 parser='bool')
484
485 logging_conf = os.path.join(os.path.dirname(global_config.get('__file__')), 'logging.ini')
486 settings_maker.enable_logging(logging_conf, level='INFO' if debug_enabled else 'DEBUG')
487
488 # Default includes, possible to change as a user
489 pyramid_includes = settings_maker.make_setting('pyramid.includes', [], parser='list:newline')
490 log.debug(
491 "Using the following pyramid.includes: %s",
492 pyramid_includes)
493
494 settings_maker.make_setting('rhodecode.edition', 'Community Edition')
495 settings_maker.make_setting('rhodecode.edition_id', 'CE')
440 496
441 497 if 'mako.default_filters' not in settings:
442 498 # set custom default filters if we don't have it defined
@@ -458,25 +514,41 b' def sanitize_settings_and_apply_defaults'
458 514 if not raw_url.startswith(('redis://', 'rediss://', 'unix://')):
459 515 settings['beaker.session.url'] = 'redis://' + raw_url
460 516
461 # Default includes, possible to change as a user
462 pyramid_includes = settings.setdefault('pyramid.includes', [])
463 log.debug(
464 "Using the following pyramid.includes: %s",
465 pyramid_includes)
517 settings_maker.make_setting('__file__', global_config.get('__file__'))
466 518
467 519 # TODO: johbo: Re-think this, usually the call to config.include
468 520 # should allow to pass in a prefix.
469 settings.setdefault('rhodecode.api.url', '/_admin/api')
470 settings.setdefault('__file__', global_config.get('__file__'))
521 settings_maker.make_setting('rhodecode.api.url', '/_admin/api')
471 522
472 523 # Sanitize generic settings.
473 _list_setting(settings, 'default_encoding', 'UTF-8')
474 _bool_setting(settings, 'is_test', 'false')
475 _bool_setting(settings, 'gzip_responses', 'false')
524 settings_maker.make_setting('default_encoding', 'UTF-8', parser='list')
525 settings_maker.make_setting('is_test', False, parser='bool')
526 settings_maker.make_setting('gzip_responses', False, parser='bool')
476 527
477 # Call split out functions that sanitize settings for each topic.
478 _sanitize_appenlight_settings(settings)
479 _sanitize_vcs_settings(settings)
528 settings_maker.make_setting('vcs.svn.compatible_version', '')
529 settings_maker.make_setting('vcs.hooks.protocol', 'http')
530 settings_maker.make_setting('vcs.hooks.host', '127.0.0.1')
531 settings_maker.make_setting('vcs.scm_app_implementation', 'http')
532 settings_maker.make_setting('vcs.server', '')
533 settings_maker.make_setting('vcs.server.protocol', 'http')
534 settings_maker.make_setting('startup.import_repos', 'false', parser='bool')
535 settings_maker.make_setting('vcs.hooks.direct_calls', 'false', parser='bool')
536 settings_maker.make_setting('vcs.server.enable', 'true', parser='bool')
537 settings_maker.make_setting('vcs.start_server', 'false', parser='bool')
538 settings_maker.make_setting('vcs.backends', 'hg, git, svn', parser='list')
539 settings_maker.make_setting('vcs.connection_timeout', 3600, parser='int')
540
541 settings_maker.make_setting('vcs.methods.cache', True, parser='bool')
542
543 # Support legacy values of vcs.scm_app_implementation. Legacy
544 # configurations may use 'rhodecode.lib.middleware.utils.scm_app_http', or
545 # disabled since 4.13 'vcsserver.scm_app' which is now mapped to 'http'.
546 scm_app_impl = settings['vcs.scm_app_implementation']
547 if scm_app_impl in ['rhodecode.lib.middleware.utils.scm_app_http', 'vcsserver.scm_app']:
548 settings['vcs.scm_app_implementation'] = 'http'
549
550 settings_maker.make_setting('appenlight', False, parser='bool')
551
480 552 _sanitize_cache_settings(settings)
481 553
482 554 # configure instance id
@@ -485,277 +557,55 b' def sanitize_settings_and_apply_defaults'
485 557 return settings
486 558
487 559
488 def enable_debug():
489 """
490 Helper to enable debug on running instance
491 :return:
492 """
493 import tempfile
494 import textwrap
495 import logging.config
496
497 ini_template = textwrap.dedent("""
498 #####################################
499 ### DEBUG LOGGING CONFIGURATION ####
500 #####################################
501 [loggers]
502 keys = root, sqlalchemy, beaker, celery, rhodecode, ssh_wrapper
503
504 [handlers]
505 keys = console, console_sql
506
507 [formatters]
508 keys = generic, color_formatter, color_formatter_sql
509
510 #############
511 ## LOGGERS ##
512 #############
513 [logger_root]
514 level = NOTSET
515 handlers = console
516
517 [logger_sqlalchemy]
518 level = INFO
519 handlers = console_sql
520 qualname = sqlalchemy.engine
521 propagate = 0
522
523 [logger_beaker]
524 level = DEBUG
525 handlers =
526 qualname = beaker.container
527 propagate = 1
528
529 [logger_rhodecode]
530 level = DEBUG
531 handlers =
532 qualname = rhodecode
533 propagate = 1
534
535 [logger_ssh_wrapper]
536 level = DEBUG
537 handlers =
538 qualname = ssh_wrapper
539 propagate = 1
540
541 [logger_celery]
542 level = DEBUG
543 handlers =
544 qualname = celery
545
546
547 ##############
548 ## HANDLERS ##
549 ##############
550
551 [handler_console]
552 class = StreamHandler
553 args = (sys.stderr, )
554 level = DEBUG
555 formatter = color_formatter
560 def _sanitize_cache_settings(settings):
561 settings_maker = SettingsMaker(settings)
556 562
557 [handler_console_sql]
558 # "level = DEBUG" logs SQL queries and results.
559 # "level = INFO" logs SQL queries.
560 # "level = WARN" logs neither. (Recommended for production systems.)
561 class = StreamHandler
562 args = (sys.stderr, )
563 level = WARN
564 formatter = color_formatter_sql
565
566 ################
567 ## FORMATTERS ##
568 ################
569
570 [formatter_generic]
571 class = rhodecode.lib.logging_formatter.ExceptionAwareFormatter
572 format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s | %(req_id)s
573 datefmt = %Y-%m-%d %H:%M:%S
574
575 [formatter_color_formatter]
576 class = rhodecode.lib.logging_formatter.ColorRequestTrackingFormatter
577 format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s | %(req_id)s
578 datefmt = %Y-%m-%d %H:%M:%S
579
580 [formatter_color_formatter_sql]
581 class = rhodecode.lib.logging_formatter.ColorFormatterSql
582 format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s
583 datefmt = %Y-%m-%d %H:%M:%S
584 """)
585
586 with tempfile.NamedTemporaryFile(prefix='rc_debug_logging_', suffix='.ini',
587 delete=False) as f:
588 log.info('Saved Temporary DEBUG config at %s', f.name)
589 f.write(ini_template)
590
591 logging.config.fileConfig(f.name)
592 log.debug('DEBUG MODE ON')
593 os.remove(f.name)
594
595
596 def _sanitize_appenlight_settings(settings):
597 _bool_setting(settings, 'appenlight', 'false')
598
599
600 def _sanitize_vcs_settings(settings):
601 """
602 Applies settings defaults and does type conversion for all VCS related
603 settings.
604 """
605 _string_setting(settings, 'vcs.svn.compatible_version', '')
606 _string_setting(settings, 'vcs.hooks.protocol', 'http')
607 _string_setting(settings, 'vcs.hooks.host', '127.0.0.1')
608 _string_setting(settings, 'vcs.scm_app_implementation', 'http')
609 _string_setting(settings, 'vcs.server', '')
610 _string_setting(settings, 'vcs.server.protocol', 'http')
611 _bool_setting(settings, 'startup.import_repos', 'false')
612 _bool_setting(settings, 'vcs.hooks.direct_calls', 'false')
613 _bool_setting(settings, 'vcs.server.enable', 'true')
614 _bool_setting(settings, 'vcs.start_server', 'false')
615 _list_setting(settings, 'vcs.backends', 'hg, git, svn')
616 _int_setting(settings, 'vcs.connection_timeout', 3600)
617
618 # Support legacy values of vcs.scm_app_implementation. Legacy
619 # configurations may use 'rhodecode.lib.middleware.utils.scm_app_http', or
620 # disabled since 4.13 'vcsserver.scm_app' which is now mapped to 'http'.
621 scm_app_impl = settings['vcs.scm_app_implementation']
622 if scm_app_impl in ['rhodecode.lib.middleware.utils.scm_app_http', 'vcsserver.scm_app']:
623 settings['vcs.scm_app_implementation'] = 'http'
624
625
626 def _sanitize_cache_settings(settings):
627 563 temp_store = tempfile.gettempdir()
628 564 default_cache_dir = os.path.join(temp_store, 'rc_cache')
629 565
630 566 # save default, cache dir, and use it for all backends later.
631 default_cache_dir = _string_setting(
632 settings,
567 default_cache_dir = settings_maker.make_setting(
633 568 'cache_dir',
634 default_cache_dir, lower=False, default_when_empty=True)
635
636 # ensure we have our dir created
637 if not os.path.isdir(default_cache_dir):
638 os.makedirs(default_cache_dir, mode=0o755)
569 default=default_cache_dir, default_when_empty=True,
570 parser='dir:ensured')
639 571
640 572 # exception store cache
641 _string_setting(
642 settings,
573 settings_maker.make_setting(
643 574 'exception_tracker.store_path',
644 temp_store, lower=False, default_when_empty=True)
645 _bool_setting(
646 settings,
647 'exception_tracker.send_email',
648 'false')
649 _string_setting(
650 settings,
651 'exception_tracker.email_prefix',
652 '[RHODECODE ERROR]', lower=False, default_when_empty=True)
575 default=os.path.join(default_cache_dir, 'exc_store'), default_when_empty=True,
576 parser='dir:ensured'
577 )
578
579 settings_maker.make_setting(
580 'celerybeat-schedule.path',
581 default=os.path.join(default_cache_dir, 'celerybeat_schedule', 'celerybeat-schedule.db'), default_when_empty=True,
582 parser='file:ensured'
583 )
584
585 settings_maker.make_setting('exception_tracker.send_email', False, parser='bool')
586 settings_maker.make_setting('exception_tracker.email_prefix', '[RHODECODE ERROR]', default_when_empty=True)
653 587
654 588 # cache_perms
655 _string_setting(
656 settings,
657 'rc_cache.cache_perms.backend',
658 'dogpile.cache.rc.file_namespace', lower=False)
659 _int_setting(
660 settings,
661 'rc_cache.cache_perms.expiration_time',
662 60)
663 _string_setting(
664 settings,
665 'rc_cache.cache_perms.arguments.filename',
666 os.path.join(default_cache_dir, 'rc_cache_1'), lower=False)
589 settings_maker.make_setting('rc_cache.cache_perms.backend', 'dogpile.cache.rc.file_namespace')
590 settings_maker.make_setting('rc_cache.cache_perms.expiration_time', 60, parser='int')
591 settings_maker.make_setting('rc_cache.cache_perms.arguments.filename', os.path.join(default_cache_dir, 'rhodecode_cache_perms.db'))
667 592
668 593 # cache_repo
669 _string_setting(
670 settings,
671 'rc_cache.cache_repo.backend',
672 'dogpile.cache.rc.file_namespace', lower=False)
673 _int_setting(
674 settings,
675 'rc_cache.cache_repo.expiration_time',
676 60)
677 _string_setting(
678 settings,
679 'rc_cache.cache_repo.arguments.filename',
680 os.path.join(default_cache_dir, 'rc_cache_2'), lower=False)
594 settings_maker.make_setting('rc_cache.cache_repo.backend', 'dogpile.cache.rc.file_namespace')
595 settings_maker.make_setting('rc_cache.cache_repo.expiration_time', 60, parser='int')
596 settings_maker.make_setting('rc_cache.cache_repo.arguments.filename', os.path.join(default_cache_dir, 'rhodecode_cache_repo.db'))
681 597
682 598 # cache_license
683 _string_setting(
684 settings,
685 'rc_cache.cache_license.backend',
686 'dogpile.cache.rc.file_namespace', lower=False)
687 _int_setting(
688 settings,
689 'rc_cache.cache_license.expiration_time',
690 5*60)
691 _string_setting(
692 settings,
693 'rc_cache.cache_license.arguments.filename',
694 os.path.join(default_cache_dir, 'rc_cache_3'), lower=False)
599 settings_maker.make_setting('rc_cache.cache_license.backend', 'dogpile.cache.rc.file_namespace')
600 settings_maker.make_setting('rc_cache.cache_license.expiration_time', 5*60, parser='int')
601 settings_maker.make_setting('rc_cache.cache_license.arguments.filename', os.path.join(default_cache_dir, 'rhodecode_cache_license.db'))
695 602
696 603 # cache_repo_longterm memory, 96H
697 _string_setting(
698 settings,
699 'rc_cache.cache_repo_longterm.backend',
700 'dogpile.cache.rc.memory_lru', lower=False)
701 _int_setting(
702 settings,
703 'rc_cache.cache_repo_longterm.expiration_time',
704 345600)
705 _int_setting(
706 settings,
707 'rc_cache.cache_repo_longterm.max_size',
708 10000)
604 settings_maker.make_setting('rc_cache.cache_repo_longterm.backend', 'dogpile.cache.rc.memory_lru')
605 settings_maker.make_setting('rc_cache.cache_repo_longterm.expiration_time', 345600, parser='int')
606 settings_maker.make_setting('rc_cache.cache_repo_longterm.max_size', 10000, parser='int')
709 607
710 608 # sql_cache_short
711 _string_setting(
712 settings,
713 'rc_cache.sql_cache_short.backend',
714 'dogpile.cache.rc.memory_lru', lower=False)
715 _int_setting(
716 settings,
717 'rc_cache.sql_cache_short.expiration_time',
718 30)
719 _int_setting(
720 settings,
721 'rc_cache.sql_cache_short.max_size',
722 10000)
723
724
725 def _int_setting(settings, name, default):
726 settings[name] = int(settings.get(name, default))
727 return settings[name]
728
729
730 def _bool_setting(settings, name, default):
731 input_val = settings.get(name, default)
732 if isinstance(input_val, unicode):
733 input_val = input_val.encode('utf8')
734 settings[name] = asbool(input_val)
735 return settings[name]
736
737
738 def _list_setting(settings, name, default):
739 raw_value = settings.get(name, default)
740
741 old_separator = ','
742 if old_separator in raw_value:
743 # If we get a comma separated list, pass it to our own function.
744 settings[name] = rhodecode_aslist(raw_value, sep=old_separator)
745 else:
746 # Otherwise we assume it uses pyramids space/newline separation.
747 settings[name] = aslist(raw_value)
748 return settings[name]
749
750
751 def _string_setting(settings, name, default, lower=True, default_when_empty=False):
752 value = settings.get(name, default)
753
754 if default_when_empty and not value:
755 # use default value when value is empty
756 value = default
757
758 if lower:
759 value = value.lower()
760 settings[name] = value
761 return settings[name]
609 settings_maker.make_setting('rc_cache.sql_cache_short.backend', 'dogpile.cache.rc.memory_lru')
610 settings_maker.make_setting('rc_cache.sql_cache_short.expiration_time', 30, parser='int')
611 settings_maker.make_setting('rc_cache.sql_cache_short.max_size', 10000, parser='int')
@@ -371,7 +371,7 b' def attach_context_attributes(context, r'
371 371 config.get('license.hide_license_info', False))
372 372
373 373 # AppEnlight
374 context.appenlight_enabled = str2bool(config.get('appenlight', 'false'))
374 context.appenlight_enabled = config.get('appenlight', False)
375 375 context.appenlight_api_public_key = config.get(
376 376 'appenlight.api_public_key', '')
377 377 context.appenlight_server_url = config.get('appenlight.server_url', '')
@@ -40,7 +40,7 b' from pyramid.threadlocal import get_curr'
40 40 import rhodecode
41 41
42 42 from rhodecode.lib.auth import AuthUser
43 from rhodecode.lib.celerylib.utils import get_ini_config, parse_ini_vars, ping_db
43 from rhodecode.lib.celerylib.utils import parse_ini_vars, ping_db
44 44 from rhodecode.lib.ext_json import json
45 45 from rhodecode.lib.pyramid_utils import bootstrap, setup_logging, prepare_request
46 46 from rhodecode.lib.utils2 import str2bool
@@ -116,6 +116,8 b' def setup_logging_callback(**kwargs):'
116 116
117 117 @signals.user_preload_options.connect
118 118 def on_preload_parsed(options, **kwargs):
119 from rhodecode.config.middleware import get_celery_config
120
119 121 ini_location = options['ini']
120 122 ini_vars = options['ini_var']
121 123 celery_app.conf['INI_PYRAMID'] = options['ini']
@@ -134,10 +136,11 b' def on_preload_parsed(options, **kwargs)'
134 136 log.debug('Bootstrapping RhodeCode application...')
135 137 env = bootstrap(ini_location, options=options)
136 138
139 celery_settings = get_celery_config(env['registry'].settings)
137 140 setup_celery_app(
138 141 app=env['app'], root=env['root'], request=env['request'],
139 142 registry=env['registry'], closer=env['closer'],
140 ini_location=ini_location)
143 celery_settings=celery_settings)
141 144
142 145 # fix the global flag even if it's disabled via .ini file because this
143 146 # is a worker code that doesn't need this to be disabled.
@@ -196,17 +199,15 b' def task_revoked_signal('
196 199 closer()
197 200
198 201
199 def setup_celery_app(app, root, request, registry, closer, ini_location):
200 ini_dir = os.path.dirname(os.path.abspath(ini_location))
202 def setup_celery_app(app, root, request, registry, closer, celery_settings):
203 log.debug('Got custom celery conf: %s', celery_settings)
201 204 celery_config = base_celery_config
202 205 celery_config.update({
203 206 # store celerybeat scheduler db where the .ini file is
204 'beat_schedule_filename': os.path.join(ini_dir, 'celerybeat-schedule'),
207 'beat_schedule_filename': registry.settings['celerybeat-schedule.path'],
205 208 })
206 ini_settings = get_ini_config(ini_location)
207 log.debug('Got custom celery conf: %s', ini_settings)
208 209
209 celery_config.update(ini_settings)
210 celery_config.update(celery_settings)
210 211 celery_app.config_from_object(celery_config)
211 212
212 213 celery_app.conf.update({'PYRAMID_APP': app})
@@ -216,7 +217,7 b' def setup_celery_app(app, root, request,'
216 217 celery_app.conf.update({'PYRAMID_CLOSER': closer})
217 218
218 219
219 def configure_celery(config, ini_location):
220 def configure_celery(config, celery_settings):
220 221 """
221 222 Helper that is called from our application creation logic. It gives
222 223 connection info into running webapp and allows execution of tasks from
@@ -226,10 +227,10 b' def configure_celery(config, ini_locatio'
226 227 rhodecode.CELERY_ENABLED = str2bool(
227 228 config.registry.settings.get('use_celery'))
228 229 if rhodecode.CELERY_ENABLED:
229 log.info('Configuring celery based on `%s` file', ini_location)
230 log.info('Configuring celery based on `%s` settings', celery_settings)
230 231 setup_celery_app(
231 232 app=None, root=None, request=None, registry=config.registry,
232 closer=None, ini_location=ini_location)
233 closer=None, celery_settings=celery_settings)
233 234
234 235
235 236 def maybe_prepare_env(req):
@@ -115,52 +115,6 b' def get_beat_config(parser, section):'
115 115 return config
116 116
117 117
118 def get_ini_config(ini_location):
119 """
120 Converts basic ini configuration into celery 4.X options
121 """
122 def key_converter(key_name):
123 pref = 'celery.'
124 if key_name.startswith(pref):
125 return key_name[len(pref):].replace('.', '_').lower()
126
127 def type_converter(parsed_key, value):
128 # cast to int
129 if value.isdigit():
130 return int(value)
131
132 # cast to bool
133 if value.lower() in ['true', 'false', 'True', 'False']:
134 return value.lower() == 'true'
135 return value
136
137 parser = configparser.SafeConfigParser(
138 defaults={'here': os.path.abspath(ini_location)})
139 parser.read(ini_location)
140
141 ini_config = {}
142 for k, v in parser.items('app:main'):
143 pref = 'celery.'
144 if k.startswith(pref):
145 ini_config[key_converter(k)] = type_converter(key_converter(k), v)
146
147 beat_config = {}
148 for section in parser.sections():
149 if section.startswith('celerybeat:'):
150 name = section.split(':', 1)[1]
151 beat_config[name] = get_beat_config(parser, section)
152
153 # final compose of settings
154 celery_settings = {}
155
156 if ini_config:
157 celery_settings.update(ini_config)
158 if beat_config:
159 celery_settings.update({'beat_schedule': beat_config})
160
161 return celery_settings
162
163
164 118 def parse_ini_vars(ini_vars):
165 119 options = {}
166 120 for pairs in ini_vars.split(','):
@@ -22,9 +22,8 b''
22 22 import pytest
23 23
24 24 from rhodecode.tests import no_newline_id_generator
25 from rhodecode.config.middleware import (
26 _sanitize_vcs_settings, _bool_setting, _string_setting, _list_setting,
27 _int_setting)
25 from rhodecode.config.middleware import sanitize_settings_and_apply_defaults
26 from rhodecode.config.settings_maker import SettingsMaker
28 27
29 28
30 29 class TestHelperFunctions(object):
@@ -39,11 +38,9 b' class TestHelperFunctions(object):'
39 38 ('invalid-∫øø@-√Γ₯@¨€', False),
40 39 (u'invalid-∫øø@-√Γ₯@¨€', False),
41 40 ])
42 def test_bool_setting_helper(self, raw, expected):
43 key = 'dummy-key'
44 settings = {key: raw}
45 _bool_setting(settings, key, None)
46 assert settings[key] is expected
41 def test_bool_func_helper(self, raw, expected):
42 val = SettingsMaker._bool_func(raw)
43 assert val == expected
47 44
48 45 @pytest.mark.parametrize('raw, expected', [
49 46 ('', ''),
@@ -52,11 +49,9 b' class TestHelperFunctions(object):'
52 49 ('test-string-烩€', 'test-string-烩€'),
53 50 (u'test-string-烩€', u'test-string-烩€'),
54 51 ])
55 def test_string_setting_helper(self, raw, expected):
56 key = 'dummy-key'
57 settings = {key: raw}
58 _string_setting(settings, key, None)
59 assert settings[key] == expected
52 def test_string_func_helper(self, raw, expected):
53 val = SettingsMaker._string_func(raw)
54 assert val == expected
60 55
61 56 @pytest.mark.parametrize('raw, expected', [
62 57 ('', []),
@@ -64,19 +59,30 b' class TestHelperFunctions(object):'
64 59 ('CaSe-TeSt', ['CaSe-TeSt']),
65 60 ('test-string-烩€', ['test-string-烩€']),
66 61 (u'test-string-烩€', [u'test-string-烩€']),
67 ('hg git svn', ['hg', 'git', 'svn']),
68 62 ('hg,git,svn', ['hg', 'git', 'svn']),
69 63 ('hg, git, svn', ['hg', 'git', 'svn']),
70 ('hg\ngit\nsvn', ['hg', 'git', 'svn']),
71 (' hg\n git\n svn ', ['hg', 'git', 'svn']),
64
72 65 (', hg , git , svn , ', ['', 'hg', 'git', 'svn', '']),
73 66 ('cheese,free node,other', ['cheese', 'free node', 'other']),
74 67 ], ids=no_newline_id_generator)
75 68 def test_list_setting_helper(self, raw, expected):
76 key = 'dummy-key'
77 settings = {key: raw}
78 _list_setting(settings, key, None)
79 assert settings[key] == expected
69 val = SettingsMaker._list_func(raw)
70 assert val == expected
71
72 @pytest.mark.parametrize('raw, expected', [
73 ('hg git svn', ['hg', 'git', 'svn']),
74 ], ids=no_newline_id_generator)
75 def test_list_setting_spaces_helper(self, raw, expected):
76 val = SettingsMaker._list_func(raw, sep=' ')
77 assert val == expected
78
79 @pytest.mark.parametrize('raw, expected', [
80 ('hg\ngit\nsvn', ['hg', 'git', 'svn']),
81 (' hg\n git\n svn ', ['hg', 'git', 'svn']),
82 ], ids=no_newline_id_generator)
83 def test_list_setting_newlines_helper(self, raw, expected):
84 val = SettingsMaker._list_func(raw, sep='\n')
85 assert val == expected
80 86
81 87 @pytest.mark.parametrize('raw, expected', [
82 88 ('0', 0),
@@ -86,10 +92,8 b' class TestHelperFunctions(object):'
86 92 (u'-12345', -12345),
87 93 ])
88 94 def test_int_setting_helper(self, raw, expected):
89 key = 'dummy-key'
90 settings = {key: raw}
91 _int_setting(settings, key, None)
92 assert settings[key] == expected
95 val = SettingsMaker._int_func(raw)
96 assert val == expected
93 97
94 98 @pytest.mark.parametrize('raw', [
95 99 ('0xff'),
@@ -99,21 +103,19 b' class TestHelperFunctions(object):'
99 103 (u'invalid-⁄~†'),
100 104 ])
101 105 def test_int_setting_helper_invalid_input(self, raw):
102 key = 'dummy-key'
103 settings = {key: raw}
104 106 with pytest.raises(Exception):
105 _int_setting(settings, key, None)
107 SettingsMaker._int_func(raw)
106 108
107 109
108 110 class TestSanitizeVcsSettings(object):
109 _bool_settings = [
111 _bool_funcs = [
110 112 ('vcs.hooks.direct_calls', False),
111 113 ('vcs.server.enable', True),
112 114 ('vcs.start_server', False),
113 115 ('startup.import_repos', False),
114 116 ]
115 117
116 _string_settings = [
118 _string_funcs = [
117 119 ('vcs.svn.compatible_version', ''),
118 120 ('vcs.hooks.protocol', 'http'),
119 121 ('vcs.hooks.host', '127.0.0.1'),
@@ -126,28 +128,28 b' class TestSanitizeVcsSettings(object):'
126 128 ('vcs.backends', 'hg git'),
127 129 ]
128 130
129 @pytest.mark.parametrize('key, default', _list_settings)
130 def test_list_setting_spacesep_list(self, key, default):
131 test_list = ['test', 'list', 'values', 'for', key]
132 input_value = ' '.join(test_list)
133 settings = {key: input_value}
134 _sanitize_vcs_settings(settings)
135 assert settings[key] == test_list
136
137 @pytest.mark.parametrize('key, default', _list_settings)
138 def test_list_setting_newlinesep_list(self, key, default):
139 test_list = ['test', 'list', 'values', 'for', key]
140 input_value = '\n'.join(test_list)
141 settings = {key: input_value}
142 _sanitize_vcs_settings(settings)
143 assert settings[key] == test_list
131 # @pytest.mark.parametrize('key, default', _list_settings)
132 # def test_list_setting_spacesep_list(self, key, default):
133 # test_list = ['test', 'list', 'values', 'for', key]
134 # input_value = ' '.join(test_list)
135 # settings = {key: input_value}
136 # sanitize_settings_and_apply_defaults({'__file__': ''}, settings)
137 # assert settings[key] == test_list
138 #
139 # @pytest.mark.parametrize('key, default', _list_settings)
140 # def test_list_setting_newlinesep_list(self, key, default):
141 # test_list = ['test', 'list', 'values', 'for', key]
142 # input_value = '\n'.join(test_list)
143 # settings = {key: input_value}
144 # sanitize_settings_and_apply_defaults({'__file__': ''}, settings)
145 # assert settings[key] == test_list
144 146
145 147 @pytest.mark.parametrize('key, default', _list_settings)
146 148 def test_list_setting_commasep_list(self, key, default):
147 149 test_list = ['test', 'list', 'values', 'for', key]
148 150 input_value = ','.join(test_list)
149 151 settings = {key: input_value}
150 _sanitize_vcs_settings(settings)
152 sanitize_settings_and_apply_defaults({'__file__': ''}, settings)
151 153 assert settings[key] == test_list
152 154
153 155 @pytest.mark.parametrize('key, default', _list_settings)
@@ -155,49 +157,49 b' class TestSanitizeVcsSettings(object):'
155 157 test_list = ['test', 'list', 'values', 'for', key]
156 158 input_value = ', '.join(test_list)
157 159 settings = {key: input_value}
158 _sanitize_vcs_settings(settings)
160 sanitize_settings_and_apply_defaults({'__file__': ''}, settings)
159 161 assert settings[key] == test_list
160 162
161 @pytest.mark.parametrize('key, default', _string_settings)
162 def test_string_setting_string(self, key, default):
163 @pytest.mark.parametrize('key, default', _string_funcs)
164 def test_string_func_string(self, key, default):
163 165 test_value = 'test-string-for-{}'.format(key)
164 166 settings = {key: test_value}
165 _sanitize_vcs_settings(settings)
167 sanitize_settings_and_apply_defaults({'__file__': ''}, settings)
166 168 assert settings[key] == test_value
167 169
168 @pytest.mark.parametrize('key, default', _string_settings)
169 def test_string_setting_default(self, key, default):
170 @pytest.mark.parametrize('key, default', _string_funcs)
171 def test_string_func_default(self, key, default):
170 172 settings = {}
171 _sanitize_vcs_settings(settings)
173 sanitize_settings_and_apply_defaults({'__file__': ''}, settings)
172 174 assert settings[key] == default
173 175
174 @pytest.mark.parametrize('key, default', _string_settings)
175 def test_string_setting_lowercase(self, key, default):
176 test_value = 'Test-String-For-{}'.format(key)
177 settings = {key: test_value}
178 _sanitize_vcs_settings(settings)
179 assert settings[key] == test_value.lower()
176 # @pytest.mark.parametrize('key, default', _string_funcs)
177 # def test_string_func_lowercase(self, key, default):
178 # test_value = 'Test-String-For-{}'.format(key)
179 # settings = {key: test_value}
180 # sanitize_settings_and_apply_defaults({'__file__': ''}, settings)
181 # assert settings[key] == test_value.lower()
180 182
181 @pytest.mark.parametrize('key, default', _bool_settings)
182 def test_bool_setting_true(self, key, default):
183 @pytest.mark.parametrize('key, default', _bool_funcs)
184 def test_bool_func_true(self, key, default):
183 185 settings = {key: 'true'}
184 _sanitize_vcs_settings(settings)
186 sanitize_settings_and_apply_defaults({'__file__': ''}, settings)
185 187 assert settings[key] is True
186 188
187 @pytest.mark.parametrize('key, default', _bool_settings)
188 def test_bool_setting_false(self, key, default):
189 @pytest.mark.parametrize('key, default', _bool_funcs)
190 def test_bool_func_false(self, key, default):
189 191 settings = {key: 'false'}
190 _sanitize_vcs_settings(settings)
192 sanitize_settings_and_apply_defaults({'__file__': ''}, settings)
191 193 assert settings[key] is False
192 194
193 @pytest.mark.parametrize('key, default', _bool_settings)
194 def test_bool_setting_invalid_string(self, key, default):
195 @pytest.mark.parametrize('key, default', _bool_funcs)
196 def test_bool_func_invalid_string(self, key, default):
195 197 settings = {key: 'no-bool-val-string'}
196 _sanitize_vcs_settings(settings)
198 sanitize_settings_and_apply_defaults({'__file__': ''}, settings)
197 199 assert settings[key] is False
198 200
199 @pytest.mark.parametrize('key, default', _bool_settings)
200 def test_bool_setting_default(self, key, default):
201 @pytest.mark.parametrize('key, default', _bool_funcs)
202 def test_bool_func_default(self, key, default):
201 203 settings = {}
202 _sanitize_vcs_settings(settings)
204 sanitize_settings_and_apply_defaults({'__file__': ''}, settings)
203 205 assert settings[key] is default
This diff has been collapsed as it changes many lines, (568 lines changed) Show them Hide them
@@ -1,30 +1,23 b''
1 1
2
3 ################################################################################
4 ## RHODECODE COMMUNITY EDITION CONFIGURATION ##
5 # The %(here)s variable will be replaced with the parent directory of this file#
6 ################################################################################
2 ; #########################################
3 ; RHODECODE COMMUNITY EDITION CONFIGURATION
4 ; #########################################
7 5
8 6 [DEFAULT]
7 ; Debug flag sets all loggers to debug, and enables request tracking
9 8 debug = true
10 9
11 ################################################################################
12 ## EMAIL CONFIGURATION ##
13 ## Uncomment and replace with the email address which should receive ##
14 ## any error reports after an application crash ##
15 ## Additionally these settings will be used by the RhodeCode mailing system ##
16 ################################################################################
10 ; ########################################################################
11 ; EMAIL CONFIGURATION
12 ; These settings will be used by the RhodeCode mailing system
13 ; ########################################################################
17 14
18 ## prefix all emails subjects with given prefix, helps filtering out emails
15 ; prefix all emails subjects with given prefix, helps filtering out emails
19 16 #email_prefix = [RhodeCode]
20 17
21 ## email FROM address all mails will be sent
18 ; email FROM address all mails will be sent
22 19 #app_email_from = rhodecode-noreply@localhost
23 20
24 ## Uncomment and replace with the address which should receive any error report
25 ## note: using appenlight for error handling doesn't need this to be uncommented
26 #email_to = admin@localhost
27
28 21 #smtp_server = mail.server.com
29 22 #smtp_username =
30 23 #smtp_password =
@@ -33,16 +26,20 b' debug = true'
33 26 #smtp_use_ssl = true
34 27
35 28 [server:main]
36 ## COMMON ##
29 ; COMMON HOST/IP CONFIG
37 30 host = 0.0.0.0
38 31 port = 5000
39 32
40 ##########################
41 ## GUNICORN WSGI SERVER ##
42 ##########################
43 ## run with gunicorn --log-config rhodecode.ini --paste rhodecode.ini
33
34 ; ###########################
35 ; GUNICORN APPLICATION SERVER
36 ; ###########################
44 37
38 ; run with gunicorn --log-config rhodecode.ini --paste rhodecode.ini
39
40 ; Module to use, this setting shouldn't be changed
45 41 use = egg:gunicorn#main
42
46 43 ## Sets the number of process workers. You must set `instance_id = *`
47 44 ## when this option is set to more than one worker, recommended
48 45 ## value is (2 * NUMBER_OF_CPUS + 1), eg 2CPU = 5 workers
@@ -81,7 +78,7 b' prefix = /'
81 78 is_test = True
82 79 use = egg:rhodecode-enterprise-ce
83 80
84 ## enable proxy prefix middleware, defined above
81 ; enable proxy prefix middleware, defined above
85 82 #filter-with = proxy-prefix
86 83
87 84
@@ -99,64 +96,69 b' rhodecode.api.url = /_admin/api'
99 96 ## `beaker.session.secret`
100 97 #rhodecode.encrypted_values.secret =
101 98
102 ## decryption strict mode (enabled by default). It controls if decryption raises
103 ## `SignatureVerificationError` in case of wrong key, or damaged encryption data.
99 ; decryption strict mode (enabled by default). It controls if decryption raises
100 ; `SignatureVerificationError` in case of wrong key, or damaged encryption data.
104 101 #rhodecode.encrypted_values.strict = false
105 102
106 ## return gzipped responses from Rhodecode (static files/application)
103 ; Pick algorithm for encryption. Either fernet (more secure) or aes (default)
104 ; fernet is safer, and we strongly recommend switching to it.
105 ; Due to backward compatibility aes is used as default.
106 #rhodecode.encrypted_values.algorithm = fernet
107
108 ; Return gzipped responses from RhodeCode (static files/application)
107 109 gzip_responses = false
108 110
109 ## autogenerate javascript routes file on startup
111 ; Auto-generate javascript routes file on startup
110 112 generate_js_files = false
111 113
112 ## Optional Languages
113 ## en(default), be, de, es, fr, it, ja, pl, pt, ru, zh
114 ; System global default language.
115 ; All available languages: en (default), be, de, es, fr, it, ja, pl, pt, ru, zh
114 116 lang = en
115 117
116 118 ## perform a full repository scan on each server start, this should be
117 119 ## set to false after first startup, to allow faster server restarts.
118 120 startup.import_repos = true
119 121
120 ## Uncomment and set this path to use archive download cache.
121 ## Once enabled, generated archives will be cached at this location
122 ## and served from the cache during subsequent requests for the same archive of
123 ## the repository.
122 ; Uncomment and set this path to use archive download cache.
123 ; Once enabled, generated archives will be cached at this location
124 ; and served from the cache during subsequent requests for the same archive of
125 ; the repository.
124 126 #archive_cache_dir = /tmp/tarballcache
125 127
126 ## URL at which the application is running. This is used for bootstraping
127 ## requests in context when no web request is available. Used in ishell, or
128 ## SSH calls. Set this for events to receive proper url for SSH calls.
128 ; URL at which the application is running. This is used for Bootstrapping
129 ; requests in context when no web request is available. Used in ishell, or
130 ; SSH calls. Set this for events to receive proper url for SSH calls.
129 131 app.base_url = http://rhodecode.local
130 132
131 ## change this to unique ID for security
133 ; Unique application ID. Should be a random unique string for security.
132 134 app_instance_uuid = rc-production
133 135
134 136 ## cut off limit for large diffs (size in bytes)
135 137 cut_off_limit_diff = 1024000
136 138 cut_off_limit_file = 256000
137 139
138 ## use cache version of scm repo everywhere
140 ; Use cached version of vcs repositories everywhere. Recommended to be `true`
139 141 vcs_full_cache = false
140 142
141 ## force https in RhodeCode, fixes https redirects, assumes it's always https
142 ## Normally this is controlled by proper http flags sent from http server
143 ; Force https in RhodeCode, fixes https redirects, assumes it's always https.
144 ; Normally this is controlled by proper flags sent from http server such as Nginx or Apache
143 145 force_https = false
144 146
145 ## use Strict-Transport-Security headers
147 ; use Strict-Transport-Security headers
146 148 use_htsts = false
147 149
148 # Set to true if your repos are exposed using the dumb protocol
150 ; Set to true if your repos are exposed using the dumb protocol
149 151 git_update_server_info = false
150 152
151 ## RSS/ATOM feed options
153 ; RSS/ATOM feed options
152 154 rss_cut_off_limit = 256000
153 155 rss_items_per_page = 10
154 156 rss_include_diff = false
155 157
156 ## gist URL alias, used to create nicer urls for gist. This should be an
157 ## url that does rewrites to _admin/gists/{gistid}.
158 ## example: http://gist.rhodecode.org/{gistid}. Empty means use the internal
159 ## RhodeCode url, ie. http[s]://rhodecode.server/_admin/gists/{gistid}
158 ; gist URL alias, used to create nicer urls for gist. This should be an
159 ; url that does rewrites to _admin/gists/{gistid}.
160 ; example: http://gist.rhodecode.org/{gistid}. Empty means use the internal
161 ; RhodeCode url, ie. http[s]://rhodecode.server/_admin/gists/{gistid}
160 162 gist_alias_url =
161 163
162 164 ## List of views (using glob pattern syntax) that AUTH TOKENS could be
@@ -181,36 +183,39 b' gist_alias_url ='
181 183 # GistView:*
182 184 api_access_controllers_whitelist =
183 185
184 ## default encoding used to convert from and to unicode
185 ## can be also a comma separated list of encoding in case of mixed encodings
186 ; Default encoding used to convert from and to unicode
187 ; can be also a comma separated list of encoding in case of mixed encodings
186 188 default_encoding = UTF-8
187 189
188 ## instance-id prefix
189 ## a prefix key for this instance used for cache invalidation when running
190 ## multiple instances of rhodecode, make sure it's globally unique for
191 ## all running rhodecode instances. Leave empty if you don't use it
190 ; instance-id prefix
191 ; a prefix key for this instance used for cache invalidation when running
192 ; multiple instances of RhodeCode, make sure it's globally unique for
193 ; all running RhodeCode instances. Leave empty if you don't use it
192 194 instance_id =
193 195
194 ## Fallback authentication plugin. Set this to a plugin ID to force the usage
195 ## of an authentication plugin also if it is disabled by it's settings.
196 ## This could be useful if you are unable to log in to the system due to broken
197 ## authentication settings. Then you can enable e.g. the internal rhodecode auth
198 ## module to log in again and fix the settings.
199 ##
200 ## Available builtin plugin IDs (hash is part of the ID):
201 ## egg:rhodecode-enterprise-ce#rhodecode
202 ## egg:rhodecode-enterprise-ce#pam
203 ## egg:rhodecode-enterprise-ce#ldap
204 ## egg:rhodecode-enterprise-ce#jasig_cas
205 ## egg:rhodecode-enterprise-ce#headers
206 ## egg:rhodecode-enterprise-ce#crowd
196 ; Fallback authentication plugin. Set this to a plugin ID to force the usage
197 ; of an authentication plugin also if it is disabled by it's settings.
198 ; This could be useful if you are unable to log in to the system due to broken
199 ; authentication settings. Then you can enable e.g. the internal RhodeCode auth
200 ; module to log in again and fix the settings.
201 ; Available builtin plugin IDs (hash is part of the ID):
202 ; egg:rhodecode-enterprise-ce#rhodecode
203 ; egg:rhodecode-enterprise-ce#pam
204 ; egg:rhodecode-enterprise-ce#ldap
205 ; egg:rhodecode-enterprise-ce#jasig_cas
206 ; egg:rhodecode-enterprise-ce#headers
207 ; egg:rhodecode-enterprise-ce#crowd
208
207 209 #rhodecode.auth_plugin_fallback = egg:rhodecode-enterprise-ce#rhodecode
208 210
209 ## alternative return HTTP header for failed authentication. Default HTTP
210 ## response is 401 HTTPUnauthorized. Currently HG clients have troubles with
211 ## handling that causing a series of failed authentication calls.
212 ## Set this variable to 403 to return HTTPForbidden, or any other HTTP code
213 ## This will be served instead of default 401 on bad authnetication
211 ; Flag to control loading of legacy plugins in py:/path format
212 auth_plugin.import_legacy_plugins = true
213
214 ; alternative return HTTP header for failed authentication. Default HTTP
215 ; response is 401 HTTPUnauthorized. Currently HG clients have troubles with
216 ; handling that causing a series of failed authentication calls.
217 ; Set this variable to 403 to return HTTPForbidden, or any other HTTP code
218 ; This will be served instead of default 401 on bad authentication
214 219 auth_ret_code =
215 220
216 221 ## use special detection method when serving auth_ret_code, instead of serving
@@ -240,38 +245,35 b' supervisor.group_id = dev'
240 245 ## Display extended labs settings
241 246 labs_settings_active = true
242 247
243 ####################################
244 ### CELERY CONFIG ####
245 ####################################
248 ; #############
249 ; CELERY CONFIG
250 ; #############
251
252 ; manually run celery: /path/to/celery worker -E --beat --app rhodecode.lib.celerylib.loader --scheduler rhodecode.lib.celerylib.scheduler.RcScheduler --loglevel DEBUG --ini /path/to/rhodecode.ini
253
246 254 use_celery = false
247 broker.host = localhost
248 broker.vhost = rabbitmqhost
249 broker.port = 5672
250 broker.user = rabbitmq
251 broker.password = qweqwe
252 255
253 celery.imports = rhodecode.lib.celerylib.tasks
256 ; path to store schedule database
257 #celerybeat-schedule.path =
254 258
255 celery.result.backend = amqp
256 celery.result.dburi = amqp://
257 celery.result.serialier = json
259 ; connection url to the message broker (default redis)
260 celery.broker_url = redis://localhost:6379/8
258 261
259 #celery.send.task.error.emails = true
260 #celery.amqp.task.result.expires = 18000
262 ; rabbitmq example
263 #celery.broker_url = amqp://rabbitmq:qweqwe@localhost:5672/rabbitmqhost
261 264
262 celeryd.concurrency = 2
263 #celeryd.log.file = celeryd.log
264 celeryd.log.level = debug
265 celeryd.max.tasks.per.child = 1
265 ; maximum tasks to execute before worker restart
266 celery.max_tasks_per_child = 100
266 267
267 ## tasks will never be sent to the queue, but executed locally instead.
268 celery.always.eager = false
268 ; tasks will never be sent to the queue, but executed locally instead.
269 celery.task_always_eager = false
269 270
270 ####################################
271 ### BEAKER CACHE ####
272 ####################################
273 # default cache dir for templates. Putting this into a ramdisk
274 ## can boost performance, eg. %(here)s/data_ramdisk
271 ; #############
272 ; DOGPILE CACHE
273 ; #############
274
275 ; Default cache dir for caches. Putting this into a ramdisk can boost performance.
276 ; eg. /tmpfs/data_ramdisk, however this directory might require large amount of space
275 277 cache_dir = %(here)s/data
276 278
277 279 ## locking and default file storage for Beaker. Putting this into a ramdisk
@@ -301,16 +303,21 b' rc_cache.sql_cache_short.backend = dogpi'
301 303 rc_cache.sql_cache_short.expiration_time = 0
302 304
303 305
304 ####################################
305 ### BEAKER SESSION ####
306 ####################################
306 ; ##############
307 ; BEAKER SESSION
308 ; ##############
307 309
308 ## .session.type is type of storage options for the session, current allowed
309 ## types are file, ext:memcached, ext:database, and memory (default).
310 ; beaker.session.type is type of storage options for the logged users sessions. Current allowed
311 ; types are file, ext:redis, ext:database, ext:memcached, and memory (default if not specified).
312 ; Fastest ones are Redis and ext:database
310 313 beaker.session.type = file
311 314 beaker.session.data_dir = %(here)s/rc/data/sessions/data
312 315
313 ## db based session, fast, and allows easy management over logged in users
316 ; Redis based sessions
317 #beaker.session.type = ext:redis
318 #beaker.session.url = redis://127.0.0.1:6379/2
319
320 ; DB based session, fast, and allows easy management over logged in users
314 321 #beaker.session.type = ext:database
315 322 #beaker.session.table_name = db_session
316 323 #beaker.session.sa.url = postgresql://postgres:secret@localhost/rhodecode
@@ -322,19 +329,20 b' beaker.session.key = rhodecode'
322 329 beaker.session.secret = test-rc-uytcxaz
323 330 beaker.session.lock_dir = %(here)s/rc/data/sessions/lock
324 331
325 ## Secure encrypted cookie. Requires AES and AES python libraries
326 ## you must disable beaker.session.secret to use this
332 ; Secure encrypted cookie. Requires AES and AES python libraries
333 ; you must disable beaker.session.secret to use this
327 334 #beaker.session.encrypt_key = key_for_encryption
328 335 #beaker.session.validate_key = validation_key
329 336
330 ## sets session as invalid(also logging out user) if it haven not been
331 ## accessed for given amount of time in seconds
337 ; Sets session as invalid (also logging out user) if it haven not been
338 ; accessed for given amount of time in seconds
332 339 beaker.session.timeout = 2592000
333 340 beaker.session.httponly = true
334 ## Path to use for the cookie. Set to prefix if you use prefix middleware
341
342 ; Path to use for the cookie. Set to prefix if you use prefix middleware
335 343 #beaker.session.cookie_path = /custom_prefix
336 344
337 ## uncomment for https secure cookie
345 ; Set https secure cookie
338 346 beaker.session.secure = false
339 347
340 348 ## auto save the session to not to use .save()
@@ -344,242 +352,213 b' beaker.session.auto = false'
344 352 ## at browser close
345 353 #beaker.session.cookie_expires = 3600
346 354
347 ###################################
348 ## SEARCH INDEXING CONFIGURATION ##
349 ###################################
350 ## Full text search indexer is available in rhodecode-tools under
351 ## `rhodecode-tools index` command
355 ; #############################
356 ; SEARCH INDEXING CONFIGURATION
357 ; #############################
352 358
353 359 ## WHOOSH Backend, doesn't require additional services to run
354 360 ## it works good with few dozen repos
355 361 search.module = rhodecode.lib.index.whoosh
356 362 search.location = %(here)s/data/index
357 363
358 ########################################
359 ### CHANNELSTREAM CONFIG ####
360 ########################################
361 ## channelstream enables persistent connections and live notification
362 ## in the system. It's also used by the chat system
364 ; ####################
365 ; CHANNELSTREAM CONFIG
366 ; ####################
367
368 ; channelstream enables persistent connections and live notification
369 ; in the system. It's also used by the chat system
363 370
364 371 channelstream.enabled = false
365 372
366 ## server address for channelstream server on the backend
373 ; server address for channelstream server on the backend
367 374 channelstream.server = 127.0.0.1:9800
368 ## location of the channelstream server from outside world
369 ## use ws:// for http or wss:// for https. This address needs to be handled
370 ## by external HTTP server such as Nginx or Apache
371 ## see nginx/apache configuration examples in our docs
375
376 ; location of the channelstream server from outside world
377 ; use ws:// for http or wss:// for https. This address needs to be handled
378 ; by external HTTP server such as Nginx or Apache
379 ; see Nginx/Apache configuration examples in our docs
372 380 channelstream.ws_url = ws://rhodecode.yourserver.com/_channelstream
373 381 channelstream.secret = secret
374 382 channelstream.history.location = %(here)s/channelstream_history
375 383
376 ## Internal application path that Javascript uses to connect into.
377 ## If you use proxy-prefix the prefix should be added before /_channelstream
384 ; Internal application path that Javascript uses to connect into.
385 ; If you use proxy-prefix the prefix should be added before /_channelstream
378 386 channelstream.proxy_path = /_channelstream
379 387
380 388
381 ###################################
382 ## APPENLIGHT CONFIG ##
383 ###################################
384
385 ## Appenlight is tailored to work with RhodeCode, see
386 ## http://appenlight.com for details how to obtain an account
387
388 ## appenlight integration enabled
389 appenlight = false
390
391 appenlight.server_url = https://api.appenlight.com
392 appenlight.api_key = YOUR_API_KEY
393 #appenlight.transport_config = https://api.appenlight.com?threaded=1&timeout=5
394
395 # used for JS client
396 appenlight.api_public_key = YOUR_API_PUBLIC_KEY
397
398 ## TWEAK AMOUNT OF INFO SENT HERE
399
400 ## enables 404 error logging (default False)
401 appenlight.report_404 = false
402
403 ## time in seconds after request is considered being slow (default 1)
404 appenlight.slow_request_time = 1
405
406 ## record slow requests in application
407 ## (needs to be enabled for slow datastore recording and time tracking)
408 appenlight.slow_requests = true
409
410 ## enable hooking to application loggers
411 appenlight.logging = true
412
413 ## minimum log level for log capture
414 appenlight.logging.level = WARNING
415
416 ## send logs only from erroneous/slow requests
417 ## (saves API quota for intensive logging)
418 appenlight.logging_on_error = false
389 ; ##############################
390 ; MAIN RHODECODE DATABASE CONFIG
391 ; ##############################
419 392
420 ## list of additonal keywords that should be grabbed from environ object
421 ## can be string with comma separated list of words in lowercase
422 ## (by default client will always send following info:
423 ## 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that
424 ## start with HTTP* this list be extended with additional keywords here
425 appenlight.environ_keys_whitelist =
426
427 ## list of keywords that should be blanked from request object
428 ## can be string with comma separated list of words in lowercase
429 ## (by default client will always blank keys that contain following words
430 ## 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'
431 ## this list be extended with additional keywords set here
432 appenlight.request_keys_blacklist =
433
434 ## list of namespaces that should be ignores when gathering log entries
435 ## can be string with comma separated list of namespaces
436 ## (by default the client ignores own entries: appenlight_client.client)
437 appenlight.log_namespace_blacklist =
438
393 #sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db?timeout=30
394 #sqlalchemy.db1.url = postgresql://postgres:qweqwe@localhost/rhodecode
395 #sqlalchemy.db1.url = mysql://root:qweqwe@localhost/rhodecode?charset=utf8
396 ; pymysql is an alternative driver for MySQL, use in case of problems with default one
397 #sqlalchemy.db1.url = mysql+pymysql://root:qweqwe@localhost/rhodecode
439 398
440 ################################################################################
441 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
442 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
443 ## execute malicious code after an exception is raised. ##
444 ################################################################################
445 set debug = false
446
447
448 ##############
449 ## STYLING ##
450 ##############
451 debug_style = false
452
453 ###########################################
454 ### MAIN RHODECODE DATABASE CONFIG ###
455 ###########################################
456 #sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode_test.db?timeout=30
457 #sqlalchemy.db1.url = postgresql://postgres:qweqwe@localhost/rhodecode_test
458 #sqlalchemy.db1.url = mysql://root:qweqwe@localhost/rhodecode_test
459 399 sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode_test.db?timeout=30
460 400
461 # see sqlalchemy docs for other advanced settings
462
463 ## print the sql statements to output
401 ; see sqlalchemy docs for other advanced settings
402 ; print the sql statements to output
464 403 sqlalchemy.db1.echo = false
465 ## recycle the connections after this amount of seconds
466 sqlalchemy.db1.pool_recycle = 3600
467 404
468 ## the number of connections to keep open inside the connection pool.
469 ## 0 indicates no limit
405 ; recycle the connections after this amount of seconds
406 sqlalchemy.db1.pool_recycle = 3600
407 sqlalchemy.db1.convert_unicode = true
408
409 ; the number of connections to keep open inside the connection pool.
410 ; 0 indicates no limit
470 411 #sqlalchemy.db1.pool_size = 5
471 412
472 ## the number of connections to allow in connection pool "overflow", that is
473 ## connections that can be opened above and beyond the pool_size setting,
474 ## which defaults to five.
413 ; The number of connections to allow in connection pool "overflow", that is
414 ; connections that can be opened above and beyond the pool_size setting,
415 ; which defaults to five.
475 416 #sqlalchemy.db1.max_overflow = 10
476 417
418 ; Connection check ping, used to detect broken database connections
419 ; could be enabled to better handle cases if MySQL has gone away errors
420 #sqlalchemy.db1.ping_connection = true
477 421
478 ##################
479 ### VCS CONFIG ###
480 ##################
422 ; ##########
423 ; VCS CONFIG
424 ; ##########
481 425 vcs.server.enable = true
482 426 vcs.server = localhost:9901
483 427
484 ## Web server connectivity protocol, responsible for web based VCS operatations
485 ## Available protocols are:
486 ## `http` - use http-rpc backend (default)
428 ; Web server connectivity protocol, responsible for web based VCS operations
429 ; Available protocols are:
430 ; `http` - use http-rpc backend (default)
487 431 vcs.server.protocol = http
488 432
489 ## Push/Pull operations protocol, available options are:
490 ## `http` - use http-rpc backend (default)
491 ## `vcsserver.scm_app` - internal app (EE only)
433 ; Push/Pull operations protocol, available options are:
434 ; `http` - use http-rpc backend (default)
492 435 vcs.scm_app_implementation = http
493 436
494 ## Push/Pull operations hooks protocol, available options are:
495 ## `http` - use http-rpc backend (default)
437 ; Push/Pull operations hooks protocol, available options are:
438 ; `http` - use http-rpc backend (default)
496 439 vcs.hooks.protocol = http
440
441 ; Host on which this instance is listening for hooks. If vcsserver is in other location
442 ; this should be adjusted.
497 443 vcs.hooks.host = 127.0.0.1
498 444
499
500 ## Start VCSServer with this instance as a subprocess, Useful for development
445 ; Start VCSServer with this instance as a subprocess, useful for development
501 446 vcs.start_server = false
502 447
503 ## List of enabled VCS backends, available options are:
504 ## `hg` - mercurial
505 ## `git` - git
506 ## `svn` - subversion
448 ; List of enabled VCS backends, available options are:
449 ; `hg` - mercurial
450 ; `git` - git
451 ; `svn` - subversion
507 452 vcs.backends = hg, git, svn
508 453
454 ; Wait this number of seconds before killing connection to the vcsserver
509 455 vcs.connection_timeout = 3600
510 ## Compatibility version when creating SVN repositories. Defaults to newest version when commented out.
511 ## Available options are: pre-1.4-compatible, pre-1.5-compatible, pre-1.6-compatible, pre-1.8-compatible, pre-1.9-compatible
512 #vcs.svn.compatible_version = pre-1.8-compatible
513 456
457 ; Compatibility version when creating SVN repositories. Defaults to newest version when commented out.
458 ; Set a numeric version for your current SVN e.g 1.8, or 1.12
459 ; Legacy available options are: pre-1.4-compatible, pre-1.5-compatible, pre-1.6-compatible, pre-1.8-compatible, pre-1.9-compatible
460 #vcs.svn.compatible_version = 1.8
514 461
515 ############################################################
516 ### Subversion proxy support (mod_dav_svn) ###
517 ### Maps RhodeCode repo groups into SVN paths for Apache ###
518 ############################################################
519 ## Enable or disable the config file generation.
462 ; Cache flag to cache vcsserver remote calls locally
463 ; It uses cache_region `cache_repo`
464 vcs.methods.cache = false
465
466 ; ####################################################
467 ; Subversion proxy support (mod_dav_svn)
468 ; Maps RhodeCode repo groups into SVN paths for Apache
469 ; ####################################################
470
471 ; Enable or disable the config file generation.
520 472 svn.proxy.generate_config = false
521 ## Generate config file with `SVNListParentPath` set to `On`.
473
474 ; Generate config file with `SVNListParentPath` set to `On`.
522 475 svn.proxy.list_parent_path = true
523 ## Set location and file name of generated config file.
476
477 ; Set location and file name of generated config file.
524 478 svn.proxy.config_file_path = %(here)s/mod_dav_svn.conf
525 ## Used as a prefix to the `Location` block in the generated config file.
526 ## In most cases it should be set to `/`.
479
480 ; alternative mod_dav config template. This needs to be a valid mako template
481 ; Example template can be found in the source code:
482 ; rhodecode/apps/svn_support/templates/mod-dav-svn.conf.mako
483 #svn.proxy.config_template = ~/.rccontrol/enterprise-1/custom_svn_conf.mako
484
485 ; Used as a prefix to the `Location` block in the generated config file.
486 ; In most cases it should be set to `/`.
527 487 svn.proxy.location_root = /
528 ## Command to reload the mod dav svn configuration on change.
529 ## Example: `/etc/init.d/apache2 reload`
488
489 ; Command to reload the mod dav svn configuration on change.
490 ; Example: `/etc/init.d/apache2 reload` or /home/USER/apache_reload.sh
491 ; Make sure user who runs RhodeCode process is allowed to reload Apache
530 492 #svn.proxy.reload_cmd = /etc/init.d/apache2 reload
531 ## If the timeout expires before the reload command finishes, the command will
532 ## be killed. Setting it to zero means no timeout. Defaults to 10 seconds.
493
494 ; If the timeout expires before the reload command finishes, the command will
495 ; be killed. Setting it to zero means no timeout. Defaults to 10 seconds.
533 496 #svn.proxy.reload_timeout = 10
534 497
535 ############################################################
536 ### SSH Support Settings ###
537 ############################################################
498 ; ####################
499 ; SSH Support Settings
500 ; ####################
538 501
539 ## Defines if the authorized_keys file should be written on any change of
540 ## user ssh keys, setting this to false also disables posibility of adding
541 ## ssh keys for users from web interface.
502 ; Defines if a custom authorized_keys file should be created and written on
503 ; any change user ssh keys. Setting this to false also disables possibility
504 ; of adding SSH keys by users from web interface. Super admins can still
505 ; manage SSH Keys.
542 506 ssh.generate_authorized_keyfile = true
543 507
544 ## Options for ssh, default is `no-pty,no-port-forwarding,no-X11-forwarding,no-agent-forwarding`
508 ; Options for ssh, default is `no-pty,no-port-forwarding,no-X11-forwarding,no-agent-forwarding`
545 509 # ssh.authorized_keys_ssh_opts =
546 510
547 ## File to generate the authorized keys together with options
548 ## It is possible to have multiple key files specified in `sshd_config` e.g.
549 ## AuthorizedKeysFile %h/.ssh/authorized_keys %h/.ssh/authorized_keys_rhodecode
511 ; Path to the authorized_keys file where the generate entries are placed.
512 ; It is possible to have multiple key files specified in `sshd_config` e.g.
513 ; AuthorizedKeysFile %h/.ssh/authorized_keys %h/.ssh/authorized_keys_rhodecode
550 514 ssh.authorized_keys_file_path = %(here)s/rc/authorized_keys_rhodecode
551 515
552 ## Command to execute the SSH wrapper. The binary is available in the
553 ## rhodecode installation directory.
554 ## e.g ~/.rccontrol/community-1/profile/bin/rc-ssh-wrapper
516 ; Command to execute the SSH wrapper. The binary is available in the
517 ; RhodeCode installation directory.
518 ; e.g ~/.rccontrol/community-1/profile/bin/rc-ssh-wrapper
555 519 ssh.wrapper_cmd = ~/.rccontrol/community-1/rc-ssh-wrapper
556 520
557 ## Allow shell when executing the ssh-wrapper command
521 ; Allow shell when executing the ssh-wrapper command
558 522 ssh.wrapper_cmd_allow_shell = false
559 523
560 ## Enables logging, and detailed output send back to the client. Useful for
561 ## debugging, shouldn't be used in production.
524 ; Enables logging, and detailed output send back to the client during SSH
525 ; operations. Useful for debugging, shouldn't be used in production.
562 526 ssh.enable_debug_logging = false
563 527
564 ## Paths to binary executrables, by default they are the names, but we can
565 ## override them if we want to use a custom one
528 ; Paths to binary executable, by default they are the names, but we can
529 ; override them if we want to use a custom one
566 530 ssh.executable.hg = ~/.rccontrol/vcsserver-1/profile/bin/hg
567 531 ssh.executable.git = ~/.rccontrol/vcsserver-1/profile/bin/git
568 532 ssh.executable.svn = ~/.rccontrol/vcsserver-1/profile/bin/svnserve
569 533
570 ## Enables SSH key generator web interface. Disabling this still allows users
571 ## to add their own keys.
534 ; Enables SSH key generator web interface. Disabling this still allows users
535 ; to add their own keys.
572 536 ssh.enable_ui_key_generator = true
573 537
538 ; Statsd client config, this is used to send metrics to statsd
539 ; We recommend setting statsd_exported and scrape them using Promethues
540 #statsd.enabled = false
541 #statsd.statsd_host = 0.0.0.0
542 #statsd.statsd_port = 8125
543 #statsd.statsd_prefix =
544 #statsd.statsd_ipv6 = false
574 545
575 ## Dummy marker to add new entries after.
576 ## Add any custom entries below. Please don't remove.
546
547 ; configure logging automatically at server startup set to false
548 ; to use the below custom logging config.
549 logging.autoconfigure = false
550
551 ; specify your own custom logging config file to configure logging
552 #logging.logging_conf_file = /path/to/custom_logging.ini
553
554 ; Dummy marker to add new entries after.
555 ; Add any custom entries below. Please don't remove this marker.
577 556 custom.conf = 1
578 557
579 558
580 ################################
581 ### LOGGING CONFIGURATION ####
582 ################################
559 ; #####################
560 ; LOGGING CONFIGURATION
561 ; #####################
583 562 [loggers]
584 563 keys = root, sqlalchemy, beaker, rhodecode, ssh_wrapper
585 564
@@ -589,9 +568,9 b' keys = console, console_sql'
589 568 [formatters]
590 569 keys = generic, color_formatter, color_formatter_sql
591 570
592 #############
593 ## LOGGERS ##
594 #############
571 ; #######
572 ; LOGGERS
573 ; #######
595 574 [logger_root]
596 575 level = NOTSET
597 576 handlers = console
@@ -603,6 +582,12 b' qualname = routes.middleware'
603 582 ## "level = DEBUG" logs the route matched and routing variables.
604 583 propagate = 1
605 584
585 [logger_sqlalchemy]
586 level = INFO
587 handlers = console_sql
588 qualname = sqlalchemy.engine
589 propagate = 0
590
606 591 [logger_beaker]
607 592 level = DEBUG
608 593 handlers =
@@ -615,50 +600,59 b' handlers ='
615 600 qualname = rhodecode
616 601 propagate = 1
617 602
618 [logger_sqlalchemy]
619 level = ERROR
620 handlers = console_sql
621 qualname = sqlalchemy.engine
622 propagate = 0
623
624 603 [logger_ssh_wrapper]
625 604 level = DEBUG
626 605 handlers =
627 606 qualname = ssh_wrapper
628 607 propagate = 1
629 608
609 [logger_celery]
610 level = DEBUG
611 handlers =
612 qualname = celery
630 613
631 ##############
632 ## HANDLERS ##
633 ##############
614
615 ; ########
616 ; HANDLERS
617 ; ########
634 618
635 619 [handler_console]
636 620 class = StreamHandler
637 621 args = (sys.stderr,)
638 622 level = DEBUG
639 623 formatter = generic
624 ; To enable JSON formatted logs replace generic with json
625 ; This allows sending properly formatted logs to grafana loki or elasticsearch
626 #formatter = json
640 627
641 628 [handler_console_sql]
629 ; "level = DEBUG" logs SQL queries and results.
630 ; "level = INFO" logs SQL queries.
631 ; "level = WARN" logs neither. (Recommended for production systems.)
642 632 class = StreamHandler
643 633 args = (sys.stderr,)
644 634 level = WARN
645 635 formatter = generic
646 636
647 ################
648 ## FORMATTERS ##
649 ################
637 ; ##########
638 ; FORMATTERS
639 ; ##########
650 640
651 641 [formatter_generic]
652 642 class = rhodecode.lib.logging_formatter.ExceptionAwareFormatter
653 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
643 format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s
654 644 datefmt = %Y-%m-%d %H:%M:%S
655 645
656 646 [formatter_color_formatter]
657 647 class = rhodecode.lib.logging_formatter.ColorFormatter
658 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
648 format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s
659 649 datefmt = %Y-%m-%d %H:%M:%S
660 650
661 651 [formatter_color_formatter_sql]
662 652 class = rhodecode.lib.logging_formatter.ColorFormatterSql
663 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
653 format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s
664 654 datefmt = %Y-%m-%d %H:%M:%S
655
656 [formatter_json]
657 format = %(message)s
658 class = rhodecode.lib._vendor.jsonlogger.JsonFormatter No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now