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