system_info.py
796 lines
| 25.2 KiB
| text/x-python
|
PythonLexer
r1552 | # -*- coding: utf-8 -*- | ||
r3363 | # Copyright (C) 2017-2019 RhodeCode GmbH | ||
r1552 | # | ||
# This program is free software: you can redistribute it and/or modify | |||
# it under the terms of the GNU Affero General Public License, version 3 | |||
# (only), as published by the Free Software Foundation. | |||
# | |||
# This program is distributed in the hope that it will be useful, | |||
# but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
# GNU General Public License for more details. | |||
# | |||
# You should have received a copy of the GNU Affero General Public License | |||
# along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
# | |||
# This program is dual-licensed. If you wish to learn more about the | |||
# RhodeCode Enterprise Edition, including its added features, Support services, | |||
# and proprietary license terms, please see https://rhodecode.com/licenses/ | |||
r1111 | import os | ||
import sys | |||
import time | |||
import platform | |||
r2674 | import collections | ||
r1111 | import pkg_resources | ||
import logging | |||
r2674 | import resource | ||
r1111 | |||
r2355 | from pyramid.compat import configparser | ||
r1111 | |||
log = logging.getLogger(__name__) | |||
psutil = None | |||
try: | |||
# cygwin cannot have yet psutil support. | |||
import psutil as psutil | |||
except ImportError: | |||
pass | |||
_NA = 'NOT AVAILABLE' | |||
STATE_OK = 'ok' | |||
STATE_ERR = 'error' | |||
STATE_WARN = 'warning' | |||
STATE_OK_DEFAULT = {'message': '', 'type': STATE_OK} | |||
# HELPERS | |||
def percentage(part, whole): | |||
whole = float(whole) | |||
if whole > 0: | |||
r1155 | return round(100 * float(part) / whole, 1) | ||
return 0.0 | |||
r1111 | |||
def get_storage_size(storage_path): | |||
sizes = [] | |||
for file_ in os.listdir(storage_path): | |||
storage_file = os.path.join(storage_path, file_) | |||
if os.path.isfile(storage_file): | |||
try: | |||
sizes.append(os.path.getsize(storage_file)) | |||
except OSError: | |||
r3337 | log.exception('Failed to get size of storage file %s', storage_file) | ||
r1111 | pass | ||
return sum(sizes) | |||
r3184 | def get_resource(resource_type): | ||
try: | |||
return resource.getrlimit(resource_type) | |||
except Exception: | |||
return 'NOT_SUPPORTED' | |||
r3337 | def get_cert_path(ini_path): | ||
default = '/etc/ssl/certs/ca-certificates.crt' | |||
control_ca_bundle = os.path.join( | |||
os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(ini_path)))), | |||
'.rccontrol-profile/etc/ca-bundle.crt') | |||
if os.path.isfile(control_ca_bundle): | |||
default = control_ca_bundle | |||
return default | |||
r3900 | |||
r1111 | class SysInfoRes(object): | ||
r3184 | def __init__(self, value, state=None, human_value=None): | ||
r1111 | self.value = value | ||
r3184 | self.state = state or STATE_OK_DEFAULT | ||
r1111 | self.human_value = human_value or value | ||
def __json__(self): | |||
return { | |||
'value': self.value, | |||
'state': self.state, | |||
'human_value': self.human_value, | |||
} | |||
r1295 | def get_value(self): | ||
return self.__json__() | |||
r1111 | def __str__(self): | ||
return '<SysInfoRes({})>'.format(self.__json__()) | |||
class SysInfo(object): | |||
def __init__(self, func_name, **kwargs): | |||
self.func_name = func_name | |||
self.value = _NA | |||
self.state = None | |||
self.kwargs = kwargs or {} | |||
def __call__(self): | |||
computed = self.compute(**self.kwargs) | |||
if not isinstance(computed, SysInfoRes): | |||
raise ValueError( | |||
'computed value for {} is not instance of ' | |||
'{}, got {} instead'.format( | |||
self.func_name, SysInfoRes, type(computed))) | |||
return computed.__json__() | |||
def __str__(self): | |||
return '<SysInfo({})>'.format(self.func_name) | |||
def compute(self, **kwargs): | |||
return self.func_name(**kwargs) | |||
# SysInfo functions | |||
def python_info(): | |||
r1112 | value = dict(version=' '.join(platform._sys_version()), | ||
executable=sys.executable) | |||
r1111 | return SysInfoRes(value=value) | ||
def py_modules(): | |||
mods = dict([(p.project_name, p.version) | |||
for p in pkg_resources.working_set]) | |||
value = sorted(mods.items(), key=lambda k: k[0].lower()) | |||
return SysInfoRes(value=value) | |||
def platform_type(): | |||
r1115 | from rhodecode.lib.utils import safe_unicode, generate_platform_uuid | ||
value = dict( | |||
name=safe_unicode(platform.platform()), | |||
uuid=generate_platform_uuid() | |||
) | |||
r1111 | return SysInfoRes(value=value) | ||
r2914 | def locale_info(): | ||
import locale | |||
value = dict( | |||
locale_default=locale.getdefaultlocale(), | |||
locale_lc_all=locale.getlocale(locale.LC_ALL), | |||
lang_env=os.environ.get('LANG'), | |||
lc_all_env=os.environ.get('LC_ALL'), | |||
local_archive_env=os.environ.get('LOCALE_ARCHIVE'), | |||
) | |||
human_value = 'LANG: {}, locale LC_ALL: {}, Default locales: {}'.format( | |||
value['lang_env'], value['locale_lc_all'], value['locale_default']) | |||
return SysInfoRes(value=value, human_value=human_value) | |||
r2673 | def ulimit_info(): | ||
r2674 | data = collections.OrderedDict([ | ||
r3184 | ('cpu time (seconds)', get_resource(resource.RLIMIT_CPU)), | ||
('file size', get_resource(resource.RLIMIT_FSIZE)), | |||
('stack size', get_resource(resource.RLIMIT_STACK)), | |||
('core file size', get_resource(resource.RLIMIT_CORE)), | |||
('address space size', get_resource(resource.RLIMIT_AS)), | |||
('locked in mem size', get_resource(resource.RLIMIT_MEMLOCK)), | |||
('heap size', get_resource(resource.RLIMIT_DATA)), | |||
('rss size', get_resource(resource.RLIMIT_RSS)), | |||
('number of processes', get_resource(resource.RLIMIT_NPROC)), | |||
('open files', get_resource(resource.RLIMIT_NOFILE)), | |||
r2674 | ]) | ||
r2673 | |||
r3900 | text = ', '.join('{}:{}'.format(k, v) for k, v in data.items()) | ||
r2673 | |||
value = { | |||
r2674 | 'limits': data, | ||
r2673 | 'text': text, | ||
} | |||
return SysInfoRes(value=value) | |||
r1111 | def uptime(): | ||
from rhodecode.lib.helpers import age, time_to_datetime | |||
r1462 | from rhodecode.translation import TranslationString | ||
r1111 | |||
r1112 | value = dict(boot_time=0, uptime=0, text='') | ||
r1111 | state = STATE_OK_DEFAULT | ||
if not psutil: | |||
r1112 | return SysInfoRes(value=value, state=state) | ||
r1111 | |||
boot_time = psutil.boot_time() | |||
r1112 | value['boot_time'] = boot_time | ||
value['uptime'] = time.time() - boot_time | |||
r1111 | |||
r1462 | date_or_age = age(time_to_datetime(boot_time)) | ||
if isinstance(date_or_age, TranslationString): | |||
date_or_age = date_or_age.interpolate() | |||
r1112 | human_value = value.copy() | ||
human_value['boot_time'] = time_to_datetime(boot_time) | |||
human_value['uptime'] = age(time_to_datetime(boot_time), show_suffix=False) | |||
r1308 | |||
r1462 | human_value['text'] = u'Server started {}'.format(date_or_age) | ||
r1112 | return SysInfoRes(value=value, human_value=human_value) | ||
r1111 | |||
def memory(): | |||
from rhodecode.lib.helpers import format_byte_size_binary | |||
r1116 | value = dict(available=0, used=0, used_real=0, cached=0, percent=0, | ||
percent_used=0, free=0, inactive=0, active=0, shared=0, | |||
total=0, buffers=0, text='') | |||
r1112 | |||
r1111 | state = STATE_OK_DEFAULT | ||
if not psutil: | |||
r1112 | return SysInfoRes(value=value, state=state) | ||
r1111 | |||
r1112 | value.update(dict(psutil.virtual_memory()._asdict())) | ||
r1116 | value['used_real'] = value['total'] - value['available'] | ||
r1112 | value['percent_used'] = psutil._common.usage_percent( | ||
r1116 | value['used_real'], value['total'], 1) | ||
r1111 | |||
r1112 | human_value = value.copy() | ||
human_value['text'] = '%s/%s, %s%% used' % ( | |||
r1116 | format_byte_size_binary(value['used_real']), | ||
r1112 | format_byte_size_binary(value['total']), | ||
value['percent_used'],) | |||
r1111 | |||
r1112 | keys = value.keys()[::] | ||
keys.pop(keys.index('percent')) | |||
keys.pop(keys.index('percent_used')) | |||
keys.pop(keys.index('text')) | |||
for k in keys: | |||
human_value[k] = format_byte_size_binary(value[k]) | |||
if state['type'] == STATE_OK and value['percent_used'] > 90: | |||
r1111 | msg = 'Critical: your available RAM memory is very low.' | ||
state = {'message': msg, 'type': STATE_ERR} | |||
r1112 | elif state['type'] == STATE_OK and value['percent_used'] > 70: | ||
r1111 | msg = 'Warning: your available RAM memory is running low.' | ||
state = {'message': msg, 'type': STATE_WARN} | |||
r1112 | return SysInfoRes(value=value, state=state, human_value=human_value) | ||
r1111 | |||
def machine_load(): | |||
r1112 | value = {'1_min': _NA, '5_min': _NA, '15_min': _NA, 'text': ''} | ||
r1111 | state = STATE_OK_DEFAULT | ||
if not psutil: | |||
r1112 | return SysInfoRes(value=value, state=state) | ||
r1111 | |||
# load averages | |||
if hasattr(psutil.os, 'getloadavg'): | |||
r1112 | value.update(dict( | ||
zip(['1_min', '5_min', '15_min'], psutil.os.getloadavg()))) | |||
r1111 | |||
r1112 | human_value = value.copy() | ||
human_value['text'] = '1min: {}, 5min: {}, 15min: {}'.format( | |||
value['1_min'], value['5_min'], value['15_min']) | |||
r1111 | |||
r1112 | if state['type'] == STATE_OK and value['15_min'] > 5: | ||
msg = 'Warning: your machine load is very high.' | |||
state = {'message': msg, 'type': STATE_WARN} | |||
return SysInfoRes(value=value, state=state, human_value=human_value) | |||
r1111 | |||
def cpu(): | |||
r1464 | value = {'cpu': 0, 'cpu_count': 0, 'cpu_usage': []} | ||
r1111 | state = STATE_OK_DEFAULT | ||
r1112 | |||
r1111 | if not psutil: | ||
r1112 | return SysInfoRes(value=value, state=state) | ||
r1111 | |||
r1464 | value['cpu'] = psutil.cpu_percent(0.5) | ||
value['cpu_usage'] = psutil.cpu_percent(0.5, percpu=True) | |||
value['cpu_count'] = psutil.cpu_count() | |||
human_value = value.copy() | |||
human_value['text'] = '{} cores at {} %'.format( | |||
value['cpu_count'], value['cpu']) | |||
r1112 | return SysInfoRes(value=value, state=state, human_value=human_value) | ||
r1111 | |||
def storage(): | |||
from rhodecode.lib.helpers import format_byte_size_binary | |||
from rhodecode.model.settings import VcsSettingsModel | |||
path = VcsSettingsModel().get_repos_location() | |||
r1112 | value = dict(percent=0, used=0, total=0, path=path, text='') | ||
r1111 | state = STATE_OK_DEFAULT | ||
if not psutil: | |||
r1112 | return SysInfoRes(value=value, state=state) | ||
r1111 | |||
try: | |||
r1112 | value.update(dict(psutil.disk_usage(path)._asdict())) | ||
r1111 | except Exception as e: | ||
log.exception('Failed to fetch disk info') | |||
state = {'message': str(e), 'type': STATE_ERR} | |||
r1112 | human_value = value.copy() | ||
human_value['used'] = format_byte_size_binary(value['used']) | |||
human_value['total'] = format_byte_size_binary(value['total']) | |||
r1111 | human_value['text'] = "{}/{}, {}% used".format( | ||
r1112 | format_byte_size_binary(value['used']), | ||
format_byte_size_binary(value['total']), | |||
value['percent']) | |||
r1111 | |||
r1112 | if state['type'] == STATE_OK and value['percent'] > 90: | ||
r1111 | msg = 'Critical: your disk space is very low.' | ||
state = {'message': msg, 'type': STATE_ERR} | |||
r1112 | elif state['type'] == STATE_OK and value['percent'] > 70: | ||
r1111 | msg = 'Warning: your disk space is running low.' | ||
state = {'message': msg, 'type': STATE_WARN} | |||
r1112 | return SysInfoRes(value=value, state=state, human_value=human_value) | ||
r1111 | |||
def storage_inodes(): | |||
from rhodecode.model.settings import VcsSettingsModel | |||
path = VcsSettingsModel().get_repos_location() | |||
r1112 | value = dict(percent=0, free=0, used=0, total=0, path=path, text='') | ||
r1111 | state = STATE_OK_DEFAULT | ||
if not psutil: | |||
r1112 | return SysInfoRes(value=value, state=state) | ||
r1111 | |||
try: | |||
i_stat = os.statvfs(path) | |||
r1219 | value['free'] = i_stat.f_ffree | ||
value['used'] = i_stat.f_files-i_stat.f_favail | |||
r1112 | value['total'] = i_stat.f_files | ||
r1155 | value['percent'] = percentage(value['used'], value['total']) | ||
r1111 | except Exception as e: | ||
log.exception('Failed to fetch disk inodes info') | |||
state = {'message': str(e), 'type': STATE_ERR} | |||
r1112 | human_value = value.copy() | ||
r1111 | human_value['text'] = "{}/{}, {}% used".format( | ||
r1112 | value['used'], value['total'], value['percent']) | ||
r1111 | |||
r1112 | if state['type'] == STATE_OK and value['percent'] > 90: | ||
r1111 | msg = 'Critical: your disk free inodes are very low.' | ||
state = {'message': msg, 'type': STATE_ERR} | |||
r1112 | elif state['type'] == STATE_OK and value['percent'] > 70: | ||
r1111 | msg = 'Warning: your disk free inodes are running low.' | ||
state = {'message': msg, 'type': STATE_WARN} | |||
r1155 | return SysInfoRes(value=value, state=state, human_value=human_value) | ||
r1111 | |||
def storage_archives(): | |||
import rhodecode | |||
from rhodecode.lib.utils import safe_str | |||
from rhodecode.lib.helpers import format_byte_size_binary | |||
msg = 'Enable this by setting ' \ | |||
'archive_cache_dir=/path/to/cache option in the .ini file' | |||
path = safe_str(rhodecode.CONFIG.get('archive_cache_dir', msg)) | |||
r1112 | value = dict(percent=0, used=0, total=0, items=0, path=path, text='') | ||
r1111 | state = STATE_OK_DEFAULT | ||
try: | |||
items_count = 0 | |||
used = 0 | |||
for root, dirs, files in os.walk(path): | |||
if root == path: | |||
r1112 | items_count = len(files) | ||
r1111 | |||
for f in files: | |||
try: | |||
used += os.path.getsize(os.path.join(root, f)) | |||
except OSError: | |||
pass | |||
r1112 | value.update({ | ||
r1111 | 'percent': 100, | ||
'used': used, | |||
'total': used, | |||
'items': items_count | |||
}) | |||
except Exception as e: | |||
log.exception('failed to fetch archive cache storage') | |||
state = {'message': str(e), 'type': STATE_ERR} | |||
r1112 | human_value = value.copy() | ||
human_value['used'] = format_byte_size_binary(value['used']) | |||
human_value['total'] = format_byte_size_binary(value['total']) | |||
human_value['text'] = "{} ({} items)".format( | |||
human_value['used'], value['items']) | |||
r1111 | |||
r1112 | return SysInfoRes(value=value, state=state, human_value=human_value) | ||
r1111 | |||
def storage_gist(): | |||
from rhodecode.model.gist import GIST_STORE_LOC | |||
from rhodecode.model.settings import VcsSettingsModel | |||
from rhodecode.lib.utils import safe_str | |||
from rhodecode.lib.helpers import format_byte_size_binary | |||
path = safe_str(os.path.join( | |||
VcsSettingsModel().get_repos_location(), GIST_STORE_LOC)) | |||
# gist storage | |||
r1112 | value = dict(percent=0, used=0, total=0, items=0, path=path, text='') | ||
r1111 | state = STATE_OK_DEFAULT | ||
try: | |||
items_count = 0 | |||
used = 0 | |||
for root, dirs, files in os.walk(path): | |||
if root == path: | |||
items_count = len(dirs) | |||
for f in files: | |||
try: | |||
used += os.path.getsize(os.path.join(root, f)) | |||
except OSError: | |||
pass | |||
r1112 | value.update({ | ||
r1111 | 'percent': 100, | ||
'used': used, | |||
'total': used, | |||
'items': items_count | |||
}) | |||
except Exception as e: | |||
log.exception('failed to fetch gist storage items') | |||
state = {'message': str(e), 'type': STATE_ERR} | |||
r1112 | human_value = value.copy() | ||
human_value['used'] = format_byte_size_binary(value['used']) | |||
human_value['total'] = format_byte_size_binary(value['total']) | |||
human_value['text'] = "{} ({} items)".format( | |||
human_value['used'], value['items']) | |||
return SysInfoRes(value=value, state=state, human_value=human_value) | |||
r1111 | |||
r1124 | def storage_temp(): | ||
import tempfile | |||
from rhodecode.lib.helpers import format_byte_size_binary | |||
path = tempfile.gettempdir() | |||
value = dict(percent=0, used=0, total=0, items=0, path=path, text='') | |||
state = STATE_OK_DEFAULT | |||
if not psutil: | |||
return SysInfoRes(value=value, state=state) | |||
try: | |||
value.update(dict(psutil.disk_usage(path)._asdict())) | |||
except Exception as e: | |||
log.exception('Failed to fetch temp dir info') | |||
state = {'message': str(e), 'type': STATE_ERR} | |||
human_value = value.copy() | |||
human_value['used'] = format_byte_size_binary(value['used']) | |||
human_value['total'] = format_byte_size_binary(value['total']) | |||
human_value['text'] = "{}/{}, {}% used".format( | |||
format_byte_size_binary(value['used']), | |||
format_byte_size_binary(value['total']), | |||
value['percent']) | |||
return SysInfoRes(value=value, state=state, human_value=human_value) | |||
r1112 | def search_info(): | ||
r1111 | import rhodecode | ||
r1112 | from rhodecode.lib.index import searcher_from_config | ||
r1111 | |||
r1112 | backend = rhodecode.CONFIG.get('search.module', '') | ||
location = rhodecode.CONFIG.get('search.location', '') | |||
r1111 | try: | ||
r1112 | searcher = searcher_from_config(rhodecode.CONFIG) | ||
searcher = searcher.__class__.__name__ | |||
except Exception: | |||
searcher = None | |||
r1111 | |||
r1112 | value = dict( | ||
backend=backend, searcher=searcher, location=location, text='') | |||
state = STATE_OK_DEFAULT | |||
r1111 | |||
r1112 | human_value = value.copy() | ||
human_value['text'] = "backend:`{}`".format(human_value['backend']) | |||
return SysInfoRes(value=value, state=state, human_value=human_value) | |||
r1111 | |||
def git_info(): | |||
from rhodecode.lib.vcs.backends import git | |||
state = STATE_OK_DEFAULT | |||
value = human_value = '' | |||
try: | |||
value = git.discover_git_version(raise_on_exc=True) | |||
human_value = 'version reported from VCSServer: {}'.format(value) | |||
except Exception as e: | |||
state = {'message': str(e), 'type': STATE_ERR} | |||
return SysInfoRes(value=value, state=state, human_value=human_value) | |||
def hg_info(): | |||
from rhodecode.lib.vcs.backends import hg | |||
state = STATE_OK_DEFAULT | |||
value = human_value = '' | |||
try: | |||
value = hg.discover_hg_version(raise_on_exc=True) | |||
human_value = 'version reported from VCSServer: {}'.format(value) | |||
except Exception as e: | |||
state = {'message': str(e), 'type': STATE_ERR} | |||
return SysInfoRes(value=value, state=state, human_value=human_value) | |||
def svn_info(): | |||
from rhodecode.lib.vcs.backends import svn | |||
state = STATE_OK_DEFAULT | |||
value = human_value = '' | |||
try: | |||
value = svn.discover_svn_version(raise_on_exc=True) | |||
human_value = 'version reported from VCSServer: {}'.format(value) | |||
except Exception as e: | |||
state = {'message': str(e), 'type': STATE_ERR} | |||
return SysInfoRes(value=value, state=state, human_value=human_value) | |||
def vcs_backends(): | |||
import rhodecode | |||
r2314 | value = rhodecode.CONFIG.get('vcs.backends') | ||
r1111 | human_value = 'Enabled backends in order: {}'.format(','.join(value)) | ||
return SysInfoRes(value=value, human_value=human_value) | |||
def vcs_server(): | |||
import rhodecode | |||
r1465 | from rhodecode.lib.vcs.backends import get_vcsserver_service_data | ||
r1111 | |||
server_url = rhodecode.CONFIG.get('vcs.server') | |||
enabled = rhodecode.CONFIG.get('vcs.server.enable') | |||
r1182 | protocol = rhodecode.CONFIG.get('vcs.server.protocol') or 'http' | ||
r1111 | state = STATE_OK_DEFAULT | ||
version = None | |||
r1465 | workers = 0 | ||
r1111 | |||
try: | |||
r1465 | data = get_vcsserver_service_data() | ||
if data and 'version' in data: | |||
version = data['version'] | |||
if data and 'config' in data: | |||
conf = data['config'] | |||
r1576 | workers = conf.get('workers', 'NOT AVAILABLE') | ||
r1465 | |||
r1111 | connection = 'connected' | ||
except Exception as e: | |||
connection = 'failed' | |||
state = {'message': str(e), 'type': STATE_ERR} | |||
value = dict( | |||
url=server_url, | |||
enabled=enabled, | |||
protocol=protocol, | |||
connection=connection, | |||
version=version, | |||
text='', | |||
) | |||
r1112 | human_value = value.copy() | ||
r1111 | human_value['text'] = \ | ||
r1465 | '{url}@ver:{ver} via {mode} mode[workers:{workers}], connection:{conn}'.format( | ||
url=server_url, ver=version, workers=workers, mode=protocol, | |||
conn=connection) | |||
r1111 | |||
r1112 | return SysInfoRes(value=value, state=state, human_value=human_value) | ||
r1111 | |||
r3943 | def vcs_server_config(): | ||
from rhodecode.lib.vcs.backends import get_vcsserver_service_data | |||
state = STATE_OK_DEFAULT | |||
value = {} | |||
try: | |||
data = get_vcsserver_service_data() | |||
value = data['app_config'] | |||
except Exception as e: | |||
state = {'message': str(e), 'type': STATE_ERR} | |||
human_value = value.copy() | |||
human_value['text'] = 'VCS Server config' | |||
return SysInfoRes(value=value, state=state, human_value=human_value) | |||
r1111 | def rhodecode_app_info(): | ||
import rhodecode | |||
r1113 | edition = rhodecode.CONFIG.get('rhodecode.edition') | ||
r1112 | value = dict( | ||
rhodecode_version=rhodecode.__version__, | |||
r1113 | rhodecode_lib_path=os.path.abspath(rhodecode.__file__), | ||
text='' | |||
r1112 | ) | ||
r1113 | human_value = value.copy() | ||
human_value['text'] = 'RhodeCode {edition}, version {ver}'.format( | |||
edition=edition, ver=value['rhodecode_version'] | |||
) | |||
return SysInfoRes(value=value, human_value=human_value) | |||
r1111 | |||
def rhodecode_config(): | |||
import rhodecode | |||
path = rhodecode.CONFIG.get('__file__') | |||
rhodecode_ini_safe = rhodecode.CONFIG.copy() | |||
r3337 | cert_path = get_cert_path(path) | ||
r1111 | |||
r1463 | try: | ||
r1465 | config = configparser.ConfigParser() | ||
r1463 | config.read(path) | ||
parsed_ini = config | |||
if parsed_ini.has_section('server:main'): | |||
parsed_ini = dict(parsed_ini.items('server:main')) | |||
except Exception: | |||
log.exception('Failed to read .ini file for display') | |||
parsed_ini = {} | |||
rhodecode_ini_safe['server:main'] = parsed_ini | |||
r1111 | blacklist = [ | ||
'rhodecode_license_key', | |||
'routes.map', | |||
'sqlalchemy.db1.url', | |||
'channelstream.secret', | |||
'beaker.session.secret', | |||
'rhodecode.encrypted_values.secret', | |||
'rhodecode_auth_github_consumer_key', | |||
'rhodecode_auth_github_consumer_secret', | |||
'rhodecode_auth_google_consumer_key', | |||
'rhodecode_auth_google_consumer_secret', | |||
'rhodecode_auth_bitbucket_consumer_secret', | |||
'rhodecode_auth_bitbucket_consumer_key', | |||
'rhodecode_auth_twitter_consumer_secret', | |||
'rhodecode_auth_twitter_consumer_key', | |||
'rhodecode_auth_twitter_secret', | |||
'rhodecode_auth_github_secret', | |||
'rhodecode_auth_google_secret', | |||
'rhodecode_auth_bitbucket_secret', | |||
'appenlight.api_key', | |||
('app_conf', 'sqlalchemy.db1.url') | |||
] | |||
for k in blacklist: | |||
if isinstance(k, tuple): | |||
section, key = k | |||
if section in rhodecode_ini_safe: | |||
rhodecode_ini_safe[section] = '**OBFUSCATED**' | |||
else: | |||
rhodecode_ini_safe.pop(k, None) | |||
# TODO: maybe put some CONFIG checks here ? | |||
r1729 | return SysInfoRes(value={'config': rhodecode_ini_safe, | ||
'path': path, 'cert_path': cert_path}) | |||
r1111 | |||
def database_info(): | |||
import rhodecode | |||
from sqlalchemy.engine import url as engine_url | |||
from rhodecode.model.meta import Base as sql_base, Session | |||
from rhodecode.model.db import DbMigrateVersion | |||
state = STATE_OK_DEFAULT | |||
db_migrate = DbMigrateVersion.query().filter( | |||
DbMigrateVersion.repository_id == 'rhodecode_db_migrations').one() | |||
db_url_obj = engine_url.make_url(rhodecode.CONFIG['sqlalchemy.db1.url']) | |||
try: | |||
engine = sql_base.metadata.bind | |||
db_server_info = engine.dialect._get_server_version_info( | |||
Session.connection(bind=engine)) | |||
db_version = '.'.join(map(str, db_server_info)) | |||
except Exception: | |||
log.exception('failed to fetch db version') | |||
db_version = 'UNKNOWN' | |||
db_info = dict( | |||
migrate_version=db_migrate.version, | |||
type=db_url_obj.get_backend_name(), | |||
version=db_version, | |||
url=repr(db_url_obj) | |||
) | |||
r1575 | current_version = db_migrate.version | ||
expected_version = rhodecode.__dbversion__ | |||
if state['type'] == STATE_OK and current_version != expected_version: | |||
msg = 'Critical: database schema mismatch, ' \ | |||
'expected version {}, got {}. ' \ | |||
'Please run migrations on your database.'.format( | |||
expected_version, current_version) | |||
state = {'message': msg, 'type': STATE_ERR} | |||