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