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