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