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