##// END OF EJS Templates
system-info: fix unicode problem on translation
marcink -
r1308:8c3404aa default
parent child Browse files
Show More
@@ -1,642 +1,643 b''
1 import os
1 import os
2 import sys
2 import sys
3 import time
3 import time
4 import platform
4 import platform
5 import pkg_resources
5 import pkg_resources
6 import logging
6 import logging
7 import string
7 import string
8
8
9
9
10 log = logging.getLogger(__name__)
10 log = logging.getLogger(__name__)
11
11
12
12
13 psutil = None
13 psutil = None
14
14
15 try:
15 try:
16 # cygwin cannot have yet psutil support.
16 # cygwin cannot have yet psutil support.
17 import psutil as psutil
17 import psutil as psutil
18 except ImportError:
18 except ImportError:
19 pass
19 pass
20
20
21
21
22 _NA = 'NOT AVAILABLE'
22 _NA = 'NOT AVAILABLE'
23
23
24 STATE_OK = 'ok'
24 STATE_OK = 'ok'
25 STATE_ERR = 'error'
25 STATE_ERR = 'error'
26 STATE_WARN = 'warning'
26 STATE_WARN = 'warning'
27
27
28 STATE_OK_DEFAULT = {'message': '', 'type': STATE_OK}
28 STATE_OK_DEFAULT = {'message': '', 'type': STATE_OK}
29
29
30
30
31 # HELPERS
31 # HELPERS
32 def percentage(part, whole):
32 def percentage(part, whole):
33 whole = float(whole)
33 whole = float(whole)
34 if whole > 0:
34 if whole > 0:
35 return round(100 * float(part) / whole, 1)
35 return round(100 * float(part) / whole, 1)
36 return 0.0
36 return 0.0
37
37
38
38
39 def get_storage_size(storage_path):
39 def get_storage_size(storage_path):
40 sizes = []
40 sizes = []
41 for file_ in os.listdir(storage_path):
41 for file_ in os.listdir(storage_path):
42 storage_file = os.path.join(storage_path, file_)
42 storage_file = os.path.join(storage_path, file_)
43 if os.path.isfile(storage_file):
43 if os.path.isfile(storage_file):
44 try:
44 try:
45 sizes.append(os.path.getsize(storage_file))
45 sizes.append(os.path.getsize(storage_file))
46 except OSError:
46 except OSError:
47 log.exception('Failed to get size of storage file %s',
47 log.exception('Failed to get size of storage file %s',
48 storage_file)
48 storage_file)
49 pass
49 pass
50
50
51 return sum(sizes)
51 return sum(sizes)
52
52
53
53
54 class SysInfoRes(object):
54 class SysInfoRes(object):
55 def __init__(self, value, state=STATE_OK_DEFAULT, human_value=None):
55 def __init__(self, value, state=STATE_OK_DEFAULT, human_value=None):
56 self.value = value
56 self.value = value
57 self.state = state
57 self.state = state
58 self.human_value = human_value or value
58 self.human_value = human_value or value
59
59
60 def __json__(self):
60 def __json__(self):
61 return {
61 return {
62 'value': self.value,
62 'value': self.value,
63 'state': self.state,
63 'state': self.state,
64 'human_value': self.human_value,
64 'human_value': self.human_value,
65 }
65 }
66
66
67 def get_value(self):
67 def get_value(self):
68 return self.__json__()
68 return self.__json__()
69
69
70 def __str__(self):
70 def __str__(self):
71 return '<SysInfoRes({})>'.format(self.__json__())
71 return '<SysInfoRes({})>'.format(self.__json__())
72
72
73
73
74 class SysInfo(object):
74 class SysInfo(object):
75
75
76 def __init__(self, func_name, **kwargs):
76 def __init__(self, func_name, **kwargs):
77 self.func_name = func_name
77 self.func_name = func_name
78 self.value = _NA
78 self.value = _NA
79 self.state = None
79 self.state = None
80 self.kwargs = kwargs or {}
80 self.kwargs = kwargs or {}
81
81
82 def __call__(self):
82 def __call__(self):
83 computed = self.compute(**self.kwargs)
83 computed = self.compute(**self.kwargs)
84 if not isinstance(computed, SysInfoRes):
84 if not isinstance(computed, SysInfoRes):
85 raise ValueError(
85 raise ValueError(
86 'computed value for {} is not instance of '
86 'computed value for {} is not instance of '
87 '{}, got {} instead'.format(
87 '{}, got {} instead'.format(
88 self.func_name, SysInfoRes, type(computed)))
88 self.func_name, SysInfoRes, type(computed)))
89 return computed.__json__()
89 return computed.__json__()
90
90
91 def __str__(self):
91 def __str__(self):
92 return '<SysInfo({})>'.format(self.func_name)
92 return '<SysInfo({})>'.format(self.func_name)
93
93
94 def compute(self, **kwargs):
94 def compute(self, **kwargs):
95 return self.func_name(**kwargs)
95 return self.func_name(**kwargs)
96
96
97
97
98 # SysInfo functions
98 # SysInfo functions
99 def python_info():
99 def python_info():
100 value = dict(version=' '.join(platform._sys_version()),
100 value = dict(version=' '.join(platform._sys_version()),
101 executable=sys.executable)
101 executable=sys.executable)
102 return SysInfoRes(value=value)
102 return SysInfoRes(value=value)
103
103
104
104
105 def py_modules():
105 def py_modules():
106 mods = dict([(p.project_name, p.version)
106 mods = dict([(p.project_name, p.version)
107 for p in pkg_resources.working_set])
107 for p in pkg_resources.working_set])
108 value = sorted(mods.items(), key=lambda k: k[0].lower())
108 value = sorted(mods.items(), key=lambda k: k[0].lower())
109 return SysInfoRes(value=value)
109 return SysInfoRes(value=value)
110
110
111
111
112 def platform_type():
112 def platform_type():
113 from rhodecode.lib.utils import safe_unicode, generate_platform_uuid
113 from rhodecode.lib.utils import safe_unicode, generate_platform_uuid
114
114
115 value = dict(
115 value = dict(
116 name=safe_unicode(platform.platform()),
116 name=safe_unicode(platform.platform()),
117 uuid=generate_platform_uuid()
117 uuid=generate_platform_uuid()
118 )
118 )
119 return SysInfoRes(value=value)
119 return SysInfoRes(value=value)
120
120
121
121
122 def uptime():
122 def uptime():
123 from rhodecode.lib.helpers import age, time_to_datetime
123 from rhodecode.lib.helpers import age, time_to_datetime
124
124
125 value = dict(boot_time=0, uptime=0, text='')
125 value = dict(boot_time=0, uptime=0, text='')
126 state = STATE_OK_DEFAULT
126 state = STATE_OK_DEFAULT
127 if not psutil:
127 if not psutil:
128 return SysInfoRes(value=value, state=state)
128 return SysInfoRes(value=value, state=state)
129
129
130 boot_time = psutil.boot_time()
130 boot_time = psutil.boot_time()
131 value['boot_time'] = boot_time
131 value['boot_time'] = boot_time
132 value['uptime'] = time.time() - boot_time
132 value['uptime'] = time.time() - boot_time
133
133
134 human_value = value.copy()
134 human_value = value.copy()
135 human_value['boot_time'] = time_to_datetime(boot_time)
135 human_value['boot_time'] = time_to_datetime(boot_time)
136 human_value['uptime'] = age(time_to_datetime(boot_time), show_suffix=False)
136 human_value['uptime'] = age(time_to_datetime(boot_time), show_suffix=False)
137 human_value['text'] = 'Server started {}'.format(
137
138 human_value['text'] = u'Server started {}'.format(
138 age(time_to_datetime(boot_time)))
139 age(time_to_datetime(boot_time)))
139
140
140 return SysInfoRes(value=value, human_value=human_value)
141 return SysInfoRes(value=value, human_value=human_value)
141
142
142
143
143 def memory():
144 def memory():
144 from rhodecode.lib.helpers import format_byte_size_binary
145 from rhodecode.lib.helpers import format_byte_size_binary
145 value = dict(available=0, used=0, used_real=0, cached=0, percent=0,
146 value = dict(available=0, used=0, used_real=0, cached=0, percent=0,
146 percent_used=0, free=0, inactive=0, active=0, shared=0,
147 percent_used=0, free=0, inactive=0, active=0, shared=0,
147 total=0, buffers=0, text='')
148 total=0, buffers=0, text='')
148
149
149 state = STATE_OK_DEFAULT
150 state = STATE_OK_DEFAULT
150 if not psutil:
151 if not psutil:
151 return SysInfoRes(value=value, state=state)
152 return SysInfoRes(value=value, state=state)
152
153
153 value.update(dict(psutil.virtual_memory()._asdict()))
154 value.update(dict(psutil.virtual_memory()._asdict()))
154 value['used_real'] = value['total'] - value['available']
155 value['used_real'] = value['total'] - value['available']
155 value['percent_used'] = psutil._common.usage_percent(
156 value['percent_used'] = psutil._common.usage_percent(
156 value['used_real'], value['total'], 1)
157 value['used_real'], value['total'], 1)
157
158
158 human_value = value.copy()
159 human_value = value.copy()
159 human_value['text'] = '%s/%s, %s%% used' % (
160 human_value['text'] = '%s/%s, %s%% used' % (
160 format_byte_size_binary(value['used_real']),
161 format_byte_size_binary(value['used_real']),
161 format_byte_size_binary(value['total']),
162 format_byte_size_binary(value['total']),
162 value['percent_used'],)
163 value['percent_used'],)
163
164
164 keys = value.keys()[::]
165 keys = value.keys()[::]
165 keys.pop(keys.index('percent'))
166 keys.pop(keys.index('percent'))
166 keys.pop(keys.index('percent_used'))
167 keys.pop(keys.index('percent_used'))
167 keys.pop(keys.index('text'))
168 keys.pop(keys.index('text'))
168 for k in keys:
169 for k in keys:
169 human_value[k] = format_byte_size_binary(value[k])
170 human_value[k] = format_byte_size_binary(value[k])
170
171
171 if state['type'] == STATE_OK and value['percent_used'] > 90:
172 if state['type'] == STATE_OK and value['percent_used'] > 90:
172 msg = 'Critical: your available RAM memory is very low.'
173 msg = 'Critical: your available RAM memory is very low.'
173 state = {'message': msg, 'type': STATE_ERR}
174 state = {'message': msg, 'type': STATE_ERR}
174
175
175 elif state['type'] == STATE_OK and value['percent_used'] > 70:
176 elif state['type'] == STATE_OK and value['percent_used'] > 70:
176 msg = 'Warning: your available RAM memory is running low.'
177 msg = 'Warning: your available RAM memory is running low.'
177 state = {'message': msg, 'type': STATE_WARN}
178 state = {'message': msg, 'type': STATE_WARN}
178
179
179 return SysInfoRes(value=value, state=state, human_value=human_value)
180 return SysInfoRes(value=value, state=state, human_value=human_value)
180
181
181
182
182 def machine_load():
183 def machine_load():
183 value = {'1_min': _NA, '5_min': _NA, '15_min': _NA, 'text': ''}
184 value = {'1_min': _NA, '5_min': _NA, '15_min': _NA, 'text': ''}
184 state = STATE_OK_DEFAULT
185 state = STATE_OK_DEFAULT
185 if not psutil:
186 if not psutil:
186 return SysInfoRes(value=value, state=state)
187 return SysInfoRes(value=value, state=state)
187
188
188 # load averages
189 # load averages
189 if hasattr(psutil.os, 'getloadavg'):
190 if hasattr(psutil.os, 'getloadavg'):
190 value.update(dict(
191 value.update(dict(
191 zip(['1_min', '5_min', '15_min'], psutil.os.getloadavg())))
192 zip(['1_min', '5_min', '15_min'], psutil.os.getloadavg())))
192
193
193 human_value = value.copy()
194 human_value = value.copy()
194 human_value['text'] = '1min: {}, 5min: {}, 15min: {}'.format(
195 human_value['text'] = '1min: {}, 5min: {}, 15min: {}'.format(
195 value['1_min'], value['5_min'], value['15_min'])
196 value['1_min'], value['5_min'], value['15_min'])
196
197
197 if state['type'] == STATE_OK and value['15_min'] > 5:
198 if state['type'] == STATE_OK and value['15_min'] > 5:
198 msg = 'Warning: your machine load is very high.'
199 msg = 'Warning: your machine load is very high.'
199 state = {'message': msg, 'type': STATE_WARN}
200 state = {'message': msg, 'type': STATE_WARN}
200
201
201 return SysInfoRes(value=value, state=state, human_value=human_value)
202 return SysInfoRes(value=value, state=state, human_value=human_value)
202
203
203
204
204 def cpu():
205 def cpu():
205 value = 0
206 value = 0
206 state = STATE_OK_DEFAULT
207 state = STATE_OK_DEFAULT
207
208
208 if not psutil:
209 if not psutil:
209 return SysInfoRes(value=value, state=state)
210 return SysInfoRes(value=value, state=state)
210
211
211 value = psutil.cpu_percent(0.5)
212 value = psutil.cpu_percent(0.5)
212 human_value = '{} %'.format(value)
213 human_value = '{} %'.format(value)
213 return SysInfoRes(value=value, state=state, human_value=human_value)
214 return SysInfoRes(value=value, state=state, human_value=human_value)
214
215
215
216
216 def storage():
217 def storage():
217 from rhodecode.lib.helpers import format_byte_size_binary
218 from rhodecode.lib.helpers import format_byte_size_binary
218 from rhodecode.model.settings import VcsSettingsModel
219 from rhodecode.model.settings import VcsSettingsModel
219 path = VcsSettingsModel().get_repos_location()
220 path = VcsSettingsModel().get_repos_location()
220
221
221 value = dict(percent=0, used=0, total=0, path=path, text='')
222 value = dict(percent=0, used=0, total=0, path=path, text='')
222 state = STATE_OK_DEFAULT
223 state = STATE_OK_DEFAULT
223 if not psutil:
224 if not psutil:
224 return SysInfoRes(value=value, state=state)
225 return SysInfoRes(value=value, state=state)
225
226
226 try:
227 try:
227 value.update(dict(psutil.disk_usage(path)._asdict()))
228 value.update(dict(psutil.disk_usage(path)._asdict()))
228 except Exception as e:
229 except Exception as e:
229 log.exception('Failed to fetch disk info')
230 log.exception('Failed to fetch disk info')
230 state = {'message': str(e), 'type': STATE_ERR}
231 state = {'message': str(e), 'type': STATE_ERR}
231
232
232 human_value = value.copy()
233 human_value = value.copy()
233 human_value['used'] = format_byte_size_binary(value['used'])
234 human_value['used'] = format_byte_size_binary(value['used'])
234 human_value['total'] = format_byte_size_binary(value['total'])
235 human_value['total'] = format_byte_size_binary(value['total'])
235 human_value['text'] = "{}/{}, {}% used".format(
236 human_value['text'] = "{}/{}, {}% used".format(
236 format_byte_size_binary(value['used']),
237 format_byte_size_binary(value['used']),
237 format_byte_size_binary(value['total']),
238 format_byte_size_binary(value['total']),
238 value['percent'])
239 value['percent'])
239
240
240 if state['type'] == STATE_OK and value['percent'] > 90:
241 if state['type'] == STATE_OK and value['percent'] > 90:
241 msg = 'Critical: your disk space is very low.'
242 msg = 'Critical: your disk space is very low.'
242 state = {'message': msg, 'type': STATE_ERR}
243 state = {'message': msg, 'type': STATE_ERR}
243
244
244 elif state['type'] == STATE_OK and value['percent'] > 70:
245 elif state['type'] == STATE_OK and value['percent'] > 70:
245 msg = 'Warning: your disk space is running low.'
246 msg = 'Warning: your disk space is running low.'
246 state = {'message': msg, 'type': STATE_WARN}
247 state = {'message': msg, 'type': STATE_WARN}
247
248
248 return SysInfoRes(value=value, state=state, human_value=human_value)
249 return SysInfoRes(value=value, state=state, human_value=human_value)
249
250
250
251
251 def storage_inodes():
252 def storage_inodes():
252 from rhodecode.model.settings import VcsSettingsModel
253 from rhodecode.model.settings import VcsSettingsModel
253 path = VcsSettingsModel().get_repos_location()
254 path = VcsSettingsModel().get_repos_location()
254
255
255 value = dict(percent=0, free=0, used=0, total=0, path=path, text='')
256 value = dict(percent=0, free=0, used=0, total=0, path=path, text='')
256 state = STATE_OK_DEFAULT
257 state = STATE_OK_DEFAULT
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 try:
261 try:
261 i_stat = os.statvfs(path)
262 i_stat = os.statvfs(path)
262 value['free'] = i_stat.f_ffree
263 value['free'] = i_stat.f_ffree
263 value['used'] = i_stat.f_files-i_stat.f_favail
264 value['used'] = i_stat.f_files-i_stat.f_favail
264 value['total'] = i_stat.f_files
265 value['total'] = i_stat.f_files
265 value['percent'] = percentage(value['used'], value['total'])
266 value['percent'] = percentage(value['used'], value['total'])
266 except Exception as e:
267 except Exception as e:
267 log.exception('Failed to fetch disk inodes info')
268 log.exception('Failed to fetch disk inodes info')
268 state = {'message': str(e), 'type': STATE_ERR}
269 state = {'message': str(e), 'type': STATE_ERR}
269
270
270 human_value = value.copy()
271 human_value = value.copy()
271 human_value['text'] = "{}/{}, {}% used".format(
272 human_value['text'] = "{}/{}, {}% used".format(
272 value['used'], value['total'], value['percent'])
273 value['used'], value['total'], value['percent'])
273
274
274 if state['type'] == STATE_OK and value['percent'] > 90:
275 if state['type'] == STATE_OK and value['percent'] > 90:
275 msg = 'Critical: your disk free inodes are very low.'
276 msg = 'Critical: your disk free inodes are very low.'
276 state = {'message': msg, 'type': STATE_ERR}
277 state = {'message': msg, 'type': STATE_ERR}
277
278
278 elif state['type'] == STATE_OK and value['percent'] > 70:
279 elif state['type'] == STATE_OK and value['percent'] > 70:
279 msg = 'Warning: your disk free inodes are running low.'
280 msg = 'Warning: your disk free inodes are running low.'
280 state = {'message': msg, 'type': STATE_WARN}
281 state = {'message': msg, 'type': STATE_WARN}
281
282
282 return SysInfoRes(value=value, state=state, human_value=human_value)
283 return SysInfoRes(value=value, state=state, human_value=human_value)
283
284
284
285
285 def storage_archives():
286 def storage_archives():
286 import rhodecode
287 import rhodecode
287 from rhodecode.lib.utils import safe_str
288 from rhodecode.lib.utils import safe_str
288 from rhodecode.lib.helpers import format_byte_size_binary
289 from rhodecode.lib.helpers import format_byte_size_binary
289
290
290 msg = 'Enable this by setting ' \
291 msg = 'Enable this by setting ' \
291 'archive_cache_dir=/path/to/cache option in the .ini file'
292 'archive_cache_dir=/path/to/cache option in the .ini file'
292 path = safe_str(rhodecode.CONFIG.get('archive_cache_dir', msg))
293 path = safe_str(rhodecode.CONFIG.get('archive_cache_dir', msg))
293
294
294 value = dict(percent=0, used=0, total=0, items=0, path=path, text='')
295 value = dict(percent=0, used=0, total=0, items=0, path=path, text='')
295 state = STATE_OK_DEFAULT
296 state = STATE_OK_DEFAULT
296 try:
297 try:
297 items_count = 0
298 items_count = 0
298 used = 0
299 used = 0
299 for root, dirs, files in os.walk(path):
300 for root, dirs, files in os.walk(path):
300 if root == path:
301 if root == path:
301 items_count = len(files)
302 items_count = len(files)
302
303
303 for f in files:
304 for f in files:
304 try:
305 try:
305 used += os.path.getsize(os.path.join(root, f))
306 used += os.path.getsize(os.path.join(root, f))
306 except OSError:
307 except OSError:
307 pass
308 pass
308 value.update({
309 value.update({
309 'percent': 100,
310 'percent': 100,
310 'used': used,
311 'used': used,
311 'total': used,
312 'total': used,
312 'items': items_count
313 'items': items_count
313 })
314 })
314
315
315 except Exception as e:
316 except Exception as e:
316 log.exception('failed to fetch archive cache storage')
317 log.exception('failed to fetch archive cache storage')
317 state = {'message': str(e), 'type': STATE_ERR}
318 state = {'message': str(e), 'type': STATE_ERR}
318
319
319 human_value = value.copy()
320 human_value = value.copy()
320 human_value['used'] = format_byte_size_binary(value['used'])
321 human_value['used'] = format_byte_size_binary(value['used'])
321 human_value['total'] = format_byte_size_binary(value['total'])
322 human_value['total'] = format_byte_size_binary(value['total'])
322 human_value['text'] = "{} ({} items)".format(
323 human_value['text'] = "{} ({} items)".format(
323 human_value['used'], value['items'])
324 human_value['used'], value['items'])
324
325
325 return SysInfoRes(value=value, state=state, human_value=human_value)
326 return SysInfoRes(value=value, state=state, human_value=human_value)
326
327
327
328
328 def storage_gist():
329 def storage_gist():
329 from rhodecode.model.gist import GIST_STORE_LOC
330 from rhodecode.model.gist import GIST_STORE_LOC
330 from rhodecode.model.settings import VcsSettingsModel
331 from rhodecode.model.settings import VcsSettingsModel
331 from rhodecode.lib.utils import safe_str
332 from rhodecode.lib.utils import safe_str
332 from rhodecode.lib.helpers import format_byte_size_binary
333 from rhodecode.lib.helpers import format_byte_size_binary
333 path = safe_str(os.path.join(
334 path = safe_str(os.path.join(
334 VcsSettingsModel().get_repos_location(), GIST_STORE_LOC))
335 VcsSettingsModel().get_repos_location(), GIST_STORE_LOC))
335
336
336 # gist storage
337 # gist storage
337 value = dict(percent=0, used=0, total=0, items=0, path=path, text='')
338 value = dict(percent=0, used=0, total=0, items=0, path=path, text='')
338 state = STATE_OK_DEFAULT
339 state = STATE_OK_DEFAULT
339
340
340 try:
341 try:
341 items_count = 0
342 items_count = 0
342 used = 0
343 used = 0
343 for root, dirs, files in os.walk(path):
344 for root, dirs, files in os.walk(path):
344 if root == path:
345 if root == path:
345 items_count = len(dirs)
346 items_count = len(dirs)
346
347
347 for f in files:
348 for f in files:
348 try:
349 try:
349 used += os.path.getsize(os.path.join(root, f))
350 used += os.path.getsize(os.path.join(root, f))
350 except OSError:
351 except OSError:
351 pass
352 pass
352 value.update({
353 value.update({
353 'percent': 100,
354 'percent': 100,
354 'used': used,
355 'used': used,
355 'total': used,
356 'total': used,
356 'items': items_count
357 'items': items_count
357 })
358 })
358 except Exception as e:
359 except Exception as e:
359 log.exception('failed to fetch gist storage items')
360 log.exception('failed to fetch gist storage items')
360 state = {'message': str(e), 'type': STATE_ERR}
361 state = {'message': str(e), 'type': STATE_ERR}
361
362
362 human_value = value.copy()
363 human_value = value.copy()
363 human_value['used'] = format_byte_size_binary(value['used'])
364 human_value['used'] = format_byte_size_binary(value['used'])
364 human_value['total'] = format_byte_size_binary(value['total'])
365 human_value['total'] = format_byte_size_binary(value['total'])
365 human_value['text'] = "{} ({} items)".format(
366 human_value['text'] = "{} ({} items)".format(
366 human_value['used'], value['items'])
367 human_value['used'], value['items'])
367
368
368 return SysInfoRes(value=value, state=state, human_value=human_value)
369 return SysInfoRes(value=value, state=state, human_value=human_value)
369
370
370
371
371 def storage_temp():
372 def storage_temp():
372 import tempfile
373 import tempfile
373 from rhodecode.lib.helpers import format_byte_size_binary
374 from rhodecode.lib.helpers import format_byte_size_binary
374
375
375 path = tempfile.gettempdir()
376 path = tempfile.gettempdir()
376 value = dict(percent=0, used=0, total=0, items=0, path=path, text='')
377 value = dict(percent=0, used=0, total=0, items=0, path=path, text='')
377 state = STATE_OK_DEFAULT
378 state = STATE_OK_DEFAULT
378
379
379 if not psutil:
380 if not psutil:
380 return SysInfoRes(value=value, state=state)
381 return SysInfoRes(value=value, state=state)
381
382
382 try:
383 try:
383 value.update(dict(psutil.disk_usage(path)._asdict()))
384 value.update(dict(psutil.disk_usage(path)._asdict()))
384 except Exception as e:
385 except Exception as e:
385 log.exception('Failed to fetch temp dir info')
386 log.exception('Failed to fetch temp dir info')
386 state = {'message': str(e), 'type': STATE_ERR}
387 state = {'message': str(e), 'type': STATE_ERR}
387
388
388 human_value = value.copy()
389 human_value = value.copy()
389 human_value['used'] = format_byte_size_binary(value['used'])
390 human_value['used'] = format_byte_size_binary(value['used'])
390 human_value['total'] = format_byte_size_binary(value['total'])
391 human_value['total'] = format_byte_size_binary(value['total'])
391 human_value['text'] = "{}/{}, {}% used".format(
392 human_value['text'] = "{}/{}, {}% used".format(
392 format_byte_size_binary(value['used']),
393 format_byte_size_binary(value['used']),
393 format_byte_size_binary(value['total']),
394 format_byte_size_binary(value['total']),
394 value['percent'])
395 value['percent'])
395
396
396 return SysInfoRes(value=value, state=state, human_value=human_value)
397 return SysInfoRes(value=value, state=state, human_value=human_value)
397
398
398
399
399 def search_info():
400 def search_info():
400 import rhodecode
401 import rhodecode
401 from rhodecode.lib.index import searcher_from_config
402 from rhodecode.lib.index import searcher_from_config
402
403
403 backend = rhodecode.CONFIG.get('search.module', '')
404 backend = rhodecode.CONFIG.get('search.module', '')
404 location = rhodecode.CONFIG.get('search.location', '')
405 location = rhodecode.CONFIG.get('search.location', '')
405
406
406 try:
407 try:
407 searcher = searcher_from_config(rhodecode.CONFIG)
408 searcher = searcher_from_config(rhodecode.CONFIG)
408 searcher = searcher.__class__.__name__
409 searcher = searcher.__class__.__name__
409 except Exception:
410 except Exception:
410 searcher = None
411 searcher = None
411
412
412 value = dict(
413 value = dict(
413 backend=backend, searcher=searcher, location=location, text='')
414 backend=backend, searcher=searcher, location=location, text='')
414 state = STATE_OK_DEFAULT
415 state = STATE_OK_DEFAULT
415
416
416 human_value = value.copy()
417 human_value = value.copy()
417 human_value['text'] = "backend:`{}`".format(human_value['backend'])
418 human_value['text'] = "backend:`{}`".format(human_value['backend'])
418
419
419 return SysInfoRes(value=value, state=state, human_value=human_value)
420 return SysInfoRes(value=value, state=state, human_value=human_value)
420
421
421
422
422 def git_info():
423 def git_info():
423 from rhodecode.lib.vcs.backends import git
424 from rhodecode.lib.vcs.backends import git
424 state = STATE_OK_DEFAULT
425 state = STATE_OK_DEFAULT
425 value = human_value = ''
426 value = human_value = ''
426 try:
427 try:
427 value = git.discover_git_version(raise_on_exc=True)
428 value = git.discover_git_version(raise_on_exc=True)
428 human_value = 'version reported from VCSServer: {}'.format(value)
429 human_value = 'version reported from VCSServer: {}'.format(value)
429 except Exception as e:
430 except Exception as e:
430 state = {'message': str(e), 'type': STATE_ERR}
431 state = {'message': str(e), 'type': STATE_ERR}
431
432
432 return SysInfoRes(value=value, state=state, human_value=human_value)
433 return SysInfoRes(value=value, state=state, human_value=human_value)
433
434
434
435
435 def hg_info():
436 def hg_info():
436 from rhodecode.lib.vcs.backends import hg
437 from rhodecode.lib.vcs.backends import hg
437 state = STATE_OK_DEFAULT
438 state = STATE_OK_DEFAULT
438 value = human_value = ''
439 value = human_value = ''
439 try:
440 try:
440 value = hg.discover_hg_version(raise_on_exc=True)
441 value = hg.discover_hg_version(raise_on_exc=True)
441 human_value = 'version reported from VCSServer: {}'.format(value)
442 human_value = 'version reported from VCSServer: {}'.format(value)
442 except Exception as e:
443 except Exception as e:
443 state = {'message': str(e), 'type': STATE_ERR}
444 state = {'message': str(e), 'type': STATE_ERR}
444 return SysInfoRes(value=value, state=state, human_value=human_value)
445 return SysInfoRes(value=value, state=state, human_value=human_value)
445
446
446
447
447 def svn_info():
448 def svn_info():
448 from rhodecode.lib.vcs.backends import svn
449 from rhodecode.lib.vcs.backends import svn
449 state = STATE_OK_DEFAULT
450 state = STATE_OK_DEFAULT
450 value = human_value = ''
451 value = human_value = ''
451 try:
452 try:
452 value = svn.discover_svn_version(raise_on_exc=True)
453 value = svn.discover_svn_version(raise_on_exc=True)
453 human_value = 'version reported from VCSServer: {}'.format(value)
454 human_value = 'version reported from VCSServer: {}'.format(value)
454 except Exception as e:
455 except Exception as e:
455 state = {'message': str(e), 'type': STATE_ERR}
456 state = {'message': str(e), 'type': STATE_ERR}
456 return SysInfoRes(value=value, state=state, human_value=human_value)
457 return SysInfoRes(value=value, state=state, human_value=human_value)
457
458
458
459
459 def vcs_backends():
460 def vcs_backends():
460 import rhodecode
461 import rhodecode
461 value = map(
462 value = map(
462 string.strip, rhodecode.CONFIG.get('vcs.backends', '').split(','))
463 string.strip, rhodecode.CONFIG.get('vcs.backends', '').split(','))
463 human_value = 'Enabled backends in order: {}'.format(','.join(value))
464 human_value = 'Enabled backends in order: {}'.format(','.join(value))
464 return SysInfoRes(value=value, human_value=human_value)
465 return SysInfoRes(value=value, human_value=human_value)
465
466
466
467
467 def vcs_server():
468 def vcs_server():
468 import rhodecode
469 import rhodecode
469 from rhodecode.lib.vcs.backends import get_vcsserver_version
470 from rhodecode.lib.vcs.backends import get_vcsserver_version
470
471
471 server_url = rhodecode.CONFIG.get('vcs.server')
472 server_url = rhodecode.CONFIG.get('vcs.server')
472 enabled = rhodecode.CONFIG.get('vcs.server.enable')
473 enabled = rhodecode.CONFIG.get('vcs.server.enable')
473 protocol = rhodecode.CONFIG.get('vcs.server.protocol') or 'http'
474 protocol = rhodecode.CONFIG.get('vcs.server.protocol') or 'http'
474 state = STATE_OK_DEFAULT
475 state = STATE_OK_DEFAULT
475 version = None
476 version = None
476
477
477 try:
478 try:
478 version = get_vcsserver_version()
479 version = get_vcsserver_version()
479 connection = 'connected'
480 connection = 'connected'
480 except Exception as e:
481 except Exception as e:
481 connection = 'failed'
482 connection = 'failed'
482 state = {'message': str(e), 'type': STATE_ERR}
483 state = {'message': str(e), 'type': STATE_ERR}
483
484
484 value = dict(
485 value = dict(
485 url=server_url,
486 url=server_url,
486 enabled=enabled,
487 enabled=enabled,
487 protocol=protocol,
488 protocol=protocol,
488 connection=connection,
489 connection=connection,
489 version=version,
490 version=version,
490 text='',
491 text='',
491 )
492 )
492
493
493 human_value = value.copy()
494 human_value = value.copy()
494 human_value['text'] = \
495 human_value['text'] = \
495 '{url}@ver:{ver} via {mode} mode, connection:{conn}'.format(
496 '{url}@ver:{ver} via {mode} mode, connection:{conn}'.format(
496 url=server_url, ver=version, mode=protocol, conn=connection)
497 url=server_url, ver=version, mode=protocol, conn=connection)
497
498
498 return SysInfoRes(value=value, state=state, human_value=human_value)
499 return SysInfoRes(value=value, state=state, human_value=human_value)
499
500
500
501
501 def rhodecode_app_info():
502 def rhodecode_app_info():
502 import rhodecode
503 import rhodecode
503 edition = rhodecode.CONFIG.get('rhodecode.edition')
504 edition = rhodecode.CONFIG.get('rhodecode.edition')
504
505
505 value = dict(
506 value = dict(
506 rhodecode_version=rhodecode.__version__,
507 rhodecode_version=rhodecode.__version__,
507 rhodecode_lib_path=os.path.abspath(rhodecode.__file__),
508 rhodecode_lib_path=os.path.abspath(rhodecode.__file__),
508 text=''
509 text=''
509 )
510 )
510 human_value = value.copy()
511 human_value = value.copy()
511 human_value['text'] = 'RhodeCode {edition}, version {ver}'.format(
512 human_value['text'] = 'RhodeCode {edition}, version {ver}'.format(
512 edition=edition, ver=value['rhodecode_version']
513 edition=edition, ver=value['rhodecode_version']
513 )
514 )
514 return SysInfoRes(value=value, human_value=human_value)
515 return SysInfoRes(value=value, human_value=human_value)
515
516
516
517
517 def rhodecode_config():
518 def rhodecode_config():
518 import rhodecode
519 import rhodecode
519 path = rhodecode.CONFIG.get('__file__')
520 path = rhodecode.CONFIG.get('__file__')
520 rhodecode_ini_safe = rhodecode.CONFIG.copy()
521 rhodecode_ini_safe = rhodecode.CONFIG.copy()
521
522
522 blacklist = [
523 blacklist = [
523 'rhodecode_license_key',
524 'rhodecode_license_key',
524 'routes.map',
525 'routes.map',
525 'pylons.h',
526 'pylons.h',
526 'pylons.app_globals',
527 'pylons.app_globals',
527 'pylons.environ_config',
528 'pylons.environ_config',
528 'sqlalchemy.db1.url',
529 'sqlalchemy.db1.url',
529 'channelstream.secret',
530 'channelstream.secret',
530 'beaker.session.secret',
531 'beaker.session.secret',
531 'rhodecode.encrypted_values.secret',
532 'rhodecode.encrypted_values.secret',
532 'rhodecode_auth_github_consumer_key',
533 'rhodecode_auth_github_consumer_key',
533 'rhodecode_auth_github_consumer_secret',
534 'rhodecode_auth_github_consumer_secret',
534 'rhodecode_auth_google_consumer_key',
535 'rhodecode_auth_google_consumer_key',
535 'rhodecode_auth_google_consumer_secret',
536 'rhodecode_auth_google_consumer_secret',
536 'rhodecode_auth_bitbucket_consumer_secret',
537 'rhodecode_auth_bitbucket_consumer_secret',
537 'rhodecode_auth_bitbucket_consumer_key',
538 'rhodecode_auth_bitbucket_consumer_key',
538 'rhodecode_auth_twitter_consumer_secret',
539 'rhodecode_auth_twitter_consumer_secret',
539 'rhodecode_auth_twitter_consumer_key',
540 'rhodecode_auth_twitter_consumer_key',
540
541
541 'rhodecode_auth_twitter_secret',
542 'rhodecode_auth_twitter_secret',
542 'rhodecode_auth_github_secret',
543 'rhodecode_auth_github_secret',
543 'rhodecode_auth_google_secret',
544 'rhodecode_auth_google_secret',
544 'rhodecode_auth_bitbucket_secret',
545 'rhodecode_auth_bitbucket_secret',
545
546
546 'appenlight.api_key',
547 'appenlight.api_key',
547 ('app_conf', 'sqlalchemy.db1.url')
548 ('app_conf', 'sqlalchemy.db1.url')
548 ]
549 ]
549 for k in blacklist:
550 for k in blacklist:
550 if isinstance(k, tuple):
551 if isinstance(k, tuple):
551 section, key = k
552 section, key = k
552 if section in rhodecode_ini_safe:
553 if section in rhodecode_ini_safe:
553 rhodecode_ini_safe[section] = '**OBFUSCATED**'
554 rhodecode_ini_safe[section] = '**OBFUSCATED**'
554 else:
555 else:
555 rhodecode_ini_safe.pop(k, None)
556 rhodecode_ini_safe.pop(k, None)
556
557
557 # TODO: maybe put some CONFIG checks here ?
558 # TODO: maybe put some CONFIG checks here ?
558 return SysInfoRes(value={'config': rhodecode_ini_safe, 'path': path})
559 return SysInfoRes(value={'config': rhodecode_ini_safe, 'path': path})
559
560
560
561
561 def database_info():
562 def database_info():
562 import rhodecode
563 import rhodecode
563 from sqlalchemy.engine import url as engine_url
564 from sqlalchemy.engine import url as engine_url
564 from rhodecode.model.meta import Base as sql_base, Session
565 from rhodecode.model.meta import Base as sql_base, Session
565 from rhodecode.model.db import DbMigrateVersion
566 from rhodecode.model.db import DbMigrateVersion
566
567
567 state = STATE_OK_DEFAULT
568 state = STATE_OK_DEFAULT
568
569
569 db_migrate = DbMigrateVersion.query().filter(
570 db_migrate = DbMigrateVersion.query().filter(
570 DbMigrateVersion.repository_id == 'rhodecode_db_migrations').one()
571 DbMigrateVersion.repository_id == 'rhodecode_db_migrations').one()
571
572
572 db_url_obj = engine_url.make_url(rhodecode.CONFIG['sqlalchemy.db1.url'])
573 db_url_obj = engine_url.make_url(rhodecode.CONFIG['sqlalchemy.db1.url'])
573
574
574 try:
575 try:
575 engine = sql_base.metadata.bind
576 engine = sql_base.metadata.bind
576 db_server_info = engine.dialect._get_server_version_info(
577 db_server_info = engine.dialect._get_server_version_info(
577 Session.connection(bind=engine))
578 Session.connection(bind=engine))
578 db_version = '.'.join(map(str, db_server_info))
579 db_version = '.'.join(map(str, db_server_info))
579 except Exception:
580 except Exception:
580 log.exception('failed to fetch db version')
581 log.exception('failed to fetch db version')
581 db_version = 'UNKNOWN'
582 db_version = 'UNKNOWN'
582
583
583 db_info = dict(
584 db_info = dict(
584 migrate_version=db_migrate.version,
585 migrate_version=db_migrate.version,
585 type=db_url_obj.get_backend_name(),
586 type=db_url_obj.get_backend_name(),
586 version=db_version,
587 version=db_version,
587 url=repr(db_url_obj)
588 url=repr(db_url_obj)
588 )
589 )
589
590
590 human_value = db_info.copy()
591 human_value = db_info.copy()
591 human_value['url'] = "{} @ migration version: {}".format(
592 human_value['url'] = "{} @ migration version: {}".format(
592 db_info['url'], db_info['migrate_version'])
593 db_info['url'], db_info['migrate_version'])
593 human_value['version'] = "{} {}".format(db_info['type'], db_info['version'])
594 human_value['version'] = "{} {}".format(db_info['type'], db_info['version'])
594 return SysInfoRes(value=db_info, state=state, human_value=human_value)
595 return SysInfoRes(value=db_info, state=state, human_value=human_value)
595
596
596
597
597 def server_info(environ):
598 def server_info(environ):
598 import rhodecode
599 import rhodecode
599 from rhodecode.lib.base import get_server_ip_addr, get_server_port
600 from rhodecode.lib.base import get_server_ip_addr, get_server_port
600
601
601 value = {
602 value = {
602 'server_ip': '%s:%s' % (
603 'server_ip': '%s:%s' % (
603 get_server_ip_addr(environ, log_errors=False),
604 get_server_ip_addr(environ, log_errors=False),
604 get_server_port(environ)
605 get_server_port(environ)
605 ),
606 ),
606 'server_id': rhodecode.CONFIG.get('instance_id'),
607 'server_id': rhodecode.CONFIG.get('instance_id'),
607 }
608 }
608 return SysInfoRes(value=value)
609 return SysInfoRes(value=value)
609
610
610
611
611 def get_system_info(environ):
612 def get_system_info(environ):
612 environ = environ or {}
613 environ = environ or {}
613 return {
614 return {
614 'rhodecode_app': SysInfo(rhodecode_app_info)(),
615 'rhodecode_app': SysInfo(rhodecode_app_info)(),
615 'rhodecode_config': SysInfo(rhodecode_config)(),
616 'rhodecode_config': SysInfo(rhodecode_config)(),
616 'python': SysInfo(python_info)(),
617 'python': SysInfo(python_info)(),
617 'py_modules': SysInfo(py_modules)(),
618 'py_modules': SysInfo(py_modules)(),
618
619
619 'platform': SysInfo(platform_type)(),
620 'platform': SysInfo(platform_type)(),
620 'server': SysInfo(server_info, environ=environ)(),
621 'server': SysInfo(server_info, environ=environ)(),
621 'database': SysInfo(database_info)(),
622 'database': SysInfo(database_info)(),
622
623
623 'storage': SysInfo(storage)(),
624 'storage': SysInfo(storage)(),
624 'storage_inodes': SysInfo(storage_inodes)(),
625 'storage_inodes': SysInfo(storage_inodes)(),
625 'storage_archive': SysInfo(storage_archives)(),
626 'storage_archive': SysInfo(storage_archives)(),
626 'storage_gist': SysInfo(storage_gist)(),
627 'storage_gist': SysInfo(storage_gist)(),
627 'storage_temp': SysInfo(storage_temp)(),
628 'storage_temp': SysInfo(storage_temp)(),
628
629
629 'search': SysInfo(search_info)(),
630 'search': SysInfo(search_info)(),
630
631
631 'uptime': SysInfo(uptime)(),
632 'uptime': SysInfo(uptime)(),
632 'load': SysInfo(machine_load)(),
633 'load': SysInfo(machine_load)(),
633 'cpu': SysInfo(cpu)(),
634 'cpu': SysInfo(cpu)(),
634 'memory': SysInfo(memory)(),
635 'memory': SysInfo(memory)(),
635
636
636 'vcs_backends': SysInfo(vcs_backends)(),
637 'vcs_backends': SysInfo(vcs_backends)(),
637 'vcs_server': SysInfo(vcs_server)(),
638 'vcs_server': SysInfo(vcs_server)(),
638
639
639 'git': SysInfo(git_info)(),
640 'git': SysInfo(git_info)(),
640 'hg': SysInfo(hg_info)(),
641 'hg': SysInfo(hg_info)(),
641 'svn': SysInfo(svn_info)(),
642 'svn': SysInfo(svn_info)(),
642 }
643 }
@@ -1,166 +1,166 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21
21
22 import logging
22 import logging
23 import pylons
23 import pylons
24 import Queue
24 import Queue
25 import subprocess32
25 import subprocess32
26
26
27 from pyramid.i18n import get_localizer
27 from pyramid.i18n import get_localizer
28 from pyramid.threadlocal import get_current_request
28 from pyramid.threadlocal import get_current_request
29 from threading import Thread
29 from threading import Thread
30
30
31 from rhodecode.translation import _ as tsf
31 from rhodecode.translation import _ as tsf
32
32
33
34 log = logging.getLogger(__name__)
33 log = logging.getLogger(__name__)
35
34
36
35
37 def add_renderer_globals(event):
36 def add_renderer_globals(event):
38 # Put pylons stuff into the context. This will be removed as soon as
37 # Put pylons stuff into the context. This will be removed as soon as
39 # migration to pyramid is finished.
38 # migration to pyramid is finished.
40 conf = pylons.config._current_obj()
39 conf = pylons.config._current_obj()
41 event['h'] = conf.get('pylons.h')
40 event['h'] = conf.get('pylons.h')
42 event['c'] = pylons.tmpl_context
41 event['c'] = pylons.tmpl_context
43 event['url'] = pylons.url
42 event['url'] = pylons.url
44
43
45 # TODO: When executed in pyramid view context the request is not available
44 # TODO: When executed in pyramid view context the request is not available
46 # in the event. Find a better solution to get the request.
45 # in the event. Find a better solution to get the request.
47 request = event['request'] or get_current_request()
46 request = event['request'] or get_current_request()
48
47
49 # Add Pyramid translation as '_' to context
48 # Add Pyramid translation as '_' to context
50 event['_'] = request.translate
49 event['_'] = request.translate
51 event['_ungettext'] = request.plularize
50 event['_ungettext'] = request.plularize
52
51
53
52
54 def add_localizer(event):
53 def add_localizer(event):
55 request = event.request
54 request = event.request
56 localizer = get_localizer(request)
55 localizer = get_localizer(request)
57
56
58 def auto_translate(*args, **kwargs):
57 def auto_translate(*args, **kwargs):
59 return localizer.translate(tsf(*args, **kwargs))
58 return localizer.translate(tsf(*args, **kwargs))
60
59
61 request.localizer = localizer
60 request.localizer = localizer
62 request.translate = auto_translate
61 request.translate = auto_translate
63 request.plularize = localizer.pluralize
62 request.plularize = localizer.pluralize
64
63
65
64
66 def set_user_lang(event):
65 def set_user_lang(event):
67 cur_user = getattr(event.request, 'user', None)
66 cur_user = getattr(event.request, 'user', None)
68
67
69 if cur_user:
68 if cur_user:
70 user_lang = cur_user.get_instance().user_data.get('language')
69 user_lang = cur_user.get_instance().user_data.get('language')
71 if user_lang:
70 if user_lang:
71 log.debug('lang: setting current user:%s language to: %s', cur_user, user_lang)
72 event.request._LOCALE_ = user_lang
72 event.request._LOCALE_ = user_lang
73
73
74
74
75 def scan_repositories_if_enabled(event):
75 def scan_repositories_if_enabled(event):
76 """
76 """
77 This is subscribed to the `pyramid.events.ApplicationCreated` event. It
77 This is subscribed to the `pyramid.events.ApplicationCreated` event. It
78 does a repository scan if enabled in the settings.
78 does a repository scan if enabled in the settings.
79 """
79 """
80 from rhodecode.model.scm import ScmModel
80 from rhodecode.model.scm import ScmModel
81 from rhodecode.lib.utils import repo2db_mapper, get_rhodecode_base_path
81 from rhodecode.lib.utils import repo2db_mapper, get_rhodecode_base_path
82 settings = event.app.registry.settings
82 settings = event.app.registry.settings
83 vcs_server_enabled = settings['vcs.server.enable']
83 vcs_server_enabled = settings['vcs.server.enable']
84 import_on_startup = settings['startup.import_repos']
84 import_on_startup = settings['startup.import_repos']
85 if vcs_server_enabled and import_on_startup:
85 if vcs_server_enabled and import_on_startup:
86 repositories = ScmModel().repo_scan(get_rhodecode_base_path())
86 repositories = ScmModel().repo_scan(get_rhodecode_base_path())
87 repo2db_mapper(repositories, remove_obsolete=False)
87 repo2db_mapper(repositories, remove_obsolete=False)
88
88
89
89
90 class Subscriber(object):
90 class Subscriber(object):
91 """
91 """
92 Base class for subscribers to the pyramid event system.
92 Base class for subscribers to the pyramid event system.
93 """
93 """
94 def __call__(self, event):
94 def __call__(self, event):
95 self.run(event)
95 self.run(event)
96
96
97 def run(self, event):
97 def run(self, event):
98 raise NotImplementedError('Subclass has to implement this.')
98 raise NotImplementedError('Subclass has to implement this.')
99
99
100
100
101 class AsyncSubscriber(Subscriber):
101 class AsyncSubscriber(Subscriber):
102 """
102 """
103 Subscriber that handles the execution of events in a separate task to not
103 Subscriber that handles the execution of events in a separate task to not
104 block the execution of the code which triggers the event. It puts the
104 block the execution of the code which triggers the event. It puts the
105 received events into a queue from which the worker process takes them in
105 received events into a queue from which the worker process takes them in
106 order.
106 order.
107 """
107 """
108 def __init__(self):
108 def __init__(self):
109 self._stop = False
109 self._stop = False
110 self._eventq = Queue.Queue()
110 self._eventq = Queue.Queue()
111 self._worker = self.create_worker()
111 self._worker = self.create_worker()
112 self._worker.start()
112 self._worker.start()
113
113
114 def __call__(self, event):
114 def __call__(self, event):
115 self._eventq.put(event)
115 self._eventq.put(event)
116
116
117 def create_worker(self):
117 def create_worker(self):
118 worker = Thread(target=self.do_work)
118 worker = Thread(target=self.do_work)
119 worker.daemon = True
119 worker.daemon = True
120 return worker
120 return worker
121
121
122 def stop_worker(self):
122 def stop_worker(self):
123 self._stop = False
123 self._stop = False
124 self._eventq.put(None)
124 self._eventq.put(None)
125 self._worker.join()
125 self._worker.join()
126
126
127 def do_work(self):
127 def do_work(self):
128 while not self._stop:
128 while not self._stop:
129 event = self._eventq.get()
129 event = self._eventq.get()
130 if event is not None:
130 if event is not None:
131 self.run(event)
131 self.run(event)
132
132
133
133
134 class AsyncSubprocessSubscriber(AsyncSubscriber):
134 class AsyncSubprocessSubscriber(AsyncSubscriber):
135 """
135 """
136 Subscriber that uses the subprocess32 module to execute a command if an
136 Subscriber that uses the subprocess32 module to execute a command if an
137 event is received. Events are handled asynchronously.
137 event is received. Events are handled asynchronously.
138 """
138 """
139
139
140 def __init__(self, cmd, timeout=None):
140 def __init__(self, cmd, timeout=None):
141 super(AsyncSubprocessSubscriber, self).__init__()
141 super(AsyncSubprocessSubscriber, self).__init__()
142 self._cmd = cmd
142 self._cmd = cmd
143 self._timeout = timeout
143 self._timeout = timeout
144
144
145 def run(self, event):
145 def run(self, event):
146 cmd = self._cmd
146 cmd = self._cmd
147 timeout = self._timeout
147 timeout = self._timeout
148 log.debug('Executing command %s.', cmd)
148 log.debug('Executing command %s.', cmd)
149
149
150 try:
150 try:
151 output = subprocess32.check_output(
151 output = subprocess32.check_output(
152 cmd, timeout=timeout, stderr=subprocess32.STDOUT)
152 cmd, timeout=timeout, stderr=subprocess32.STDOUT)
153 log.debug('Command finished %s', cmd)
153 log.debug('Command finished %s', cmd)
154 if output:
154 if output:
155 log.debug('Command output: %s', output)
155 log.debug('Command output: %s', output)
156 except subprocess32.TimeoutExpired as e:
156 except subprocess32.TimeoutExpired as e:
157 log.exception('Timeout while executing command.')
157 log.exception('Timeout while executing command.')
158 if e.output:
158 if e.output:
159 log.error('Command output: %s', e.output)
159 log.error('Command output: %s', e.output)
160 except subprocess32.CalledProcessError as e:
160 except subprocess32.CalledProcessError as e:
161 log.exception('Error while executing command.')
161 log.exception('Error while executing command.')
162 if e.output:
162 if e.output:
163 log.error('Command output: %s', e.output)
163 log.error('Command output: %s', e.output)
164 except:
164 except:
165 log.exception(
165 log.exception(
166 'Exception while executing command %s.', cmd)
166 'Exception while executing command %s.', cmd)
General Comments 0
You need to be logged in to leave comments. Login now