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