##// END OF EJS Templates
env-config: use proper ALL keys reconfiguration based on env vars
super-admin -
r4825:a78e628e default
parent child Browse files
Show More
@@ -1,66 +1,68 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2020 RhodeCode GmbH
3 # Copyright (C) 2016-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 import os
20 import os
21 from rhodecode.apps.file_store import config_keys
21 from rhodecode.apps.file_store import config_keys
22 from rhodecode.config.settings_maker import SettingsMaker
22 from rhodecode.config.settings_maker import SettingsMaker
23
23
24
24
25 def _sanitize_settings_and_apply_defaults(settings):
25 def _sanitize_settings_and_apply_defaults(settings):
26 """
26 """
27 Set defaults, convert to python types and validate settings.
27 Set defaults, convert to python types and validate settings.
28 """
28 """
29 settings_maker = SettingsMaker(settings)
29 settings_maker = SettingsMaker(settings)
30
30
31 settings_maker.make_setting(config_keys.enabled, True, parser='bool')
31 settings_maker.make_setting(config_keys.enabled, True, parser='bool')
32 settings_maker.make_setting(config_keys.backend, 'local')
32 settings_maker.make_setting(config_keys.backend, 'local')
33
33
34 default_store = os.path.join(os.path.dirname(settings['__file__']), 'upload_store')
34 default_store = os.path.join(os.path.dirname(settings['__file__']), 'upload_store')
35 settings_maker.make_setting(config_keys.store_path, default_store)
35 settings_maker.make_setting(config_keys.store_path, default_store)
36
36
37 settings_maker.env_expand()
38
37
39
38 def includeme(config):
40 def includeme(config):
39 from rhodecode.apps.file_store.views import FileStoreView
41 from rhodecode.apps.file_store.views import FileStoreView
40
42
41 settings = config.registry.settings
43 settings = config.registry.settings
42 _sanitize_settings_and_apply_defaults(settings)
44 _sanitize_settings_and_apply_defaults(settings)
43
45
44 config.add_route(
46 config.add_route(
45 name='upload_file',
47 name='upload_file',
46 pattern='/_file_store/upload')
48 pattern='/_file_store/upload')
47 config.add_view(
49 config.add_view(
48 FileStoreView,
50 FileStoreView,
49 attr='upload_file',
51 attr='upload_file',
50 route_name='upload_file', request_method='POST', renderer='json_ext')
52 route_name='upload_file', request_method='POST', renderer='json_ext')
51
53
52 config.add_route(
54 config.add_route(
53 name='download_file',
55 name='download_file',
54 pattern='/_file_store/download/{fid:.*}')
56 pattern='/_file_store/download/{fid:.*}')
55 config.add_view(
57 config.add_view(
56 FileStoreView,
58 FileStoreView,
57 attr='download_file',
59 attr='download_file',
58 route_name='download_file')
60 route_name='download_file')
59
61
60 config.add_route(
62 config.add_route(
61 name='download_file_by_token',
63 name='download_file_by_token',
62 pattern='/_file_store/token-download/{_auth_token}/{fid:.*}')
64 pattern='/_file_store/token-download/{_auth_token}/{fid:.*}')
63 config.add_view(
65 config.add_view(
64 FileStoreView,
66 FileStoreView,
65 attr='download_file_by_token',
67 attr='download_file_by_token',
66 route_name='download_file_by_token')
68 route_name='download_file_by_token')
@@ -1,59 +1,61 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2020 RhodeCode GmbH
3 # Copyright (C) 2016-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 logging
21 import logging
22
22
23 from . import config_keys
23 from . import config_keys
24 from .events import SshKeyFileChangeEvent
24 from .events import SshKeyFileChangeEvent
25 from .subscribers import generate_ssh_authorized_keys_file_subscriber
25 from .subscribers import generate_ssh_authorized_keys_file_subscriber
26
26
27 from rhodecode.config.settings_maker import SettingsMaker
27 from rhodecode.config.settings_maker import SettingsMaker
28
28
29 log = logging.getLogger(__name__)
29 log = logging.getLogger(__name__)
30
30
31
31
32 def _sanitize_settings_and_apply_defaults(settings):
32 def _sanitize_settings_and_apply_defaults(settings):
33 """
33 """
34 Set defaults, convert to python types and validate settings.
34 Set defaults, convert to python types and validate settings.
35 """
35 """
36 settings_maker = SettingsMaker(settings)
36 settings_maker = SettingsMaker(settings)
37
37
38 settings_maker.make_setting(config_keys.generate_authorized_keyfile, False, parser='bool')
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')
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')
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')
41 settings_maker.make_setting(config_keys.ssh_key_generator_enabled, True, parser='bool')
42
42
43 settings_maker.make_setting(config_keys.authorized_keys_file_path, '~/.ssh/authorized_keys_rhodecode')
43 settings_maker.make_setting(config_keys.authorized_keys_file_path, '~/.ssh/authorized_keys_rhodecode')
44 settings_maker.make_setting(config_keys.wrapper_cmd, '')
44 settings_maker.make_setting(config_keys.wrapper_cmd, '')
45 settings_maker.make_setting(config_keys.authorized_keys_line_ssh_opts, '')
45 settings_maker.make_setting(config_keys.authorized_keys_line_ssh_opts, '')
46
46
47 settings_maker.make_setting(config_keys.ssh_hg_bin, '~/.rccontrol/vcsserver-1/profile/bin/hg')
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')
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')
49 settings_maker.make_setting(config_keys.ssh_svn_bin, '~/.rccontrol/vcsserver-1/profile/bin/svnserve')
50
50
51 settings_maker.env_expand()
52
51
53
52 def includeme(config):
54 def includeme(config):
53 settings = config.registry.settings
55 settings = config.registry.settings
54 _sanitize_settings_and_apply_defaults(settings)
56 _sanitize_settings_and_apply_defaults(settings)
55
57
56 # if we have enable generation of file, subscribe to event
58 # if we have enable generation of file, subscribe to event
57 if settings[config_keys.generate_authorized_keyfile]:
59 if settings[config_keys.generate_authorized_keyfile]:
58 config.add_subscriber(
60 config.add_subscriber(
59 generate_ssh_authorized_keys_file_subscriber, SshKeyFileChangeEvent)
61 generate_ssh_authorized_keys_file_subscriber, SshKeyFileChangeEvent)
@@ -1,89 +1,91 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2020 RhodeCode GmbH
3 # Copyright (C) 2016-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 import os
20 import os
21 import logging
21 import logging
22 from pyramid import compat
22 from pyramid import compat
23
23
24 # Do not use `from rhodecode import events` here, it will be overridden by the
24 # Do not use `from rhodecode import events` here, it will be overridden by the
25 # events module in this package due to pythons import mechanism.
25 # events module in this package due to pythons import mechanism.
26 from rhodecode.events import RepoGroupEvent
26 from rhodecode.events import RepoGroupEvent
27 from rhodecode.subscribers import AsyncSubprocessSubscriber
27 from rhodecode.subscribers import AsyncSubprocessSubscriber
28 from rhodecode.config.settings_maker import SettingsMaker
28 from rhodecode.config.settings_maker import SettingsMaker
29
29
30 from .events import ModDavSvnConfigChange
30 from .events import ModDavSvnConfigChange
31 from .subscribers import generate_config_subscriber
31 from .subscribers import generate_config_subscriber
32 from . import config_keys
32 from . import config_keys
33
33
34
34
35 log = logging.getLogger(__name__)
35 log = logging.getLogger(__name__)
36
36
37
37
38 def _sanitize_settings_and_apply_defaults(settings):
38 def _sanitize_settings_and_apply_defaults(settings):
39 """
39 """
40 Set defaults, convert to python types and validate settings.
40 Set defaults, convert to python types and validate settings.
41 """
41 """
42 settings_maker = SettingsMaker(settings)
42 settings_maker = SettingsMaker(settings)
43 settings_maker.make_setting(config_keys.generate_config, False, parser='bool')
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')
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')
45 settings_maker.make_setting(config_keys.reload_timeout, 10, parser='bool')
46 settings_maker.make_setting(config_keys.config_file_path, '')
46 settings_maker.make_setting(config_keys.config_file_path, '')
47 settings_maker.make_setting(config_keys.location_root, '/')
47 settings_maker.make_setting(config_keys.location_root, '/')
48 settings_maker.make_setting(config_keys.reload_command, '')
48 settings_maker.make_setting(config_keys.reload_command, '')
49 settings_maker.make_setting(config_keys.template, '')
49 settings_maker.make_setting(config_keys.template, '')
50
50
51 settings_maker.env_expand()
52
51 # Convert negative timeout values to zero.
53 # Convert negative timeout values to zero.
52 if settings[config_keys.reload_timeout] < 0:
54 if settings[config_keys.reload_timeout] < 0:
53 settings[config_keys.reload_timeout] = 0
55 settings[config_keys.reload_timeout] = 0
54
56
55 # Append path separator to location root.
57 # Append path separator to location root.
56 settings[config_keys.location_root] = _append_path_sep(
58 settings[config_keys.location_root] = _append_path_sep(
57 settings[config_keys.location_root])
59 settings[config_keys.location_root])
58
60
59 # Validate settings.
61 # Validate settings.
60 if settings[config_keys.generate_config]:
62 if settings[config_keys.generate_config]:
61 assert len(settings[config_keys.config_file_path]) > 0
63 assert len(settings[config_keys.config_file_path]) > 0
62
64
63
65
64 def _append_path_sep(path):
66 def _append_path_sep(path):
65 """
67 """
66 Append the path separator if missing.
68 Append the path separator if missing.
67 """
69 """
68 if isinstance(path, compat.string_types) and not path.endswith(os.path.sep):
70 if isinstance(path, compat.string_types) and not path.endswith(os.path.sep):
69 path += os.path.sep
71 path += os.path.sep
70 return path
72 return path
71
73
72
74
73 def includeme(config):
75 def includeme(config):
74 settings = config.registry.settings
76 settings = config.registry.settings
75 _sanitize_settings_and_apply_defaults(settings)
77 _sanitize_settings_and_apply_defaults(settings)
76
78
77 if settings[config_keys.generate_config]:
79 if settings[config_keys.generate_config]:
78 # Add subscriber to generate the Apache mod dav svn configuration on
80 # Add subscriber to generate the Apache mod dav svn configuration on
79 # repository group events.
81 # repository group events.
80 config.add_subscriber(generate_config_subscriber, RepoGroupEvent)
82 config.add_subscriber(generate_config_subscriber, RepoGroupEvent)
81
83
82 # If a reload command is set add a subscriber to execute it on
84 # If a reload command is set add a subscriber to execute it on
83 # configuration changes.
85 # configuration changes.
84 reload_cmd = settings[config_keys.reload_command]
86 reload_cmd = settings[config_keys.reload_command]
85 if reload_cmd:
87 if reload_cmd:
86 reload_timeout = settings[config_keys.reload_timeout] or None
88 reload_timeout = settings[config_keys.reload_timeout] or None
87 reload_subscriber = AsyncSubprocessSubscriber(
89 reload_subscriber = AsyncSubprocessSubscriber(
88 cmd=reload_cmd, timeout=reload_timeout)
90 cmd=reload_cmd, timeout=reload_timeout)
89 config.add_subscriber(reload_subscriber, ModDavSvnConfigChange)
91 config.add_subscriber(reload_subscriber, ModDavSvnConfigChange)
@@ -1,611 +1,614 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 collections
23 import collections
24 import tempfile
24 import tempfile
25 import time
25 import time
26 import logging.config
26 import logging.config
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.settings_maker import SettingsMaker
41 from rhodecode.config.settings_maker import SettingsMaker
42 from rhodecode.config.environment import load_pyramid_environment
42 from rhodecode.config.environment import load_pyramid_environment
43
43
44 import rhodecode.events
44 import rhodecode.events
45 from rhodecode.lib.middleware.vcs import VCSMiddleware
45 from rhodecode.lib.middleware.vcs import VCSMiddleware
46 from rhodecode.lib.request import Request
46 from rhodecode.lib.request import Request
47 from rhodecode.lib.vcs import VCSCommunicationError
47 from rhodecode.lib.vcs import VCSCommunicationError
48 from rhodecode.lib.exceptions import VCSServerUnavailable
48 from rhodecode.lib.exceptions import VCSServerUnavailable
49 from rhodecode.lib.middleware.appenlight import wrap_in_appenlight_if_enabled
49 from rhodecode.lib.middleware.appenlight import wrap_in_appenlight_if_enabled
50 from rhodecode.lib.middleware.https_fixup import HttpsFixup
50 from rhodecode.lib.middleware.https_fixup import HttpsFixup
51 from rhodecode.lib.plugins.utils import register_rhodecode_plugin
51 from rhodecode.lib.plugins.utils import register_rhodecode_plugin
52 from rhodecode.lib.utils2 import AttributeDict
52 from rhodecode.lib.utils2 import AttributeDict
53 from rhodecode.lib.exc_tracking import store_exception
53 from rhodecode.lib.exc_tracking import store_exception
54 from rhodecode.subscribers import (
54 from rhodecode.subscribers import (
55 scan_repositories_if_enabled, write_js_routes_if_enabled,
55 scan_repositories_if_enabled, write_js_routes_if_enabled,
56 write_metadata_if_needed, write_usage_data)
56 write_metadata_if_needed, write_usage_data)
57 from rhodecode.lib.statsd_client import StatsdClient
57 from rhodecode.lib.statsd_client import StatsdClient
58
58
59 log = logging.getLogger(__name__)
59 log = logging.getLogger(__name__)
60
60
61
61
62 def is_http_error(response):
62 def is_http_error(response):
63 # error which should have traceback
63 # error which should have traceback
64 return response.status_code > 499
64 return response.status_code > 499
65
65
66
66
67 def should_load_all():
67 def should_load_all():
68 """
68 """
69 Returns if all application components should be loaded. In some cases it's
69 Returns if all application components should be loaded. In some cases it's
70 desired to skip apps loading for faster shell script execution
70 desired to skip apps loading for faster shell script execution
71 """
71 """
72 ssh_cmd = os.environ.get('RC_CMD_SSH_WRAPPER')
72 ssh_cmd = os.environ.get('RC_CMD_SSH_WRAPPER')
73 if ssh_cmd:
73 if ssh_cmd:
74 return False
74 return False
75
75
76 return True
76 return True
77
77
78
78
79 def make_pyramid_app(global_config, **settings):
79 def make_pyramid_app(global_config, **settings):
80 """
80 """
81 Constructs the WSGI application based on Pyramid.
81 Constructs the WSGI application based on Pyramid.
82
82
83 Specials:
83 Specials:
84
84
85 * The application can also be integrated like a plugin via the call to
85 * The application can also be integrated like a plugin via the call to
86 `includeme`. This is accompanied with the other utility functions which
86 `includeme`. This is accompanied with the other utility functions which
87 are called. Changing this should be done with great care to not break
87 are called. Changing this should be done with great care to not break
88 cases when these fragments are assembled from another place.
88 cases when these fragments are assembled from another place.
89
89
90 """
90 """
91 start_time = time.time()
91 start_time = time.time()
92 log.info('Pyramid app config starting')
92 log.info('Pyramid app config starting')
93
93
94 sanitize_settings_and_apply_defaults(global_config, settings)
94 sanitize_settings_and_apply_defaults(global_config, settings)
95
95
96 # init and bootstrap StatsdClient
96 # init and bootstrap StatsdClient
97 StatsdClient.setup(settings)
97 StatsdClient.setup(settings)
98
98
99 config = Configurator(settings=settings)
99 config = Configurator(settings=settings)
100 # Init our statsd at very start
100 # Init our statsd at very start
101 config.registry.statsd = StatsdClient.statsd
101 config.registry.statsd = StatsdClient.statsd
102
102
103 # Apply compatibility patches
103 # Apply compatibility patches
104 patches.inspect_getargspec()
104 patches.inspect_getargspec()
105
105
106 load_pyramid_environment(global_config, settings)
106 load_pyramid_environment(global_config, settings)
107
107
108 # Static file view comes first
108 # Static file view comes first
109 includeme_first(config)
109 includeme_first(config)
110
110
111 includeme(config)
111 includeme(config)
112
112
113 pyramid_app = config.make_wsgi_app()
113 pyramid_app = config.make_wsgi_app()
114 pyramid_app = wrap_app_in_wsgi_middlewares(pyramid_app, config)
114 pyramid_app = wrap_app_in_wsgi_middlewares(pyramid_app, config)
115 pyramid_app.config = config
115 pyramid_app.config = config
116
116
117 celery_settings = get_celery_config(settings)
117 celery_settings = get_celery_config(settings)
118 config.configure_celery(celery_settings)
118 config.configure_celery(celery_settings)
119
119
120 # creating the app uses a connection - return it after we are done
120 # creating the app uses a connection - return it after we are done
121 meta.Session.remove()
121 meta.Session.remove()
122
122
123 total_time = time.time() - start_time
123 total_time = time.time() - start_time
124 log.info('Pyramid app `%s` created and configured in %.2fs',
124 log.info('Pyramid app `%s` created and configured in %.2fs',
125 getattr(pyramid_app, 'func_name', 'pyramid_app'), total_time)
125 getattr(pyramid_app, 'func_name', 'pyramid_app'), total_time)
126 return pyramid_app
126 return pyramid_app
127
127
128
128
129 def get_celery_config(settings):
129 def get_celery_config(settings):
130 """
130 """
131 Converts basic ini configuration into celery 4.X options
131 Converts basic ini configuration into celery 4.X options
132 """
132 """
133
133
134 def key_converter(key_name):
134 def key_converter(key_name):
135 pref = 'celery.'
135 pref = 'celery.'
136 if key_name.startswith(pref):
136 if key_name.startswith(pref):
137 return key_name[len(pref):].replace('.', '_').lower()
137 return key_name[len(pref):].replace('.', '_').lower()
138
138
139 def type_converter(parsed_key, value):
139 def type_converter(parsed_key, value):
140 # cast to int
140 # cast to int
141 if value.isdigit():
141 if value.isdigit():
142 return int(value)
142 return int(value)
143
143
144 # cast to bool
144 # cast to bool
145 if value.lower() in ['true', 'false', 'True', 'False']:
145 if value.lower() in ['true', 'false', 'True', 'False']:
146 return value.lower() == 'true'
146 return value.lower() == 'true'
147 return value
147 return value
148
148
149 celery_config = {}
149 celery_config = {}
150 for k, v in settings.items():
150 for k, v in settings.items():
151 pref = 'celery.'
151 pref = 'celery.'
152 if k.startswith(pref):
152 if k.startswith(pref):
153 celery_config[key_converter(k)] = type_converter(key_converter(k), v)
153 celery_config[key_converter(k)] = type_converter(key_converter(k), v)
154
154
155 # TODO:rethink if we want to support celerybeat based file config, probably NOT
155 # TODO:rethink if we want to support celerybeat based file config, probably NOT
156 # beat_config = {}
156 # beat_config = {}
157 # for section in parser.sections():
157 # for section in parser.sections():
158 # if section.startswith('celerybeat:'):
158 # if section.startswith('celerybeat:'):
159 # name = section.split(':', 1)[1]
159 # name = section.split(':', 1)[1]
160 # beat_config[name] = get_beat_config(parser, section)
160 # beat_config[name] = get_beat_config(parser, section)
161
161
162 # final compose of settings
162 # final compose of settings
163 celery_settings = {}
163 celery_settings = {}
164
164
165 if celery_config:
165 if celery_config:
166 celery_settings.update(celery_config)
166 celery_settings.update(celery_config)
167 # if beat_config:
167 # if beat_config:
168 # celery_settings.update({'beat_schedule': beat_config})
168 # celery_settings.update({'beat_schedule': beat_config})
169
169
170 return celery_settings
170 return celery_settings
171
171
172
172
173 def not_found_view(request):
173 def not_found_view(request):
174 """
174 """
175 This creates the view which should be registered as not-found-view to
175 This creates the view which should be registered as not-found-view to
176 pyramid.
176 pyramid.
177 """
177 """
178
178
179 if not getattr(request, 'vcs_call', None):
179 if not getattr(request, 'vcs_call', None):
180 # handle like regular case with our error_handler
180 # handle like regular case with our error_handler
181 return error_handler(HTTPNotFound(), request)
181 return error_handler(HTTPNotFound(), request)
182
182
183 # handle not found view as a vcs call
183 # handle not found view as a vcs call
184 settings = request.registry.settings
184 settings = request.registry.settings
185 ae_client = getattr(request, 'ae_client', None)
185 ae_client = getattr(request, 'ae_client', None)
186 vcs_app = VCSMiddleware(
186 vcs_app = VCSMiddleware(
187 HTTPNotFound(), request.registry, settings,
187 HTTPNotFound(), request.registry, settings,
188 appenlight_client=ae_client)
188 appenlight_client=ae_client)
189
189
190 return wsgiapp(vcs_app)(None, request)
190 return wsgiapp(vcs_app)(None, request)
191
191
192
192
193 def error_handler(exception, request):
193 def error_handler(exception, request):
194 import rhodecode
194 import rhodecode
195 from rhodecode.lib import helpers
195 from rhodecode.lib import helpers
196 from rhodecode.lib.utils2 import str2bool
196 from rhodecode.lib.utils2 import str2bool
197
197
198 rhodecode_title = rhodecode.CONFIG.get('rhodecode_title') or 'RhodeCode'
198 rhodecode_title = rhodecode.CONFIG.get('rhodecode_title') or 'RhodeCode'
199
199
200 base_response = HTTPInternalServerError()
200 base_response = HTTPInternalServerError()
201 # prefer original exception for the response since it may have headers set
201 # prefer original exception for the response since it may have headers set
202 if isinstance(exception, HTTPException):
202 if isinstance(exception, HTTPException):
203 base_response = exception
203 base_response = exception
204 elif isinstance(exception, VCSCommunicationError):
204 elif isinstance(exception, VCSCommunicationError):
205 base_response = VCSServerUnavailable()
205 base_response = VCSServerUnavailable()
206
206
207 if is_http_error(base_response):
207 if is_http_error(base_response):
208 log.exception(
208 log.exception(
209 'error occurred handling this request for path: %s', request.path)
209 'error occurred handling this request for path: %s', request.path)
210
210
211 error_explanation = base_response.explanation or str(base_response)
211 error_explanation = base_response.explanation or str(base_response)
212 if base_response.status_code == 404:
212 if base_response.status_code == 404:
213 error_explanation += " Optionally you don't have permission to access this page."
213 error_explanation += " Optionally you don't have permission to access this page."
214 c = AttributeDict()
214 c = AttributeDict()
215 c.error_message = base_response.status
215 c.error_message = base_response.status
216 c.error_explanation = error_explanation
216 c.error_explanation = error_explanation
217 c.visual = AttributeDict()
217 c.visual = AttributeDict()
218
218
219 c.visual.rhodecode_support_url = (
219 c.visual.rhodecode_support_url = (
220 request.registry.settings.get('rhodecode_support_url') or
220 request.registry.settings.get('rhodecode_support_url') or
221 request.route_url('rhodecode_support')
221 request.route_url('rhodecode_support')
222 )
222 )
223 c.redirect_time = 0
223 c.redirect_time = 0
224 c.rhodecode_name = rhodecode_title
224 c.rhodecode_name = rhodecode_title
225 if not c.rhodecode_name:
225 if not c.rhodecode_name:
226 c.rhodecode_name = 'Rhodecode'
226 c.rhodecode_name = 'Rhodecode'
227
227
228 c.causes = []
228 c.causes = []
229 if is_http_error(base_response):
229 if is_http_error(base_response):
230 c.causes.append('Server is overloaded.')
230 c.causes.append('Server is overloaded.')
231 c.causes.append('Server database connection is lost.')
231 c.causes.append('Server database connection is lost.')
232 c.causes.append('Server expected unhandled error.')
232 c.causes.append('Server expected unhandled error.')
233
233
234 if hasattr(base_response, 'causes'):
234 if hasattr(base_response, 'causes'):
235 c.causes = base_response.causes
235 c.causes = base_response.causes
236
236
237 c.messages = helpers.flash.pop_messages(request=request)
237 c.messages = helpers.flash.pop_messages(request=request)
238
238
239 exc_info = sys.exc_info()
239 exc_info = sys.exc_info()
240 c.exception_id = id(exc_info)
240 c.exception_id = id(exc_info)
241 c.show_exception_id = isinstance(base_response, VCSServerUnavailable) \
241 c.show_exception_id = isinstance(base_response, VCSServerUnavailable) \
242 or base_response.status_code > 499
242 or base_response.status_code > 499
243 c.exception_id_url = request.route_url(
243 c.exception_id_url = request.route_url(
244 'admin_settings_exception_tracker_show', exception_id=c.exception_id)
244 'admin_settings_exception_tracker_show', exception_id=c.exception_id)
245
245
246 if c.show_exception_id:
246 if c.show_exception_id:
247 store_exception(c.exception_id, exc_info)
247 store_exception(c.exception_id, exc_info)
248 c.exception_debug = str2bool(rhodecode.CONFIG.get('debug'))
248 c.exception_debug = str2bool(rhodecode.CONFIG.get('debug'))
249 c.exception_config_ini = rhodecode.CONFIG.get('__file__')
249 c.exception_config_ini = rhodecode.CONFIG.get('__file__')
250
250
251 response = render_to_response(
251 response = render_to_response(
252 '/errors/error_document.mako', {'c': c, 'h': helpers}, request=request,
252 '/errors/error_document.mako', {'c': c, 'h': helpers}, request=request,
253 response=base_response)
253 response=base_response)
254
254
255 statsd = request.registry.statsd
255 statsd = request.registry.statsd
256 if statsd and base_response.status_code > 499:
256 if statsd and base_response.status_code > 499:
257 exc_type = "{}.{}".format(exception.__class__.__module__, exception.__class__.__name__)
257 exc_type = "{}.{}".format(exception.__class__.__module__, exception.__class__.__name__)
258 statsd.incr('rhodecode_exception_total',
258 statsd.incr('rhodecode_exception_total',
259 tags=["exc_source:web",
259 tags=["exc_source:web",
260 "http_code:{}".format(base_response.status_code),
260 "http_code:{}".format(base_response.status_code),
261 "type:{}".format(exc_type)])
261 "type:{}".format(exc_type)])
262
262
263 return response
263 return response
264
264
265
265
266 def includeme_first(config):
266 def includeme_first(config):
267 # redirect automatic browser favicon.ico requests to correct place
267 # redirect automatic browser favicon.ico requests to correct place
268 def favicon_redirect(context, request):
268 def favicon_redirect(context, request):
269 return HTTPFound(
269 return HTTPFound(
270 request.static_path('rhodecode:public/images/favicon.ico'))
270 request.static_path('rhodecode:public/images/favicon.ico'))
271
271
272 config.add_view(favicon_redirect, route_name='favicon')
272 config.add_view(favicon_redirect, route_name='favicon')
273 config.add_route('favicon', '/favicon.ico')
273 config.add_route('favicon', '/favicon.ico')
274
274
275 def robots_redirect(context, request):
275 def robots_redirect(context, request):
276 return HTTPFound(
276 return HTTPFound(
277 request.static_path('rhodecode:public/robots.txt'))
277 request.static_path('rhodecode:public/robots.txt'))
278
278
279 config.add_view(robots_redirect, route_name='robots')
279 config.add_view(robots_redirect, route_name='robots')
280 config.add_route('robots', '/robots.txt')
280 config.add_route('robots', '/robots.txt')
281
281
282 config.add_static_view(
282 config.add_static_view(
283 '_static/deform', 'deform:static')
283 '_static/deform', 'deform:static')
284 config.add_static_view(
284 config.add_static_view(
285 '_static/rhodecode', path='rhodecode:public', cache_max_age=3600 * 24)
285 '_static/rhodecode', path='rhodecode:public', cache_max_age=3600 * 24)
286
286
287
287
288 def includeme(config, auth_resources=None):
288 def includeme(config, auth_resources=None):
289 from rhodecode.lib.celerylib.loader import configure_celery
289 from rhodecode.lib.celerylib.loader import configure_celery
290 log.debug('Initializing main includeme from %s', os.path.basename(__file__))
290 log.debug('Initializing main includeme from %s', os.path.basename(__file__))
291 settings = config.registry.settings
291 settings = config.registry.settings
292 config.set_request_factory(Request)
292 config.set_request_factory(Request)
293
293
294 # plugin information
294 # plugin information
295 config.registry.rhodecode_plugins = collections.OrderedDict()
295 config.registry.rhodecode_plugins = collections.OrderedDict()
296
296
297 config.add_directive(
297 config.add_directive(
298 'register_rhodecode_plugin', register_rhodecode_plugin)
298 'register_rhodecode_plugin', register_rhodecode_plugin)
299
299
300 config.add_directive('configure_celery', configure_celery)
300 config.add_directive('configure_celery', configure_celery)
301
301
302 if settings.get('appenlight', False):
302 if settings.get('appenlight', False):
303 config.include('appenlight_client.ext.pyramid_tween')
303 config.include('appenlight_client.ext.pyramid_tween')
304
304
305 load_all = should_load_all()
305 load_all = should_load_all()
306
306
307 # Includes which are required. The application would fail without them.
307 # Includes which are required. The application would fail without them.
308 config.include('pyramid_mako')
308 config.include('pyramid_mako')
309 config.include('rhodecode.lib.rc_beaker')
309 config.include('rhodecode.lib.rc_beaker')
310 config.include('rhodecode.lib.rc_cache')
310 config.include('rhodecode.lib.rc_cache')
311 config.include('rhodecode.apps._base.navigation')
311 config.include('rhodecode.apps._base.navigation')
312 config.include('rhodecode.apps._base.subscribers')
312 config.include('rhodecode.apps._base.subscribers')
313 config.include('rhodecode.tweens')
313 config.include('rhodecode.tweens')
314 config.include('rhodecode.authentication')
314 config.include('rhodecode.authentication')
315
315
316 if load_all:
316 if load_all:
317 ce_auth_resources = [
317 ce_auth_resources = [
318 'rhodecode.authentication.plugins.auth_crowd',
318 'rhodecode.authentication.plugins.auth_crowd',
319 'rhodecode.authentication.plugins.auth_headers',
319 'rhodecode.authentication.plugins.auth_headers',
320 'rhodecode.authentication.plugins.auth_jasig_cas',
320 'rhodecode.authentication.plugins.auth_jasig_cas',
321 'rhodecode.authentication.plugins.auth_ldap',
321 'rhodecode.authentication.plugins.auth_ldap',
322 'rhodecode.authentication.plugins.auth_pam',
322 'rhodecode.authentication.plugins.auth_pam',
323 'rhodecode.authentication.plugins.auth_rhodecode',
323 'rhodecode.authentication.plugins.auth_rhodecode',
324 'rhodecode.authentication.plugins.auth_token',
324 'rhodecode.authentication.plugins.auth_token',
325 ]
325 ]
326
326
327 # load CE authentication plugins
327 # load CE authentication plugins
328
328
329 if auth_resources:
329 if auth_resources:
330 ce_auth_resources.extend(auth_resources)
330 ce_auth_resources.extend(auth_resources)
331
331
332 for resource in ce_auth_resources:
332 for resource in ce_auth_resources:
333 config.include(resource)
333 config.include(resource)
334
334
335 # Auto discover authentication plugins and include their configuration.
335 # Auto discover authentication plugins and include their configuration.
336 if asbool(settings.get('auth_plugin.import_legacy_plugins', 'true')):
336 if asbool(settings.get('auth_plugin.import_legacy_plugins', 'true')):
337 from rhodecode.authentication import discover_legacy_plugins
337 from rhodecode.authentication import discover_legacy_plugins
338 discover_legacy_plugins(config)
338 discover_legacy_plugins(config)
339
339
340 # apps
340 # apps
341 if load_all:
341 if load_all:
342 config.include('rhodecode.api')
342 config.include('rhodecode.api')
343 config.include('rhodecode.apps._base')
343 config.include('rhodecode.apps._base')
344 config.include('rhodecode.apps.hovercards')
344 config.include('rhodecode.apps.hovercards')
345 config.include('rhodecode.apps.ops')
345 config.include('rhodecode.apps.ops')
346 config.include('rhodecode.apps.channelstream')
346 config.include('rhodecode.apps.channelstream')
347 config.include('rhodecode.apps.file_store')
347 config.include('rhodecode.apps.file_store')
348 config.include('rhodecode.apps.admin')
348 config.include('rhodecode.apps.admin')
349 config.include('rhodecode.apps.login')
349 config.include('rhodecode.apps.login')
350 config.include('rhodecode.apps.home')
350 config.include('rhodecode.apps.home')
351 config.include('rhodecode.apps.journal')
351 config.include('rhodecode.apps.journal')
352
352
353 config.include('rhodecode.apps.repository')
353 config.include('rhodecode.apps.repository')
354 config.include('rhodecode.apps.repo_group')
354 config.include('rhodecode.apps.repo_group')
355 config.include('rhodecode.apps.user_group')
355 config.include('rhodecode.apps.user_group')
356 config.include('rhodecode.apps.search')
356 config.include('rhodecode.apps.search')
357 config.include('rhodecode.apps.user_profile')
357 config.include('rhodecode.apps.user_profile')
358 config.include('rhodecode.apps.user_group_profile')
358 config.include('rhodecode.apps.user_group_profile')
359 config.include('rhodecode.apps.my_account')
359 config.include('rhodecode.apps.my_account')
360 config.include('rhodecode.apps.gist')
360 config.include('rhodecode.apps.gist')
361
361
362 config.include('rhodecode.apps.svn_support')
362 config.include('rhodecode.apps.svn_support')
363 config.include('rhodecode.apps.ssh_support')
363 config.include('rhodecode.apps.ssh_support')
364 config.include('rhodecode.apps.debug_style')
364 config.include('rhodecode.apps.debug_style')
365
365
366 if load_all:
366 if load_all:
367 config.include('rhodecode.integrations')
367 config.include('rhodecode.integrations')
368
368
369 config.add_route('rhodecode_support', 'https://rhodecode.com/help/', static=True)
369 config.add_route('rhodecode_support', 'https://rhodecode.com/help/', static=True)
370 config.add_translation_dirs('rhodecode:i18n/')
370 config.add_translation_dirs('rhodecode:i18n/')
371 settings['default_locale_name'] = settings.get('lang', 'en')
371 settings['default_locale_name'] = settings.get('lang', 'en')
372
372
373 # Add subscribers.
373 # Add subscribers.
374 if load_all:
374 if load_all:
375 config.add_subscriber(scan_repositories_if_enabled,
375 config.add_subscriber(scan_repositories_if_enabled,
376 pyramid.events.ApplicationCreated)
376 pyramid.events.ApplicationCreated)
377 config.add_subscriber(write_metadata_if_needed,
377 config.add_subscriber(write_metadata_if_needed,
378 pyramid.events.ApplicationCreated)
378 pyramid.events.ApplicationCreated)
379 config.add_subscriber(write_usage_data,
379 config.add_subscriber(write_usage_data,
380 pyramid.events.ApplicationCreated)
380 pyramid.events.ApplicationCreated)
381 config.add_subscriber(write_js_routes_if_enabled,
381 config.add_subscriber(write_js_routes_if_enabled,
382 pyramid.events.ApplicationCreated)
382 pyramid.events.ApplicationCreated)
383
383
384 # request custom methods
384 # request custom methods
385 config.add_request_method(
385 config.add_request_method(
386 'rhodecode.lib.partial_renderer.get_partial_renderer',
386 'rhodecode.lib.partial_renderer.get_partial_renderer',
387 'get_partial_renderer')
387 'get_partial_renderer')
388
388
389 config.add_request_method(
389 config.add_request_method(
390 'rhodecode.lib.request_counter.get_request_counter',
390 'rhodecode.lib.request_counter.get_request_counter',
391 'request_count')
391 'request_count')
392
392
393 # Set the authorization policy.
393 # Set the authorization policy.
394 authz_policy = ACLAuthorizationPolicy()
394 authz_policy = ACLAuthorizationPolicy()
395 config.set_authorization_policy(authz_policy)
395 config.set_authorization_policy(authz_policy)
396
396
397 # Set the default renderer for HTML templates to mako.
397 # Set the default renderer for HTML templates to mako.
398 config.add_mako_renderer('.html')
398 config.add_mako_renderer('.html')
399
399
400 config.add_renderer(
400 config.add_renderer(
401 name='json_ext',
401 name='json_ext',
402 factory='rhodecode.lib.ext_json_renderer.pyramid_ext_json')
402 factory='rhodecode.lib.ext_json_renderer.pyramid_ext_json')
403
403
404 config.add_renderer(
404 config.add_renderer(
405 name='string_html',
405 name='string_html',
406 factory='rhodecode.lib.string_renderer.html')
406 factory='rhodecode.lib.string_renderer.html')
407
407
408 # include RhodeCode plugins
408 # include RhodeCode plugins
409 includes = aslist(settings.get('rhodecode.includes', []))
409 includes = aslist(settings.get('rhodecode.includes', []))
410 for inc in includes:
410 for inc in includes:
411 config.include(inc)
411 config.include(inc)
412
412
413 # custom not found view, if our pyramid app doesn't know how to handle
413 # custom not found view, if our pyramid app doesn't know how to handle
414 # the request pass it to potential VCS handling ap
414 # the request pass it to potential VCS handling ap
415 config.add_notfound_view(not_found_view)
415 config.add_notfound_view(not_found_view)
416 if not settings.get('debugtoolbar.enabled', False):
416 if not settings.get('debugtoolbar.enabled', False):
417 # disabled debugtoolbar handle all exceptions via the error_handlers
417 # disabled debugtoolbar handle all exceptions via the error_handlers
418 config.add_view(error_handler, context=Exception)
418 config.add_view(error_handler, context=Exception)
419
419
420 # all errors including 403/404/50X
420 # all errors including 403/404/50X
421 config.add_view(error_handler, context=HTTPError)
421 config.add_view(error_handler, context=HTTPError)
422
422
423
423
424 def wrap_app_in_wsgi_middlewares(pyramid_app, config):
424 def wrap_app_in_wsgi_middlewares(pyramid_app, config):
425 """
425 """
426 Apply outer WSGI middlewares around the application.
426 Apply outer WSGI middlewares around the application.
427 """
427 """
428 registry = config.registry
428 registry = config.registry
429 settings = registry.settings
429 settings = registry.settings
430
430
431 # enable https redirects based on HTTP_X_URL_SCHEME set by proxy
431 # enable https redirects based on HTTP_X_URL_SCHEME set by proxy
432 pyramid_app = HttpsFixup(pyramid_app, settings)
432 pyramid_app = HttpsFixup(pyramid_app, settings)
433
433
434 pyramid_app, _ae_client = wrap_in_appenlight_if_enabled(
434 pyramid_app, _ae_client = wrap_in_appenlight_if_enabled(
435 pyramid_app, settings)
435 pyramid_app, settings)
436 registry.ae_client = _ae_client
436 registry.ae_client = _ae_client
437
437
438 if settings['gzip_responses']:
438 if settings['gzip_responses']:
439 pyramid_app = make_gzip_middleware(
439 pyramid_app = make_gzip_middleware(
440 pyramid_app, settings, compress_level=1)
440 pyramid_app, settings, compress_level=1)
441
441
442 # this should be the outer most middleware in the wsgi stack since
442 # this should be the outer most middleware in the wsgi stack since
443 # middleware like Routes make database calls
443 # middleware like Routes make database calls
444 def pyramid_app_with_cleanup(environ, start_response):
444 def pyramid_app_with_cleanup(environ, start_response):
445 try:
445 try:
446 return pyramid_app(environ, start_response)
446 return pyramid_app(environ, start_response)
447 finally:
447 finally:
448 # Dispose current database session and rollback uncommitted
448 # Dispose current database session and rollback uncommitted
449 # transactions.
449 # transactions.
450 meta.Session.remove()
450 meta.Session.remove()
451
451
452 # In a single threaded mode server, on non sqlite db we should have
452 # In a single threaded mode server, on non sqlite db we should have
453 # '0 Current Checked out connections' at the end of a request,
453 # '0 Current Checked out connections' at the end of a request,
454 # if not, then something, somewhere is leaving a connection open
454 # if not, then something, somewhere is leaving a connection open
455 pool = meta.Base.metadata.bind.engine.pool
455 pool = meta.Base.metadata.bind.engine.pool
456 log.debug('sa pool status: %s', pool.status())
456 log.debug('sa pool status: %s', pool.status())
457 log.debug('Request processing finalized')
457 log.debug('Request processing finalized')
458
458
459 return pyramid_app_with_cleanup
459 return pyramid_app_with_cleanup
460
460
461
461
462 def sanitize_settings_and_apply_defaults(global_config, settings):
462 def sanitize_settings_and_apply_defaults(global_config, settings):
463 """
463 """
464 Applies settings defaults and does all type conversion.
464 Applies settings defaults and does all type conversion.
465
465
466 We would move all settings parsing and preparation into this place, so that
466 We would move all settings parsing and preparation into this place, so that
467 we have only one place left which deals with this part. The remaining parts
467 we have only one place left which deals with this part. The remaining parts
468 of the application would start to rely fully on well prepared settings.
468 of the application would start to rely fully on well prepared settings.
469
469
470 This piece would later be split up per topic to avoid a big fat monster
470 This piece would later be split up per topic to avoid a big fat monster
471 function.
471 function.
472 """
472 """
473
473
474 global_settings_maker = SettingsMaker(global_config)
474 global_settings_maker = SettingsMaker(global_config)
475 global_settings_maker.make_setting('debug', default=False, parser='bool')
475 global_settings_maker.make_setting('debug', default=False, parser='bool')
476 debug_enabled = asbool(global_config.get('debug'))
476 debug_enabled = asbool(global_config.get('debug'))
477
477
478 settings_maker = SettingsMaker(settings)
478 settings_maker = SettingsMaker(settings)
479
479
480 settings_maker.make_setting(
480 settings_maker.make_setting(
481 'logging.autoconfigure',
481 'logging.autoconfigure',
482 default=True,
482 default=True,
483 parser='bool')
483 parser='bool')
484
484
485 logging_conf = os.path.join(os.path.dirname(global_config.get('__file__')), 'logging.ini')
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')
486 settings_maker.enable_logging(logging_conf, level='INFO' if debug_enabled else 'DEBUG')
487
487
488 # Default includes, possible to change as a user
488 # Default includes, possible to change as a user
489 pyramid_includes = settings_maker.make_setting('pyramid.includes', [], parser='list:newline')
489 pyramid_includes = settings_maker.make_setting('pyramid.includes', [], parser='list:newline')
490 log.debug(
490 log.debug(
491 "Using the following pyramid.includes: %s",
491 "Using the following pyramid.includes: %s",
492 pyramid_includes)
492 pyramid_includes)
493
493
494 settings_maker.make_setting('rhodecode.edition', 'Community Edition')
494 settings_maker.make_setting('rhodecode.edition', 'Community Edition')
495 settings_maker.make_setting('rhodecode.edition_id', 'CE')
495 settings_maker.make_setting('rhodecode.edition_id', 'CE')
496
496
497 if 'mako.default_filters' not in settings:
497 if 'mako.default_filters' not in settings:
498 # set custom default filters if we don't have it defined
498 # set custom default filters if we don't have it defined
499 settings['mako.imports'] = 'from rhodecode.lib.base import h_filter'
499 settings['mako.imports'] = 'from rhodecode.lib.base import h_filter'
500 settings['mako.default_filters'] = 'h_filter'
500 settings['mako.default_filters'] = 'h_filter'
501
501
502 if 'mako.directories' not in settings:
502 if 'mako.directories' not in settings:
503 mako_directories = settings.setdefault('mako.directories', [
503 mako_directories = settings.setdefault('mako.directories', [
504 # Base templates of the original application
504 # Base templates of the original application
505 'rhodecode:templates',
505 'rhodecode:templates',
506 ])
506 ])
507 log.debug(
507 log.debug(
508 "Using the following Mako template directories: %s",
508 "Using the following Mako template directories: %s",
509 mako_directories)
509 mako_directories)
510
510
511 # NOTE(marcink): fix redis requirement for schema of connection since 3.X
511 # NOTE(marcink): fix redis requirement for schema of connection since 3.X
512 if 'beaker.session.type' in settings and settings['beaker.session.type'] == 'ext:redis':
512 if 'beaker.session.type' in settings and settings['beaker.session.type'] == 'ext:redis':
513 raw_url = settings['beaker.session.url']
513 raw_url = settings['beaker.session.url']
514 if not raw_url.startswith(('redis://', 'rediss://', 'unix://')):
514 if not raw_url.startswith(('redis://', 'rediss://', 'unix://')):
515 settings['beaker.session.url'] = 'redis://' + raw_url
515 settings['beaker.session.url'] = 'redis://' + raw_url
516
516
517 settings_maker.make_setting('__file__', global_config.get('__file__'))
517 settings_maker.make_setting('__file__', global_config.get('__file__'))
518
518
519 # TODO: johbo: Re-think this, usually the call to config.include
519 # TODO: johbo: Re-think this, usually the call to config.include
520 # should allow to pass in a prefix.
520 # should allow to pass in a prefix.
521 settings_maker.make_setting('rhodecode.api.url', '/_admin/api')
521 settings_maker.make_setting('rhodecode.api.url', '/_admin/api')
522
522
523 # Sanitize generic settings.
523 # Sanitize generic settings.
524 settings_maker.make_setting('default_encoding', 'UTF-8', parser='list')
524 settings_maker.make_setting('default_encoding', 'UTF-8', parser='list')
525 settings_maker.make_setting('is_test', False, parser='bool')
525 settings_maker.make_setting('is_test', False, parser='bool')
526 settings_maker.make_setting('gzip_responses', False, parser='bool')
526 settings_maker.make_setting('gzip_responses', False, parser='bool')
527
527
528 # statsd
529 settings_maker.make_setting('statsd.enabled', False, parser='bool')
530 settings_maker.make_setting('statsd.statsd_host', '0.0.0.0')
531 settings_maker.make_setting('statsd.statsd_port', 8125, parser='int')
532 settings_maker.make_setting('statsd.statsd_prefix', '')
533 settings_maker.make_setting('statsd.statsd_ipv6', False, parser='bool')
534
528 settings_maker.make_setting('vcs.svn.compatible_version', '')
535 settings_maker.make_setting('vcs.svn.compatible_version', '')
529 settings_maker.make_setting('vcs.hooks.protocol', 'http')
536 settings_maker.make_setting('vcs.hooks.protocol', 'http')
530 settings_maker.make_setting('vcs.hooks.host', '127.0.0.1')
537 settings_maker.make_setting('vcs.hooks.host', '127.0.0.1')
531 settings_maker.make_setting('vcs.scm_app_implementation', 'http')
538 settings_maker.make_setting('vcs.scm_app_implementation', 'http')
532 settings_maker.make_setting('vcs.server', '')
539 settings_maker.make_setting('vcs.server', '')
533 settings_maker.make_setting('vcs.server.protocol', 'http')
540 settings_maker.make_setting('vcs.server.protocol', 'http')
534 settings_maker.make_setting('startup.import_repos', 'false', parser='bool')
541 settings_maker.make_setting('startup.import_repos', 'false', parser='bool')
535 settings_maker.make_setting('vcs.hooks.direct_calls', 'false', parser='bool')
542 settings_maker.make_setting('vcs.hooks.direct_calls', 'false', parser='bool')
536 settings_maker.make_setting('vcs.server.enable', 'true', parser='bool')
543 settings_maker.make_setting('vcs.server.enable', 'true', parser='bool')
537 settings_maker.make_setting('vcs.start_server', 'false', parser='bool')
544 settings_maker.make_setting('vcs.start_server', 'false', parser='bool')
538 settings_maker.make_setting('vcs.backends', 'hg, git, svn', parser='list')
545 settings_maker.make_setting('vcs.backends', 'hg, git, svn', parser='list')
539 settings_maker.make_setting('vcs.connection_timeout', 3600, parser='int')
546 settings_maker.make_setting('vcs.connection_timeout', 3600, parser='int')
540
547
541 settings_maker.make_setting('vcs.methods.cache', True, parser='bool')
548 settings_maker.make_setting('vcs.methods.cache', True, parser='bool')
542
549
543 # Support legacy values of vcs.scm_app_implementation. Legacy
550 # Support legacy values of vcs.scm_app_implementation. Legacy
544 # configurations may use 'rhodecode.lib.middleware.utils.scm_app_http', or
551 # 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'.
552 # disabled since 4.13 'vcsserver.scm_app' which is now mapped to 'http'.
546 scm_app_impl = settings['vcs.scm_app_implementation']
553 scm_app_impl = settings['vcs.scm_app_implementation']
547 if scm_app_impl in ['rhodecode.lib.middleware.utils.scm_app_http', 'vcsserver.scm_app']:
554 if scm_app_impl in ['rhodecode.lib.middleware.utils.scm_app_http', 'vcsserver.scm_app']:
548 settings['vcs.scm_app_implementation'] = 'http'
555 settings['vcs.scm_app_implementation'] = 'http'
549
556
550 settings_maker.make_setting('appenlight', False, parser='bool')
557 settings_maker.make_setting('appenlight', False, parser='bool')
551
558
552 _sanitize_cache_settings(settings)
553
554 # configure instance id
555 config_utils.set_instance_id(settings)
556
557 return settings
558
559
560 def _sanitize_cache_settings(settings):
561 settings_maker = SettingsMaker(settings)
562
563 temp_store = tempfile.gettempdir()
559 temp_store = tempfile.gettempdir()
564 default_cache_dir = os.path.join(temp_store, 'rc_cache')
560 default_cache_dir = os.path.join(temp_store, 'rc_cache')
565
561
566 # save default, cache dir, and use it for all backends later.
562 # save default, cache dir, and use it for all backends later.
567 default_cache_dir = settings_maker.make_setting(
563 default_cache_dir = settings_maker.make_setting(
568 'cache_dir',
564 'cache_dir',
569 default=default_cache_dir, default_when_empty=True,
565 default=default_cache_dir, default_when_empty=True,
570 parser='dir:ensured')
566 parser='dir:ensured')
571
567
572 # exception store cache
568 # exception store cache
573 settings_maker.make_setting(
569 settings_maker.make_setting(
574 'exception_tracker.store_path',
570 'exception_tracker.store_path',
575 default=os.path.join(default_cache_dir, 'exc_store'), default_when_empty=True,
571 default=os.path.join(default_cache_dir, 'exc_store'), default_when_empty=True,
576 parser='dir:ensured'
572 parser='dir:ensured'
577 )
573 )
578
574
579 settings_maker.make_setting(
575 settings_maker.make_setting(
580 'celerybeat-schedule.path',
576 'celerybeat-schedule.path',
581 default=os.path.join(default_cache_dir, 'celerybeat_schedule', 'celerybeat-schedule.db'), default_when_empty=True,
577 default=os.path.join(default_cache_dir, 'celerybeat_schedule', 'celerybeat-schedule.db'), default_when_empty=True,
582 parser='file:ensured'
578 parser='file:ensured'
583 )
579 )
584
580
585 settings_maker.make_setting('exception_tracker.send_email', False, parser='bool')
581 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)
582 settings_maker.make_setting('exception_tracker.email_prefix', '[RHODECODE ERROR]', default_when_empty=True)
587
583
588 # cache_perms
584 # cache_perms
589 settings_maker.make_setting('rc_cache.cache_perms.backend', 'dogpile.cache.rc.file_namespace')
585 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')
586 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'))
587 settings_maker.make_setting('rc_cache.cache_perms.arguments.filename', os.path.join(default_cache_dir, 'rhodecode_cache_perms.db'))
592
588
593 # cache_repo
589 # cache_repo
594 settings_maker.make_setting('rc_cache.cache_repo.backend', 'dogpile.cache.rc.file_namespace')
590 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')
591 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'))
592 settings_maker.make_setting('rc_cache.cache_repo.arguments.filename', os.path.join(default_cache_dir, 'rhodecode_cache_repo.db'))
597
593
598 # cache_license
594 # cache_license
599 settings_maker.make_setting('rc_cache.cache_license.backend', 'dogpile.cache.rc.file_namespace')
595 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')
596 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'))
597 settings_maker.make_setting('rc_cache.cache_license.arguments.filename', os.path.join(default_cache_dir, 'rhodecode_cache_license.db'))
602
598
603 # cache_repo_longterm memory, 96H
599 # cache_repo_longterm memory, 96H
604 settings_maker.make_setting('rc_cache.cache_repo_longterm.backend', 'dogpile.cache.rc.memory_lru')
600 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')
601 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')
602 settings_maker.make_setting('rc_cache.cache_repo_longterm.max_size', 10000, parser='int')
607
603
608 # sql_cache_short
604 # sql_cache_short
609 settings_maker.make_setting('rc_cache.sql_cache_short.backend', 'dogpile.cache.rc.memory_lru')
605 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')
606 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')
607 settings_maker.make_setting('rc_cache.sql_cache_short.max_size', 10000, parser='int')
608
609 settings_maker.env_expand()
610
611 # configure instance id
612 config_utils.set_instance_id(settings)
613
614 return settings
@@ -1,182 +1,204 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 textwrap
22 import textwrap
23 import string
23 import string
24 import functools
24 import functools
25 import logging
25 import logging
26 import tempfile
26 import tempfile
27 import logging.config
27 import logging.config
28 log = logging.getLogger(__name__)
28 log = logging.getLogger(__name__)
29
29
30 set_keys = {}
31
30
32
31 def str2bool(_str):
33 def str2bool(_str):
32 """
34 """
33 returns True/False value from given string, it tries to translate the
35 returns True/False value from given string, it tries to translate the
34 string into boolean
36 string into boolean
35
37
36 :param _str: string value to translate into boolean
38 :param _str: string value to translate into boolean
37 :rtype: boolean
39 :rtype: boolean
38 :returns: boolean from given string
40 :returns: boolean from given string
39 """
41 """
40 if _str is None:
42 if _str is None:
41 return False
43 return False
42 if _str in (True, False):
44 if _str in (True, False):
43 return _str
45 return _str
44 _str = str(_str).strip().lower()
46 _str = str(_str).strip().lower()
45 return _str in ('t', 'true', 'y', 'yes', 'on', '1')
47 return _str in ('t', 'true', 'y', 'yes', 'on', '1')
46
48
47
49
48 def aslist(obj, sep=None, strip=True):
50 def aslist(obj, sep=None, strip=True):
49 """
51 """
50 Returns given string separated by sep as list
52 Returns given string separated by sep as list
51
53
52 :param obj:
54 :param obj:
53 :param sep:
55 :param sep:
54 :param strip:
56 :param strip:
55 """
57 """
56 if isinstance(obj, (basestring,)):
58 if isinstance(obj, (basestring,)):
57 if obj in ['', ""]:
59 if obj in ['', ""]:
58 return []
60 return []
59
61
60 lst = obj.split(sep)
62 lst = obj.split(sep)
61 if strip:
63 if strip:
62 lst = [v.strip() for v in lst]
64 lst = [v.strip() for v in lst]
63 return lst
65 return lst
64 elif isinstance(obj, (list, tuple)):
66 elif isinstance(obj, (list, tuple)):
65 return obj
67 return obj
66 elif obj is None:
68 elif obj is None:
67 return []
69 return []
68 else:
70 else:
69 return [obj]
71 return [obj]
70
72
71
73
72 class SettingsMaker(object):
74 class SettingsMaker(object):
73
75
74 def __init__(self, app_settings):
76 def __init__(self, app_settings):
75 self.settings = app_settings
77 self.settings = app_settings
76
78
77 @classmethod
79 @classmethod
78 def _bool_func(cls, input_val):
80 def _bool_func(cls, input_val):
79 if isinstance(input_val, unicode):
81 if isinstance(input_val, unicode):
80 input_val = input_val.encode('utf8')
82 input_val = input_val.encode('utf8')
81 return str2bool(input_val)
83 return str2bool(input_val)
82
84
83 @classmethod
85 @classmethod
84 def _int_func(cls, input_val):
86 def _int_func(cls, input_val):
85 return int(input_val)
87 return int(input_val)
86
88
87 @classmethod
89 @classmethod
88 def _list_func(cls, input_val, sep=','):
90 def _list_func(cls, input_val, sep=','):
89 return aslist(input_val, sep=sep)
91 return aslist(input_val, sep=sep)
90
92
91 @classmethod
93 @classmethod
92 def _string_func(cls, input_val, lower=True):
94 def _string_func(cls, input_val, lower=True):
93 if lower:
95 if lower:
94 input_val = input_val.lower()
96 input_val = input_val.lower()
95 return input_val
97 return input_val
96
98
97 @classmethod
99 @classmethod
98 def _float_func(cls, input_val):
100 def _float_func(cls, input_val):
99 return float(input_val)
101 return float(input_val)
100
102
101 @classmethod
103 @classmethod
102 def _dir_func(cls, input_val, ensure_dir=False, mode=0o755):
104 def _dir_func(cls, input_val, ensure_dir=False, mode=0o755):
103
105
104 # ensure we have our dir created
106 # ensure we have our dir created
105 if not os.path.isdir(input_val) and ensure_dir:
107 if not os.path.isdir(input_val) and ensure_dir:
106 os.makedirs(input_val, mode=mode)
108 os.makedirs(input_val, mode=mode)
107
109
108 if not os.path.isdir(input_val):
110 if not os.path.isdir(input_val):
109 raise Exception('Dir at {} does not exist'.format(input_val))
111 raise Exception('Dir at {} does not exist'.format(input_val))
110 return input_val
112 return input_val
111
113
112 @classmethod
114 @classmethod
113 def _file_path_func(cls, input_val, ensure_dir=False, mode=0o755):
115 def _file_path_func(cls, input_val, ensure_dir=False, mode=0o755):
114 dirname = os.path.dirname(input_val)
116 dirname = os.path.dirname(input_val)
115 cls._dir_func(dirname, ensure_dir=ensure_dir)
117 cls._dir_func(dirname, ensure_dir=ensure_dir)
116 return input_val
118 return input_val
117
119
118 @classmethod
120 @classmethod
119 def _key_transformator(cls, key):
121 def _key_transformator(cls, key):
120 return "{}_{}".format('RC'.upper(), key.upper().replace('.', '_').replace('-', '_'))
122 return "{}_{}".format('RC'.upper(), key.upper().replace('.', '_').replace('-', '_'))
121
123
124 def maybe_env_key(self, key):
125 # now maybe we have this KEY in env, search and use the value with higher priority.
126 transformed_key = self._key_transformator(key)
127 envvar_value = os.environ.get(transformed_key)
128 if envvar_value:
129 log.debug('using `%s` key instead of `%s` key for config', transformed_key, key)
130
131 return envvar_value
132
133 def env_expand(self):
134 replaced = {}
135 for k, v in self.settings.items():
136 if k not in set_keys:
137 envvar_value = self.maybe_env_key(k)
138 if envvar_value:
139 replaced[k] = envvar_value
140 set_keys[k] = envvar_value
141
142 # replace ALL keys updated
143 self.settings.update(replaced)
144
122 def enable_logging(self, logging_conf=None, level='INFO', formatter='generic'):
145 def enable_logging(self, logging_conf=None, level='INFO', formatter='generic'):
123 """
146 """
124 Helper to enable debug on running instance
147 Helper to enable debug on running instance
125 :return:
148 :return:
126 """
149 """
127
150
128 if not str2bool(self.settings.get('logging.autoconfigure')):
151 if not str2bool(self.settings.get('logging.autoconfigure')):
129 log.info('logging configuration based on main .ini file')
152 log.info('logging configuration based on main .ini file')
130 return
153 return
131
154
132 if logging_conf is None:
155 if logging_conf is None:
133 logging_conf = self.settings.get('logging.logging_conf_file') or ''
156 logging_conf = self.settings.get('logging.logging_conf_file') or ''
134
157
135 if not os.path.isfile(logging_conf):
158 if not os.path.isfile(logging_conf):
136 log.error('Unable to setup logging based on %s, file does not exist...', logging_conf)
159 log.error('Unable to setup logging based on %s, '
160 'file does not exist.... specify path using logging.logging_conf_file= config setting. ', logging_conf)
137 return
161 return
138
162
139 with open(logging_conf, 'rb') as f:
163 with open(logging_conf, 'rb') as f:
140 ini_template = textwrap.dedent(f.read())
164 ini_template = textwrap.dedent(f.read())
141 ini_template = string.Template(ini_template).safe_substitute(
165 ini_template = string.Template(ini_template).safe_substitute(
142 RC_LOGGING_LEVEL=os.environ.get('RC_LOGGING_LEVEL', '') or level,
166 RC_LOGGING_LEVEL=os.environ.get('RC_LOGGING_LEVEL', '') or level,
143 RC_LOGGING_FORMATTER=os.environ.get('RC_LOGGING_FORMATTER', '') or formatter
167 RC_LOGGING_FORMATTER=os.environ.get('RC_LOGGING_FORMATTER', '') or formatter
144 )
168 )
145
169
146 with tempfile.NamedTemporaryFile(prefix='rc_logging_', suffix='.ini', delete=False) as f:
170 with tempfile.NamedTemporaryFile(prefix='rc_logging_', suffix='.ini', delete=False) as f:
147 log.info('Saved Temporary LOGGING config at %s', f.name)
171 log.info('Saved Temporary LOGGING config at %s', f.name)
148 f.write(ini_template)
172 f.write(ini_template)
149
173
150 logging.config.fileConfig(f.name)
174 logging.config.fileConfig(f.name)
151 os.remove(f.name)
175 os.remove(f.name)
152
176
153 def make_setting(self, key, default, lower=False, default_when_empty=False, parser=None):
177 def make_setting(self, key, default, lower=False, default_when_empty=False, parser=None):
154
155 input_val = self.settings.get(key, default)
178 input_val = self.settings.get(key, default)
156
179
157 if default_when_empty and not input_val:
180 if default_when_empty and not input_val:
158 # use default value when value is set in the config but it is empty
181 # use default value when value is set in the config but it is empty
159 input_val = default
182 input_val = default
160
183
161 parser_func = {
184 parser_func = {
162 'bool': self._bool_func,
185 'bool': self._bool_func,
163 'int': self._int_func,
186 'int': self._int_func,
164 'list': self._list_func,
187 'list': self._list_func,
165 'list:newline': functools.partial(self._list_func, sep='/n'),
188 'list:newline': functools.partial(self._list_func, sep='/n'),
166 'list:spacesep': functools.partial(self._list_func, sep=' '),
189 'list:spacesep': functools.partial(self._list_func, sep=' '),
167 'string': functools.partial(self._string_func, lower=lower),
190 'string': functools.partial(self._string_func, lower=lower),
168 'dir': self._dir_func,
191 'dir': self._dir_func,
169 'dir:ensured': functools.partial(self._dir_func, ensure_dir=True),
192 'dir:ensured': functools.partial(self._dir_func, ensure_dir=True),
170 'file': self._file_path_func,
193 'file': self._file_path_func,
171 'file:ensured': functools.partial(self._file_path_func, ensure_dir=True),
194 'file:ensured': functools.partial(self._file_path_func, ensure_dir=True),
172 None: lambda i: i
195 None: lambda i: i
173 }[parser]
196 }[parser]
174
197
175 # now maybe we have this KEY in env, search and use the value with higher priority.
198 envvar_value = self.maybe_env_key(key)
176 transformed_key = self._key_transformator(key)
177 envvar_value = os.environ.get(transformed_key)
178 if envvar_value:
199 if envvar_value:
179 log.debug('using `%s` key instead of `%s` key for config', transformed_key, key)
180 input_val = envvar_value
200 input_val = envvar_value
201 set_keys[key] = input_val
202
181 self.settings[key] = parser_func(input_val)
203 self.settings[key] = parser_func(input_val)
182 return self.settings[key]
204 return self.settings[key]
General Comments 0
You need to be logged in to leave comments. Login now