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