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