##// END OF EJS Templates
system-info: fixed calls to get locales on python3
super-admin -
r4982:4fcca1ba default
parent child Browse files
Show More
@@ -1,834 +1,845 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2017-2020 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 os
23 23 import sys
24 24 import time
25 25 import platform
26 26 import collections
27 27 import psutil
28 28 from functools import wraps
29 29
30 30 import pkg_resources
31 31 import logging
32 32 import resource
33 33
34 34 import configparser
35 35
36 36 log = logging.getLogger(__name__)
37 37
38 38
39 39 _NA = 'NOT AVAILABLE'
40 40 _NA_FLOAT = 0.0
41 41
42 42 STATE_OK = 'ok'
43 43 STATE_ERR = 'error'
44 44 STATE_WARN = 'warning'
45 45
46 46 STATE_OK_DEFAULT = {'message': '', 'type': STATE_OK}
47 47
48 48
49 49 registered_helpers = {}
50 50
51 51
52 52 def register_sysinfo(func):
53 53 """
54 54 @register_helper
55 55 def db_check():
56 56 pass
57 57
58 58 db_check == registered_helpers['db_check']
59 59 """
60 60 global registered_helpers
61 61 registered_helpers[func.__name__] = func
62 62
63 63 @wraps(func)
64 64 def _wrapper(*args, **kwargs):
65 65 return func(*args, **kwargs)
66 66 return _wrapper
67 67
68 68
69 69 # HELPERS
70 70 def percentage(part: (int, float), whole: (int, float)):
71 71 whole = float(whole)
72 72 if whole > 0:
73 73 return round(100 * float(part) / whole, 1)
74 74 return 0.0
75 75
76 76
77 77 def get_storage_size(storage_path):
78 78 sizes = []
79 79 for file_ in os.listdir(storage_path):
80 80 storage_file = os.path.join(storage_path, file_)
81 81 if os.path.isfile(storage_file):
82 82 try:
83 83 sizes.append(os.path.getsize(storage_file))
84 84 except OSError:
85 85 log.exception('Failed to get size of storage file %s', storage_file)
86 86 pass
87 87
88 88 return sum(sizes)
89 89
90 90
91 91 def get_resource(resource_type):
92 92 try:
93 93 return resource.getrlimit(resource_type)
94 94 except Exception:
95 95 return 'NOT_SUPPORTED'
96 96
97 97
98 98 def get_cert_path(ini_path):
99 99 default = '/etc/ssl/certs/ca-certificates.crt'
100 100 control_ca_bundle = os.path.join(
101 101 os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(ini_path)))),
102 102 '.rccontrol-profile/etc/ca-bundle.crt')
103 103 if os.path.isfile(control_ca_bundle):
104 104 default = control_ca_bundle
105 105
106 106 return default
107 107
108 108
109 109 class SysInfoRes(object):
110 110 def __init__(self, value, state=None, human_value=None):
111 111 self.value = value
112 112 self.state = state or STATE_OK_DEFAULT
113 113 self.human_value = human_value or value
114 114
115 115 def __json__(self):
116 116 return {
117 117 'value': self.value,
118 118 'state': self.state,
119 119 'human_value': self.human_value,
120 120 }
121 121
122 122 def get_value(self):
123 123 return self.__json__()
124 124
125 125 def __str__(self):
126 126 return '<SysInfoRes({})>'.format(self.__json__())
127 127
128 128
129 129 class SysInfo(object):
130 130
131 131 def __init__(self, func_name, **kwargs):
132 132 self.func_name = func_name
133 133 self.value = _NA
134 134 self.state = None
135 135 self.kwargs = kwargs or {}
136 136
137 137 def __call__(self):
138 138 computed = self.compute(**self.kwargs)
139 139 if not isinstance(computed, SysInfoRes):
140 140 raise ValueError(
141 141 'computed value for {} is not instance of '
142 142 '{}, got {} instead'.format(
143 143 self.func_name, SysInfoRes, type(computed)))
144 144 return computed.__json__()
145 145
146 146 def __str__(self):
147 147 return '<SysInfo({})>'.format(self.func_name)
148 148
149 149 def compute(self, **kwargs):
150 150 return self.func_name(**kwargs)
151 151
152 152
153 153 # SysInfo functions
154 154 @register_sysinfo
155 155 def python_info():
156 156 value = dict(version=f'{platform.python_version()}:{platform.python_implementation()}',
157 157 executable=sys.executable)
158 158 return SysInfoRes(value=value)
159 159
160 160
161 161 @register_sysinfo
162 162 def py_modules():
163 163 mods = dict([(p.project_name, {'version': p.version, 'location': p.location})
164 164 for p in pkg_resources.working_set])
165 165
166 166 value = sorted(mods.items(), key=lambda k: k[0].lower())
167 167 return SysInfoRes(value=value)
168 168
169 169
170 170 @register_sysinfo
171 171 def platform_type():
172 172 from rhodecode.lib.utils import safe_unicode, generate_platform_uuid
173 173
174 174 value = dict(
175 175 name=safe_unicode(platform.platform()),
176 176 uuid=generate_platform_uuid()
177 177 )
178 178 return SysInfoRes(value=value)
179 179
180 180
181 181 @register_sysinfo
182 182 def locale_info():
183 183 import locale
184 184
185 def safe_get_locale(locale_name):
186 try:
187 locale.getlocale(locale_name)
188 except TypeError:
189 return f'FAILED_LOCALE_GET:{locale_name}'
190
185 191 value = dict(
186 192 locale_default=locale.getdefaultlocale(),
187 locale_lc_all=locale.getlocale(locale.LC_ALL),
193 locale_lc_all=safe_get_locale(locale.LC_ALL),
194 locale_lc_ctype=safe_get_locale(locale.LC_CTYPE),
188 195 lang_env=os.environ.get('LANG'),
189 196 lc_all_env=os.environ.get('LC_ALL'),
190 197 local_archive_env=os.environ.get('LOCALE_ARCHIVE'),
191 198 )
192 human_value = 'LANG: {}, locale LC_ALL: {}, Default locales: {}'.format(
193 value['lang_env'], value['locale_lc_all'], value['locale_default'])
199 human_value = \
200 f"LANG: {value['lang_env']}, \
201 locale LC_ALL: {value['locale_lc_all']}, \
202 locale LC_CTYPE: {value['locale_lc_ctype']}, \
203 Default locales: {value['locale_default']}"
204
194 205 return SysInfoRes(value=value, human_value=human_value)
195 206
196 207
197 208 @register_sysinfo
198 209 def ulimit_info():
199 210 data = collections.OrderedDict([
200 211 ('cpu time (seconds)', get_resource(resource.RLIMIT_CPU)),
201 212 ('file size', get_resource(resource.RLIMIT_FSIZE)),
202 213 ('stack size', get_resource(resource.RLIMIT_STACK)),
203 214 ('core file size', get_resource(resource.RLIMIT_CORE)),
204 215 ('address space size', get_resource(resource.RLIMIT_AS)),
205 216 ('locked in mem size', get_resource(resource.RLIMIT_MEMLOCK)),
206 217 ('heap size', get_resource(resource.RLIMIT_DATA)),
207 218 ('rss size', get_resource(resource.RLIMIT_RSS)),
208 219 ('number of processes', get_resource(resource.RLIMIT_NPROC)),
209 220 ('open files', get_resource(resource.RLIMIT_NOFILE)),
210 221 ])
211 222
212 223 text = ', '.join('{}:{}'.format(k, v) for k, v in data.items())
213 224
214 225 value = {
215 226 'limits': data,
216 227 'text': text,
217 228 }
218 229 return SysInfoRes(value=value)
219 230
220 231
221 232 @register_sysinfo
222 233 def uptime():
223 234 from rhodecode.lib.helpers import age, time_to_datetime
224 235 from rhodecode.translation import TranslationString
225 236
226 237 value = dict(boot_time=0, uptime=0, text='')
227 238 state = STATE_OK_DEFAULT
228 239
229 240 boot_time = psutil.boot_time()
230 241 value['boot_time'] = boot_time
231 242 value['uptime'] = time.time() - boot_time
232 243
233 244 date_or_age = age(time_to_datetime(boot_time))
234 245 if isinstance(date_or_age, TranslationString):
235 246 date_or_age = date_or_age.interpolate()
236 247
237 248 human_value = value.copy()
238 249 human_value['boot_time'] = time_to_datetime(boot_time)
239 250 human_value['uptime'] = age(time_to_datetime(boot_time), show_suffix=False)
240 251
241 human_value['text'] = u'Server started {}'.format(date_or_age)
252 human_value['text'] = 'Server started {}'.format(date_or_age)
242 253 return SysInfoRes(value=value, human_value=human_value)
243 254
244 255
245 256 @register_sysinfo
246 257 def memory():
247 258 from rhodecode.lib.helpers import format_byte_size_binary
248 259 value = dict(available=0, used=0, used_real=0, cached=0, percent=0,
249 260 percent_used=0, free=0, inactive=0, active=0, shared=0,
250 261 total=0, buffers=0, text='')
251 262
252 263 state = STATE_OK_DEFAULT
253 264
254 265 value.update(dict(psutil.virtual_memory()._asdict()))
255 266 value['used_real'] = value['total'] - value['available']
256 267 value['percent_used'] = psutil._common.usage_percent(
257 268 value['used_real'], value['total'], 1)
258 269
259 270 human_value = value.copy()
260 271 human_value['text'] = '%s/%s, %s%% used' % (
261 272 format_byte_size_binary(value['used_real']),
262 273 format_byte_size_binary(value['total']),
263 274 value['percent_used'],)
264 275
265 276 keys = list(value.keys())[::]
266 277 keys.pop(keys.index('percent'))
267 278 keys.pop(keys.index('percent_used'))
268 279 keys.pop(keys.index('text'))
269 280 for k in keys:
270 281 human_value[k] = format_byte_size_binary(value[k])
271 282
272 283 if state['type'] == STATE_OK and value['percent_used'] > 90:
273 284 msg = 'Critical: your available RAM memory is very low.'
274 285 state = {'message': msg, 'type': STATE_ERR}
275 286
276 287 elif state['type'] == STATE_OK and value['percent_used'] > 70:
277 288 msg = 'Warning: your available RAM memory is running low.'
278 289 state = {'message': msg, 'type': STATE_WARN}
279 290
280 291 return SysInfoRes(value=value, state=state, human_value=human_value)
281 292
282 293
283 294 @register_sysinfo
284 295 def machine_load():
285 296 value = {'1_min': _NA_FLOAT, '5_min': _NA_FLOAT, '15_min': _NA_FLOAT, 'text': ''}
286 297 state = STATE_OK_DEFAULT
287 298
288 299 # load averages
289 300 if hasattr(psutil.os, 'getloadavg'):
290 301 value.update(dict(
291 302 zip(['1_min', '5_min', '15_min'], psutil.os.getloadavg())
292 303 ))
293 304
294 305 human_value = value.copy()
295 306 human_value['text'] = '1min: {}, 5min: {}, 15min: {}'.format(
296 307 value['1_min'], value['5_min'], value['15_min'])
297 308
298 309 if state['type'] == STATE_OK and value['15_min'] > 5.0:
299 310 msg = 'Warning: your machine load is very high.'
300 311 state = {'message': msg, 'type': STATE_WARN}
301 312
302 313 return SysInfoRes(value=value, state=state, human_value=human_value)
303 314
304 315
305 316 @register_sysinfo
306 317 def cpu():
307 318 value = {'cpu': 0, 'cpu_count': 0, 'cpu_usage': []}
308 319 state = STATE_OK_DEFAULT
309 320
310 321 value['cpu'] = psutil.cpu_percent(0.5)
311 322 value['cpu_usage'] = psutil.cpu_percent(0.5, percpu=True)
312 323 value['cpu_count'] = psutil.cpu_count()
313 324
314 325 human_value = value.copy()
315 326 human_value['text'] = '{} cores at {} %'.format(
316 327 value['cpu_count'], value['cpu'])
317 328
318 329 return SysInfoRes(value=value, state=state, human_value=human_value)
319 330
320 331
321 332 @register_sysinfo
322 333 def storage():
323 334 from rhodecode.lib.helpers import format_byte_size_binary
324 335 from rhodecode.model.settings import VcsSettingsModel
325 336 path = VcsSettingsModel().get_repos_location()
326 337
327 338 value = dict(percent=0, used=0, total=0, path=path, text='')
328 339 state = STATE_OK_DEFAULT
329 340
330 341 try:
331 342 value.update(dict(psutil.disk_usage(path)._asdict()))
332 343 except Exception as e:
333 344 log.exception('Failed to fetch disk info')
334 345 state = {'message': str(e), 'type': STATE_ERR}
335 346
336 347 human_value = value.copy()
337 348 human_value['used'] = format_byte_size_binary(value['used'])
338 349 human_value['total'] = format_byte_size_binary(value['total'])
339 350 human_value['text'] = "{}/{}, {}% used".format(
340 351 format_byte_size_binary(value['used']),
341 352 format_byte_size_binary(value['total']),
342 353 value['percent'])
343 354
344 355 if state['type'] == STATE_OK and value['percent'] > 90:
345 356 msg = 'Critical: your disk space is very low.'
346 357 state = {'message': msg, 'type': STATE_ERR}
347 358
348 359 elif state['type'] == STATE_OK and value['percent'] > 70:
349 360 msg = 'Warning: your disk space is running low.'
350 361 state = {'message': msg, 'type': STATE_WARN}
351 362
352 363 return SysInfoRes(value=value, state=state, human_value=human_value)
353 364
354 365
355 366 @register_sysinfo
356 367 def storage_inodes():
357 368 from rhodecode.model.settings import VcsSettingsModel
358 369 path = VcsSettingsModel().get_repos_location()
359 370
360 371 value = dict(percent=0.0, free=0, used=0, total=0, path=path, text='')
361 372 state = STATE_OK_DEFAULT
362 373
363 374 try:
364 375 i_stat = os.statvfs(path)
365 376 value['free'] = i_stat.f_ffree
366 377 value['used'] = i_stat.f_files-i_stat.f_favail
367 378 value['total'] = i_stat.f_files
368 379 value['percent'] = percentage(value['used'], value['total'])
369 380 except Exception as e:
370 381 log.exception('Failed to fetch disk inodes info')
371 382 state = {'message': str(e), 'type': STATE_ERR}
372 383
373 384 human_value = value.copy()
374 385 human_value['text'] = "{}/{}, {}% used".format(
375 386 value['used'], value['total'], value['percent'])
376 387
377 388 if state['type'] == STATE_OK and value['percent'] > 90:
378 389 msg = 'Critical: your disk free inodes are very low.'
379 390 state = {'message': msg, 'type': STATE_ERR}
380 391
381 392 elif state['type'] == STATE_OK and value['percent'] > 70:
382 393 msg = 'Warning: your disk free inodes are running low.'
383 394 state = {'message': msg, 'type': STATE_WARN}
384 395
385 396 return SysInfoRes(value=value, state=state, human_value=human_value)
386 397
387 398
388 399 @register_sysinfo
389 400 def storage_archives():
390 401 import rhodecode
391 402 from rhodecode.lib.utils import safe_str
392 403 from rhodecode.lib.helpers import format_byte_size_binary
393 404
394 405 msg = 'Enable this by setting ' \
395 406 'archive_cache_dir=/path/to/cache option in the .ini file'
396 407 path = safe_str(rhodecode.CONFIG.get('archive_cache_dir', msg))
397 408
398 409 value = dict(percent=0, used=0, total=0, items=0, path=path, text='')
399 410 state = STATE_OK_DEFAULT
400 411 try:
401 412 items_count = 0
402 413 used = 0
403 414 for root, dirs, files in os.walk(path):
404 415 if root == path:
405 416 items_count = len(files)
406 417
407 418 for f in files:
408 419 try:
409 420 used += os.path.getsize(os.path.join(root, f))
410 421 except OSError:
411 422 pass
412 423 value.update({
413 424 'percent': 100,
414 425 'used': used,
415 426 'total': used,
416 427 'items': items_count
417 428 })
418 429
419 430 except Exception as e:
420 431 log.exception('failed to fetch archive cache storage')
421 432 state = {'message': str(e), 'type': STATE_ERR}
422 433
423 434 human_value = value.copy()
424 435 human_value['used'] = format_byte_size_binary(value['used'])
425 436 human_value['total'] = format_byte_size_binary(value['total'])
426 437 human_value['text'] = "{} ({} items)".format(
427 438 human_value['used'], value['items'])
428 439
429 440 return SysInfoRes(value=value, state=state, human_value=human_value)
430 441
431 442
432 443 @register_sysinfo
433 444 def storage_gist():
434 445 from rhodecode.model.gist import GIST_STORE_LOC
435 446 from rhodecode.model.settings import VcsSettingsModel
436 447 from rhodecode.lib.utils import safe_str
437 448 from rhodecode.lib.helpers import format_byte_size_binary
438 449 path = safe_str(os.path.join(
439 450 VcsSettingsModel().get_repos_location(), GIST_STORE_LOC))
440 451
441 452 # gist storage
442 453 value = dict(percent=0, used=0, total=0, items=0, path=path, text='')
443 454 state = STATE_OK_DEFAULT
444 455
445 456 try:
446 457 items_count = 0
447 458 used = 0
448 459 for root, dirs, files in os.walk(path):
449 460 if root == path:
450 461 items_count = len(dirs)
451 462
452 463 for f in files:
453 464 try:
454 465 used += os.path.getsize(os.path.join(root, f))
455 466 except OSError:
456 467 pass
457 468 value.update({
458 469 'percent': 100,
459 470 'used': used,
460 471 'total': used,
461 472 'items': items_count
462 473 })
463 474 except Exception as e:
464 475 log.exception('failed to fetch gist storage items')
465 476 state = {'message': str(e), 'type': STATE_ERR}
466 477
467 478 human_value = value.copy()
468 479 human_value['used'] = format_byte_size_binary(value['used'])
469 480 human_value['total'] = format_byte_size_binary(value['total'])
470 481 human_value['text'] = "{} ({} items)".format(
471 482 human_value['used'], value['items'])
472 483
473 484 return SysInfoRes(value=value, state=state, human_value=human_value)
474 485
475 486
476 487 @register_sysinfo
477 488 def storage_temp():
478 489 import tempfile
479 490 from rhodecode.lib.helpers import format_byte_size_binary
480 491
481 492 path = tempfile.gettempdir()
482 493 value = dict(percent=0, used=0, total=0, items=0, path=path, text='')
483 494 state = STATE_OK_DEFAULT
484 495
485 496 if not psutil:
486 497 return SysInfoRes(value=value, state=state)
487 498
488 499 try:
489 500 value.update(dict(psutil.disk_usage(path)._asdict()))
490 501 except Exception as e:
491 502 log.exception('Failed to fetch temp dir info')
492 503 state = {'message': str(e), 'type': STATE_ERR}
493 504
494 505 human_value = value.copy()
495 506 human_value['used'] = format_byte_size_binary(value['used'])
496 507 human_value['total'] = format_byte_size_binary(value['total'])
497 508 human_value['text'] = "{}/{}, {}% used".format(
498 509 format_byte_size_binary(value['used']),
499 510 format_byte_size_binary(value['total']),
500 511 value['percent'])
501 512
502 513 return SysInfoRes(value=value, state=state, human_value=human_value)
503 514
504 515
505 516 @register_sysinfo
506 517 def search_info():
507 518 import rhodecode
508 519 from rhodecode.lib.index import searcher_from_config
509 520
510 521 backend = rhodecode.CONFIG.get('search.module', '')
511 522 location = rhodecode.CONFIG.get('search.location', '')
512 523
513 524 try:
514 525 searcher = searcher_from_config(rhodecode.CONFIG)
515 526 searcher = searcher.__class__.__name__
516 527 except Exception:
517 528 searcher = None
518 529
519 530 value = dict(
520 531 backend=backend, searcher=searcher, location=location, text='')
521 532 state = STATE_OK_DEFAULT
522 533
523 534 human_value = value.copy()
524 535 human_value['text'] = "backend:`{}`".format(human_value['backend'])
525 536
526 537 return SysInfoRes(value=value, state=state, human_value=human_value)
527 538
528 539
529 540 @register_sysinfo
530 541 def git_info():
531 542 from rhodecode.lib.vcs.backends import git
532 543 state = STATE_OK_DEFAULT
533 544 value = human_value = ''
534 545 try:
535 546 value = git.discover_git_version(raise_on_exc=True)
536 547 human_value = 'version reported from VCSServer: {}'.format(value)
537 548 except Exception as e:
538 549 state = {'message': str(e), 'type': STATE_ERR}
539 550
540 551 return SysInfoRes(value=value, state=state, human_value=human_value)
541 552
542 553
543 554 @register_sysinfo
544 555 def hg_info():
545 556 from rhodecode.lib.vcs.backends import hg
546 557 state = STATE_OK_DEFAULT
547 558 value = human_value = ''
548 559 try:
549 560 value = hg.discover_hg_version(raise_on_exc=True)
550 561 human_value = 'version reported from VCSServer: {}'.format(value)
551 562 except Exception as e:
552 563 state = {'message': str(e), 'type': STATE_ERR}
553 564 return SysInfoRes(value=value, state=state, human_value=human_value)
554 565
555 566
556 567 @register_sysinfo
557 568 def svn_info():
558 569 from rhodecode.lib.vcs.backends import svn
559 570 state = STATE_OK_DEFAULT
560 571 value = human_value = ''
561 572 try:
562 573 value = svn.discover_svn_version(raise_on_exc=True)
563 574 human_value = 'version reported from VCSServer: {}'.format(value)
564 575 except Exception as e:
565 576 state = {'message': str(e), 'type': STATE_ERR}
566 577 return SysInfoRes(value=value, state=state, human_value=human_value)
567 578
568 579
569 580 @register_sysinfo
570 581 def vcs_backends():
571 582 import rhodecode
572 583 value = rhodecode.CONFIG.get('vcs.backends')
573 584 human_value = 'Enabled backends in order: {}'.format(','.join(value))
574 585 return SysInfoRes(value=value, human_value=human_value)
575 586
576 587
577 588 @register_sysinfo
578 589 def vcs_server():
579 590 import rhodecode
580 591 from rhodecode.lib.vcs.backends import get_vcsserver_service_data
581 592
582 593 server_url = rhodecode.CONFIG.get('vcs.server')
583 594 enabled = rhodecode.CONFIG.get('vcs.server.enable')
584 595 protocol = rhodecode.CONFIG.get('vcs.server.protocol') or 'http'
585 596 state = STATE_OK_DEFAULT
586 597 version = None
587 598 workers = 0
588 599
589 600 try:
590 601 data = get_vcsserver_service_data()
591 602 if data and 'version' in data:
592 603 version = data['version']
593 604
594 605 if data and 'config' in data:
595 606 conf = data['config']
596 607 workers = conf.get('workers', 'NOT AVAILABLE')
597 608
598 609 connection = 'connected'
599 610 except Exception as e:
600 611 connection = 'failed'
601 612 state = {'message': str(e), 'type': STATE_ERR}
602 613
603 614 value = dict(
604 615 url=server_url,
605 616 enabled=enabled,
606 617 protocol=protocol,
607 618 connection=connection,
608 619 version=version,
609 620 text='',
610 621 )
611 622
612 623 human_value = value.copy()
613 624 human_value['text'] = \
614 625 '{url}@ver:{ver} via {mode} mode[workers:{workers}], connection:{conn}'.format(
615 626 url=server_url, ver=version, workers=workers, mode=protocol,
616 627 conn=connection)
617 628
618 629 return SysInfoRes(value=value, state=state, human_value=human_value)
619 630
620 631
621 632 @register_sysinfo
622 633 def vcs_server_config():
623 634 from rhodecode.lib.vcs.backends import get_vcsserver_service_data
624 635 state = STATE_OK_DEFAULT
625 636
626 637 value = {}
627 638 try:
628 639 data = get_vcsserver_service_data()
629 640 value = data['app_config']
630 641 except Exception as e:
631 642 state = {'message': str(e), 'type': STATE_ERR}
632 643
633 644 human_value = value.copy()
634 645 human_value['text'] = 'VCS Server config'
635 646
636 647 return SysInfoRes(value=value, state=state, human_value=human_value)
637 648
638 649
639 650 @register_sysinfo
640 651 def rhodecode_app_info():
641 652 import rhodecode
642 653 edition = rhodecode.CONFIG.get('rhodecode.edition')
643 654
644 655 value = dict(
645 656 rhodecode_version=rhodecode.__version__,
646 657 rhodecode_lib_path=os.path.abspath(rhodecode.__file__),
647 658 text=''
648 659 )
649 660 human_value = value.copy()
650 661 human_value['text'] = 'RhodeCode {edition}, version {ver}'.format(
651 662 edition=edition, ver=value['rhodecode_version']
652 663 )
653 664 return SysInfoRes(value=value, human_value=human_value)
654 665
655 666
656 667 @register_sysinfo
657 668 def rhodecode_config():
658 669 import rhodecode
659 670 path = rhodecode.CONFIG.get('__file__')
660 671 rhodecode_ini_safe = rhodecode.CONFIG.copy()
661 672 cert_path = get_cert_path(path)
662 673
663 674 try:
664 675 config = configparser.ConfigParser()
665 676 config.read(path)
666 677 parsed_ini = config
667 678 if parsed_ini.has_section('server:main'):
668 679 parsed_ini = dict(parsed_ini.items('server:main'))
669 680 except Exception:
670 681 log.exception('Failed to read .ini file for display')
671 682 parsed_ini = {}
672 683
673 684 rhodecode_ini_safe['server:main'] = parsed_ini
674 685
675 686 blacklist = [
676 687 'rhodecode_license_key',
677 688 'routes.map',
678 689 'sqlalchemy.db1.url',
679 690 'channelstream.secret',
680 691 'beaker.session.secret',
681 692 'rhodecode.encrypted_values.secret',
682 693 'rhodecode_auth_github_consumer_key',
683 694 'rhodecode_auth_github_consumer_secret',
684 695 'rhodecode_auth_google_consumer_key',
685 696 'rhodecode_auth_google_consumer_secret',
686 697 'rhodecode_auth_bitbucket_consumer_secret',
687 698 'rhodecode_auth_bitbucket_consumer_key',
688 699 'rhodecode_auth_twitter_consumer_secret',
689 700 'rhodecode_auth_twitter_consumer_key',
690 701
691 702 'rhodecode_auth_twitter_secret',
692 703 'rhodecode_auth_github_secret',
693 704 'rhodecode_auth_google_secret',
694 705 'rhodecode_auth_bitbucket_secret',
695 706
696 707 'appenlight.api_key',
697 708 ('app_conf', 'sqlalchemy.db1.url')
698 709 ]
699 710 for k in blacklist:
700 711 if isinstance(k, tuple):
701 712 section, key = k
702 713 if section in rhodecode_ini_safe:
703 714 rhodecode_ini_safe[section] = '**OBFUSCATED**'
704 715 else:
705 716 rhodecode_ini_safe.pop(k, None)
706 717
707 718 # TODO: maybe put some CONFIG checks here ?
708 719 return SysInfoRes(value={'config': rhodecode_ini_safe,
709 720 'path': path, 'cert_path': cert_path})
710 721
711 722
712 723 @register_sysinfo
713 724 def database_info():
714 725 import rhodecode
715 726 from sqlalchemy.engine import url as engine_url
716 727 from rhodecode.model.meta import Base as sql_base, Session
717 728 from rhodecode.model.db import DbMigrateVersion
718 729
719 730 state = STATE_OK_DEFAULT
720 731
721 732 db_migrate = DbMigrateVersion.query().filter(
722 733 DbMigrateVersion.repository_id == 'rhodecode_db_migrations').one()
723 734
724 735 db_url_obj = engine_url.make_url(rhodecode.CONFIG['sqlalchemy.db1.url'])
725 736
726 737 try:
727 738 engine = sql_base.metadata.bind
728 739 db_server_info = engine.dialect._get_server_version_info(
729 740 Session.connection(bind=engine))
730 741 db_version = '.'.join(map(str, db_server_info))
731 742 except Exception:
732 743 log.exception('failed to fetch db version')
733 744 db_version = 'UNKNOWN'
734 745
735 746 db_info = dict(
736 747 migrate_version=db_migrate.version,
737 748 type=db_url_obj.get_backend_name(),
738 749 version=db_version,
739 750 url=repr(db_url_obj)
740 751 )
741 752 current_version = db_migrate.version
742 753 expected_version = rhodecode.__dbversion__
743 754 if state['type'] == STATE_OK and current_version != expected_version:
744 755 msg = 'Critical: database schema mismatch, ' \
745 756 'expected version {}, got {}. ' \
746 757 'Please run migrations on your database.'.format(
747 758 expected_version, current_version)
748 759 state = {'message': msg, 'type': STATE_ERR}
749 760
750 761 human_value = db_info.copy()
751 762 human_value['url'] = "{} @ migration version: {}".format(
752 763 db_info['url'], db_info['migrate_version'])
753 764 human_value['version'] = "{} {}".format(db_info['type'], db_info['version'])
754 765 return SysInfoRes(value=db_info, state=state, human_value=human_value)
755 766
756 767
757 768 @register_sysinfo
758 769 def server_info(environ):
759 770 import rhodecode
760 771 from rhodecode.lib.base import get_server_ip_addr, get_server_port
761 772
762 773 value = {
763 774 'server_ip': '%s:%s' % (
764 775 get_server_ip_addr(environ, log_errors=False),
765 776 get_server_port(environ)
766 777 ),
767 778 'server_id': rhodecode.CONFIG.get('instance_id'),
768 779 }
769 780 return SysInfoRes(value=value)
770 781
771 782
772 783 @register_sysinfo
773 784 def usage_info():
774 785 from rhodecode.model.db import User, Repository
775 786 value = {
776 787 'users': User.query().count(),
777 788 'users_active': User.query().filter(User.active == True).count(),
778 789 'repositories': Repository.query().count(),
779 790 'repository_types': {
780 791 'hg': Repository.query().filter(
781 792 Repository.repo_type == 'hg').count(),
782 793 'git': Repository.query().filter(
783 794 Repository.repo_type == 'git').count(),
784 795 'svn': Repository.query().filter(
785 796 Repository.repo_type == 'svn').count(),
786 797 },
787 798 }
788 799 return SysInfoRes(value=value)
789 800
790 801
791 802 def get_system_info(environ):
792 803 environ = environ or {}
793 804 return {
794 805 'rhodecode_app': SysInfo(rhodecode_app_info)(),
795 806 'rhodecode_config': SysInfo(rhodecode_config)(),
796 807 'rhodecode_usage': SysInfo(usage_info)(),
797 808 'python': SysInfo(python_info)(),
798 809 'py_modules': SysInfo(py_modules)(),
799 810
800 811 'platform': SysInfo(platform_type)(),
801 812 'locale': SysInfo(locale_info)(),
802 813 'server': SysInfo(server_info, environ=environ)(),
803 814 'database': SysInfo(database_info)(),
804 815 'ulimit': SysInfo(ulimit_info)(),
805 816 'storage': SysInfo(storage)(),
806 817 'storage_inodes': SysInfo(storage_inodes)(),
807 818 'storage_archive': SysInfo(storage_archives)(),
808 819 'storage_gist': SysInfo(storage_gist)(),
809 820 'storage_temp': SysInfo(storage_temp)(),
810 821
811 822 'search': SysInfo(search_info)(),
812 823
813 824 'uptime': SysInfo(uptime)(),
814 825 'load': SysInfo(machine_load)(),
815 826 'cpu': SysInfo(cpu)(),
816 827 'memory': SysInfo(memory)(),
817 828
818 829 'vcs_backends': SysInfo(vcs_backends)(),
819 830 'vcs_server': SysInfo(vcs_server)(),
820 831
821 832 'vcs_server_config': SysInfo(vcs_server_config)(),
822 833
823 834 'git': SysInfo(git_info)(),
824 835 'hg': SysInfo(hg_info)(),
825 836 'svn': SysInfo(svn_info)(),
826 837 }
827 838
828 839
829 840 def load_system_info(key):
830 841 """
831 842 get_sys_info('vcs_server')
832 843 get_sys_info('database')
833 844 """
834 845 return SysInfo(registered_helpers[key])()
General Comments 0
You need to be logged in to leave comments. Login now