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