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