##// END OF EJS Templates
system-info: added info about temporary storage....
marcink -
r1124:c43085bc default
parent child Browse files
Show More
@@ -1,67 +1,69 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2016 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
21
22 import pytest
22 import pytest
23
23
24 from rhodecode.model.scm import ScmModel
24 from rhodecode.model.scm import ScmModel
25 from rhodecode.api.tests.utils import build_data, api_call, assert_ok
25 from rhodecode.api.tests.utils import build_data, api_call, assert_ok
26
26
27
27
28 @pytest.fixture
28 @pytest.fixture
29 def http_host_stub():
29 def http_host_stub():
30 """
30 """
31 To ensure that we can get an IP address, this test shall run with a
31 To ensure that we can get an IP address, this test shall run with a
32 hostname set to "localhost".
32 hostname set to "localhost".
33 """
33 """
34 return 'localhost:80'
34 return 'localhost:80'
35
35
36
36
37 @pytest.mark.usefixtures("testuser_api", "app")
37 @pytest.mark.usefixtures("testuser_api", "app")
38 class TestGetServerInfo(object):
38 class TestGetServerInfo(object):
39 def test_api_get_server_info(self):
39 def test_api_get_server_info(self):
40 id_, params = build_data(self.apikey, 'get_server_info')
40 id_, params = build_data(self.apikey, 'get_server_info')
41 response = api_call(self.app, params)
41 response = api_call(self.app, params)
42 resp = response.json
42 resp = response.json
43 expected = ScmModel().get_server_info()
43 expected = ScmModel().get_server_info()
44 expected['memory'] = resp['result']['memory']
44 expected['memory'] = resp['result']['memory']
45 expected['uptime'] = resp['result']['uptime']
45 expected['uptime'] = resp['result']['uptime']
46 expected['load'] = resp['result']['load']
46 expected['load'] = resp['result']['load']
47 expected['cpu'] = resp['result']['cpu']
47 expected['cpu'] = resp['result']['cpu']
48 expected['storage'] = resp['result']['storage']
48 expected['storage'] = resp['result']['storage']
49 expected['storage_temp'] = resp['result']['storage_temp']
49 expected['storage_inodes'] = resp['result']['storage_inodes']
50 expected['storage_inodes'] = resp['result']['storage_inodes']
50 expected['server'] = resp['result']['server']
51 expected['server'] = resp['result']['server']
51
52
52 assert_ok(id_, expected, given=response.body)
53 assert_ok(id_, expected, given=response.body)
53
54
54 def test_api_get_server_info_ip(self):
55 def test_api_get_server_info_ip(self):
55 id_, params = build_data(self.apikey, 'get_server_info')
56 id_, params = build_data(self.apikey, 'get_server_info')
56 response = api_call(self.app, params)
57 response = api_call(self.app, params)
57 resp = response.json
58 resp = response.json
58 expected = ScmModel().get_server_info({'SERVER_NAME': 'unknown'})
59 expected = ScmModel().get_server_info({'SERVER_NAME': 'unknown'})
59 expected['memory'] = resp['result']['memory']
60 expected['memory'] = resp['result']['memory']
60 expected['uptime'] = resp['result']['uptime']
61 expected['uptime'] = resp['result']['uptime']
61 expected['load'] = resp['result']['load']
62 expected['load'] = resp['result']['load']
62 expected['cpu'] = resp['result']['cpu']
63 expected['cpu'] = resp['result']['cpu']
63 expected['storage'] = resp['result']['storage']
64 expected['storage'] = resp['result']['storage']
65 expected['storage_temp'] = resp['result']['storage_temp']
64 expected['storage_inodes'] = resp['result']['storage_inodes']
66 expected['storage_inodes'] = resp['result']['storage_inodes']
65 expected['server'] = resp['result']['server']
67 expected['server'] = resp['result']['server']
66
68
67 assert_ok(id_, expected, given=response.body)
69 assert_ok(id_, expected, given=response.body)
@@ -1,839 +1,842 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2016 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
21
22 """
22 """
23 settings controller for rhodecode admin
23 settings controller for rhodecode admin
24 """
24 """
25
25
26 import collections
26 import collections
27 import logging
27 import logging
28 import urllib2
28 import urllib2
29
29
30 import datetime
30 import datetime
31 import formencode
31 import formencode
32 from formencode import htmlfill
32 from formencode import htmlfill
33 import packaging.version
33 import packaging.version
34 from pylons import request, tmpl_context as c, url, config
34 from pylons import request, tmpl_context as c, url, config
35 from pylons.controllers.util import redirect
35 from pylons.controllers.util import redirect
36 from pylons.i18n.translation import _, lazy_ugettext
36 from pylons.i18n.translation import _, lazy_ugettext
37 from pyramid.threadlocal import get_current_registry
37 from pyramid.threadlocal import get_current_registry
38 from webob.exc import HTTPBadRequest
38 from webob.exc import HTTPBadRequest
39
39
40 import rhodecode
40 import rhodecode
41 from rhodecode.admin.navigation import navigation_list
41 from rhodecode.admin.navigation import navigation_list
42 from rhodecode.lib import auth
42 from rhodecode.lib import auth
43 from rhodecode.lib import helpers as h
43 from rhodecode.lib import helpers as h
44 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
44 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
45 from rhodecode.lib.base import BaseController, render
45 from rhodecode.lib.base import BaseController, render
46 from rhodecode.lib.celerylib import tasks, run_task
46 from rhodecode.lib.celerylib import tasks, run_task
47 from rhodecode.lib.utils import repo2db_mapper
47 from rhodecode.lib.utils import repo2db_mapper
48 from rhodecode.lib.utils2 import (
48 from rhodecode.lib.utils2 import (
49 str2bool, safe_unicode, AttributeDict, safe_int)
49 str2bool, safe_unicode, AttributeDict, safe_int)
50 from rhodecode.lib.compat import OrderedDict
50 from rhodecode.lib.compat import OrderedDict
51 from rhodecode.lib.ext_json import json
51 from rhodecode.lib.ext_json import json
52 from rhodecode.lib.utils import jsonify
52 from rhodecode.lib.utils import jsonify
53
53
54 from rhodecode.model.db import RhodeCodeUi, Repository
54 from rhodecode.model.db import RhodeCodeUi, Repository
55 from rhodecode.model.forms import ApplicationSettingsForm, \
55 from rhodecode.model.forms import ApplicationSettingsForm, \
56 ApplicationUiSettingsForm, ApplicationVisualisationForm, \
56 ApplicationUiSettingsForm, ApplicationVisualisationForm, \
57 LabsSettingsForm, IssueTrackerPatternsForm
57 LabsSettingsForm, IssueTrackerPatternsForm
58 from rhodecode.model.repo_group import RepoGroupModel
58 from rhodecode.model.repo_group import RepoGroupModel
59
59
60 from rhodecode.model.scm import ScmModel
60 from rhodecode.model.scm import ScmModel
61 from rhodecode.model.notification import EmailNotificationModel
61 from rhodecode.model.notification import EmailNotificationModel
62 from rhodecode.model.meta import Session
62 from rhodecode.model.meta import Session
63 from rhodecode.model.settings import (
63 from rhodecode.model.settings import (
64 IssueTrackerSettingsModel, VcsSettingsModel, SettingNotFound,
64 IssueTrackerSettingsModel, VcsSettingsModel, SettingNotFound,
65 SettingsModel)
65 SettingsModel)
66
66
67 from rhodecode.model.supervisor import SupervisorModel, SUPERVISOR_MASTER
67 from rhodecode.model.supervisor import SupervisorModel, SUPERVISOR_MASTER
68 from rhodecode.svn_support.config_keys import generate_config
68 from rhodecode.svn_support.config_keys import generate_config
69
69
70
70
71 log = logging.getLogger(__name__)
71 log = logging.getLogger(__name__)
72
72
73
73
74 class SettingsController(BaseController):
74 class SettingsController(BaseController):
75 """REST Controller styled on the Atom Publishing Protocol"""
75 """REST Controller styled on the Atom Publishing Protocol"""
76 # To properly map this controller, ensure your config/routing.py
76 # To properly map this controller, ensure your config/routing.py
77 # file has a resource setup:
77 # file has a resource setup:
78 # map.resource('setting', 'settings', controller='admin/settings',
78 # map.resource('setting', 'settings', controller='admin/settings',
79 # path_prefix='/admin', name_prefix='admin_')
79 # path_prefix='/admin', name_prefix='admin_')
80
80
81 @LoginRequired()
81 @LoginRequired()
82 def __before__(self):
82 def __before__(self):
83 super(SettingsController, self).__before__()
83 super(SettingsController, self).__before__()
84 c.labs_active = str2bool(
84 c.labs_active = str2bool(
85 rhodecode.CONFIG.get('labs_settings_active', 'true'))
85 rhodecode.CONFIG.get('labs_settings_active', 'true'))
86 c.navlist = navigation_list(request)
86 c.navlist = navigation_list(request)
87
87
88 def _get_hg_ui_settings(self):
88 def _get_hg_ui_settings(self):
89 ret = RhodeCodeUi.query().all()
89 ret = RhodeCodeUi.query().all()
90
90
91 if not ret:
91 if not ret:
92 raise Exception('Could not get application ui settings !')
92 raise Exception('Could not get application ui settings !')
93 settings = {}
93 settings = {}
94 for each in ret:
94 for each in ret:
95 k = each.ui_key
95 k = each.ui_key
96 v = each.ui_value
96 v = each.ui_value
97 if k == '/':
97 if k == '/':
98 k = 'root_path'
98 k = 'root_path'
99
99
100 if k in ['push_ssl', 'publish']:
100 if k in ['push_ssl', 'publish']:
101 v = str2bool(v)
101 v = str2bool(v)
102
102
103 if k.find('.') != -1:
103 if k.find('.') != -1:
104 k = k.replace('.', '_')
104 k = k.replace('.', '_')
105
105
106 if each.ui_section in ['hooks', 'extensions']:
106 if each.ui_section in ['hooks', 'extensions']:
107 v = each.ui_active
107 v = each.ui_active
108
108
109 settings[each.ui_section + '_' + k] = v
109 settings[each.ui_section + '_' + k] = v
110 return settings
110 return settings
111
111
112 @HasPermissionAllDecorator('hg.admin')
112 @HasPermissionAllDecorator('hg.admin')
113 @auth.CSRFRequired()
113 @auth.CSRFRequired()
114 @jsonify
114 @jsonify
115 def delete_svn_pattern(self):
115 def delete_svn_pattern(self):
116 if not request.is_xhr:
116 if not request.is_xhr:
117 raise HTTPBadRequest()
117 raise HTTPBadRequest()
118
118
119 delete_pattern_id = request.POST.get('delete_svn_pattern')
119 delete_pattern_id = request.POST.get('delete_svn_pattern')
120 model = VcsSettingsModel()
120 model = VcsSettingsModel()
121 try:
121 try:
122 model.delete_global_svn_pattern(delete_pattern_id)
122 model.delete_global_svn_pattern(delete_pattern_id)
123 except SettingNotFound:
123 except SettingNotFound:
124 raise HTTPBadRequest()
124 raise HTTPBadRequest()
125
125
126 Session().commit()
126 Session().commit()
127 return True
127 return True
128
128
129 @HasPermissionAllDecorator('hg.admin')
129 @HasPermissionAllDecorator('hg.admin')
130 @auth.CSRFRequired()
130 @auth.CSRFRequired()
131 def settings_vcs_update(self):
131 def settings_vcs_update(self):
132 """POST /admin/settings: All items in the collection"""
132 """POST /admin/settings: All items in the collection"""
133 # url('admin_settings_vcs')
133 # url('admin_settings_vcs')
134 c.active = 'vcs'
134 c.active = 'vcs'
135
135
136 model = VcsSettingsModel()
136 model = VcsSettingsModel()
137 c.svn_branch_patterns = model.get_global_svn_branch_patterns()
137 c.svn_branch_patterns = model.get_global_svn_branch_patterns()
138 c.svn_tag_patterns = model.get_global_svn_tag_patterns()
138 c.svn_tag_patterns = model.get_global_svn_tag_patterns()
139
139
140 # TODO: Replace with request.registry after migrating to pyramid.
140 # TODO: Replace with request.registry after migrating to pyramid.
141 pyramid_settings = get_current_registry().settings
141 pyramid_settings = get_current_registry().settings
142 c.svn_proxy_generate_config = pyramid_settings[generate_config]
142 c.svn_proxy_generate_config = pyramid_settings[generate_config]
143
143
144 application_form = ApplicationUiSettingsForm()()
144 application_form = ApplicationUiSettingsForm()()
145
145
146 try:
146 try:
147 form_result = application_form.to_python(dict(request.POST))
147 form_result = application_form.to_python(dict(request.POST))
148 except formencode.Invalid as errors:
148 except formencode.Invalid as errors:
149 h.flash(
149 h.flash(
150 _("Some form inputs contain invalid data."),
150 _("Some form inputs contain invalid data."),
151 category='error')
151 category='error')
152 return htmlfill.render(
152 return htmlfill.render(
153 render('admin/settings/settings.html'),
153 render('admin/settings/settings.html'),
154 defaults=errors.value,
154 defaults=errors.value,
155 errors=errors.error_dict or {},
155 errors=errors.error_dict or {},
156 prefix_error=False,
156 prefix_error=False,
157 encoding="UTF-8",
157 encoding="UTF-8",
158 force_defaults=False
158 force_defaults=False
159 )
159 )
160
160
161 try:
161 try:
162 if c.visual.allow_repo_location_change:
162 if c.visual.allow_repo_location_change:
163 model.update_global_path_setting(
163 model.update_global_path_setting(
164 form_result['paths_root_path'])
164 form_result['paths_root_path'])
165
165
166 model.update_global_ssl_setting(form_result['web_push_ssl'])
166 model.update_global_ssl_setting(form_result['web_push_ssl'])
167 model.update_global_hook_settings(form_result)
167 model.update_global_hook_settings(form_result)
168
168
169 model.create_or_update_global_svn_settings(form_result)
169 model.create_or_update_global_svn_settings(form_result)
170 model.create_or_update_global_hg_settings(form_result)
170 model.create_or_update_global_hg_settings(form_result)
171 model.create_or_update_global_pr_settings(form_result)
171 model.create_or_update_global_pr_settings(form_result)
172 except Exception:
172 except Exception:
173 log.exception("Exception while updating settings")
173 log.exception("Exception while updating settings")
174 h.flash(_('Error occurred during updating '
174 h.flash(_('Error occurred during updating '
175 'application settings'), category='error')
175 'application settings'), category='error')
176 else:
176 else:
177 Session().commit()
177 Session().commit()
178 h.flash(_('Updated VCS settings'), category='success')
178 h.flash(_('Updated VCS settings'), category='success')
179 return redirect(url('admin_settings_vcs'))
179 return redirect(url('admin_settings_vcs'))
180
180
181 return htmlfill.render(
181 return htmlfill.render(
182 render('admin/settings/settings.html'),
182 render('admin/settings/settings.html'),
183 defaults=self._form_defaults(),
183 defaults=self._form_defaults(),
184 encoding="UTF-8",
184 encoding="UTF-8",
185 force_defaults=False)
185 force_defaults=False)
186
186
187 @HasPermissionAllDecorator('hg.admin')
187 @HasPermissionAllDecorator('hg.admin')
188 def settings_vcs(self):
188 def settings_vcs(self):
189 """GET /admin/settings: All items in the collection"""
189 """GET /admin/settings: All items in the collection"""
190 # url('admin_settings_vcs')
190 # url('admin_settings_vcs')
191 c.active = 'vcs'
191 c.active = 'vcs'
192 model = VcsSettingsModel()
192 model = VcsSettingsModel()
193 c.svn_branch_patterns = model.get_global_svn_branch_patterns()
193 c.svn_branch_patterns = model.get_global_svn_branch_patterns()
194 c.svn_tag_patterns = model.get_global_svn_tag_patterns()
194 c.svn_tag_patterns = model.get_global_svn_tag_patterns()
195
195
196 # TODO: Replace with request.registry after migrating to pyramid.
196 # TODO: Replace with request.registry after migrating to pyramid.
197 pyramid_settings = get_current_registry().settings
197 pyramid_settings = get_current_registry().settings
198 c.svn_proxy_generate_config = pyramid_settings[generate_config]
198 c.svn_proxy_generate_config = pyramid_settings[generate_config]
199
199
200 return htmlfill.render(
200 return htmlfill.render(
201 render('admin/settings/settings.html'),
201 render('admin/settings/settings.html'),
202 defaults=self._form_defaults(),
202 defaults=self._form_defaults(),
203 encoding="UTF-8",
203 encoding="UTF-8",
204 force_defaults=False)
204 force_defaults=False)
205
205
206 @HasPermissionAllDecorator('hg.admin')
206 @HasPermissionAllDecorator('hg.admin')
207 @auth.CSRFRequired()
207 @auth.CSRFRequired()
208 def settings_mapping_update(self):
208 def settings_mapping_update(self):
209 """POST /admin/settings/mapping: All items in the collection"""
209 """POST /admin/settings/mapping: All items in the collection"""
210 # url('admin_settings_mapping')
210 # url('admin_settings_mapping')
211 c.active = 'mapping'
211 c.active = 'mapping'
212 rm_obsolete = request.POST.get('destroy', False)
212 rm_obsolete = request.POST.get('destroy', False)
213 invalidate_cache = request.POST.get('invalidate', False)
213 invalidate_cache = request.POST.get('invalidate', False)
214 log.debug(
214 log.debug(
215 'rescanning repo location with destroy obsolete=%s', rm_obsolete)
215 'rescanning repo location with destroy obsolete=%s', rm_obsolete)
216
216
217 if invalidate_cache:
217 if invalidate_cache:
218 log.debug('invalidating all repositories cache')
218 log.debug('invalidating all repositories cache')
219 for repo in Repository.get_all():
219 for repo in Repository.get_all():
220 ScmModel().mark_for_invalidation(repo.repo_name, delete=True)
220 ScmModel().mark_for_invalidation(repo.repo_name, delete=True)
221
221
222 filesystem_repos = ScmModel().repo_scan()
222 filesystem_repos = ScmModel().repo_scan()
223 added, removed = repo2db_mapper(filesystem_repos, rm_obsolete)
223 added, removed = repo2db_mapper(filesystem_repos, rm_obsolete)
224 _repr = lambda l: ', '.join(map(safe_unicode, l)) or '-'
224 _repr = lambda l: ', '.join(map(safe_unicode, l)) or '-'
225 h.flash(_('Repositories successfully '
225 h.flash(_('Repositories successfully '
226 'rescanned added: %s ; removed: %s') %
226 'rescanned added: %s ; removed: %s') %
227 (_repr(added), _repr(removed)),
227 (_repr(added), _repr(removed)),
228 category='success')
228 category='success')
229 return redirect(url('admin_settings_mapping'))
229 return redirect(url('admin_settings_mapping'))
230
230
231 @HasPermissionAllDecorator('hg.admin')
231 @HasPermissionAllDecorator('hg.admin')
232 def settings_mapping(self):
232 def settings_mapping(self):
233 """GET /admin/settings/mapping: All items in the collection"""
233 """GET /admin/settings/mapping: All items in the collection"""
234 # url('admin_settings_mapping')
234 # url('admin_settings_mapping')
235 c.active = 'mapping'
235 c.active = 'mapping'
236
236
237 return htmlfill.render(
237 return htmlfill.render(
238 render('admin/settings/settings.html'),
238 render('admin/settings/settings.html'),
239 defaults=self._form_defaults(),
239 defaults=self._form_defaults(),
240 encoding="UTF-8",
240 encoding="UTF-8",
241 force_defaults=False)
241 force_defaults=False)
242
242
243 @HasPermissionAllDecorator('hg.admin')
243 @HasPermissionAllDecorator('hg.admin')
244 @auth.CSRFRequired()
244 @auth.CSRFRequired()
245 def settings_global_update(self):
245 def settings_global_update(self):
246 """POST /admin/settings/global: All items in the collection"""
246 """POST /admin/settings/global: All items in the collection"""
247 # url('admin_settings_global')
247 # url('admin_settings_global')
248 c.active = 'global'
248 c.active = 'global'
249 c.personal_repo_group_default_pattern = RepoGroupModel()\
249 c.personal_repo_group_default_pattern = RepoGroupModel()\
250 .get_personal_group_name_pattern()
250 .get_personal_group_name_pattern()
251 application_form = ApplicationSettingsForm()()
251 application_form = ApplicationSettingsForm()()
252 try:
252 try:
253 form_result = application_form.to_python(dict(request.POST))
253 form_result = application_form.to_python(dict(request.POST))
254 except formencode.Invalid as errors:
254 except formencode.Invalid as errors:
255 return htmlfill.render(
255 return htmlfill.render(
256 render('admin/settings/settings.html'),
256 render('admin/settings/settings.html'),
257 defaults=errors.value,
257 defaults=errors.value,
258 errors=errors.error_dict or {},
258 errors=errors.error_dict or {},
259 prefix_error=False,
259 prefix_error=False,
260 encoding="UTF-8",
260 encoding="UTF-8",
261 force_defaults=False)
261 force_defaults=False)
262
262
263 try:
263 try:
264 settings = [
264 settings = [
265 ('title', 'rhodecode_title', 'unicode'),
265 ('title', 'rhodecode_title', 'unicode'),
266 ('realm', 'rhodecode_realm', 'unicode'),
266 ('realm', 'rhodecode_realm', 'unicode'),
267 ('pre_code', 'rhodecode_pre_code', 'unicode'),
267 ('pre_code', 'rhodecode_pre_code', 'unicode'),
268 ('post_code', 'rhodecode_post_code', 'unicode'),
268 ('post_code', 'rhodecode_post_code', 'unicode'),
269 ('captcha_public_key', 'rhodecode_captcha_public_key', 'unicode'),
269 ('captcha_public_key', 'rhodecode_captcha_public_key', 'unicode'),
270 ('captcha_private_key', 'rhodecode_captcha_private_key', 'unicode'),
270 ('captcha_private_key', 'rhodecode_captcha_private_key', 'unicode'),
271 ('create_personal_repo_group', 'rhodecode_create_personal_repo_group', 'bool'),
271 ('create_personal_repo_group', 'rhodecode_create_personal_repo_group', 'bool'),
272 ('personal_repo_group_pattern', 'rhodecode_personal_repo_group_pattern', 'unicode'),
272 ('personal_repo_group_pattern', 'rhodecode_personal_repo_group_pattern', 'unicode'),
273 ]
273 ]
274 for setting, form_key, type_ in settings:
274 for setting, form_key, type_ in settings:
275 sett = SettingsModel().create_or_update_setting(
275 sett = SettingsModel().create_or_update_setting(
276 setting, form_result[form_key], type_)
276 setting, form_result[form_key], type_)
277 Session().add(sett)
277 Session().add(sett)
278
278
279 Session().commit()
279 Session().commit()
280 SettingsModel().invalidate_settings_cache()
280 SettingsModel().invalidate_settings_cache()
281 h.flash(_('Updated application settings'), category='success')
281 h.flash(_('Updated application settings'), category='success')
282 except Exception:
282 except Exception:
283 log.exception("Exception while updating application settings")
283 log.exception("Exception while updating application settings")
284 h.flash(
284 h.flash(
285 _('Error occurred during updating application settings'),
285 _('Error occurred during updating application settings'),
286 category='error')
286 category='error')
287
287
288 return redirect(url('admin_settings_global'))
288 return redirect(url('admin_settings_global'))
289
289
290 @HasPermissionAllDecorator('hg.admin')
290 @HasPermissionAllDecorator('hg.admin')
291 def settings_global(self):
291 def settings_global(self):
292 """GET /admin/settings/global: All items in the collection"""
292 """GET /admin/settings/global: All items in the collection"""
293 # url('admin_settings_global')
293 # url('admin_settings_global')
294 c.active = 'global'
294 c.active = 'global'
295 c.personal_repo_group_default_pattern = RepoGroupModel()\
295 c.personal_repo_group_default_pattern = RepoGroupModel()\
296 .get_personal_group_name_pattern()
296 .get_personal_group_name_pattern()
297
297
298 return htmlfill.render(
298 return htmlfill.render(
299 render('admin/settings/settings.html'),
299 render('admin/settings/settings.html'),
300 defaults=self._form_defaults(),
300 defaults=self._form_defaults(),
301 encoding="UTF-8",
301 encoding="UTF-8",
302 force_defaults=False)
302 force_defaults=False)
303
303
304 @HasPermissionAllDecorator('hg.admin')
304 @HasPermissionAllDecorator('hg.admin')
305 @auth.CSRFRequired()
305 @auth.CSRFRequired()
306 def settings_visual_update(self):
306 def settings_visual_update(self):
307 """POST /admin/settings/visual: All items in the collection"""
307 """POST /admin/settings/visual: All items in the collection"""
308 # url('admin_settings_visual')
308 # url('admin_settings_visual')
309 c.active = 'visual'
309 c.active = 'visual'
310 application_form = ApplicationVisualisationForm()()
310 application_form = ApplicationVisualisationForm()()
311 try:
311 try:
312 form_result = application_form.to_python(dict(request.POST))
312 form_result = application_form.to_python(dict(request.POST))
313 except formencode.Invalid as errors:
313 except formencode.Invalid as errors:
314 return htmlfill.render(
314 return htmlfill.render(
315 render('admin/settings/settings.html'),
315 render('admin/settings/settings.html'),
316 defaults=errors.value,
316 defaults=errors.value,
317 errors=errors.error_dict or {},
317 errors=errors.error_dict or {},
318 prefix_error=False,
318 prefix_error=False,
319 encoding="UTF-8",
319 encoding="UTF-8",
320 force_defaults=False
320 force_defaults=False
321 )
321 )
322
322
323 try:
323 try:
324 settings = [
324 settings = [
325 ('show_public_icon', 'rhodecode_show_public_icon', 'bool'),
325 ('show_public_icon', 'rhodecode_show_public_icon', 'bool'),
326 ('show_private_icon', 'rhodecode_show_private_icon', 'bool'),
326 ('show_private_icon', 'rhodecode_show_private_icon', 'bool'),
327 ('stylify_metatags', 'rhodecode_stylify_metatags', 'bool'),
327 ('stylify_metatags', 'rhodecode_stylify_metatags', 'bool'),
328 ('repository_fields', 'rhodecode_repository_fields', 'bool'),
328 ('repository_fields', 'rhodecode_repository_fields', 'bool'),
329 ('dashboard_items', 'rhodecode_dashboard_items', 'int'),
329 ('dashboard_items', 'rhodecode_dashboard_items', 'int'),
330 ('admin_grid_items', 'rhodecode_admin_grid_items', 'int'),
330 ('admin_grid_items', 'rhodecode_admin_grid_items', 'int'),
331 ('show_version', 'rhodecode_show_version', 'bool'),
331 ('show_version', 'rhodecode_show_version', 'bool'),
332 ('use_gravatar', 'rhodecode_use_gravatar', 'bool'),
332 ('use_gravatar', 'rhodecode_use_gravatar', 'bool'),
333 ('markup_renderer', 'rhodecode_markup_renderer', 'unicode'),
333 ('markup_renderer', 'rhodecode_markup_renderer', 'unicode'),
334 ('gravatar_url', 'rhodecode_gravatar_url', 'unicode'),
334 ('gravatar_url', 'rhodecode_gravatar_url', 'unicode'),
335 ('clone_uri_tmpl', 'rhodecode_clone_uri_tmpl', 'unicode'),
335 ('clone_uri_tmpl', 'rhodecode_clone_uri_tmpl', 'unicode'),
336 ('support_url', 'rhodecode_support_url', 'unicode'),
336 ('support_url', 'rhodecode_support_url', 'unicode'),
337 ('show_revision_number', 'rhodecode_show_revision_number', 'bool'),
337 ('show_revision_number', 'rhodecode_show_revision_number', 'bool'),
338 ('show_sha_length', 'rhodecode_show_sha_length', 'int'),
338 ('show_sha_length', 'rhodecode_show_sha_length', 'int'),
339 ]
339 ]
340 for setting, form_key, type_ in settings:
340 for setting, form_key, type_ in settings:
341 sett = SettingsModel().create_or_update_setting(
341 sett = SettingsModel().create_or_update_setting(
342 setting, form_result[form_key], type_)
342 setting, form_result[form_key], type_)
343 Session().add(sett)
343 Session().add(sett)
344
344
345 Session().commit()
345 Session().commit()
346 SettingsModel().invalidate_settings_cache()
346 SettingsModel().invalidate_settings_cache()
347 h.flash(_('Updated visualisation settings'), category='success')
347 h.flash(_('Updated visualisation settings'), category='success')
348 except Exception:
348 except Exception:
349 log.exception("Exception updating visualization settings")
349 log.exception("Exception updating visualization settings")
350 h.flash(_('Error occurred during updating '
350 h.flash(_('Error occurred during updating '
351 'visualisation settings'),
351 'visualisation settings'),
352 category='error')
352 category='error')
353
353
354 return redirect(url('admin_settings_visual'))
354 return redirect(url('admin_settings_visual'))
355
355
356 @HasPermissionAllDecorator('hg.admin')
356 @HasPermissionAllDecorator('hg.admin')
357 def settings_visual(self):
357 def settings_visual(self):
358 """GET /admin/settings/visual: All items in the collection"""
358 """GET /admin/settings/visual: All items in the collection"""
359 # url('admin_settings_visual')
359 # url('admin_settings_visual')
360 c.active = 'visual'
360 c.active = 'visual'
361
361
362 return htmlfill.render(
362 return htmlfill.render(
363 render('admin/settings/settings.html'),
363 render('admin/settings/settings.html'),
364 defaults=self._form_defaults(),
364 defaults=self._form_defaults(),
365 encoding="UTF-8",
365 encoding="UTF-8",
366 force_defaults=False)
366 force_defaults=False)
367
367
368 @HasPermissionAllDecorator('hg.admin')
368 @HasPermissionAllDecorator('hg.admin')
369 @auth.CSRFRequired()
369 @auth.CSRFRequired()
370 def settings_issuetracker_test(self):
370 def settings_issuetracker_test(self):
371 if request.is_xhr:
371 if request.is_xhr:
372 return h.urlify_commit_message(
372 return h.urlify_commit_message(
373 request.POST.get('test_text', ''),
373 request.POST.get('test_text', ''),
374 'repo_group/test_repo1')
374 'repo_group/test_repo1')
375 else:
375 else:
376 raise HTTPBadRequest()
376 raise HTTPBadRequest()
377
377
378 @HasPermissionAllDecorator('hg.admin')
378 @HasPermissionAllDecorator('hg.admin')
379 @auth.CSRFRequired()
379 @auth.CSRFRequired()
380 def settings_issuetracker_delete(self):
380 def settings_issuetracker_delete(self):
381 uid = request.POST.get('uid')
381 uid = request.POST.get('uid')
382 IssueTrackerSettingsModel().delete_entries(uid)
382 IssueTrackerSettingsModel().delete_entries(uid)
383 h.flash(_('Removed issue tracker entry'), category='success')
383 h.flash(_('Removed issue tracker entry'), category='success')
384 return redirect(url('admin_settings_issuetracker'))
384 return redirect(url('admin_settings_issuetracker'))
385
385
386 @HasPermissionAllDecorator('hg.admin')
386 @HasPermissionAllDecorator('hg.admin')
387 def settings_issuetracker(self):
387 def settings_issuetracker(self):
388 """GET /admin/settings/issue-tracker: All items in the collection"""
388 """GET /admin/settings/issue-tracker: All items in the collection"""
389 # url('admin_settings_issuetracker')
389 # url('admin_settings_issuetracker')
390 c.active = 'issuetracker'
390 c.active = 'issuetracker'
391 defaults = SettingsModel().get_all_settings()
391 defaults = SettingsModel().get_all_settings()
392
392
393 entry_key = 'rhodecode_issuetracker_pat_'
393 entry_key = 'rhodecode_issuetracker_pat_'
394
394
395 c.issuetracker_entries = {}
395 c.issuetracker_entries = {}
396 for k, v in defaults.items():
396 for k, v in defaults.items():
397 if k.startswith(entry_key):
397 if k.startswith(entry_key):
398 uid = k[len(entry_key):]
398 uid = k[len(entry_key):]
399 c.issuetracker_entries[uid] = None
399 c.issuetracker_entries[uid] = None
400
400
401 for uid in c.issuetracker_entries:
401 for uid in c.issuetracker_entries:
402 c.issuetracker_entries[uid] = AttributeDict({
402 c.issuetracker_entries[uid] = AttributeDict({
403 'pat': defaults.get('rhodecode_issuetracker_pat_' + uid),
403 'pat': defaults.get('rhodecode_issuetracker_pat_' + uid),
404 'url': defaults.get('rhodecode_issuetracker_url_' + uid),
404 'url': defaults.get('rhodecode_issuetracker_url_' + uid),
405 'pref': defaults.get('rhodecode_issuetracker_pref_' + uid),
405 'pref': defaults.get('rhodecode_issuetracker_pref_' + uid),
406 'desc': defaults.get('rhodecode_issuetracker_desc_' + uid),
406 'desc': defaults.get('rhodecode_issuetracker_desc_' + uid),
407 })
407 })
408
408
409 return render('admin/settings/settings.html')
409 return render('admin/settings/settings.html')
410
410
411 @HasPermissionAllDecorator('hg.admin')
411 @HasPermissionAllDecorator('hg.admin')
412 @auth.CSRFRequired()
412 @auth.CSRFRequired()
413 def settings_issuetracker_save(self):
413 def settings_issuetracker_save(self):
414 settings_model = IssueTrackerSettingsModel()
414 settings_model = IssueTrackerSettingsModel()
415
415
416 form = IssueTrackerPatternsForm()().to_python(request.POST)
416 form = IssueTrackerPatternsForm()().to_python(request.POST)
417 if form:
417 if form:
418 for uid in form.get('delete_patterns', []):
418 for uid in form.get('delete_patterns', []):
419 settings_model.delete_entries(uid)
419 settings_model.delete_entries(uid)
420
420
421 for pattern in form.get('patterns', []):
421 for pattern in form.get('patterns', []):
422 for setting, value, type_ in pattern:
422 for setting, value, type_ in pattern:
423 sett = settings_model.create_or_update_setting(
423 sett = settings_model.create_or_update_setting(
424 setting, value, type_)
424 setting, value, type_)
425 Session().add(sett)
425 Session().add(sett)
426
426
427 Session().commit()
427 Session().commit()
428
428
429 SettingsModel().invalidate_settings_cache()
429 SettingsModel().invalidate_settings_cache()
430 h.flash(_('Updated issue tracker entries'), category='success')
430 h.flash(_('Updated issue tracker entries'), category='success')
431 return redirect(url('admin_settings_issuetracker'))
431 return redirect(url('admin_settings_issuetracker'))
432
432
433 @HasPermissionAllDecorator('hg.admin')
433 @HasPermissionAllDecorator('hg.admin')
434 @auth.CSRFRequired()
434 @auth.CSRFRequired()
435 def settings_email_update(self):
435 def settings_email_update(self):
436 """POST /admin/settings/email: All items in the collection"""
436 """POST /admin/settings/email: All items in the collection"""
437 # url('admin_settings_email')
437 # url('admin_settings_email')
438 c.active = 'email'
438 c.active = 'email'
439
439
440 test_email = request.POST.get('test_email')
440 test_email = request.POST.get('test_email')
441
441
442 if not test_email:
442 if not test_email:
443 h.flash(_('Please enter email address'), category='error')
443 h.flash(_('Please enter email address'), category='error')
444 return redirect(url('admin_settings_email'))
444 return redirect(url('admin_settings_email'))
445
445
446 email_kwargs = {
446 email_kwargs = {
447 'date': datetime.datetime.now(),
447 'date': datetime.datetime.now(),
448 'user': c.rhodecode_user,
448 'user': c.rhodecode_user,
449 'rhodecode_version': c.rhodecode_version
449 'rhodecode_version': c.rhodecode_version
450 }
450 }
451
451
452 (subject, headers, email_body,
452 (subject, headers, email_body,
453 email_body_plaintext) = EmailNotificationModel().render_email(
453 email_body_plaintext) = EmailNotificationModel().render_email(
454 EmailNotificationModel.TYPE_EMAIL_TEST, **email_kwargs)
454 EmailNotificationModel.TYPE_EMAIL_TEST, **email_kwargs)
455
455
456 recipients = [test_email] if test_email else None
456 recipients = [test_email] if test_email else None
457
457
458 run_task(tasks.send_email, recipients, subject,
458 run_task(tasks.send_email, recipients, subject,
459 email_body_plaintext, email_body)
459 email_body_plaintext, email_body)
460
460
461 h.flash(_('Send email task created'), category='success')
461 h.flash(_('Send email task created'), category='success')
462 return redirect(url('admin_settings_email'))
462 return redirect(url('admin_settings_email'))
463
463
464 @HasPermissionAllDecorator('hg.admin')
464 @HasPermissionAllDecorator('hg.admin')
465 def settings_email(self):
465 def settings_email(self):
466 """GET /admin/settings/email: All items in the collection"""
466 """GET /admin/settings/email: All items in the collection"""
467 # url('admin_settings_email')
467 # url('admin_settings_email')
468 c.active = 'email'
468 c.active = 'email'
469 c.rhodecode_ini = rhodecode.CONFIG
469 c.rhodecode_ini = rhodecode.CONFIG
470
470
471 return htmlfill.render(
471 return htmlfill.render(
472 render('admin/settings/settings.html'),
472 render('admin/settings/settings.html'),
473 defaults=self._form_defaults(),
473 defaults=self._form_defaults(),
474 encoding="UTF-8",
474 encoding="UTF-8",
475 force_defaults=False)
475 force_defaults=False)
476
476
477 @HasPermissionAllDecorator('hg.admin')
477 @HasPermissionAllDecorator('hg.admin')
478 @auth.CSRFRequired()
478 @auth.CSRFRequired()
479 def settings_hooks_update(self):
479 def settings_hooks_update(self):
480 """POST or DELETE /admin/settings/hooks: All items in the collection"""
480 """POST or DELETE /admin/settings/hooks: All items in the collection"""
481 # url('admin_settings_hooks')
481 # url('admin_settings_hooks')
482 c.active = 'hooks'
482 c.active = 'hooks'
483 if c.visual.allow_custom_hooks_settings:
483 if c.visual.allow_custom_hooks_settings:
484 ui_key = request.POST.get('new_hook_ui_key')
484 ui_key = request.POST.get('new_hook_ui_key')
485 ui_value = request.POST.get('new_hook_ui_value')
485 ui_value = request.POST.get('new_hook_ui_value')
486
486
487 hook_id = request.POST.get('hook_id')
487 hook_id = request.POST.get('hook_id')
488 new_hook = False
488 new_hook = False
489
489
490 model = SettingsModel()
490 model = SettingsModel()
491 try:
491 try:
492 if ui_value and ui_key:
492 if ui_value and ui_key:
493 model.create_or_update_hook(ui_key, ui_value)
493 model.create_or_update_hook(ui_key, ui_value)
494 h.flash(_('Added new hook'), category='success')
494 h.flash(_('Added new hook'), category='success')
495 new_hook = True
495 new_hook = True
496 elif hook_id:
496 elif hook_id:
497 RhodeCodeUi.delete(hook_id)
497 RhodeCodeUi.delete(hook_id)
498 Session().commit()
498 Session().commit()
499
499
500 # check for edits
500 # check for edits
501 update = False
501 update = False
502 _d = request.POST.dict_of_lists()
502 _d = request.POST.dict_of_lists()
503 for k, v in zip(_d.get('hook_ui_key', []),
503 for k, v in zip(_d.get('hook_ui_key', []),
504 _d.get('hook_ui_value_new', [])):
504 _d.get('hook_ui_value_new', [])):
505 model.create_or_update_hook(k, v)
505 model.create_or_update_hook(k, v)
506 update = True
506 update = True
507
507
508 if update and not new_hook:
508 if update and not new_hook:
509 h.flash(_('Updated hooks'), category='success')
509 h.flash(_('Updated hooks'), category='success')
510 Session().commit()
510 Session().commit()
511 except Exception:
511 except Exception:
512 log.exception("Exception during hook creation")
512 log.exception("Exception during hook creation")
513 h.flash(_('Error occurred during hook creation'),
513 h.flash(_('Error occurred during hook creation'),
514 category='error')
514 category='error')
515
515
516 return redirect(url('admin_settings_hooks'))
516 return redirect(url('admin_settings_hooks'))
517
517
518 @HasPermissionAllDecorator('hg.admin')
518 @HasPermissionAllDecorator('hg.admin')
519 def settings_hooks(self):
519 def settings_hooks(self):
520 """GET /admin/settings/hooks: All items in the collection"""
520 """GET /admin/settings/hooks: All items in the collection"""
521 # url('admin_settings_hooks')
521 # url('admin_settings_hooks')
522 c.active = 'hooks'
522 c.active = 'hooks'
523
523
524 model = SettingsModel()
524 model = SettingsModel()
525 c.hooks = model.get_builtin_hooks()
525 c.hooks = model.get_builtin_hooks()
526 c.custom_hooks = model.get_custom_hooks()
526 c.custom_hooks = model.get_custom_hooks()
527
527
528 return htmlfill.render(
528 return htmlfill.render(
529 render('admin/settings/settings.html'),
529 render('admin/settings/settings.html'),
530 defaults=self._form_defaults(),
530 defaults=self._form_defaults(),
531 encoding="UTF-8",
531 encoding="UTF-8",
532 force_defaults=False)
532 force_defaults=False)
533
533
534 @HasPermissionAllDecorator('hg.admin')
534 @HasPermissionAllDecorator('hg.admin')
535 def settings_search(self):
535 def settings_search(self):
536 """GET /admin/settings/search: All items in the collection"""
536 """GET /admin/settings/search: All items in the collection"""
537 # url('admin_settings_search')
537 # url('admin_settings_search')
538 c.active = 'search'
538 c.active = 'search'
539
539
540 from rhodecode.lib.index import searcher_from_config
540 from rhodecode.lib.index import searcher_from_config
541 searcher = searcher_from_config(config)
541 searcher = searcher_from_config(config)
542 c.statistics = searcher.statistics()
542 c.statistics = searcher.statistics()
543
543
544 return render('admin/settings/settings.html')
544 return render('admin/settings/settings.html')
545
545
546 @HasPermissionAllDecorator('hg.admin')
546 @HasPermissionAllDecorator('hg.admin')
547 def settings_system(self):
547 def settings_system(self):
548 """GET /admin/settings/system: All items in the collection"""
548 """GET /admin/settings/system: All items in the collection"""
549 # url('admin_settings_system')
549 # url('admin_settings_system')
550 snapshot = str2bool(request.GET.get('snapshot'))
550 snapshot = str2bool(request.GET.get('snapshot'))
551 defaults = self._form_defaults()
551 defaults = self._form_defaults()
552
552
553 c.active = 'system'
553 c.active = 'system'
554 c.rhodecode_update_url = defaults.get('rhodecode_update_url')
554 c.rhodecode_update_url = defaults.get('rhodecode_update_url')
555 server_info = ScmModel().get_server_info(request.environ)
555 server_info = ScmModel().get_server_info(request.environ)
556
556
557 for key, val in server_info.iteritems():
557 for key, val in server_info.iteritems():
558 setattr(c, key, val)
558 setattr(c, key, val)
559
559
560 def val(name, subkey='human_value'):
560 def val(name, subkey='human_value'):
561 return server_info[name][subkey]
561 return server_info[name][subkey]
562
562
563 def state(name):
563 def state(name):
564 return server_info[name]['state']
564 return server_info[name]['state']
565
565
566 def val2(name):
566 def val2(name):
567 val = server_info[name]['human_value']
567 val = server_info[name]['human_value']
568 state = server_info[name]['state']
568 state = server_info[name]['state']
569 return val, state
569 return val, state
570
570
571 c.data_items = [
571 c.data_items = [
572 # update info
572 # update info
573 (_('Update info'), h.literal(
573 (_('Update info'), h.literal(
574 '<span class="link" id="check_for_update" >%s.</span>' % (
574 '<span class="link" id="check_for_update" >%s.</span>' % (
575 _('Check for updates')) +
575 _('Check for updates')) +
576 '<br/> <span >%s.</span>' % (_('Note: please make sure this server can access `%s` for the update link to work') % c.rhodecode_update_url)
576 '<br/> <span >%s.</span>' % (_('Note: please make sure this server can access `%s` for the update link to work') % c.rhodecode_update_url)
577 ), ''),
577 ), ''),
578
578
579 # RhodeCode specific
579 # RhodeCode specific
580 (_('RhodeCode Version'), val('rhodecode_app')['text'], state('rhodecode_app')),
580 (_('RhodeCode Version'), val('rhodecode_app')['text'], state('rhodecode_app')),
581 (_('RhodeCode Server IP'), val('server')['server_ip'], state('server')),
581 (_('RhodeCode Server IP'), val('server')['server_ip'], state('server')),
582 (_('RhodeCode Server ID'), val('server')['server_id'], state('server')),
582 (_('RhodeCode Server ID'), val('server')['server_id'], state('server')),
583 (_('RhodeCode Configuration'), val('rhodecode_config')['path'], state('rhodecode_config')),
583 (_('RhodeCode Configuration'), val('rhodecode_config')['path'], state('rhodecode_config')),
584 ('', '', ''), # spacer
584 ('', '', ''), # spacer
585
585
586 # Database
586 # Database
587 (_('Database'), val('database')['url'], state('database')),
587 (_('Database'), val('database')['url'], state('database')),
588 (_('Database version'), val('database')['version'], state('database')),
588 (_('Database version'), val('database')['version'], state('database')),
589 ('', '', ''), # spacer
589 ('', '', ''), # spacer
590
590
591 # Platform/Python
591 # Platform/Python
592 (_('Platform'), val('platform')['name'], state('platform')),
592 (_('Platform'), val('platform')['name'], state('platform')),
593 (_('Platform UUID'), val('platform')['uuid'], state('platform')),
593 (_('Platform UUID'), val('platform')['uuid'], state('platform')),
594 (_('Python version'), val('python')['version'], state('python')),
594 (_('Python version'), val('python')['version'], state('python')),
595 (_('Python path'), val('python')['executable'], state('python')),
595 (_('Python path'), val('python')['executable'], state('python')),
596 ('', '', ''), # spacer
596 ('', '', ''), # spacer
597
597
598 # Systems stats
598 # Systems stats
599 (_('CPU'), val('cpu'), state('cpu')),
599 (_('CPU'), val('cpu'), state('cpu')),
600 (_('Load'), val('load')['text'], state('load')),
600 (_('Load'), val('load')['text'], state('load')),
601 (_('Memory'), val('memory')['text'], state('memory')),
601 (_('Memory'), val('memory')['text'], state('memory')),
602 (_('Uptime'), val('uptime')['text'], state('uptime')),
602 (_('Uptime'), val('uptime')['text'], state('uptime')),
603 ('', '', ''), # spacer
603 ('', '', ''), # spacer
604
604
605 # Repo storage
605 # Repo storage
606 (_('Storage location'), val('storage')['path'], state('storage')),
606 (_('Storage location'), val('storage')['path'], state('storage')),
607 (_('Storage info'), val('storage')['text'], state('storage')),
607 (_('Storage info'), val('storage')['text'], state('storage')),
608 (_('Storage inodes'), val('storage_inodes')['text'], state('storage_inodes')),
608 (_('Storage inodes'), val('storage_inodes')['text'], state('storage_inodes')),
609
609
610 (_('Gist storage location'), val('storage_gist')['path'], state('storage_gist')),
610 (_('Gist storage location'), val('storage_gist')['path'], state('storage_gist')),
611 (_('Gist storage info'), val('storage_gist')['text'], state('storage_gist')),
611 (_('Gist storage info'), val('storage_gist')['text'], state('storage_gist')),
612
612
613 (_('Archive cache storage location'), val('storage_archive')['path'], state('storage_archive')),
613 (_('Archive cache storage location'), val('storage_archive')['path'], state('storage_archive')),
614 (_('Archive cache info'), val('storage_archive')['text'], state('storage_archive')),
614 (_('Archive cache info'), val('storage_archive')['text'], state('storage_archive')),
615
615
616 (_('Temp storage location'), val('storage_temp')['path'], state('storage_temp')),
617 (_('Temp storage info'), val('storage_temp')['text'], state('storage_temp')),
618
616 (_('Search info'), val('search')['text'], state('search')),
619 (_('Search info'), val('search')['text'], state('search')),
617 (_('Search location'), val('search')['location'], state('search')),
620 (_('Search location'), val('search')['location'], state('search')),
618 ('', '', ''), # spacer
621 ('', '', ''), # spacer
619
622
620 # VCS specific
623 # VCS specific
621 (_('VCS Backends'), val('vcs_backends'), state('vcs_backends')),
624 (_('VCS Backends'), val('vcs_backends'), state('vcs_backends')),
622 (_('VCS Server'), val('vcs_server')['text'], state('vcs_server')),
625 (_('VCS Server'), val('vcs_server')['text'], state('vcs_server')),
623 (_('GIT'), val('git'), state('git')),
626 (_('GIT'), val('git'), state('git')),
624 (_('HG'), val('hg'), state('hg')),
627 (_('HG'), val('hg'), state('hg')),
625 (_('SVN'), val('svn'), state('svn')),
628 (_('SVN'), val('svn'), state('svn')),
626
629
627 ]
630 ]
628
631
629 # TODO: marcink, figure out how to allow only selected users to do this
632 # TODO: marcink, figure out how to allow only selected users to do this
630 c.allowed_to_snapshot = c.rhodecode_user.admin
633 c.allowed_to_snapshot = c.rhodecode_user.admin
631
634
632 if snapshot:
635 if snapshot:
633 if c.allowed_to_snapshot:
636 if c.allowed_to_snapshot:
634 c.data_items.pop(0) # remove server info
637 c.data_items.pop(0) # remove server info
635 return render('admin/settings/settings_system_snapshot.html')
638 return render('admin/settings/settings_system_snapshot.html')
636 else:
639 else:
637 h.flash('You are not allowed to do this', category='warning')
640 h.flash('You are not allowed to do this', category='warning')
638
641
639 return htmlfill.render(
642 return htmlfill.render(
640 render('admin/settings/settings.html'),
643 render('admin/settings/settings.html'),
641 defaults=defaults,
644 defaults=defaults,
642 encoding="UTF-8",
645 encoding="UTF-8",
643 force_defaults=False)
646 force_defaults=False)
644
647
645 @staticmethod
648 @staticmethod
646 def get_update_data(update_url):
649 def get_update_data(update_url):
647 """Return the JSON update data."""
650 """Return the JSON update data."""
648 ver = rhodecode.__version__
651 ver = rhodecode.__version__
649 log.debug('Checking for upgrade on `%s` server', update_url)
652 log.debug('Checking for upgrade on `%s` server', update_url)
650 opener = urllib2.build_opener()
653 opener = urllib2.build_opener()
651 opener.addheaders = [('User-agent', 'RhodeCode-SCM/%s' % ver)]
654 opener.addheaders = [('User-agent', 'RhodeCode-SCM/%s' % ver)]
652 response = opener.open(update_url)
655 response = opener.open(update_url)
653 response_data = response.read()
656 response_data = response.read()
654 data = json.loads(response_data)
657 data = json.loads(response_data)
655
658
656 return data
659 return data
657
660
658 @HasPermissionAllDecorator('hg.admin')
661 @HasPermissionAllDecorator('hg.admin')
659 def settings_system_update(self):
662 def settings_system_update(self):
660 """GET /admin/settings/system/updates: All items in the collection"""
663 """GET /admin/settings/system/updates: All items in the collection"""
661 # url('admin_settings_system_update')
664 # url('admin_settings_system_update')
662 defaults = self._form_defaults()
665 defaults = self._form_defaults()
663 update_url = defaults.get('rhodecode_update_url', '')
666 update_url = defaults.get('rhodecode_update_url', '')
664
667
665 _err = lambda s: '<div style="color:#ff8888; padding:4px 0px">%s</div>' % (s)
668 _err = lambda s: '<div style="color:#ff8888; padding:4px 0px">%s</div>' % (s)
666 try:
669 try:
667 data = self.get_update_data(update_url)
670 data = self.get_update_data(update_url)
668 except urllib2.URLError as e:
671 except urllib2.URLError as e:
669 log.exception("Exception contacting upgrade server")
672 log.exception("Exception contacting upgrade server")
670 return _err('Failed to contact upgrade server: %r' % e)
673 return _err('Failed to contact upgrade server: %r' % e)
671 except ValueError as e:
674 except ValueError as e:
672 log.exception("Bad data sent from update server")
675 log.exception("Bad data sent from update server")
673 return _err('Bad data sent from update server')
676 return _err('Bad data sent from update server')
674
677
675 latest = data['versions'][0]
678 latest = data['versions'][0]
676
679
677 c.update_url = update_url
680 c.update_url = update_url
678 c.latest_data = latest
681 c.latest_data = latest
679 c.latest_ver = latest['version']
682 c.latest_ver = latest['version']
680 c.cur_ver = rhodecode.__version__
683 c.cur_ver = rhodecode.__version__
681 c.should_upgrade = False
684 c.should_upgrade = False
682
685
683 if (packaging.version.Version(c.latest_ver) >
686 if (packaging.version.Version(c.latest_ver) >
684 packaging.version.Version(c.cur_ver)):
687 packaging.version.Version(c.cur_ver)):
685 c.should_upgrade = True
688 c.should_upgrade = True
686 c.important_notices = latest['general']
689 c.important_notices = latest['general']
687
690
688 return render('admin/settings/settings_system_update.html')
691 return render('admin/settings/settings_system_update.html')
689
692
690 @HasPermissionAllDecorator('hg.admin')
693 @HasPermissionAllDecorator('hg.admin')
691 def settings_supervisor(self):
694 def settings_supervisor(self):
692 c.rhodecode_ini = rhodecode.CONFIG
695 c.rhodecode_ini = rhodecode.CONFIG
693 c.active = 'supervisor'
696 c.active = 'supervisor'
694
697
695 c.supervisor_procs = OrderedDict([
698 c.supervisor_procs = OrderedDict([
696 (SUPERVISOR_MASTER, {}),
699 (SUPERVISOR_MASTER, {}),
697 ])
700 ])
698
701
699 c.log_size = 10240
702 c.log_size = 10240
700 supervisor = SupervisorModel()
703 supervisor = SupervisorModel()
701
704
702 _connection = supervisor.get_connection(
705 _connection = supervisor.get_connection(
703 c.rhodecode_ini.get('supervisor.uri'))
706 c.rhodecode_ini.get('supervisor.uri'))
704 c.connection_error = None
707 c.connection_error = None
705 try:
708 try:
706 _connection.supervisor.getAllProcessInfo()
709 _connection.supervisor.getAllProcessInfo()
707 except Exception as e:
710 except Exception as e:
708 c.connection_error = str(e)
711 c.connection_error = str(e)
709 log.exception("Exception reading supervisor data")
712 log.exception("Exception reading supervisor data")
710 return render('admin/settings/settings.html')
713 return render('admin/settings/settings.html')
711
714
712 groupid = c.rhodecode_ini.get('supervisor.group_id')
715 groupid = c.rhodecode_ini.get('supervisor.group_id')
713
716
714 # feed our group processes to the main
717 # feed our group processes to the main
715 for proc in supervisor.get_group_processes(_connection, groupid):
718 for proc in supervisor.get_group_processes(_connection, groupid):
716 c.supervisor_procs[proc['name']] = {}
719 c.supervisor_procs[proc['name']] = {}
717
720
718 for k in c.supervisor_procs.keys():
721 for k in c.supervisor_procs.keys():
719 try:
722 try:
720 # master process info
723 # master process info
721 if k == SUPERVISOR_MASTER:
724 if k == SUPERVISOR_MASTER:
722 _data = supervisor.get_master_state(_connection)
725 _data = supervisor.get_master_state(_connection)
723 _data['name'] = 'supervisor master'
726 _data['name'] = 'supervisor master'
724 _data['description'] = 'pid %s, id: %s, ver: %s' % (
727 _data['description'] = 'pid %s, id: %s, ver: %s' % (
725 _data['pid'], _data['id'], _data['ver'])
728 _data['pid'], _data['id'], _data['ver'])
726 c.supervisor_procs[k] = _data
729 c.supervisor_procs[k] = _data
727 else:
730 else:
728 procid = groupid + ":" + k
731 procid = groupid + ":" + k
729 c.supervisor_procs[k] = supervisor.get_process_info(_connection, procid)
732 c.supervisor_procs[k] = supervisor.get_process_info(_connection, procid)
730 except Exception as e:
733 except Exception as e:
731 log.exception("Exception reading supervisor data")
734 log.exception("Exception reading supervisor data")
732 c.supervisor_procs[k] = {'_rhodecode_error': str(e)}
735 c.supervisor_procs[k] = {'_rhodecode_error': str(e)}
733
736
734 return render('admin/settings/settings.html')
737 return render('admin/settings/settings.html')
735
738
736 @HasPermissionAllDecorator('hg.admin')
739 @HasPermissionAllDecorator('hg.admin')
737 def settings_supervisor_log(self, procid):
740 def settings_supervisor_log(self, procid):
738 import rhodecode
741 import rhodecode
739 c.rhodecode_ini = rhodecode.CONFIG
742 c.rhodecode_ini = rhodecode.CONFIG
740 c.active = 'supervisor_tail'
743 c.active = 'supervisor_tail'
741
744
742 supervisor = SupervisorModel()
745 supervisor = SupervisorModel()
743 _connection = supervisor.get_connection(c.rhodecode_ini.get('supervisor.uri'))
746 _connection = supervisor.get_connection(c.rhodecode_ini.get('supervisor.uri'))
744 groupid = c.rhodecode_ini.get('supervisor.group_id')
747 groupid = c.rhodecode_ini.get('supervisor.group_id')
745 procid = groupid + ":" + procid if procid != SUPERVISOR_MASTER else procid
748 procid = groupid + ":" + procid if procid != SUPERVISOR_MASTER else procid
746
749
747 c.log_size = 10240
750 c.log_size = 10240
748 offset = abs(safe_int(request.GET.get('offset', c.log_size))) * -1
751 offset = abs(safe_int(request.GET.get('offset', c.log_size))) * -1
749 c.log = supervisor.read_process_log(_connection, procid, offset, 0)
752 c.log = supervisor.read_process_log(_connection, procid, offset, 0)
750
753
751 return render('admin/settings/settings.html')
754 return render('admin/settings/settings.html')
752
755
753 @HasPermissionAllDecorator('hg.admin')
756 @HasPermissionAllDecorator('hg.admin')
754 @auth.CSRFRequired()
757 @auth.CSRFRequired()
755 def settings_labs_update(self):
758 def settings_labs_update(self):
756 """POST /admin/settings/labs: All items in the collection"""
759 """POST /admin/settings/labs: All items in the collection"""
757 # url('admin_settings/labs', method={'POST'})
760 # url('admin_settings/labs', method={'POST'})
758 c.active = 'labs'
761 c.active = 'labs'
759
762
760 application_form = LabsSettingsForm()()
763 application_form = LabsSettingsForm()()
761 try:
764 try:
762 form_result = application_form.to_python(dict(request.POST))
765 form_result = application_form.to_python(dict(request.POST))
763 except formencode.Invalid as errors:
766 except formencode.Invalid as errors:
764 h.flash(
767 h.flash(
765 _('Some form inputs contain invalid data.'),
768 _('Some form inputs contain invalid data.'),
766 category='error')
769 category='error')
767 return htmlfill.render(
770 return htmlfill.render(
768 render('admin/settings/settings.html'),
771 render('admin/settings/settings.html'),
769 defaults=errors.value,
772 defaults=errors.value,
770 errors=errors.error_dict or {},
773 errors=errors.error_dict or {},
771 prefix_error=False,
774 prefix_error=False,
772 encoding='UTF-8',
775 encoding='UTF-8',
773 force_defaults=False
776 force_defaults=False
774 )
777 )
775
778
776 try:
779 try:
777 session = Session()
780 session = Session()
778 for setting in _LAB_SETTINGS:
781 for setting in _LAB_SETTINGS:
779 setting_name = setting.key[len('rhodecode_'):]
782 setting_name = setting.key[len('rhodecode_'):]
780 sett = SettingsModel().create_or_update_setting(
783 sett = SettingsModel().create_or_update_setting(
781 setting_name, form_result[setting.key], setting.type)
784 setting_name, form_result[setting.key], setting.type)
782 session.add(sett)
785 session.add(sett)
783
786
784 except Exception:
787 except Exception:
785 log.exception('Exception while updating lab settings')
788 log.exception('Exception while updating lab settings')
786 h.flash(_('Error occurred during updating labs settings'),
789 h.flash(_('Error occurred during updating labs settings'),
787 category='error')
790 category='error')
788 else:
791 else:
789 Session().commit()
792 Session().commit()
790 SettingsModel().invalidate_settings_cache()
793 SettingsModel().invalidate_settings_cache()
791 h.flash(_('Updated Labs settings'), category='success')
794 h.flash(_('Updated Labs settings'), category='success')
792 return redirect(url('admin_settings_labs'))
795 return redirect(url('admin_settings_labs'))
793
796
794 return htmlfill.render(
797 return htmlfill.render(
795 render('admin/settings/settings.html'),
798 render('admin/settings/settings.html'),
796 defaults=self._form_defaults(),
799 defaults=self._form_defaults(),
797 encoding='UTF-8',
800 encoding='UTF-8',
798 force_defaults=False)
801 force_defaults=False)
799
802
800 @HasPermissionAllDecorator('hg.admin')
803 @HasPermissionAllDecorator('hg.admin')
801 def settings_labs(self):
804 def settings_labs(self):
802 """GET /admin/settings/labs: All items in the collection"""
805 """GET /admin/settings/labs: All items in the collection"""
803 # url('admin_settings_labs')
806 # url('admin_settings_labs')
804 if not c.labs_active:
807 if not c.labs_active:
805 redirect(url('admin_settings'))
808 redirect(url('admin_settings'))
806
809
807 c.active = 'labs'
810 c.active = 'labs'
808 c.lab_settings = _LAB_SETTINGS
811 c.lab_settings = _LAB_SETTINGS
809
812
810 return htmlfill.render(
813 return htmlfill.render(
811 render('admin/settings/settings.html'),
814 render('admin/settings/settings.html'),
812 defaults=self._form_defaults(),
815 defaults=self._form_defaults(),
813 encoding='UTF-8',
816 encoding='UTF-8',
814 force_defaults=False)
817 force_defaults=False)
815
818
816 def _form_defaults(self):
819 def _form_defaults(self):
817 defaults = SettingsModel().get_all_settings()
820 defaults = SettingsModel().get_all_settings()
818 defaults.update(self._get_hg_ui_settings())
821 defaults.update(self._get_hg_ui_settings())
819 defaults.update({
822 defaults.update({
820 'new_svn_branch': '',
823 'new_svn_branch': '',
821 'new_svn_tag': '',
824 'new_svn_tag': '',
822 })
825 })
823 return defaults
826 return defaults
824
827
825
828
826 # :param key: name of the setting including the 'rhodecode_' prefix
829 # :param key: name of the setting including the 'rhodecode_' prefix
827 # :param type: the RhodeCodeSetting type to use.
830 # :param type: the RhodeCodeSetting type to use.
828 # :param group: the i18ned group in which we should dispaly this setting
831 # :param group: the i18ned group in which we should dispaly this setting
829 # :param label: the i18ned label we should display for this setting
832 # :param label: the i18ned label we should display for this setting
830 # :param help: the i18ned help we should dispaly for this setting
833 # :param help: the i18ned help we should dispaly for this setting
831 LabSetting = collections.namedtuple(
834 LabSetting = collections.namedtuple(
832 'LabSetting', ('key', 'type', 'group', 'label', 'help'))
835 'LabSetting', ('key', 'type', 'group', 'label', 'help'))
833
836
834
837
835 # This list has to be kept in sync with the form
838 # This list has to be kept in sync with the form
836 # rhodecode.model.forms.LabsSettingsForm.
839 # rhodecode.model.forms.LabsSettingsForm.
837 _LAB_SETTINGS = [
840 _LAB_SETTINGS = [
838
841
839 ]
842 ]
@@ -1,612 +1,641 b''
1 import os
1 import os
2 import sys
2 import sys
3 import time
3 import time
4 import platform
4 import platform
5 import pkg_resources
5 import pkg_resources
6 import logging
6 import logging
7 import string
7 import string
8
8
9
9
10 log = logging.getLogger(__name__)
10 log = logging.getLogger(__name__)
11
11
12
12
13 psutil = None
13 psutil = None
14
14
15 try:
15 try:
16 # cygwin cannot have yet psutil support.
16 # cygwin cannot have yet psutil support.
17 import psutil as psutil
17 import psutil as psutil
18 except ImportError:
18 except ImportError:
19 pass
19 pass
20
20
21
21
22 _NA = 'NOT AVAILABLE'
22 _NA = 'NOT AVAILABLE'
23
23
24 STATE_OK = 'ok'
24 STATE_OK = 'ok'
25 STATE_ERR = 'error'
25 STATE_ERR = 'error'
26 STATE_WARN = 'warning'
26 STATE_WARN = 'warning'
27
27
28 STATE_OK_DEFAULT = {'message': '', 'type': STATE_OK}
28 STATE_OK_DEFAULT = {'message': '', 'type': STATE_OK}
29
29
30
30
31 # HELPERS
31 # HELPERS
32 def percentage(part, whole):
32 def percentage(part, whole):
33 whole = float(whole)
33 whole = float(whole)
34 if whole > 0:
34 if whole > 0:
35 return 100 * float(part) / whole
35 return 100 * float(part) / whole
36 return 0
36 return 0
37
37
38
38
39 def get_storage_size(storage_path):
39 def get_storage_size(storage_path):
40 sizes = []
40 sizes = []
41 for file_ in os.listdir(storage_path):
41 for file_ in os.listdir(storage_path):
42 storage_file = os.path.join(storage_path, file_)
42 storage_file = os.path.join(storage_path, file_)
43 if os.path.isfile(storage_file):
43 if os.path.isfile(storage_file):
44 try:
44 try:
45 sizes.append(os.path.getsize(storage_file))
45 sizes.append(os.path.getsize(storage_file))
46 except OSError:
46 except OSError:
47 log.exception('Failed to get size of storage file %s',
47 log.exception('Failed to get size of storage file %s',
48 storage_file)
48 storage_file)
49 pass
49 pass
50
50
51 return sum(sizes)
51 return sum(sizes)
52
52
53
53
54 class SysInfoRes(object):
54 class SysInfoRes(object):
55 def __init__(self, value, state=STATE_OK_DEFAULT, human_value=None):
55 def __init__(self, value, state=STATE_OK_DEFAULT, human_value=None):
56 self.value = value
56 self.value = value
57 self.state = state
57 self.state = state
58 self.human_value = human_value or value
58 self.human_value = human_value or value
59
59
60 def __json__(self):
60 def __json__(self):
61 return {
61 return {
62 'value': self.value,
62 'value': self.value,
63 'state': self.state,
63 'state': self.state,
64 'human_value': self.human_value,
64 'human_value': self.human_value,
65 }
65 }
66
66
67 def __str__(self):
67 def __str__(self):
68 return '<SysInfoRes({})>'.format(self.__json__())
68 return '<SysInfoRes({})>'.format(self.__json__())
69
69
70
70
71 class SysInfo(object):
71 class SysInfo(object):
72
72
73 def __init__(self, func_name, **kwargs):
73 def __init__(self, func_name, **kwargs):
74 self.func_name = func_name
74 self.func_name = func_name
75 self.value = _NA
75 self.value = _NA
76 self.state = None
76 self.state = None
77 self.kwargs = kwargs or {}
77 self.kwargs = kwargs or {}
78
78
79 def __call__(self):
79 def __call__(self):
80 computed = self.compute(**self.kwargs)
80 computed = self.compute(**self.kwargs)
81 if not isinstance(computed, SysInfoRes):
81 if not isinstance(computed, SysInfoRes):
82 raise ValueError(
82 raise ValueError(
83 'computed value for {} is not instance of '
83 'computed value for {} is not instance of '
84 '{}, got {} instead'.format(
84 '{}, got {} instead'.format(
85 self.func_name, SysInfoRes, type(computed)))
85 self.func_name, SysInfoRes, type(computed)))
86 return computed.__json__()
86 return computed.__json__()
87
87
88 def __str__(self):
88 def __str__(self):
89 return '<SysInfo({})>'.format(self.func_name)
89 return '<SysInfo({})>'.format(self.func_name)
90
90
91 def compute(self, **kwargs):
91 def compute(self, **kwargs):
92 return self.func_name(**kwargs)
92 return self.func_name(**kwargs)
93
93
94
94
95 # SysInfo functions
95 # SysInfo functions
96 def python_info():
96 def python_info():
97 value = dict(version=' '.join(platform._sys_version()),
97 value = dict(version=' '.join(platform._sys_version()),
98 executable=sys.executable)
98 executable=sys.executable)
99 return SysInfoRes(value=value)
99 return SysInfoRes(value=value)
100
100
101
101
102 def py_modules():
102 def py_modules():
103 mods = dict([(p.project_name, p.version)
103 mods = dict([(p.project_name, p.version)
104 for p in pkg_resources.working_set])
104 for p in pkg_resources.working_set])
105 value = sorted(mods.items(), key=lambda k: k[0].lower())
105 value = sorted(mods.items(), key=lambda k: k[0].lower())
106 return SysInfoRes(value=value)
106 return SysInfoRes(value=value)
107
107
108
108
109 def platform_type():
109 def platform_type():
110 from rhodecode.lib.utils import safe_unicode, generate_platform_uuid
110 from rhodecode.lib.utils import safe_unicode, generate_platform_uuid
111
111
112 value = dict(
112 value = dict(
113 name=safe_unicode(platform.platform()),
113 name=safe_unicode(platform.platform()),
114 uuid=generate_platform_uuid()
114 uuid=generate_platform_uuid()
115 )
115 )
116 return SysInfoRes(value=value)
116 return SysInfoRes(value=value)
117
117
118
118
119 def uptime():
119 def uptime():
120 from rhodecode.lib.helpers import age, time_to_datetime
120 from rhodecode.lib.helpers import age, time_to_datetime
121
121
122 value = dict(boot_time=0, uptime=0, text='')
122 value = dict(boot_time=0, uptime=0, text='')
123 state = STATE_OK_DEFAULT
123 state = STATE_OK_DEFAULT
124 if not psutil:
124 if not psutil:
125 return SysInfoRes(value=value, state=state)
125 return SysInfoRes(value=value, state=state)
126
126
127 boot_time = psutil.boot_time()
127 boot_time = psutil.boot_time()
128 value['boot_time'] = boot_time
128 value['boot_time'] = boot_time
129 value['uptime'] = time.time() - boot_time
129 value['uptime'] = time.time() - boot_time
130
130
131 human_value = value.copy()
131 human_value = value.copy()
132 human_value['boot_time'] = time_to_datetime(boot_time)
132 human_value['boot_time'] = time_to_datetime(boot_time)
133 human_value['uptime'] = age(time_to_datetime(boot_time), show_suffix=False)
133 human_value['uptime'] = age(time_to_datetime(boot_time), show_suffix=False)
134 human_value['text'] = 'Server started {}'.format(
134 human_value['text'] = 'Server started {}'.format(
135 age(time_to_datetime(boot_time)))
135 age(time_to_datetime(boot_time)))
136
136
137 return SysInfoRes(value=value, human_value=human_value)
137 return SysInfoRes(value=value, human_value=human_value)
138
138
139
139
140 def memory():
140 def memory():
141 from rhodecode.lib.helpers import format_byte_size_binary
141 from rhodecode.lib.helpers import format_byte_size_binary
142 value = dict(available=0, used=0, used_real=0, cached=0, percent=0,
142 value = dict(available=0, used=0, used_real=0, cached=0, percent=0,
143 percent_used=0, free=0, inactive=0, active=0, shared=0,
143 percent_used=0, free=0, inactive=0, active=0, shared=0,
144 total=0, buffers=0, text='')
144 total=0, buffers=0, text='')
145
145
146 state = STATE_OK_DEFAULT
146 state = STATE_OK_DEFAULT
147 if not psutil:
147 if not psutil:
148 return SysInfoRes(value=value, state=state)
148 return SysInfoRes(value=value, state=state)
149
149
150 value.update(dict(psutil.virtual_memory()._asdict()))
150 value.update(dict(psutil.virtual_memory()._asdict()))
151 value['used_real'] = value['total'] - value['available']
151 value['used_real'] = value['total'] - value['available']
152 value['percent_used'] = psutil._common.usage_percent(
152 value['percent_used'] = psutil._common.usage_percent(
153 value['used_real'], value['total'], 1)
153 value['used_real'], value['total'], 1)
154
154
155 human_value = value.copy()
155 human_value = value.copy()
156 human_value['text'] = '%s/%s, %s%% used' % (
156 human_value['text'] = '%s/%s, %s%% used' % (
157 format_byte_size_binary(value['used_real']),
157 format_byte_size_binary(value['used_real']),
158 format_byte_size_binary(value['total']),
158 format_byte_size_binary(value['total']),
159 value['percent_used'],)
159 value['percent_used'],)
160
160
161 keys = value.keys()[::]
161 keys = value.keys()[::]
162 keys.pop(keys.index('percent'))
162 keys.pop(keys.index('percent'))
163 keys.pop(keys.index('percent_used'))
163 keys.pop(keys.index('percent_used'))
164 keys.pop(keys.index('text'))
164 keys.pop(keys.index('text'))
165 for k in keys:
165 for k in keys:
166 human_value[k] = format_byte_size_binary(value[k])
166 human_value[k] = format_byte_size_binary(value[k])
167
167
168 if state['type'] == STATE_OK and value['percent_used'] > 90:
168 if state['type'] == STATE_OK and value['percent_used'] > 90:
169 msg = 'Critical: your available RAM memory is very low.'
169 msg = 'Critical: your available RAM memory is very low.'
170 state = {'message': msg, 'type': STATE_ERR}
170 state = {'message': msg, 'type': STATE_ERR}
171
171
172 elif state['type'] == STATE_OK and value['percent_used'] > 70:
172 elif state['type'] == STATE_OK and value['percent_used'] > 70:
173 msg = 'Warning: your available RAM memory is running low.'
173 msg = 'Warning: your available RAM memory is running low.'
174 state = {'message': msg, 'type': STATE_WARN}
174 state = {'message': msg, 'type': STATE_WARN}
175
175
176 return SysInfoRes(value=value, state=state, human_value=human_value)
176 return SysInfoRes(value=value, state=state, human_value=human_value)
177
177
178
178
179 def machine_load():
179 def machine_load():
180 value = {'1_min': _NA, '5_min': _NA, '15_min': _NA, 'text': ''}
180 value = {'1_min': _NA, '5_min': _NA, '15_min': _NA, 'text': ''}
181 state = STATE_OK_DEFAULT
181 state = STATE_OK_DEFAULT
182 if not psutil:
182 if not psutil:
183 return SysInfoRes(value=value, state=state)
183 return SysInfoRes(value=value, state=state)
184
184
185 # load averages
185 # load averages
186 if hasattr(psutil.os, 'getloadavg'):
186 if hasattr(psutil.os, 'getloadavg'):
187 value.update(dict(
187 value.update(dict(
188 zip(['1_min', '5_min', '15_min'], psutil.os.getloadavg())))
188 zip(['1_min', '5_min', '15_min'], psutil.os.getloadavg())))
189
189
190 human_value = value.copy()
190 human_value = value.copy()
191 human_value['text'] = '1min: {}, 5min: {}, 15min: {}'.format(
191 human_value['text'] = '1min: {}, 5min: {}, 15min: {}'.format(
192 value['1_min'], value['5_min'], value['15_min'])
192 value['1_min'], value['5_min'], value['15_min'])
193
193
194 if state['type'] == STATE_OK and value['15_min'] > 5:
194 if state['type'] == STATE_OK and value['15_min'] > 5:
195 msg = 'Warning: your machine load is very high.'
195 msg = 'Warning: your machine load is very high.'
196 state = {'message': msg, 'type': STATE_WARN}
196 state = {'message': msg, 'type': STATE_WARN}
197
197
198 return SysInfoRes(value=value, state=state, human_value=human_value)
198 return SysInfoRes(value=value, state=state, human_value=human_value)
199
199
200
200
201 def cpu():
201 def cpu():
202 value = 0
202 value = 0
203 state = STATE_OK_DEFAULT
203 state = STATE_OK_DEFAULT
204
204
205 if not psutil:
205 if not psutil:
206 return SysInfoRes(value=value, state=state)
206 return SysInfoRes(value=value, state=state)
207
207
208 value = psutil.cpu_percent(0.5)
208 value = psutil.cpu_percent(0.5)
209 human_value = '{} %'.format(value)
209 human_value = '{} %'.format(value)
210 return SysInfoRes(value=value, state=state, human_value=human_value)
210 return SysInfoRes(value=value, state=state, human_value=human_value)
211
211
212
212
213 def storage():
213 def storage():
214 from rhodecode.lib.helpers import format_byte_size_binary
214 from rhodecode.lib.helpers import format_byte_size_binary
215 from rhodecode.model.settings import VcsSettingsModel
215 from rhodecode.model.settings import VcsSettingsModel
216 path = VcsSettingsModel().get_repos_location()
216 path = VcsSettingsModel().get_repos_location()
217
217
218 value = dict(percent=0, used=0, total=0, path=path, text='')
218 value = dict(percent=0, used=0, total=0, path=path, text='')
219 state = STATE_OK_DEFAULT
219 state = STATE_OK_DEFAULT
220 if not psutil:
220 if not psutil:
221 return SysInfoRes(value=value, state=state)
221 return SysInfoRes(value=value, state=state)
222
222
223 try:
223 try:
224 value.update(dict(psutil.disk_usage(path)._asdict()))
224 value.update(dict(psutil.disk_usage(path)._asdict()))
225 except Exception as e:
225 except Exception as e:
226 log.exception('Failed to fetch disk info')
226 log.exception('Failed to fetch disk info')
227 state = {'message': str(e), 'type': STATE_ERR}
227 state = {'message': str(e), 'type': STATE_ERR}
228
228
229 human_value = value.copy()
229 human_value = value.copy()
230 human_value['used'] = format_byte_size_binary(value['used'])
230 human_value['used'] = format_byte_size_binary(value['used'])
231 human_value['total'] = format_byte_size_binary(value['total'])
231 human_value['total'] = format_byte_size_binary(value['total'])
232 human_value['text'] = "{}/{}, {}% used".format(
232 human_value['text'] = "{}/{}, {}% used".format(
233 format_byte_size_binary(value['used']),
233 format_byte_size_binary(value['used']),
234 format_byte_size_binary(value['total']),
234 format_byte_size_binary(value['total']),
235 value['percent'])
235 value['percent'])
236
236
237 if state['type'] == STATE_OK and value['percent'] > 90:
237 if state['type'] == STATE_OK and value['percent'] > 90:
238 msg = 'Critical: your disk space is very low.'
238 msg = 'Critical: your disk space is very low.'
239 state = {'message': msg, 'type': STATE_ERR}
239 state = {'message': msg, 'type': STATE_ERR}
240
240
241 elif state['type'] == STATE_OK and value['percent'] > 70:
241 elif state['type'] == STATE_OK and value['percent'] > 70:
242 msg = 'Warning: your disk space is running low.'
242 msg = 'Warning: your disk space is running low.'
243 state = {'message': msg, 'type': STATE_WARN}
243 state = {'message': msg, 'type': STATE_WARN}
244
244
245 return SysInfoRes(value=value, state=state, human_value=human_value)
245 return SysInfoRes(value=value, state=state, human_value=human_value)
246
246
247
247
248 def storage_inodes():
248 def storage_inodes():
249 from rhodecode.model.settings import VcsSettingsModel
249 from rhodecode.model.settings import VcsSettingsModel
250 path = VcsSettingsModel().get_repos_location()
250 path = VcsSettingsModel().get_repos_location()
251
251
252 value = dict(percent=0, free=0, used=0, total=0, path=path, text='')
252 value = dict(percent=0, free=0, used=0, total=0, path=path, text='')
253 state = STATE_OK_DEFAULT
253 state = STATE_OK_DEFAULT
254 if not psutil:
254 if not psutil:
255 return SysInfoRes(value=value, state=state)
255 return SysInfoRes(value=value, state=state)
256
256
257 try:
257 try:
258 i_stat = os.statvfs(path)
258 i_stat = os.statvfs(path)
259
259
260 value['used'] = i_stat.f_ffree
260 value['used'] = i_stat.f_ffree
261 value['free'] = i_stat.f_favail
261 value['free'] = i_stat.f_favail
262 value['total'] = i_stat.f_files
262 value['total'] = i_stat.f_files
263 value['percent'] = percentage(
263 value['percent'] = percentage(
264 value['used'], value['total'])
264 value['used'], value['total'])
265 except Exception as e:
265 except Exception as e:
266 log.exception('Failed to fetch disk inodes info')
266 log.exception('Failed to fetch disk inodes info')
267 state = {'message': str(e), 'type': STATE_ERR}
267 state = {'message': str(e), 'type': STATE_ERR}
268
268
269 human_value = value.copy()
269 human_value = value.copy()
270 human_value['text'] = "{}/{}, {}% used".format(
270 human_value['text'] = "{}/{}, {}% used".format(
271 value['used'], value['total'], value['percent'])
271 value['used'], value['total'], value['percent'])
272
272
273 if state['type'] == STATE_OK and value['percent'] > 90:
273 if state['type'] == STATE_OK and value['percent'] > 90:
274 msg = 'Critical: your disk free inodes are very low.'
274 msg = 'Critical: your disk free inodes are very low.'
275 state = {'message': msg, 'type': STATE_ERR}
275 state = {'message': msg, 'type': STATE_ERR}
276
276
277 elif state['type'] == STATE_OK and value['percent'] > 70:
277 elif state['type'] == STATE_OK and value['percent'] > 70:
278 msg = 'Warning: your disk free inodes are running low.'
278 msg = 'Warning: your disk free inodes are running low.'
279 state = {'message': msg, 'type': STATE_WARN}
279 state = {'message': msg, 'type': STATE_WARN}
280
280
281 return SysInfoRes(value=value, state=state)
281 return SysInfoRes(value=value, state=state)
282
282
283
283
284 def storage_archives():
284 def storage_archives():
285 import rhodecode
285 import rhodecode
286 from rhodecode.lib.utils import safe_str
286 from rhodecode.lib.utils import safe_str
287 from rhodecode.lib.helpers import format_byte_size_binary
287 from rhodecode.lib.helpers import format_byte_size_binary
288
288
289 msg = 'Enable this by setting ' \
289 msg = 'Enable this by setting ' \
290 'archive_cache_dir=/path/to/cache option in the .ini file'
290 'archive_cache_dir=/path/to/cache option in the .ini file'
291 path = safe_str(rhodecode.CONFIG.get('archive_cache_dir', msg))
291 path = safe_str(rhodecode.CONFIG.get('archive_cache_dir', msg))
292
292
293 value = dict(percent=0, used=0, total=0, items=0, path=path, text='')
293 value = dict(percent=0, used=0, total=0, items=0, path=path, text='')
294 state = STATE_OK_DEFAULT
294 state = STATE_OK_DEFAULT
295 try:
295 try:
296 items_count = 0
296 items_count = 0
297 used = 0
297 used = 0
298 for root, dirs, files in os.walk(path):
298 for root, dirs, files in os.walk(path):
299 if root == path:
299 if root == path:
300 items_count = len(files)
300 items_count = len(files)
301
301
302 for f in files:
302 for f in files:
303 try:
303 try:
304 used += os.path.getsize(os.path.join(root, f))
304 used += os.path.getsize(os.path.join(root, f))
305 except OSError:
305 except OSError:
306 pass
306 pass
307 value.update({
307 value.update({
308 'percent': 100,
308 'percent': 100,
309 'used': used,
309 'used': used,
310 'total': used,
310 'total': used,
311 'items': items_count
311 'items': items_count
312 })
312 })
313
313
314 except Exception as e:
314 except Exception as e:
315 log.exception('failed to fetch archive cache storage')
315 log.exception('failed to fetch archive cache storage')
316 state = {'message': str(e), 'type': STATE_ERR}
316 state = {'message': str(e), 'type': STATE_ERR}
317
317
318 human_value = value.copy()
318 human_value = value.copy()
319 human_value['used'] = format_byte_size_binary(value['used'])
319 human_value['used'] = format_byte_size_binary(value['used'])
320 human_value['total'] = format_byte_size_binary(value['total'])
320 human_value['total'] = format_byte_size_binary(value['total'])
321 human_value['text'] = "{} ({} items)".format(
321 human_value['text'] = "{} ({} items)".format(
322 human_value['used'], value['items'])
322 human_value['used'], value['items'])
323
323
324 return SysInfoRes(value=value, state=state, human_value=human_value)
324 return SysInfoRes(value=value, state=state, human_value=human_value)
325
325
326
326
327 def storage_gist():
327 def storage_gist():
328 from rhodecode.model.gist import GIST_STORE_LOC
328 from rhodecode.model.gist import GIST_STORE_LOC
329 from rhodecode.model.settings import VcsSettingsModel
329 from rhodecode.model.settings import VcsSettingsModel
330 from rhodecode.lib.utils import safe_str
330 from rhodecode.lib.utils import safe_str
331 from rhodecode.lib.helpers import format_byte_size_binary
331 from rhodecode.lib.helpers import format_byte_size_binary
332 path = safe_str(os.path.join(
332 path = safe_str(os.path.join(
333 VcsSettingsModel().get_repos_location(), GIST_STORE_LOC))
333 VcsSettingsModel().get_repos_location(), GIST_STORE_LOC))
334
334
335 # gist storage
335 # gist storage
336 value = dict(percent=0, used=0, total=0, items=0, path=path, text='')
336 value = dict(percent=0, used=0, total=0, items=0, path=path, text='')
337 state = STATE_OK_DEFAULT
337 state = STATE_OK_DEFAULT
338
338
339 try:
339 try:
340 items_count = 0
340 items_count = 0
341 used = 0
341 used = 0
342 for root, dirs, files in os.walk(path):
342 for root, dirs, files in os.walk(path):
343 if root == path:
343 if root == path:
344 items_count = len(dirs)
344 items_count = len(dirs)
345
345
346 for f in files:
346 for f in files:
347 try:
347 try:
348 used += os.path.getsize(os.path.join(root, f))
348 used += os.path.getsize(os.path.join(root, f))
349 except OSError:
349 except OSError:
350 pass
350 pass
351 value.update({
351 value.update({
352 'percent': 100,
352 'percent': 100,
353 'used': used,
353 'used': used,
354 'total': used,
354 'total': used,
355 'items': items_count
355 'items': items_count
356 })
356 })
357 except Exception as e:
357 except Exception as e:
358 log.exception('failed to fetch gist storage items')
358 log.exception('failed to fetch gist storage items')
359 state = {'message': str(e), 'type': STATE_ERR}
359 state = {'message': str(e), 'type': STATE_ERR}
360
360
361 human_value = value.copy()
361 human_value = value.copy()
362 human_value['used'] = format_byte_size_binary(value['used'])
362 human_value['used'] = format_byte_size_binary(value['used'])
363 human_value['total'] = format_byte_size_binary(value['total'])
363 human_value['total'] = format_byte_size_binary(value['total'])
364 human_value['text'] = "{} ({} items)".format(
364 human_value['text'] = "{} ({} items)".format(
365 human_value['used'], value['items'])
365 human_value['used'], value['items'])
366
366
367 return SysInfoRes(value=value, state=state, human_value=human_value)
367 return SysInfoRes(value=value, state=state, human_value=human_value)
368
368
369
369
370 def storage_temp():
371 import tempfile
372 from rhodecode.lib.helpers import format_byte_size_binary
373
374 path = tempfile.gettempdir()
375 value = dict(percent=0, used=0, total=0, items=0, path=path, text='')
376 state = STATE_OK_DEFAULT
377
378 if not psutil:
379 return SysInfoRes(value=value, state=state)
380
381 try:
382 value.update(dict(psutil.disk_usage(path)._asdict()))
383 except Exception as e:
384 log.exception('Failed to fetch temp dir info')
385 state = {'message': str(e), 'type': STATE_ERR}
386
387 human_value = value.copy()
388 human_value['used'] = format_byte_size_binary(value['used'])
389 human_value['total'] = format_byte_size_binary(value['total'])
390 human_value['text'] = "{}/{}, {}% used".format(
391 format_byte_size_binary(value['used']),
392 format_byte_size_binary(value['total']),
393 value['percent'])
394
395 return SysInfoRes(value=value, state=state, human_value=human_value)
396
397
370 def search_info():
398 def search_info():
371 import rhodecode
399 import rhodecode
372 from rhodecode.lib.index import searcher_from_config
400 from rhodecode.lib.index import searcher_from_config
373
401
374 backend = rhodecode.CONFIG.get('search.module', '')
402 backend = rhodecode.CONFIG.get('search.module', '')
375 location = rhodecode.CONFIG.get('search.location', '')
403 location = rhodecode.CONFIG.get('search.location', '')
376
404
377 try:
405 try:
378 searcher = searcher_from_config(rhodecode.CONFIG)
406 searcher = searcher_from_config(rhodecode.CONFIG)
379 searcher = searcher.__class__.__name__
407 searcher = searcher.__class__.__name__
380 except Exception:
408 except Exception:
381 searcher = None
409 searcher = None
382
410
383 value = dict(
411 value = dict(
384 backend=backend, searcher=searcher, location=location, text='')
412 backend=backend, searcher=searcher, location=location, text='')
385 state = STATE_OK_DEFAULT
413 state = STATE_OK_DEFAULT
386
414
387 human_value = value.copy()
415 human_value = value.copy()
388 human_value['text'] = "backend:`{}`".format(human_value['backend'])
416 human_value['text'] = "backend:`{}`".format(human_value['backend'])
389
417
390 return SysInfoRes(value=value, state=state, human_value=human_value)
418 return SysInfoRes(value=value, state=state, human_value=human_value)
391
419
392
420
393 def git_info():
421 def git_info():
394 from rhodecode.lib.vcs.backends import git
422 from rhodecode.lib.vcs.backends import git
395 state = STATE_OK_DEFAULT
423 state = STATE_OK_DEFAULT
396 value = human_value = ''
424 value = human_value = ''
397 try:
425 try:
398 value = git.discover_git_version(raise_on_exc=True)
426 value = git.discover_git_version(raise_on_exc=True)
399 human_value = 'version reported from VCSServer: {}'.format(value)
427 human_value = 'version reported from VCSServer: {}'.format(value)
400 except Exception as e:
428 except Exception as e:
401 state = {'message': str(e), 'type': STATE_ERR}
429 state = {'message': str(e), 'type': STATE_ERR}
402
430
403 return SysInfoRes(value=value, state=state, human_value=human_value)
431 return SysInfoRes(value=value, state=state, human_value=human_value)
404
432
405
433
406 def hg_info():
434 def hg_info():
407 from rhodecode.lib.vcs.backends import hg
435 from rhodecode.lib.vcs.backends import hg
408 state = STATE_OK_DEFAULT
436 state = STATE_OK_DEFAULT
409 value = human_value = ''
437 value = human_value = ''
410 try:
438 try:
411 value = hg.discover_hg_version(raise_on_exc=True)
439 value = hg.discover_hg_version(raise_on_exc=True)
412 human_value = 'version reported from VCSServer: {}'.format(value)
440 human_value = 'version reported from VCSServer: {}'.format(value)
413 except Exception as e:
441 except Exception as e:
414 state = {'message': str(e), 'type': STATE_ERR}
442 state = {'message': str(e), 'type': STATE_ERR}
415 return SysInfoRes(value=value, state=state, human_value=human_value)
443 return SysInfoRes(value=value, state=state, human_value=human_value)
416
444
417
445
418 def svn_info():
446 def svn_info():
419 from rhodecode.lib.vcs.backends import svn
447 from rhodecode.lib.vcs.backends import svn
420 state = STATE_OK_DEFAULT
448 state = STATE_OK_DEFAULT
421 value = human_value = ''
449 value = human_value = ''
422 try:
450 try:
423 value = svn.discover_svn_version(raise_on_exc=True)
451 value = svn.discover_svn_version(raise_on_exc=True)
424 human_value = 'version reported from VCSServer: {}'.format(value)
452 human_value = 'version reported from VCSServer: {}'.format(value)
425 except Exception as e:
453 except Exception as e:
426 state = {'message': str(e), 'type': STATE_ERR}
454 state = {'message': str(e), 'type': STATE_ERR}
427 return SysInfoRes(value=value, state=state, human_value=human_value)
455 return SysInfoRes(value=value, state=state, human_value=human_value)
428
456
429
457
430 def vcs_backends():
458 def vcs_backends():
431 import rhodecode
459 import rhodecode
432 value = map(
460 value = map(
433 string.strip, rhodecode.CONFIG.get('vcs.backends', '').split(','))
461 string.strip, rhodecode.CONFIG.get('vcs.backends', '').split(','))
434 human_value = 'Enabled backends in order: {}'.format(','.join(value))
462 human_value = 'Enabled backends in order: {}'.format(','.join(value))
435 return SysInfoRes(value=value, human_value=human_value)
463 return SysInfoRes(value=value, human_value=human_value)
436
464
437
465
438 def vcs_server():
466 def vcs_server():
439 import rhodecode
467 import rhodecode
440 from rhodecode.lib.vcs.backends import get_vcsserver_version
468 from rhodecode.lib.vcs.backends import get_vcsserver_version
441
469
442 server_url = rhodecode.CONFIG.get('vcs.server')
470 server_url = rhodecode.CONFIG.get('vcs.server')
443 enabled = rhodecode.CONFIG.get('vcs.server.enable')
471 enabled = rhodecode.CONFIG.get('vcs.server.enable')
444 protocol = rhodecode.CONFIG.get('vcs.server.protocol')
472 protocol = rhodecode.CONFIG.get('vcs.server.protocol')
445 state = STATE_OK_DEFAULT
473 state = STATE_OK_DEFAULT
446 version = None
474 version = None
447
475
448 try:
476 try:
449 version = get_vcsserver_version()
477 version = get_vcsserver_version()
450 connection = 'connected'
478 connection = 'connected'
451 except Exception as e:
479 except Exception as e:
452 connection = 'failed'
480 connection = 'failed'
453 state = {'message': str(e), 'type': STATE_ERR}
481 state = {'message': str(e), 'type': STATE_ERR}
454
482
455 value = dict(
483 value = dict(
456 url=server_url,
484 url=server_url,
457 enabled=enabled,
485 enabled=enabled,
458 protocol=protocol,
486 protocol=protocol,
459 connection=connection,
487 connection=connection,
460 version=version,
488 version=version,
461 text='',
489 text='',
462 )
490 )
463
491
464 human_value = value.copy()
492 human_value = value.copy()
465 human_value['text'] = \
493 human_value['text'] = \
466 '{url}@ver:{ver} via {mode} mode, connection:{conn}'.format(
494 '{url}@ver:{ver} via {mode} mode, connection:{conn}'.format(
467 url=server_url, ver=version, mode=protocol, conn=connection)
495 url=server_url, ver=version, mode=protocol, conn=connection)
468
496
469 return SysInfoRes(value=value, state=state, human_value=human_value)
497 return SysInfoRes(value=value, state=state, human_value=human_value)
470
498
471
499
472 def rhodecode_app_info():
500 def rhodecode_app_info():
473 import rhodecode
501 import rhodecode
474 edition = rhodecode.CONFIG.get('rhodecode.edition')
502 edition = rhodecode.CONFIG.get('rhodecode.edition')
475
503
476 value = dict(
504 value = dict(
477 rhodecode_version=rhodecode.__version__,
505 rhodecode_version=rhodecode.__version__,
478 rhodecode_lib_path=os.path.abspath(rhodecode.__file__),
506 rhodecode_lib_path=os.path.abspath(rhodecode.__file__),
479 text=''
507 text=''
480 )
508 )
481 human_value = value.copy()
509 human_value = value.copy()
482 human_value['text'] = 'RhodeCode {edition}, version {ver}'.format(
510 human_value['text'] = 'RhodeCode {edition}, version {ver}'.format(
483 edition=edition, ver=value['rhodecode_version']
511 edition=edition, ver=value['rhodecode_version']
484 )
512 )
485 return SysInfoRes(value=value, human_value=human_value)
513 return SysInfoRes(value=value, human_value=human_value)
486
514
487
515
488 def rhodecode_config():
516 def rhodecode_config():
489 import rhodecode
517 import rhodecode
490 path = rhodecode.CONFIG.get('__file__')
518 path = rhodecode.CONFIG.get('__file__')
491 rhodecode_ini_safe = rhodecode.CONFIG.copy()
519 rhodecode_ini_safe = rhodecode.CONFIG.copy()
492
520
493 blacklist = [
521 blacklist = [
494 'rhodecode_license_key',
522 'rhodecode_license_key',
495 'routes.map',
523 'routes.map',
496 'pylons.h',
524 'pylons.h',
497 'pylons.app_globals',
525 'pylons.app_globals',
498 'pylons.environ_config',
526 'pylons.environ_config',
499 'sqlalchemy.db1.url',
527 'sqlalchemy.db1.url',
500 'channelstream.secret',
528 'channelstream.secret',
501 'beaker.session.secret',
529 'beaker.session.secret',
502 'rhodecode.encrypted_values.secret',
530 'rhodecode.encrypted_values.secret',
503 'rhodecode_auth_github_consumer_key',
531 'rhodecode_auth_github_consumer_key',
504 'rhodecode_auth_github_consumer_secret',
532 'rhodecode_auth_github_consumer_secret',
505 'rhodecode_auth_google_consumer_key',
533 'rhodecode_auth_google_consumer_key',
506 'rhodecode_auth_google_consumer_secret',
534 'rhodecode_auth_google_consumer_secret',
507 'rhodecode_auth_bitbucket_consumer_secret',
535 'rhodecode_auth_bitbucket_consumer_secret',
508 'rhodecode_auth_bitbucket_consumer_key',
536 'rhodecode_auth_bitbucket_consumer_key',
509 'rhodecode_auth_twitter_consumer_secret',
537 'rhodecode_auth_twitter_consumer_secret',
510 'rhodecode_auth_twitter_consumer_key',
538 'rhodecode_auth_twitter_consumer_key',
511
539
512 'rhodecode_auth_twitter_secret',
540 'rhodecode_auth_twitter_secret',
513 'rhodecode_auth_github_secret',
541 'rhodecode_auth_github_secret',
514 'rhodecode_auth_google_secret',
542 'rhodecode_auth_google_secret',
515 'rhodecode_auth_bitbucket_secret',
543 'rhodecode_auth_bitbucket_secret',
516
544
517 'appenlight.api_key',
545 'appenlight.api_key',
518 ('app_conf', 'sqlalchemy.db1.url')
546 ('app_conf', 'sqlalchemy.db1.url')
519 ]
547 ]
520 for k in blacklist:
548 for k in blacklist:
521 if isinstance(k, tuple):
549 if isinstance(k, tuple):
522 section, key = k
550 section, key = k
523 if section in rhodecode_ini_safe:
551 if section in rhodecode_ini_safe:
524 rhodecode_ini_safe[section] = '**OBFUSCATED**'
552 rhodecode_ini_safe[section] = '**OBFUSCATED**'
525 else:
553 else:
526 rhodecode_ini_safe.pop(k, None)
554 rhodecode_ini_safe.pop(k, None)
527
555
528 # TODO: maybe put some CONFIG checks here ?
556 # TODO: maybe put some CONFIG checks here ?
529 return SysInfoRes(value={'config': rhodecode_ini_safe, 'path': path})
557 return SysInfoRes(value={'config': rhodecode_ini_safe, 'path': path})
530
558
531
559
532 def database_info():
560 def database_info():
533 import rhodecode
561 import rhodecode
534 from sqlalchemy.engine import url as engine_url
562 from sqlalchemy.engine import url as engine_url
535 from rhodecode.model.meta import Base as sql_base, Session
563 from rhodecode.model.meta import Base as sql_base, Session
536 from rhodecode.model.db import DbMigrateVersion
564 from rhodecode.model.db import DbMigrateVersion
537
565
538 state = STATE_OK_DEFAULT
566 state = STATE_OK_DEFAULT
539
567
540 db_migrate = DbMigrateVersion.query().filter(
568 db_migrate = DbMigrateVersion.query().filter(
541 DbMigrateVersion.repository_id == 'rhodecode_db_migrations').one()
569 DbMigrateVersion.repository_id == 'rhodecode_db_migrations').one()
542
570
543 db_url_obj = engine_url.make_url(rhodecode.CONFIG['sqlalchemy.db1.url'])
571 db_url_obj = engine_url.make_url(rhodecode.CONFIG['sqlalchemy.db1.url'])
544
572
545 try:
573 try:
546 engine = sql_base.metadata.bind
574 engine = sql_base.metadata.bind
547 db_server_info = engine.dialect._get_server_version_info(
575 db_server_info = engine.dialect._get_server_version_info(
548 Session.connection(bind=engine))
576 Session.connection(bind=engine))
549 db_version = '.'.join(map(str, db_server_info))
577 db_version = '.'.join(map(str, db_server_info))
550 except Exception:
578 except Exception:
551 log.exception('failed to fetch db version')
579 log.exception('failed to fetch db version')
552 db_version = 'UNKNOWN'
580 db_version = 'UNKNOWN'
553
581
554 db_info = dict(
582 db_info = dict(
555 migrate_version=db_migrate.version,
583 migrate_version=db_migrate.version,
556 type=db_url_obj.get_backend_name(),
584 type=db_url_obj.get_backend_name(),
557 version=db_version,
585 version=db_version,
558 url=repr(db_url_obj)
586 url=repr(db_url_obj)
559 )
587 )
560
588
561 human_value = db_info.copy()
589 human_value = db_info.copy()
562 human_value['url'] = "{} @ migration version: {}".format(
590 human_value['url'] = "{} @ migration version: {}".format(
563 db_info['url'], db_info['migrate_version'])
591 db_info['url'], db_info['migrate_version'])
564 human_value['version'] = "{} {}".format(db_info['type'], db_info['version'])
592 human_value['version'] = "{} {}".format(db_info['type'], db_info['version'])
565 return SysInfoRes(value=db_info, state=state, human_value=human_value)
593 return SysInfoRes(value=db_info, state=state, human_value=human_value)
566
594
567
595
568 def server_info(environ):
596 def server_info(environ):
569 import rhodecode
597 import rhodecode
570 from rhodecode.lib.base import get_server_ip_addr, get_server_port
598 from rhodecode.lib.base import get_server_ip_addr, get_server_port
571
599
572 value = {
600 value = {
573 'server_ip': '%s:%s' % (
601 'server_ip': '%s:%s' % (
574 get_server_ip_addr(environ, log_errors=False),
602 get_server_ip_addr(environ, log_errors=False),
575 get_server_port(environ)
603 get_server_port(environ)
576 ),
604 ),
577 'server_id': rhodecode.CONFIG.get('instance_id'),
605 'server_id': rhodecode.CONFIG.get('instance_id'),
578 }
606 }
579 return SysInfoRes(value=value)
607 return SysInfoRes(value=value)
580
608
581
609
582 def get_system_info(environ):
610 def get_system_info(environ):
583 environ = environ or {}
611 environ = environ or {}
584 return {
612 return {
585 'rhodecode_app': SysInfo(rhodecode_app_info)(),
613 'rhodecode_app': SysInfo(rhodecode_app_info)(),
586 'rhodecode_config': SysInfo(rhodecode_config)(),
614 'rhodecode_config': SysInfo(rhodecode_config)(),
587 'python': SysInfo(python_info)(),
615 'python': SysInfo(python_info)(),
588 'py_modules': SysInfo(py_modules)(),
616 'py_modules': SysInfo(py_modules)(),
589
617
590 'platform': SysInfo(platform_type)(),
618 'platform': SysInfo(platform_type)(),
591 'server': SysInfo(server_info, environ=environ)(),
619 'server': SysInfo(server_info, environ=environ)(),
592 'database': SysInfo(database_info)(),
620 'database': SysInfo(database_info)(),
593
621
594 'storage': SysInfo(storage)(),
622 'storage': SysInfo(storage)(),
595 'storage_inodes': SysInfo(storage_inodes)(),
623 'storage_inodes': SysInfo(storage_inodes)(),
596 'storage_archive': SysInfo(storage_archives)(),
624 'storage_archive': SysInfo(storage_archives)(),
597 'storage_gist': SysInfo(storage_gist)(),
625 'storage_gist': SysInfo(storage_gist)(),
626 'storage_temp': SysInfo(storage_temp)(),
598
627
599 'search': SysInfo(search_info)(),
628 'search': SysInfo(search_info)(),
600
629
601 'uptime': SysInfo(uptime)(),
630 'uptime': SysInfo(uptime)(),
602 'load': SysInfo(machine_load)(),
631 'load': SysInfo(machine_load)(),
603 'cpu': SysInfo(cpu)(),
632 'cpu': SysInfo(cpu)(),
604 'memory': SysInfo(memory)(),
633 'memory': SysInfo(memory)(),
605
634
606 'vcs_backends': SysInfo(vcs_backends)(),
635 'vcs_backends': SysInfo(vcs_backends)(),
607 'vcs_server': SysInfo(vcs_server)(),
636 'vcs_server': SysInfo(vcs_server)(),
608
637
609 'git': SysInfo(git_info)(),
638 'git': SysInfo(git_info)(),
610 'hg': SysInfo(hg_info)(),
639 'hg': SysInfo(hg_info)(),
611 'svn': SysInfo(svn_info)(),
640 'svn': SysInfo(svn_info)(),
612 }
641 }
General Comments 0
You need to be logged in to leave comments. Login now