9
9
class AmuletUtils(object):
10
"""This class provides common utility functions that are used by Amulet
12
This class provides common utility functions that are used by Amulet
13
16
def __init__(self, log_level=logging.ERROR):
14
17
self.log = self.get_logger(level=log_level)
17
20
"""Get a logger object that will log to stdout."""
19
22
logger = log.getLogger(name)
21
log.Formatter("%(asctime)s %(funcName)s %(levelname)s: %(message)s")
23
fmt = log.Formatter("%(asctime)s %(funcName)s "
24
"%(levelname)s: %(message)s")
23
26
handler = log.StreamHandler(stream=sys.stdout)
24
27
handler.setLevel(level)
38
41
def valid_url(self, url):
40
43
r'^(?:http|ftp)s?://'
41
r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|' # flake8: noqa
44
r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|' # noqa
43
46
r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})'
52
55
def validate_services(self, commands):
53
"""Verify the specified services are running on the corresponding
58
Verify the specified services are running on the corresponding
55
61
for k, v in commands.iteritems():
57
63
output, code = k.run(cmd)
66
72
config.readfp(io.StringIO(file_contents))
69
def validate_config_data(self, sentry_unit, config_file, section, expected):
70
"""Verify that the specified section of the config file contains
71
the expected option key:value pairs."""
75
def validate_config_data(self, sentry_unit, config_file, section,
77
"""Validate config file data.
79
Verify that the specified section of the config file contains
80
the expected option key:value pairs.
72
82
config = self._get_config(sentry_unit, config_file)
74
84
if section != 'DEFAULT' and not config.has_section(section):
78
88
if not config.has_option(section, k):
79
89
return "section [{}] is missing option {}".format(section, k)
80
90
if config.get(section, k) != expected[k]:
81
return "section [{}] {}:{} != expected {}:{}".format(section,
82
k, config.get(section, k), k, expected[k])
91
return "section [{}] {}:{} != expected {}:{}".format(
92
section, k, config.get(section, k), k, expected[k])
85
95
def _validate_dict_data(self, expected, actual):
86
"""Compare expected dictionary data vs actual dictionary data.
96
"""Validate dictionary data.
98
Compare expected dictionary data vs actual dictionary data.
87
99
The values in the 'expected' dictionary can be strings, bools, ints,
88
100
longs, or can be a function that evaluate a variable and returns a
90
103
for k, v in expected.iteritems():
92
if isinstance(v, basestring) or \
93
isinstance(v, bool) or \
94
isinstance(v, (int, long)):
105
if (isinstance(v, basestring) or
106
isinstance(v, bool) or
107
isinstance(v, (int, long))):
95
108
if v != actual[k]:
96
109
return "{}:{}".format(k, actual[k])
97
110
elif not v(actual[k]):
128
141
return sentry_unit.directory_stat(directory)['mtime']
130
143
def _get_proc_start_time(self, sentry_unit, service, pgrep_full=False):
131
"""Determine start time of the process based on the last modification
144
"""Get process' start time.
146
Determine start time of the process based on the last modification
132
147
time of the /proc/pid directory. If pgrep_full is True, the process
133
name is matched against the full command line."""
148
name is matched against the full command line.
135
151
cmd = 'pgrep -o -f {}'.format(service)
139
155
return self._get_dir_mtime(sentry_unit, proc_dir)
141
157
def service_restarted(self, sentry_unit, service, filename,
143
"""Compare a service's start time vs a file's last modification time
158
pgrep_full=False, sleep_time=20):
159
"""Check if service was restarted.
161
Compare a service's start time vs a file's last modification time
144
162
(such as a config file for that service) to determine if the service
145
has been restarted."""
147
if self._get_proc_start_time(sentry_unit, service, pgrep_full) >= \
148
self._get_file_mtime(sentry_unit, filename):
165
time.sleep(sleep_time)
166
if (self._get_proc_start_time(sentry_unit, service, pgrep_full) >=
167
self._get_file_mtime(sentry_unit, filename)):