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