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