move ExecutableService to a separate file
lgz committed
Oct 13, 2017 at 00:14 UTC
cda9a8ed2aad51ed6cedf8284cf6679d10c2d7fe
1 file changed
+82
python.d/python_modules/bases/FrameworkServices/ExecutableService.py
new
+82
@@ -0,0 +1,82 @@
1
+# -*- coding: utf-8 -*-
2
+# Description:
3
+# Author: Pawel Krupa (paulfantom)
4
+# Author: Ilya Mashchenko (l2isbad)
5
+
6
+from subprocess import Popen, PIPE
7
+
8
+from bases.FrameworkServices.SimpleService import SimpleService
9
+
10
+
11
+class ExecutableService(SimpleService):
12
+ def __init__(self, configuration=None, name=None):
13
+ SimpleService.__init__(self, configuration=configuration, name=name)
14
+ self.command = None
15
+
16
+ def _get_raw_data(self, stderr=False):
17
+ """
18
+ Get raw data from executed command
19
+ :return: <list>
20
+ """
21
+ try:
22
+ p = Popen(self.command, stdout=PIPE, stderr=PIPE)
23
+ except Exception as error:
24
+ self.error('Executing command {command} resulted in error: {error}'.format(command=self.command,
25
+ error=error))
26
+ return None
27
+ data = list()
28
+ std = p.stderr if stderr else p.stdout
29
+ for line in std:
30
+ data.append(line.decode())
31
+
32
+ return data or None
33
+
34
+ def check(self):
35
+ """
36
+ Parse basic configuration, check if command is whitelisted and is returning values
37
+ :return: <boolean>
38
+ """
39
+ # Preference: 1. "command" from configuration file 2. "command" from plugin (if specified)
40
+ if 'command' in self.configuration:
41
+ self.command = self.configuration['command']
42
+
43
+ # "command" must be: 1.not None 2. type <str>
44
+ if not (self.command and isinstance(self.command, str)):
45
+ self.error('Command is not defined or command type is not <str>')
46
+ return False
47
+
48
+ # Split "command" into: 1. command <str> 2. options <list>
49
+ command, opts = self.command.split()[0], self.command.split()[1:]
50
+
51
+ # Check for "bad" symbols in options. No pipes, redirects etc.
52
+ opts_list = ['&', '|', ';', '>', '<']
53
+ bad_opts = set(''.join(opts)) & set(opts_list)
54
+ if bad_opts:
55
+ self.error("Bad command argument(s): {opts}".format(opts=bad_opts))
56
+ return False
57
+
58
+ # Find absolute path ('echo' => '/bin/echo')
59
+ if '/' not in command:
60
+ command = self.functions.find_binary(command)
61
+ if not command:
62
+ self.error('Can\'t locate "{command}" binary'.format(command=self.command))
63
+ return False
64
+ # Check if binary exist and executable
65
+ else:
66
+ if not (self.functions.is_file_executable(command)):
67
+ self.error('"{binary}" is not a file or not executable'.format(binary=command))
68
+ return False
69
+
70
+ self.command = [command] + opts if opts else [command]
71
+
72
+ try:
73
+ data = self._get_data()
74
+ except Exception as error:
75
+ self.error('_get_data() failed. Command: {command}. Error: error'.format(command=self.command,
76
+ error=error))
77
+ return False
78
+
79
+ if isinstance(data, dict) and data:
80
+ return True
81
+ self.error('Command "{command}" returned no data'.format(command=self.command))
82
+ return False