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