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