##// END OF EJS Templates
system-info: unified data structures for usage in API....
marcink -
r1112:ff9a513b default
parent child Browse files
Show More
@@ -1,837 +1,837 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'), c.rhodecode_version, ''),
580 (_('RhodeCode Version'), c.rhodecode_version, ''),
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'), state('platform')),
592 (_('Platform'), val('platform'), state('platform')),
593 (_('Python version'), val('python')['version'], state('python')),
593 (_('Python version'), val('python')['version'], state('python')),
594 (_('Python path'), val('python')['executable'], state('python')),
594 (_('Python path'), val('python')['executable'], state('python')),
595 ('', '', ''), # spacer
595 ('', '', ''), # spacer
596
596
597 # Systems stats
597 # Systems stats
598 (_('CPU'), val('cpu'), state('cpu')),
598 (_('CPU'), val('cpu'), state('cpu')),
599 (_('Load'), val('load'), state('load')),
599 (_('Load'), val('load')['text'], state('load')),
600 (_('Memory'), val('memory'), state('memory')),
600 (_('Memory'), val('memory')['text'], state('memory')),
601 (_('Uptime'), val('uptime')['uptime'], state('uptime')),
601 (_('Uptime'), val('uptime')['text'], state('uptime')),
602 ('', '', ''), # spacer
602 ('', '', ''), # spacer
603
603
604 # Repo storage
604 # Repo storage
605 (_('Storage location'), val('storage')['path'], state('storage')),
605 (_('Storage location'), val('storage')['path'], state('storage')),
606 (_('Storage info'), val('storage')['text'], state('storage')),
606 (_('Storage info'), val('storage')['text'], state('storage')),
607 (_('Storage inodes'), val('storage_inodes')['text'], state('storage_inodes')),
607 (_('Storage inodes'), val('storage_inodes')['text'], state('storage_inodes')),
608
608
609 (_('Gist storage location'), val('storage_gist')['path'], state('storage_gist')),
609 (_('Gist storage location'), val('storage_gist')['path'], state('storage_gist')),
610 (_('Gist storage info'), val('storage_gist')['text'], state('storage_gist')),
610 (_('Gist storage info'), val('storage_gist')['text'], state('storage_gist')),
611
611
612 (_('Archive cache storage location'), val('storage_archive')['path'], state('storage_archive')),
612 (_('Archive cache storage location'), val('storage_archive')['path'], state('storage_archive')),
613 (_('Archive cache info'), val('storage_archive')['text'], state('storage_archive')),
613 (_('Archive cache info'), val('storage_archive')['text'], state('storage_archive')),
614
614
615 (_('Search storage'), val('storage_search')['path'], state('storage_search')),
615 (_('Search info'), val('search')['text'], state('search')),
616 (_('Search info'), val('storage_search')['text'], state('storage_search')),
616 (_('Search location'), val('search')['location'], state('search')),
617 ('', '', ''), # spacer
617 ('', '', ''), # spacer
618
618
619 # VCS specific
619 # VCS specific
620 (_('VCS Backends'), val('vcs_backends'), state('vcs_backends')),
620 (_('VCS Backends'), val('vcs_backends'), state('vcs_backends')),
621 (_('VCS Server'), val('vcs_server')['text'], state('vcs_server')),
621 (_('VCS Server'), val('vcs_server')['text'], state('vcs_server')),
622 (_('GIT'), val('git'), state('git')),
622 (_('GIT'), val('git'), state('git')),
623 (_('HG'), val('hg'), state('hg')),
623 (_('HG'), val('hg'), state('hg')),
624 (_('SVN'), val('svn'), state('svn')),
624 (_('SVN'), val('svn'), state('svn')),
625
625
626 ]
626 ]
627
627
628 # TODO: marcink, figure out how to allow only selected users to do this
628 # TODO: marcink, figure out how to allow only selected users to do this
629 c.allowed_to_snapshot = c.rhodecode_user.admin
629 c.allowed_to_snapshot = c.rhodecode_user.admin
630
630
631 if snapshot:
631 if snapshot:
632 if c.allowed_to_snapshot:
632 if c.allowed_to_snapshot:
633 return render('admin/settings/settings_system_snapshot.html')
633 return render('admin/settings/settings_system_snapshot.html')
634 else:
634 else:
635 h.flash('You are not allowed to do this', category='warning')
635 h.flash('You are not allowed to do this', category='warning')
636
636
637 return htmlfill.render(
637 return htmlfill.render(
638 render('admin/settings/settings.html'),
638 render('admin/settings/settings.html'),
639 defaults=defaults,
639 defaults=defaults,
640 encoding="UTF-8",
640 encoding="UTF-8",
641 force_defaults=False)
641 force_defaults=False)
642
642
643 @staticmethod
643 @staticmethod
644 def get_update_data(update_url):
644 def get_update_data(update_url):
645 """Return the JSON update data."""
645 """Return the JSON update data."""
646 ver = rhodecode.__version__
646 ver = rhodecode.__version__
647 log.debug('Checking for upgrade on `%s` server', update_url)
647 log.debug('Checking for upgrade on `%s` server', update_url)
648 opener = urllib2.build_opener()
648 opener = urllib2.build_opener()
649 opener.addheaders = [('User-agent', 'RhodeCode-SCM/%s' % ver)]
649 opener.addheaders = [('User-agent', 'RhodeCode-SCM/%s' % ver)]
650 response = opener.open(update_url)
650 response = opener.open(update_url)
651 response_data = response.read()
651 response_data = response.read()
652 data = json.loads(response_data)
652 data = json.loads(response_data)
653
653
654 return data
654 return data
655
655
656 @HasPermissionAllDecorator('hg.admin')
656 @HasPermissionAllDecorator('hg.admin')
657 def settings_system_update(self):
657 def settings_system_update(self):
658 """GET /admin/settings/system/updates: All items in the collection"""
658 """GET /admin/settings/system/updates: All items in the collection"""
659 # url('admin_settings_system_update')
659 # url('admin_settings_system_update')
660 defaults = self._form_defaults()
660 defaults = self._form_defaults()
661 update_url = defaults.get('rhodecode_update_url', '')
661 update_url = defaults.get('rhodecode_update_url', '')
662
662
663 _err = lambda s: '<div style="color:#ff8888; padding:4px 0px">%s</div>' % (s)
663 _err = lambda s: '<div style="color:#ff8888; padding:4px 0px">%s</div>' % (s)
664 try:
664 try:
665 data = self.get_update_data(update_url)
665 data = self.get_update_data(update_url)
666 except urllib2.URLError as e:
666 except urllib2.URLError as e:
667 log.exception("Exception contacting upgrade server")
667 log.exception("Exception contacting upgrade server")
668 return _err('Failed to contact upgrade server: %r' % e)
668 return _err('Failed to contact upgrade server: %r' % e)
669 except ValueError as e:
669 except ValueError as e:
670 log.exception("Bad data sent from update server")
670 log.exception("Bad data sent from update server")
671 return _err('Bad data sent from update server')
671 return _err('Bad data sent from update server')
672
672
673 latest = data['versions'][0]
673 latest = data['versions'][0]
674
674
675 c.update_url = update_url
675 c.update_url = update_url
676 c.latest_data = latest
676 c.latest_data = latest
677 c.latest_ver = latest['version']
677 c.latest_ver = latest['version']
678 c.cur_ver = rhodecode.__version__
678 c.cur_ver = rhodecode.__version__
679 c.should_upgrade = False
679 c.should_upgrade = False
680
680
681 if (packaging.version.Version(c.latest_ver) >
681 if (packaging.version.Version(c.latest_ver) >
682 packaging.version.Version(c.cur_ver)):
682 packaging.version.Version(c.cur_ver)):
683 c.should_upgrade = True
683 c.should_upgrade = True
684 c.important_notices = latest['general']
684 c.important_notices = latest['general']
685
685
686 return render('admin/settings/settings_system_update.html')
686 return render('admin/settings/settings_system_update.html')
687
687
688 @HasPermissionAllDecorator('hg.admin')
688 @HasPermissionAllDecorator('hg.admin')
689 def settings_supervisor(self):
689 def settings_supervisor(self):
690 c.rhodecode_ini = rhodecode.CONFIG
690 c.rhodecode_ini = rhodecode.CONFIG
691 c.active = 'supervisor'
691 c.active = 'supervisor'
692
692
693 c.supervisor_procs = OrderedDict([
693 c.supervisor_procs = OrderedDict([
694 (SUPERVISOR_MASTER, {}),
694 (SUPERVISOR_MASTER, {}),
695 ])
695 ])
696
696
697 c.log_size = 10240
697 c.log_size = 10240
698 supervisor = SupervisorModel()
698 supervisor = SupervisorModel()
699
699
700 _connection = supervisor.get_connection(
700 _connection = supervisor.get_connection(
701 c.rhodecode_ini.get('supervisor.uri'))
701 c.rhodecode_ini.get('supervisor.uri'))
702 c.connection_error = None
702 c.connection_error = None
703 try:
703 try:
704 _connection.supervisor.getAllProcessInfo()
704 _connection.supervisor.getAllProcessInfo()
705 except Exception as e:
705 except Exception as e:
706 c.connection_error = str(e)
706 c.connection_error = str(e)
707 log.exception("Exception reading supervisor data")
707 log.exception("Exception reading supervisor data")
708 return render('admin/settings/settings.html')
708 return render('admin/settings/settings.html')
709
709
710 groupid = c.rhodecode_ini.get('supervisor.group_id')
710 groupid = c.rhodecode_ini.get('supervisor.group_id')
711
711
712 # feed our group processes to the main
712 # feed our group processes to the main
713 for proc in supervisor.get_group_processes(_connection, groupid):
713 for proc in supervisor.get_group_processes(_connection, groupid):
714 c.supervisor_procs[proc['name']] = {}
714 c.supervisor_procs[proc['name']] = {}
715
715
716 for k in c.supervisor_procs.keys():
716 for k in c.supervisor_procs.keys():
717 try:
717 try:
718 # master process info
718 # master process info
719 if k == SUPERVISOR_MASTER:
719 if k == SUPERVISOR_MASTER:
720 _data = supervisor.get_master_state(_connection)
720 _data = supervisor.get_master_state(_connection)
721 _data['name'] = 'supervisor master'
721 _data['name'] = 'supervisor master'
722 _data['description'] = 'pid %s, id: %s, ver: %s' % (
722 _data['description'] = 'pid %s, id: %s, ver: %s' % (
723 _data['pid'], _data['id'], _data['ver'])
723 _data['pid'], _data['id'], _data['ver'])
724 c.supervisor_procs[k] = _data
724 c.supervisor_procs[k] = _data
725 else:
725 else:
726 procid = groupid + ":" + k
726 procid = groupid + ":" + k
727 c.supervisor_procs[k] = supervisor.get_process_info(_connection, procid)
727 c.supervisor_procs[k] = supervisor.get_process_info(_connection, procid)
728 except Exception as e:
728 except Exception as e:
729 log.exception("Exception reading supervisor data")
729 log.exception("Exception reading supervisor data")
730 c.supervisor_procs[k] = {'_rhodecode_error': str(e)}
730 c.supervisor_procs[k] = {'_rhodecode_error': str(e)}
731
731
732 return render('admin/settings/settings.html')
732 return render('admin/settings/settings.html')
733
733
734 @HasPermissionAllDecorator('hg.admin')
734 @HasPermissionAllDecorator('hg.admin')
735 def settings_supervisor_log(self, procid):
735 def settings_supervisor_log(self, procid):
736 import rhodecode
736 import rhodecode
737 c.rhodecode_ini = rhodecode.CONFIG
737 c.rhodecode_ini = rhodecode.CONFIG
738 c.active = 'supervisor_tail'
738 c.active = 'supervisor_tail'
739
739
740 supervisor = SupervisorModel()
740 supervisor = SupervisorModel()
741 _connection = supervisor.get_connection(c.rhodecode_ini.get('supervisor.uri'))
741 _connection = supervisor.get_connection(c.rhodecode_ini.get('supervisor.uri'))
742 groupid = c.rhodecode_ini.get('supervisor.group_id')
742 groupid = c.rhodecode_ini.get('supervisor.group_id')
743 procid = groupid + ":" + procid if procid != SUPERVISOR_MASTER else procid
743 procid = groupid + ":" + procid if procid != SUPERVISOR_MASTER else procid
744
744
745 c.log_size = 10240
745 c.log_size = 10240
746 offset = abs(safe_int(request.GET.get('offset', c.log_size))) * -1
746 offset = abs(safe_int(request.GET.get('offset', c.log_size))) * -1
747 c.log = supervisor.read_process_log(_connection, procid, offset, 0)
747 c.log = supervisor.read_process_log(_connection, procid, offset, 0)
748
748
749 return render('admin/settings/settings.html')
749 return render('admin/settings/settings.html')
750
750
751 @HasPermissionAllDecorator('hg.admin')
751 @HasPermissionAllDecorator('hg.admin')
752 @auth.CSRFRequired()
752 @auth.CSRFRequired()
753 def settings_labs_update(self):
753 def settings_labs_update(self):
754 """POST /admin/settings/labs: All items in the collection"""
754 """POST /admin/settings/labs: All items in the collection"""
755 # url('admin_settings/labs', method={'POST'})
755 # url('admin_settings/labs', method={'POST'})
756 c.active = 'labs'
756 c.active = 'labs'
757
757
758 application_form = LabsSettingsForm()()
758 application_form = LabsSettingsForm()()
759 try:
759 try:
760 form_result = application_form.to_python(dict(request.POST))
760 form_result = application_form.to_python(dict(request.POST))
761 except formencode.Invalid as errors:
761 except formencode.Invalid as errors:
762 h.flash(
762 h.flash(
763 _('Some form inputs contain invalid data.'),
763 _('Some form inputs contain invalid data.'),
764 category='error')
764 category='error')
765 return htmlfill.render(
765 return htmlfill.render(
766 render('admin/settings/settings.html'),
766 render('admin/settings/settings.html'),
767 defaults=errors.value,
767 defaults=errors.value,
768 errors=errors.error_dict or {},
768 errors=errors.error_dict or {},
769 prefix_error=False,
769 prefix_error=False,
770 encoding='UTF-8',
770 encoding='UTF-8',
771 force_defaults=False
771 force_defaults=False
772 )
772 )
773
773
774 try:
774 try:
775 session = Session()
775 session = Session()
776 for setting in _LAB_SETTINGS:
776 for setting in _LAB_SETTINGS:
777 setting_name = setting.key[len('rhodecode_'):]
777 setting_name = setting.key[len('rhodecode_'):]
778 sett = SettingsModel().create_or_update_setting(
778 sett = SettingsModel().create_or_update_setting(
779 setting_name, form_result[setting.key], setting.type)
779 setting_name, form_result[setting.key], setting.type)
780 session.add(sett)
780 session.add(sett)
781
781
782 except Exception:
782 except Exception:
783 log.exception('Exception while updating lab settings')
783 log.exception('Exception while updating lab settings')
784 h.flash(_('Error occurred during updating labs settings'),
784 h.flash(_('Error occurred during updating labs settings'),
785 category='error')
785 category='error')
786 else:
786 else:
787 Session().commit()
787 Session().commit()
788 SettingsModel().invalidate_settings_cache()
788 SettingsModel().invalidate_settings_cache()
789 h.flash(_('Updated Labs settings'), category='success')
789 h.flash(_('Updated Labs settings'), category='success')
790 return redirect(url('admin_settings_labs'))
790 return redirect(url('admin_settings_labs'))
791
791
792 return htmlfill.render(
792 return htmlfill.render(
793 render('admin/settings/settings.html'),
793 render('admin/settings/settings.html'),
794 defaults=self._form_defaults(),
794 defaults=self._form_defaults(),
795 encoding='UTF-8',
795 encoding='UTF-8',
796 force_defaults=False)
796 force_defaults=False)
797
797
798 @HasPermissionAllDecorator('hg.admin')
798 @HasPermissionAllDecorator('hg.admin')
799 def settings_labs(self):
799 def settings_labs(self):
800 """GET /admin/settings/labs: All items in the collection"""
800 """GET /admin/settings/labs: All items in the collection"""
801 # url('admin_settings_labs')
801 # url('admin_settings_labs')
802 if not c.labs_active:
802 if not c.labs_active:
803 redirect(url('admin_settings'))
803 redirect(url('admin_settings'))
804
804
805 c.active = 'labs'
805 c.active = 'labs'
806 c.lab_settings = _LAB_SETTINGS
806 c.lab_settings = _LAB_SETTINGS
807
807
808 return htmlfill.render(
808 return htmlfill.render(
809 render('admin/settings/settings.html'),
809 render('admin/settings/settings.html'),
810 defaults=self._form_defaults(),
810 defaults=self._form_defaults(),
811 encoding='UTF-8',
811 encoding='UTF-8',
812 force_defaults=False)
812 force_defaults=False)
813
813
814 def _form_defaults(self):
814 def _form_defaults(self):
815 defaults = SettingsModel().get_all_settings()
815 defaults = SettingsModel().get_all_settings()
816 defaults.update(self._get_hg_ui_settings())
816 defaults.update(self._get_hg_ui_settings())
817 defaults.update({
817 defaults.update({
818 'new_svn_branch': '',
818 'new_svn_branch': '',
819 'new_svn_tag': '',
819 'new_svn_tag': '',
820 })
820 })
821 return defaults
821 return defaults
822
822
823
823
824 # :param key: name of the setting including the 'rhodecode_' prefix
824 # :param key: name of the setting including the 'rhodecode_' prefix
825 # :param type: the RhodeCodeSetting type to use.
825 # :param type: the RhodeCodeSetting type to use.
826 # :param group: the i18ned group in which we should dispaly this setting
826 # :param group: the i18ned group in which we should dispaly this setting
827 # :param label: the i18ned label we should display for this setting
827 # :param label: the i18ned label we should display for this setting
828 # :param help: the i18ned help we should dispaly for this setting
828 # :param help: the i18ned help we should dispaly for this setting
829 LabSetting = collections.namedtuple(
829 LabSetting = collections.namedtuple(
830 'LabSetting', ('key', 'type', 'group', 'label', 'help'))
830 'LabSetting', ('key', 'type', 'group', 'label', 'help'))
831
831
832
832
833 # This list has to be kept in sync with the form
833 # This list has to be kept in sync with the form
834 # rhodecode.model.forms.LabsSettingsForm.
834 # rhodecode.model.forms.LabsSettingsForm.
835 _LAB_SETTINGS = [
835 _LAB_SETTINGS = [
836
836
837 ]
837 ]
@@ -1,582 +1,600 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
8
8
9
9 log = logging.getLogger(__name__)
10 log = logging.getLogger(__name__)
10
11
11
12
12 psutil = None
13 psutil = None
13
14
14 try:
15 try:
15 # cygwin cannot have yet psutil support.
16 # cygwin cannot have yet psutil support.
16 import psutil as psutil
17 import psutil as psutil
17 except ImportError:
18 except ImportError:
18 pass
19 pass
19
20
20
21
21 _NA = 'NOT AVAILABLE'
22 _NA = 'NOT AVAILABLE'
22
23
23 STATE_OK = 'ok'
24 STATE_OK = 'ok'
24 STATE_ERR = 'error'
25 STATE_ERR = 'error'
25 STATE_WARN = 'warning'
26 STATE_WARN = 'warning'
26
27
27 STATE_OK_DEFAULT = {'message': '', 'type': STATE_OK}
28 STATE_OK_DEFAULT = {'message': '', 'type': STATE_OK}
28
29
29
30
30 # HELPERS
31 # HELPERS
31 def percentage(part, whole):
32 def percentage(part, whole):
32 whole = float(whole)
33 whole = float(whole)
33 if whole > 0:
34 if whole > 0:
34 return 100 * float(part) / whole
35 return 100 * float(part) / whole
35 return 0
36 return 0
36
37
37
38
38 def get_storage_size(storage_path):
39 def get_storage_size(storage_path):
39 sizes = []
40 sizes = []
40 for file_ in os.listdir(storage_path):
41 for file_ in os.listdir(storage_path):
41 storage_file = os.path.join(storage_path, file_)
42 storage_file = os.path.join(storage_path, file_)
42 if os.path.isfile(storage_file):
43 if os.path.isfile(storage_file):
43 try:
44 try:
44 sizes.append(os.path.getsize(storage_file))
45 sizes.append(os.path.getsize(storage_file))
45 except OSError:
46 except OSError:
46 log.exception('Failed to get size of storage file %s',
47 log.exception('Failed to get size of storage file %s',
47 storage_file)
48 storage_file)
48 pass
49 pass
49
50
50 return sum(sizes)
51 return sum(sizes)
51
52
52
53
53 class SysInfoRes(object):
54 class SysInfoRes(object):
54 def __init__(self, value, state=STATE_OK_DEFAULT, human_value=None):
55 def __init__(self, value, state=STATE_OK_DEFAULT, human_value=None):
55 self.value = value
56 self.value = value
56 self.state = state
57 self.state = state
57 self.human_value = human_value or value
58 self.human_value = human_value or value
58
59
59 def __json__(self):
60 def __json__(self):
60 return {
61 return {
61 'value': self.value,
62 'value': self.value,
62 'state': self.state,
63 'state': self.state,
63 'human_value': self.human_value,
64 'human_value': self.human_value,
64 }
65 }
65
66
66 def __str__(self):
67 def __str__(self):
67 return '<SysInfoRes({})>'.format(self.__json__())
68 return '<SysInfoRes({})>'.format(self.__json__())
68
69
69
70
70 class SysInfo(object):
71 class SysInfo(object):
71
72
72 def __init__(self, func_name, **kwargs):
73 def __init__(self, func_name, **kwargs):
73 self.func_name = func_name
74 self.func_name = func_name
74 self.value = _NA
75 self.value = _NA
75 self.state = None
76 self.state = None
76 self.kwargs = kwargs or {}
77 self.kwargs = kwargs or {}
77
78
78 def __call__(self):
79 def __call__(self):
79 computed = self.compute(**self.kwargs)
80 computed = self.compute(**self.kwargs)
80 if not isinstance(computed, SysInfoRes):
81 if not isinstance(computed, SysInfoRes):
81 raise ValueError(
82 raise ValueError(
82 'computed value for {} is not instance of '
83 'computed value for {} is not instance of '
83 '{}, got {} instead'.format(
84 '{}, got {} instead'.format(
84 self.func_name, SysInfoRes, type(computed)))
85 self.func_name, SysInfoRes, type(computed)))
85 return computed.__json__()
86 return computed.__json__()
86
87
87 def __str__(self):
88 def __str__(self):
88 return '<SysInfo({})>'.format(self.func_name)
89 return '<SysInfo({})>'.format(self.func_name)
89
90
90 def compute(self, **kwargs):
91 def compute(self, **kwargs):
91 return self.func_name(**kwargs)
92 return self.func_name(**kwargs)
92
93
93
94
94 # SysInfo functions
95 # SysInfo functions
95 def python_info():
96 def python_info():
96 value = {
97 value = dict(version=' '.join(platform._sys_version()),
97 'version': ' '.join(platform._sys_version()),
98 executable=sys.executable)
98 'executable': sys.executable
99 }
100 return SysInfoRes(value=value)
99 return SysInfoRes(value=value)
101
100
102
101
103 def py_modules():
102 def py_modules():
104 mods = dict([(p.project_name, p.version)
103 mods = dict([(p.project_name, p.version)
105 for p in pkg_resources.working_set])
104 for p in pkg_resources.working_set])
106 value = sorted(mods.items(), key=lambda k: k[0].lower())
105 value = sorted(mods.items(), key=lambda k: k[0].lower())
107 return SysInfoRes(value=value)
106 return SysInfoRes(value=value)
108
107
109
108
110 def platform_type():
109 def platform_type():
111 from rhodecode.lib.utils import safe_unicode
110 from rhodecode.lib.utils import safe_unicode
112 value = safe_unicode(platform.platform())
111 value = safe_unicode(platform.platform())
113 return SysInfoRes(value=value)
112 return SysInfoRes(value=value)
114
113
115
114
116 def uptime():
115 def uptime():
117 from rhodecode.lib.helpers import age, time_to_datetime
116 from rhodecode.lib.helpers import age, time_to_datetime
118 from rhodecode.translation import _
119
117
120 _uptime = _uptime_human = {'boot_time': 0, 'uptime': 0}
118 value = dict(boot_time=0, uptime=0, text='')
121 state = STATE_OK_DEFAULT
119 state = STATE_OK_DEFAULT
122 if not psutil:
120 if not psutil:
123 return SysInfoRes(value=_uptime, state=state)
121 return SysInfoRes(value=value, state=state)
124
122
125 boot_time = psutil.boot_time()
123 boot_time = psutil.boot_time()
126 _uptime['boot_time'] = boot_time
124 value['boot_time'] = boot_time
127 _uptime['uptime'] = time.time() - boot_time
125 value['uptime'] = time.time() - boot_time
128
126
129 _uptime_human['boot_time'] = time_to_datetime(boot_time)
127 human_value = value.copy()
130 _uptime_human['uptime'] = _('Server started {}').format(
128 human_value['boot_time'] = time_to_datetime(boot_time)
129 human_value['uptime'] = age(time_to_datetime(boot_time), show_suffix=False)
130 human_value['text'] = 'Server started {}'.format(
131 age(time_to_datetime(boot_time)))
131 age(time_to_datetime(boot_time)))
132
132
133 return SysInfoRes(value=_uptime, human_value=_uptime_human)
133 return SysInfoRes(value=value, human_value=human_value)
134
134
135
135
136 def memory():
136 def memory():
137 from rhodecode.lib.helpers import format_byte_size_binary
137 from rhodecode.lib.helpers import format_byte_size_binary
138 _memory = {'available': 0, 'used': 0, 'cached': 0, 'percent': 0,
138 value = dict(available=0, used=0, cached=0, percent=0, percent_used=0,
139 'percent_used': 0, 'free': 0, 'inactive': 0, 'active': 0,
139 free=0, inactive=0, active=0, shared=0, total=0, buffers=0,
140 'shared': 0, 'total': 0, 'buffers': 0}
140 text='')
141
141 state = STATE_OK_DEFAULT
142 state = STATE_OK_DEFAULT
142 if not psutil:
143 if not psutil:
143 return SysInfoRes(value=_memory, state=state)
144 return SysInfoRes(value=value, state=state)
144
145
145 # memory
146 value.update(dict(psutil.virtual_memory()._asdict()))
146 _memory = dict(psutil.virtual_memory()._asdict())
147 value['percent_used'] = psutil._common.usage_percent(
147 _memory['percent_used'] = psutil._common.usage_percent(
148 (value['total'] - value['free']), value['total'], 1)
148 (_memory['total'] - _memory['free']), _memory['total'], 1)
149
149
150 try:
150 human_value = value.copy()
151 human_value = '%s/%s, %s%% used' % (
151 human_value['text'] = '%s/%s, %s%% used' % (
152 format_byte_size_binary(_memory['used']),
152 format_byte_size_binary(value['used']),
153 format_byte_size_binary(_memory['total']),
153 format_byte_size_binary(value['total']),
154 _memory['percent_used'],)
154 value['percent_used'],)
155 except TypeError:
156 human_value = 'NOT AVAILABLE'
157
155
158 if state['type'] == STATE_OK and _memory['percent_used'] > 90:
156 keys = value.keys()[::]
157 keys.pop(keys.index('percent'))
158 keys.pop(keys.index('percent_used'))
159 keys.pop(keys.index('text'))
160 for k in keys:
161 human_value[k] = format_byte_size_binary(value[k])
162
163 if state['type'] == STATE_OK and value['percent_used'] > 90:
159 msg = 'Critical: your available RAM memory is very low.'
164 msg = 'Critical: your available RAM memory is very low.'
160 state = {'message': msg, 'type': STATE_ERR}
165 state = {'message': msg, 'type': STATE_ERR}
161
166
162 elif state['type'] == STATE_OK and _memory['percent_used'] > 70:
167 elif state['type'] == STATE_OK and value['percent_used'] > 70:
163 msg = 'Warning: your available RAM memory is running low.'
168 msg = 'Warning: your available RAM memory is running low.'
164 state = {'message': msg, 'type': STATE_WARN}
169 state = {'message': msg, 'type': STATE_WARN}
165
170
166 return SysInfoRes(value=_memory, state=state, human_value=human_value)
171 return SysInfoRes(value=value, state=state, human_value=human_value)
167
172
168
173
169 def machine_load():
174 def machine_load():
170 _load = {'1_min': _NA, '5_min': _NA, '15_min': _NA}
175 value = {'1_min': _NA, '5_min': _NA, '15_min': _NA, 'text': ''}
171
172 state = STATE_OK_DEFAULT
176 state = STATE_OK_DEFAULT
173 if not psutil:
177 if not psutil:
174 return SysInfoRes(value=_load, state=state)
178 return SysInfoRes(value=value, state=state)
175
179
176 # load averages
180 # load averages
177 if hasattr(psutil.os, 'getloadavg'):
181 if hasattr(psutil.os, 'getloadavg'):
178 _load = dict(zip(['1_min', '5_min', '15_min'], psutil.os.getloadavg()))
182 value.update(dict(
183 zip(['1_min', '5_min', '15_min'], psutil.os.getloadavg())))
179
184
180 human_value = '1min: %s, 5min: %s, 15min: %s' % (
185 human_value = value.copy()
181 _load['1_min'], _load['5_min'], _load['15_min'])
186 human_value['text'] = '1min: {}, 5min: {}, 15min: {}'.format(
187 value['1_min'], value['5_min'], value['15_min'])
182
188
183 # TODO: warn about too-much load 15 min
189 if state['type'] == STATE_OK and value['15_min'] > 5:
184 return SysInfoRes(value=_load, state=state, human_value=human_value)
190 msg = 'Warning: your machine load is very high.'
191 state = {'message': msg, 'type': STATE_WARN}
192
193 return SysInfoRes(value=value, state=state, human_value=human_value)
185
194
186
195
187 def cpu():
196 def cpu():
197 value = 0
188 state = STATE_OK_DEFAULT
198 state = STATE_OK_DEFAULT
189 cpu_value = 0
199
190 if not psutil:
200 if not psutil:
191 return SysInfoRes(value=cpu_value, state=state)
201 return SysInfoRes(value=value, state=state)
192
202
193 cpu_value = psutil.cpu_percent(0.5)
203 value = psutil.cpu_percent(0.5)
194 human_value = '{} %'.format(cpu_value)
204 human_value = '{} %'.format(value)
195 return SysInfoRes(value=cpu_value, state=state, human_value=human_value)
205 return SysInfoRes(value=value, state=state, human_value=human_value)
196
206
197
207
198 def storage():
208 def storage():
199 from rhodecode.lib.helpers import format_byte_size_binary
209 from rhodecode.lib.helpers import format_byte_size_binary
200 from rhodecode.model.settings import VcsSettingsModel
210 from rhodecode.model.settings import VcsSettingsModel
201 path = VcsSettingsModel().get_repos_location()
211 path = VcsSettingsModel().get_repos_location()
202
212
203 # disk storage
213 value = dict(percent=0, used=0, total=0, path=path, text='')
204 disk = {'percent': 0, 'used': 0, 'total': 0, 'path': path, 'text': ''}
205 state = STATE_OK_DEFAULT
214 state = STATE_OK_DEFAULT
206 if not psutil:
215 if not psutil:
207 return SysInfoRes(value=disk, state=state)
216 return SysInfoRes(value=value, state=state)
208
217
209 try:
218 try:
210 disk.update(dict(psutil.disk_usage(path)._asdict()))
219 value.update(dict(psutil.disk_usage(path)._asdict()))
211 except Exception as e:
220 except Exception as e:
212 log.exception('Failed to fetch disk info')
221 log.exception('Failed to fetch disk info')
213 state = {'message': str(e), 'type': STATE_ERR}
222 state = {'message': str(e), 'type': STATE_ERR}
214
223
215 human_value = disk
224 human_value = value.copy()
225 human_value['used'] = format_byte_size_binary(value['used'])
226 human_value['total'] = format_byte_size_binary(value['total'])
216 human_value['text'] = "{}/{}, {}% used".format(
227 human_value['text'] = "{}/{}, {}% used".format(
217 format_byte_size_binary(disk['used']),
228 format_byte_size_binary(value['used']),
218 format_byte_size_binary(disk['total']),
229 format_byte_size_binary(value['total']),
219 (disk['percent']))
230 value['percent'])
220
231
221 if state['type'] == STATE_OK and disk['percent'] > 90:
232 if state['type'] == STATE_OK and value['percent'] > 90:
222 msg = 'Critical: your disk space is very low.'
233 msg = 'Critical: your disk space is very low.'
223 state = {'message': msg, 'type': STATE_ERR}
234 state = {'message': msg, 'type': STATE_ERR}
224
235
225 elif state['type'] == STATE_OK and disk['percent'] > 70:
236 elif state['type'] == STATE_OK and value['percent'] > 70:
226 msg = 'Warning: your disk space is running low.'
237 msg = 'Warning: your disk space is running low.'
227 state = {'message': msg, 'type': STATE_WARN}
238 state = {'message': msg, 'type': STATE_WARN}
228
239
229 return SysInfoRes(value=disk, state=state, human_value=human_value)
240 return SysInfoRes(value=value, state=state, human_value=human_value)
230
241
231
242
232 def storage_inodes():
243 def storage_inodes():
233 from rhodecode.model.settings import VcsSettingsModel
244 from rhodecode.model.settings import VcsSettingsModel
234 path = VcsSettingsModel().get_repos_location()
245 path = VcsSettingsModel().get_repos_location()
235
246
236 _disk_inodes = dict(percent=0, free=0, used=0, total=0, path=path, text='')
247 value = dict(percent=0, free=0, used=0, total=0, path=path, text='')
237 state = STATE_OK_DEFAULT
248 state = STATE_OK_DEFAULT
238 if not psutil:
249 if not psutil:
239 return SysInfoRes(value=_disk_inodes, state=state)
250 return SysInfoRes(value=value, state=state)
240
251
241 try:
252 try:
242 i_stat = os.statvfs(path)
253 i_stat = os.statvfs(path)
243
254
244 _disk_inodes['used'] = i_stat.f_ffree
255 value['used'] = i_stat.f_ffree
245 _disk_inodes['free'] = i_stat.f_favail
256 value['free'] = i_stat.f_favail
246 _disk_inodes['total'] = i_stat.f_files
257 value['total'] = i_stat.f_files
247 _disk_inodes['percent'] = percentage(
258 value['percent'] = percentage(
248 _disk_inodes['used'], _disk_inodes['total'])
259 value['used'], value['total'])
249 except Exception as e:
260 except Exception as e:
250 log.exception('Failed to fetch disk inodes info')
261 log.exception('Failed to fetch disk inodes info')
251 state = {'message': str(e), 'type': STATE_ERR}
262 state = {'message': str(e), 'type': STATE_ERR}
252
263
253 human_value = _disk_inodes
264 human_value = value.copy()
254 human_value['text'] = "{}/{}, {}% used".format(
265 human_value['text'] = "{}/{}, {}% used".format(
255 _disk_inodes['used'], _disk_inodes['total'], _disk_inodes['percent'])
266 value['used'], value['total'], value['percent'])
256
267
257 if state['type'] == STATE_OK and _disk_inodes['percent'] > 90:
268 if state['type'] == STATE_OK and value['percent'] > 90:
258 msg = 'Critical: your disk free inodes are very low.'
269 msg = 'Critical: your disk free inodes are very low.'
259 state = {'message': msg, 'type': STATE_ERR}
270 state = {'message': msg, 'type': STATE_ERR}
260
271
261 elif state['type'] == STATE_OK and _disk_inodes['percent'] > 70:
272 elif state['type'] == STATE_OK and value['percent'] > 70:
262 msg = 'Warning: your disk free inodes are running low.'
273 msg = 'Warning: your disk free inodes are running low.'
263 state = {'message': msg, 'type': STATE_WARN}
274 state = {'message': msg, 'type': STATE_WARN}
264
275
265 return SysInfoRes(value=_disk_inodes, state=state)
276 return SysInfoRes(value=value, state=state)
266
277
267
278
268 def storage_archives():
279 def storage_archives():
269 import rhodecode
280 import rhodecode
270 from rhodecode.lib.utils import safe_str
281 from rhodecode.lib.utils import safe_str
271 from rhodecode.lib.helpers import format_byte_size_binary
282 from rhodecode.lib.helpers import format_byte_size_binary
272
283
273 msg = 'Enable this by setting ' \
284 msg = 'Enable this by setting ' \
274 'archive_cache_dir=/path/to/cache option in the .ini file'
285 'archive_cache_dir=/path/to/cache option in the .ini file'
275 path = safe_str(rhodecode.CONFIG.get('archive_cache_dir', msg))
286 path = safe_str(rhodecode.CONFIG.get('archive_cache_dir', msg))
276
287
277 disk_archive = dict(percent=0, used=0, total=0, items=0, path=path, text='')
288 value = dict(percent=0, used=0, total=0, items=0, path=path, text='')
278 state = STATE_OK_DEFAULT
289 state = STATE_OK_DEFAULT
279 try:
290 try:
280 items_count = 0
291 items_count = 0
281 used = 0
292 used = 0
282 for root, dirs, files in os.walk(path):
293 for root, dirs, files in os.walk(path):
283 if root == path:
294 if root == path:
284 items_count = len(dirs)
295 items_count = len(files)
285
296
286 for f in files:
297 for f in files:
287 try:
298 try:
288 used += os.path.getsize(os.path.join(root, f))
299 used += os.path.getsize(os.path.join(root, f))
289 except OSError:
300 except OSError:
290 pass
301 pass
291 disk_archive.update({
302 value.update({
292 'percent': 100,
303 'percent': 100,
293 'used': used,
304 'used': used,
294 'total': used,
305 'total': used,
295 'items': items_count
306 'items': items_count
296 })
307 })
297
308
298 except Exception as e:
309 except Exception as e:
299 log.exception('failed to fetch archive cache storage')
310 log.exception('failed to fetch archive cache storage')
300 state = {'message': str(e), 'type': STATE_ERR}
311 state = {'message': str(e), 'type': STATE_ERR}
301
312
302 human_value = disk_archive
313 human_value = value.copy()
303 human_value['text'] = "{} ({} items)".format(format_byte_size_binary(
314 human_value['used'] = format_byte_size_binary(value['used'])
304 disk_archive['used']), disk_archive['total'])
315 human_value['total'] = format_byte_size_binary(value['total'])
316 human_value['text'] = "{} ({} items)".format(
317 human_value['used'], value['items'])
305
318
306 return SysInfoRes(value=disk_archive, state=state, human_value=human_value)
319 return SysInfoRes(value=value, state=state, human_value=human_value)
307
320
308
321
309 def storage_gist():
322 def storage_gist():
310 from rhodecode.model.gist import GIST_STORE_LOC
323 from rhodecode.model.gist import GIST_STORE_LOC
311 from rhodecode.model.settings import VcsSettingsModel
324 from rhodecode.model.settings import VcsSettingsModel
312 from rhodecode.lib.utils import safe_str
325 from rhodecode.lib.utils import safe_str
313 from rhodecode.lib.helpers import format_byte_size_binary
326 from rhodecode.lib.helpers import format_byte_size_binary
314 path = safe_str(os.path.join(
327 path = safe_str(os.path.join(
315 VcsSettingsModel().get_repos_location(), GIST_STORE_LOC))
328 VcsSettingsModel().get_repos_location(), GIST_STORE_LOC))
316
329
317 # gist storage
330 # gist storage
318 _disk_gist = dict(percent=0, used=0, total=0, items=0, path=path, text='')
331 value = dict(percent=0, used=0, total=0, items=0, path=path, text='')
319 state = STATE_OK_DEFAULT
332 state = STATE_OK_DEFAULT
320
333
321 try:
334 try:
322 items_count = 0
335 items_count = 0
323 used = 0
336 used = 0
324 for root, dirs, files in os.walk(path):
337 for root, dirs, files in os.walk(path):
325 if root == path:
338 if root == path:
326 items_count = len(dirs)
339 items_count = len(dirs)
327
340
328 for f in files:
341 for f in files:
329 try:
342 try:
330 used += os.path.getsize(os.path.join(root, f))
343 used += os.path.getsize(os.path.join(root, f))
331 except OSError:
344 except OSError:
332 pass
345 pass
333 _disk_gist.update({
346 value.update({
334 'percent': 100,
347 'percent': 100,
335 'used': used,
348 'used': used,
336 'total': used,
349 'total': used,
337 'items': items_count
350 'items': items_count
338 })
351 })
339 except Exception as e:
352 except Exception as e:
340 log.exception('failed to fetch gist storage items')
353 log.exception('failed to fetch gist storage items')
341 state = {'message': str(e), 'type': STATE_ERR}
354 state = {'message': str(e), 'type': STATE_ERR}
342
355
343 human_value = _disk_gist
356 human_value = value.copy()
344 human_value['text'] = "{} ({} items)".format(format_byte_size_binary(
357 human_value['used'] = format_byte_size_binary(value['used'])
345 _disk_gist['used']), _disk_gist['items'])
358 human_value['total'] = format_byte_size_binary(value['total'])
346 return SysInfoRes(value=_disk_gist, state=state, human_value=human_value)
359 human_value['text'] = "{} ({} items)".format(
360 human_value['used'], value['items'])
361
362 return SysInfoRes(value=value, state=state, human_value=human_value)
347
363
348
364
349 def storage_search():
365 def search_info():
350 import rhodecode
366 import rhodecode
351 path = rhodecode.CONFIG.get('search.location', '')
367 from rhodecode.lib.index import searcher_from_config
352
368
353 # search index storage
369 backend = rhodecode.CONFIG.get('search.module', '')
354 _disk_index = dict(percent=0, used=0, total=0, path=path, text='')
370 location = rhodecode.CONFIG.get('search.location', '')
355 state = STATE_OK_DEFAULT
371
356 try:
372 try:
357 search_index_storage_path_exists = os.path.isdir(path)
373 searcher = searcher_from_config(rhodecode.CONFIG)
358 if search_index_storage_path_exists:
374 searcher = searcher.__class__.__name__
359 used = get_storage_size(path)
375 except Exception:
360 _disk_index.update({
376 searcher = None
361 'percent': 100,
362 'used': used,
363 'total': used,
364 })
365 except Exception as e:
366 log.exception('failed to fetch search index storage')
367 state = {'message': str(e), 'type': STATE_ERR}
368
377
369 human_value = _disk_index
378 value = dict(
370 human_value['text'] = "{}/{}, {}% used".format(
379 backend=backend, searcher=searcher, location=location, text='')
371 _disk_index['used'], _disk_index['total'], _disk_index['percent'])
380 state = STATE_OK_DEFAULT
372
381
373 return SysInfoRes(value=_disk_index, state=state, human_value=human_value)
382 human_value = value.copy()
383 human_value['text'] = "backend:`{}`".format(human_value['backend'])
384
385 return SysInfoRes(value=value, state=state, human_value=human_value)
374
386
375
387
376 def git_info():
388 def git_info():
377 from rhodecode.lib.vcs.backends import git
389 from rhodecode.lib.vcs.backends import git
378 state = STATE_OK_DEFAULT
390 state = STATE_OK_DEFAULT
379 value = human_value = ''
391 value = human_value = ''
380 try:
392 try:
381 value = git.discover_git_version(raise_on_exc=True)
393 value = git.discover_git_version(raise_on_exc=True)
382 human_value = 'version reported from VCSServer: {}'.format(value)
394 human_value = 'version reported from VCSServer: {}'.format(value)
383 except Exception as e:
395 except Exception as e:
384 state = {'message': str(e), 'type': STATE_ERR}
396 state = {'message': str(e), 'type': STATE_ERR}
385
397
386 return SysInfoRes(value=value, state=state, human_value=human_value)
398 return SysInfoRes(value=value, state=state, human_value=human_value)
387
399
388
400
389 def hg_info():
401 def hg_info():
390 from rhodecode.lib.vcs.backends import hg
402 from rhodecode.lib.vcs.backends import hg
391 state = STATE_OK_DEFAULT
403 state = STATE_OK_DEFAULT
392 value = human_value = ''
404 value = human_value = ''
393 try:
405 try:
394 value = hg.discover_hg_version(raise_on_exc=True)
406 value = hg.discover_hg_version(raise_on_exc=True)
395 human_value = 'version reported from VCSServer: {}'.format(value)
407 human_value = 'version reported from VCSServer: {}'.format(value)
396 except Exception as e:
408 except Exception as e:
397 state = {'message': str(e), 'type': STATE_ERR}
409 state = {'message': str(e), 'type': STATE_ERR}
398 return SysInfoRes(value=value, state=state, human_value=human_value)
410 return SysInfoRes(value=value, state=state, human_value=human_value)
399
411
400
412
401 def svn_info():
413 def svn_info():
402 from rhodecode.lib.vcs.backends import svn
414 from rhodecode.lib.vcs.backends import svn
403 state = STATE_OK_DEFAULT
415 state = STATE_OK_DEFAULT
404 value = human_value = ''
416 value = human_value = ''
405 try:
417 try:
406 value = svn.discover_svn_version(raise_on_exc=True)
418 value = svn.discover_svn_version(raise_on_exc=True)
407 human_value = 'version reported from VCSServer: {}'.format(value)
419 human_value = 'version reported from VCSServer: {}'.format(value)
408 except Exception as e:
420 except Exception as e:
409 state = {'message': str(e), 'type': STATE_ERR}
421 state = {'message': str(e), 'type': STATE_ERR}
410 return SysInfoRes(value=value, state=state, human_value=human_value)
422 return SysInfoRes(value=value, state=state, human_value=human_value)
411
423
412
424
413 def vcs_backends():
425 def vcs_backends():
414 import rhodecode
426 import rhodecode
415 value = rhodecode.CONFIG.get('vcs.backends', '').split(',')
427 value = map(
428 string.strip, rhodecode.CONFIG.get('vcs.backends', '').split(','))
416 human_value = 'Enabled backends in order: {}'.format(','.join(value))
429 human_value = 'Enabled backends in order: {}'.format(','.join(value))
417 return SysInfoRes(value=value, human_value=human_value)
430 return SysInfoRes(value=value, human_value=human_value)
418
431
419
432
420 def vcs_server():
433 def vcs_server():
421 import rhodecode
434 import rhodecode
422 from rhodecode.lib.vcs.backends import get_vcsserver_version
435 from rhodecode.lib.vcs.backends import get_vcsserver_version
423
436
424 server_url = rhodecode.CONFIG.get('vcs.server')
437 server_url = rhodecode.CONFIG.get('vcs.server')
425 enabled = rhodecode.CONFIG.get('vcs.server.enable')
438 enabled = rhodecode.CONFIG.get('vcs.server.enable')
426 protocol = rhodecode.CONFIG.get('vcs.server.protocol')
439 protocol = rhodecode.CONFIG.get('vcs.server.protocol')
427 state = STATE_OK_DEFAULT
440 state = STATE_OK_DEFAULT
428 version = None
441 version = None
429
442
430 try:
443 try:
431 version = get_vcsserver_version()
444 version = get_vcsserver_version()
432 connection = 'connected'
445 connection = 'connected'
433 except Exception as e:
446 except Exception as e:
434 connection = 'failed'
447 connection = 'failed'
435 state = {'message': str(e), 'type': STATE_ERR}
448 state = {'message': str(e), 'type': STATE_ERR}
436
449
437 value = dict(
450 value = dict(
438 url=server_url,
451 url=server_url,
439 enabled=enabled,
452 enabled=enabled,
440 protocol=protocol,
453 protocol=protocol,
441 connection=connection,
454 connection=connection,
442 version=version,
455 version=version,
443 text='',
456 text='',
444 )
457 )
445
458
446 human_value = value
459 human_value = value.copy()
447 human_value['text'] = \
460 human_value['text'] = \
448 '{url}@ver:{ver} via {mode} mode, connection:{conn}'.format(
461 '{url}@ver:{ver} via {mode} mode, connection:{conn}'.format(
449 url=server_url, ver=version, mode=protocol, conn=connection)
462 url=server_url, ver=version, mode=protocol, conn=connection)
450
463
451 return SysInfoRes(value='', state=state, human_value=human_value)
464 return SysInfoRes(value=value, state=state, human_value=human_value)
452
465
453
466
454 def rhodecode_app_info():
467 def rhodecode_app_info():
455 import rhodecode
468 import rhodecode
456 return SysInfoRes(value={'rhodecode_version': rhodecode.__version__})
469 value = dict(
470 rhodecode_version=rhodecode.__version__,
471 rhodecode_lib_path=os.path.abspath(rhodecode.__file__)
472 )
473 return SysInfoRes(value=value)
457
474
458
475
459 def rhodecode_config():
476 def rhodecode_config():
460 import rhodecode
477 import rhodecode
461 path = rhodecode.CONFIG.get('__file__')
478 path = rhodecode.CONFIG.get('__file__')
462 rhodecode_ini_safe = rhodecode.CONFIG.copy()
479 rhodecode_ini_safe = rhodecode.CONFIG.copy()
463
480
464 blacklist = [
481 blacklist = [
465 'rhodecode_license_key',
482 'rhodecode_license_key',
466 'routes.map',
483 'routes.map',
467 'pylons.h',
484 'pylons.h',
468 'pylons.app_globals',
485 'pylons.app_globals',
469 'pylons.environ_config',
486 'pylons.environ_config',
470 'sqlalchemy.db1.url',
487 'sqlalchemy.db1.url',
471 'channelstream.secret',
488 'channelstream.secret',
472 'beaker.session.secret',
489 'beaker.session.secret',
473 'rhodecode.encrypted_values.secret',
490 'rhodecode.encrypted_values.secret',
474 'rhodecode_auth_github_consumer_key',
491 'rhodecode_auth_github_consumer_key',
475 'rhodecode_auth_github_consumer_secret',
492 'rhodecode_auth_github_consumer_secret',
476 'rhodecode_auth_google_consumer_key',
493 'rhodecode_auth_google_consumer_key',
477 'rhodecode_auth_google_consumer_secret',
494 'rhodecode_auth_google_consumer_secret',
478 'rhodecode_auth_bitbucket_consumer_secret',
495 'rhodecode_auth_bitbucket_consumer_secret',
479 'rhodecode_auth_bitbucket_consumer_key',
496 'rhodecode_auth_bitbucket_consumer_key',
480 'rhodecode_auth_twitter_consumer_secret',
497 'rhodecode_auth_twitter_consumer_secret',
481 'rhodecode_auth_twitter_consumer_key',
498 'rhodecode_auth_twitter_consumer_key',
482
499
483 'rhodecode_auth_twitter_secret',
500 'rhodecode_auth_twitter_secret',
484 'rhodecode_auth_github_secret',
501 'rhodecode_auth_github_secret',
485 'rhodecode_auth_google_secret',
502 'rhodecode_auth_google_secret',
486 'rhodecode_auth_bitbucket_secret',
503 'rhodecode_auth_bitbucket_secret',
487
504
488 'appenlight.api_key',
505 'appenlight.api_key',
489 ('app_conf', 'sqlalchemy.db1.url')
506 ('app_conf', 'sqlalchemy.db1.url')
490 ]
507 ]
491 for k in blacklist:
508 for k in blacklist:
492 if isinstance(k, tuple):
509 if isinstance(k, tuple):
493 section, key = k
510 section, key = k
494 if section in rhodecode_ini_safe:
511 if section in rhodecode_ini_safe:
495 rhodecode_ini_safe[section] = '**OBFUSCATED**'
512 rhodecode_ini_safe[section] = '**OBFUSCATED**'
496 else:
513 else:
497 rhodecode_ini_safe.pop(k, None)
514 rhodecode_ini_safe.pop(k, None)
498
515
499 # TODO: maybe put some CONFIG checks here ?
516 # TODO: maybe put some CONFIG checks here ?
500 return SysInfoRes(value={'config': rhodecode_ini_safe, 'path': path})
517 return SysInfoRes(value={'config': rhodecode_ini_safe, 'path': path})
501
518
502
519
503 def database_info():
520 def database_info():
504 import rhodecode
521 import rhodecode
505 from sqlalchemy.engine import url as engine_url
522 from sqlalchemy.engine import url as engine_url
506 from rhodecode.model.meta import Base as sql_base, Session
523 from rhodecode.model.meta import Base as sql_base, Session
507 from rhodecode.model.db import DbMigrateVersion
524 from rhodecode.model.db import DbMigrateVersion
508
525
509 state = STATE_OK_DEFAULT
526 state = STATE_OK_DEFAULT
510
527
511 db_migrate = DbMigrateVersion.query().filter(
528 db_migrate = DbMigrateVersion.query().filter(
512 DbMigrateVersion.repository_id == 'rhodecode_db_migrations').one()
529 DbMigrateVersion.repository_id == 'rhodecode_db_migrations').one()
513
530
514 db_url_obj = engine_url.make_url(rhodecode.CONFIG['sqlalchemy.db1.url'])
531 db_url_obj = engine_url.make_url(rhodecode.CONFIG['sqlalchemy.db1.url'])
515
532
516 try:
533 try:
517 engine = sql_base.metadata.bind
534 engine = sql_base.metadata.bind
518 db_server_info = engine.dialect._get_server_version_info(
535 db_server_info = engine.dialect._get_server_version_info(
519 Session.connection(bind=engine))
536 Session.connection(bind=engine))
520 db_version = '.'.join(map(str, db_server_info))
537 db_version = '.'.join(map(str, db_server_info))
521 except Exception:
538 except Exception:
522 log.exception('failed to fetch db version')
539 log.exception('failed to fetch db version')
523 db_version = 'UNKNOWN'
540 db_version = 'UNKNOWN'
524
541
525 db_info = dict(
542 db_info = dict(
526 migrate_version=db_migrate.version,
543 migrate_version=db_migrate.version,
527 type=db_url_obj.get_backend_name(),
544 type=db_url_obj.get_backend_name(),
528 version=db_version,
545 version=db_version,
529 url=repr(db_url_obj)
546 url=repr(db_url_obj)
530 )
547 )
531
548
532 human_value = db_info
549 human_value = db_info.copy()
533 human_value['url'] = "{} @ migration version: {}".format(
550 human_value['url'] = "{} @ migration version: {}".format(
534 db_info['url'], db_info['migrate_version'])
551 db_info['url'], db_info['migrate_version'])
535 human_value['version'] = "{} {}".format(db_info['type'], db_info['version'])
552 human_value['version'] = "{} {}".format(db_info['type'], db_info['version'])
536 return SysInfoRes(value=db_info, state=state, human_value=human_value)
553 return SysInfoRes(value=db_info, state=state, human_value=human_value)
537
554
538
555
539 def server_info(environ):
556 def server_info(environ):
540 import rhodecode
557 import rhodecode
541 from rhodecode.lib.base import get_server_ip_addr, get_server_port
558 from rhodecode.lib.base import get_server_ip_addr, get_server_port
542
559
543 value = {
560 value = {
544 'server_ip': '%s:%s' % (
561 'server_ip': '%s:%s' % (
545 get_server_ip_addr(environ, log_errors=False),
562 get_server_ip_addr(environ, log_errors=False),
546 get_server_port(environ)
563 get_server_port(environ)
547 ),
564 ),
548 'server_id': rhodecode.CONFIG.get('instance_id'),
565 'server_id': rhodecode.CONFIG.get('instance_id'),
549 }
566 }
550 return SysInfoRes(value=value)
567 return SysInfoRes(value=value)
551
568
552
569
553 def get_system_info(environ):
570 def get_system_info(environ):
554 environ = environ or {}
571 environ = environ or {}
555 return {
572 return {
556 'rhodecode_app': SysInfo(rhodecode_app_info)(),
573 'rhodecode_app': SysInfo(rhodecode_app_info)(),
557 'rhodecode_config': SysInfo(rhodecode_config)(),
574 'rhodecode_config': SysInfo(rhodecode_config)(),
558 'python': SysInfo(python_info)(),
575 'python': SysInfo(python_info)(),
559 'py_modules': SysInfo(py_modules)(),
576 'py_modules': SysInfo(py_modules)(),
560
577
561 'platform': SysInfo(platform_type)(),
578 'platform': SysInfo(platform_type)(),
562 'server': SysInfo(server_info, environ=environ)(),
579 'server': SysInfo(server_info, environ=environ)(),
563 'database': SysInfo(database_info)(),
580 'database': SysInfo(database_info)(),
564
581
565 'storage': SysInfo(storage)(),
582 'storage': SysInfo(storage)(),
566 'storage_inodes': SysInfo(storage_inodes)(),
583 'storage_inodes': SysInfo(storage_inodes)(),
567 'storage_archive': SysInfo(storage_archives)(),
584 'storage_archive': SysInfo(storage_archives)(),
568 'storage_search': SysInfo(storage_search)(),
569 'storage_gist': SysInfo(storage_gist)(),
585 'storage_gist': SysInfo(storage_gist)(),
570
586
587 'search': SysInfo(search_info)(),
588
571 'uptime': SysInfo(uptime)(),
589 'uptime': SysInfo(uptime)(),
572 'load': SysInfo(machine_load)(),
590 'load': SysInfo(machine_load)(),
573 'cpu': SysInfo(cpu)(),
591 'cpu': SysInfo(cpu)(),
574 'memory': SysInfo(memory)(),
592 'memory': SysInfo(memory)(),
575
593
576 'vcs_backends': SysInfo(vcs_backends)(),
594 'vcs_backends': SysInfo(vcs_backends)(),
577 'vcs_server': SysInfo(vcs_server)(),
595 'vcs_server': SysInfo(vcs_server)(),
578
596
579 'git': SysInfo(git_info)(),
597 'git': SysInfo(git_info)(),
580 'hg': SysInfo(hg_info)(),
598 'hg': SysInfo(hg_info)(),
581 'svn': SysInfo(svn_info)(),
599 'svn': SysInfo(svn_info)(),
582 }
600 }
General Comments 0
You need to be logged in to leave comments. Login now