Merge ~afreiberger/charm-openstack-service-checks/+git/charm-openstack-service-checks:blacken-20.08 into ~llama-charmers/charm-openstack-service-checks:master

Proposed by Drew Freiberger
Status: Merged
Merged at revision: f241e9d107b90302f6c3c80bdd4977e6b5727b5f
Proposed branch: ~afreiberger/charm-openstack-service-checks/+git/charm-openstack-service-checks:blacken-20.08
Merge into: ~llama-charmers/charm-openstack-service-checks:master
Prerequisite: ~afreiberger/charm-openstack-service-checks/+git/charm-openstack-service-checks:makefile-20.10
Diff against target: 4042 lines (+1442/-1008)
16 files modified
src/files/plugins/check_contrail_analytics_alarms.py (+51/-49)
src/files/plugins/check_nova_services.py (+83/-60)
src/files/plugins/check_octavia.py (+141/-91)
src/files/plugins/check_rally.py (+48/-38)
src/files/run_rally.py (+44/-26)
src/lib/lib_openstack_service_checks.py (+350/-250)
src/reactive/openstack_service_checks.py (+130/-109)
src/tests/functional/conftest.py (+51/-39)
src/tests/functional/test_deploy.py (+250/-150)
src/tests/nagios_plugin/setup.py (+22/-22)
src/tests/unit/conftest.py (+33/-23)
src/tests/unit/test_check_contrail_analytics_alarms.py (+44/-21)
src/tests/unit/test_check_nova_services.py (+59/-46)
src/tests/unit/test_check_octavia.py (+46/-29)
src/tests/unit/test_lib.py (+88/-52)
src/tox.ini (+2/-3)
Reviewer Review Type Date Requested Status
Alvaro Uria (community) Approve
Review via email: mp+392246@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Alvaro Uria (aluria) wrote :

lgtm

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/src/files/plugins/check_contrail_analytics_alarms.py b/src/files/plugins/check_contrail_analytics_alarms.py
2index 0b4d3be..aa12a3e 100755
3--- a/src/files/plugins/check_contrail_analytics_alarms.py
4+++ b/src/files/plugins/check_contrail_analytics_alarms.py
5@@ -12,8 +12,8 @@ import subprocess
6
7 import nagios_plugin3
8
9-DEFAULT_IGNORED = r''
10-Alarm = collections.namedtuple('Alarm', 'ts, desc')
11+DEFAULT_IGNORED = r""
12+Alarm = collections.namedtuple("Alarm", "ts, desc")
13
14
15 def parse_contrail_alarms(data, ignored=DEFAULT_IGNORED):
16@@ -37,37 +37,31 @@ def parse_contrail_alarms(data, ignored=DEFAULT_IGNORED):
17 for alarm in item["value"]["UVEAlarms"]["alarms"]:
18 ack = alarm["ack"]
19 alarm_info = {
20- 'hostname': hostname,
21- 'nagios_status': 'WARNING',
22- 'desc': alarm["description"],
23- 'sev': alarm["severity"],
24- 'ts': datetime.datetime.utcfromtimestamp(alarm["timestamp"] / 1e6),
25- 'type': alarm["type"],
26+ "hostname": hostname,
27+ "nagios_status": "WARNING",
28+ "desc": alarm["description"],
29+ "sev": alarm["severity"],
30+ "ts": datetime.datetime.utcfromtimestamp(alarm["timestamp"] / 1e6),
31+ "type": alarm["type"],
32 }
33 if not ack:
34- alarm_info["nagios_status"] = 'CRITICAL'
35+ alarm_info["nagios_status"] = "CRITICAL"
36
37 alarm_event = (
38- '{nagios_status}: {node_type}{{{hostname}, sev={sev}, '
39- 'ts[{ts}]}} {desc}'.format(node_type=node_type, **alarm_info)
40+ "{nagios_status}: {node_type}{{{hostname}, sev={sev}, "
41+ "ts[{ts}]}} {desc}".format(node_type=node_type, **alarm_info)
42 )
43 msgs[alarm["timestamp"]].append(alarm_event)
44
45 # msgs is a dict keyed on integer timestamp
46 # whose values are lists of strings representing the alerts
47 search_re = re.compile(ignored)
48- full = [
49- Alarm(ts, alert)
50- for ts, alerts in msgs.items()
51- for alert in alerts
52- ]
53- ignoring = list(
54- filter(lambda m: search_re.search(m.desc), full)
55- ) if ignored else []
56+ full = [Alarm(ts, alert) for ts, alerts in msgs.items() for alert in alerts]
57+ ignoring = list(filter(lambda m: search_re.search(m.desc), full)) if ignored else []
58 important = set(full) - set(ignoring)
59
60- total_crit_count = len([a for a in full if a.desc.startswith('CRITICAL')])
61- important_crit = len([a for a in important if a.desc.startswith('CRITICAL')])
62+ total_crit_count = len([a for a in full if a.desc.startswith("CRITICAL")])
63+ important_crit = len([a for a in important if a.desc.startswith("CRITICAL")])
64 important_count = len(important)
65 if important_crit > 0:
66 msg = "CRITICAL: "
67@@ -77,10 +71,9 @@ def parse_contrail_alarms(data, ignored=DEFAULT_IGNORED):
68 msg = "OK: "
69 msg += (
70 "total_alarms[{}], unacked_or_sev_gt_0[{}], total_ignored[{}], "
71- "ignoring r'{}'\n"
72- .format(len(full), total_crit_count, len(ignoring), ignored)
73+ "ignoring r'{}'\n".format(len(full), total_crit_count, len(ignoring), ignored)
74 )
75- msg += '\n'.join(_.desc for _ in sorted(important))
76+ msg += "\n".join(_.desc for _ in sorted(important))
77 return msg
78
79
80@@ -93,35 +86,37 @@ def check_contrail_alarms(contrail_vip, token, **kwargs):
81
82 :returns: None
83 """
84- url = 'http://{}:8081/analytics/alarms'.format(contrail_vip)
85- headers = {'X-Auth-Token': token}
86+ url = "http://{}:8081/analytics/alarms".format(contrail_vip)
87+ headers = {"X-Auth-Token": token}
88 try:
89 r = requests.get(url=url, headers=headers)
90 except requests.exceptions.ConnectionError as error:
91 raise nagios_plugin3.CriticalError(
92- 'CRITICAL: contrail analytics API error: {}'.format(error))
93+ "CRITICAL: contrail analytics API error: {}".format(error)
94+ )
95
96 if r.status_code != 200:
97 raise nagios_plugin3.CriticalError(
98- 'CRITICAL: contrail analytics API return code is {}'.format(r.status_code))
99+ "CRITICAL: contrail analytics API return code is {}".format(r.status_code)
100+ )
101
102 result = r.json()
103 msg = parse_contrail_alarms(result, **kwargs)
104
105- if msg.startswith('CRITICAL: '):
106+ if msg.startswith("CRITICAL: "):
107 raise nagios_plugin3.CriticalError(msg)
108- elif msg.startswith('WARNING: '):
109+ elif msg.startswith("WARNING: "):
110 raise nagios_plugin3.WarnError(msg)
111 print(msg)
112
113
114 def load_os_envvars(args):
115 # grab environment vars
116- command = ['/bin/bash', '-c', "source {} && env".format(args.env)]
117+ command = ["/bin/bash", "-c", "source {} && env".format(args.env)]
118 proc = subprocess.Popen(command, stdout=subprocess.PIPE)
119 for line in proc.stdout:
120- (key, _, value) = line.partition(b'=')
121- os.environ[key.decode('utf-8')] = value.rstrip().decode('utf-8')
122+ (key, _, value) = line.partition(b"=")
123+ os.environ[key.decode("utf-8")] = value.rstrip().decode("utf-8")
124 proc.communicate()
125
126
127@@ -130,19 +125,28 @@ def validate_ipv4(ipv4_addr):
128 ipaddress.IPv4Address(ipv4_addr)
129 except ipaddress.AddressValueError:
130 raise nagios_plugin3.UnknownError(
131- 'UNKNOWN: invalid contrail IPv4 address {}'.format(ipv4_addr))
132+ "UNKNOWN: invalid contrail IPv4 address {}".format(ipv4_addr)
133+ )
134
135
136 def main():
137- parser = argparse.ArgumentParser(description='Check Contrail alarms')
138- parser.add_argument('--env', dest='env',
139- default='/var/lib/nagios/nagios.novarc',
140- help='Novarc file to use for this check')
141- parser.add_argument('--host', '-H', dest='host', nargs=1,
142- help='Contrail Analytics Virtual IP')
143- parser.add_argument('--ignored', dest="ignored", type=str,
144- default=DEFAULT_IGNORED,
145- help='Comma separated list of alerts to ignore')
146+ parser = argparse.ArgumentParser(description="Check Contrail alarms")
147+ parser.add_argument(
148+ "--env",
149+ dest="env",
150+ default="/var/lib/nagios/nagios.novarc",
151+ help="Novarc file to use for this check",
152+ )
153+ parser.add_argument(
154+ "--host", "-H", dest="host", nargs=1, help="Contrail Analytics Virtual IP"
155+ )
156+ parser.add_argument(
157+ "--ignored",
158+ dest="ignored",
159+ type=str,
160+ default=DEFAULT_IGNORED,
161+ help="Comma separated list of alerts to ignore",
162+ )
163 args = parser.parse_args()
164
165 # Validate Contrail Analytics IP
166@@ -153,19 +157,17 @@ def main():
167
168 # parse ignored list
169 unique = sorted(set(args.ignored.split(",")))
170- ignored_re = r'|'.join('(?:{})'.format(_) for _ in unique)
171+ ignored_re = r"|".join("(?:{})".format(_) for _ in unique)
172
173 # Retrieve token from Keystone
174 load_os_envvars(args)
175- keystone_client = os_client_config.session_client('identity', cloud='envvars')
176+ keystone_client = os_client_config.session_client("identity", cloud="envvars")
177 token = keystone_client.get_token()
178
179 nagios_plugin3.try_check(
180- check_contrail_alarms,
181- contrail_analytics_vip, token,
182- ignored=ignored_re
183+ check_contrail_alarms, contrail_analytics_vip, token, ignored=ignored_re
184 )
185
186
187-if __name__ == '__main__':
188+if __name__ == "__main__":
189 main()
190diff --git a/src/files/plugins/check_nova_services.py b/src/files/plugins/check_nova_services.py
191index 4ee6420..5da5955 100755
192--- a/src/files/plugins/check_nova_services.py
193+++ b/src/files/plugins/check_nova_services.py
194@@ -15,107 +15,130 @@ def check_hosts_up(args, aggregate, hosts, services_compute):
195 # out: dict, msg_text, status
196 status_crit = False
197 status_warn = False
198- counts = {'down': 0, 'disabled': 0, 'ok': 0}
199+ counts = {"down": 0, "disabled": 0, "ok": 0}
200 local_msg = []
201 for host in hosts:
202- host_svc = next(svc for svc in services_compute if svc['host'] == host)
203- if host_svc['status'] == 'enabled':
204- if host_svc['state'] == 'up':
205+ host_svc = next(svc for svc in services_compute if svc["host"] == host)
206+ if host_svc["status"] == "enabled":
207+ if host_svc["state"] == "up":
208 # enabled and up, increment the counter
209- counts['ok'] += 1
210+ counts["ok"] += 1
211 else:
212 # enabled and down
213- counts['down'] += 1
214- local_msg.append('{} down'.format(host))
215+ counts["down"] += 1
216+ local_msg.append("{} down".format(host))
217 else:
218- counts['disabled'] += 1
219- local_msg.append('Host {} disabled'.format(host))
220+ counts["disabled"] += 1
221+ local_msg.append("Host {} disabled".format(host))
222 # check the counts
223- if counts['down'] > 0:
224+ if counts["down"] > 0:
225 status_crit = True
226- if counts['disabled'] > 0 and not args.skip_disabled:
227+ if counts["disabled"] > 0 and not args.skip_disabled:
228 status_warn = True
229- if counts['ok'] <= args.warn:
230+ if counts["ok"] <= args.warn:
231 status_warn = True
232- if counts['ok'] <= args.crit:
233+ if counts["ok"] <= args.crit:
234 status_crit = True
235- local_msg.append('Host Aggregate {} has {} hosts alive'.format(
236- aggregate, counts['ok']))
237+ local_msg.append(
238+ "Host Aggregate {} has {} hosts alive".format(aggregate, counts["ok"])
239+ )
240 nova_status = {
241- 'agg_name': aggregate,
242- 'msg_text': ', '.join(local_msg),
243- 'critical': status_crit,
244- 'warning': status_warn,
245+ "agg_name": aggregate,
246+ "msg_text": ", ".join(local_msg),
247+ "critical": status_crit,
248+ "warning": status_warn,
249 }
250 return nova_status
251
252
253 def check_nova_services(args, nova):
254- aggregates = nova.get('/os-aggregates').json()['aggregates']
255- services = nova.get('/os-services').json()['services']
256- services_compute = [x for x in services if x['binary'] == 'nova-compute']
257- msg = ['nova-compute']
258+ aggregates = nova.get("/os-aggregates").json()["aggregates"]
259+ services = nova.get("/os-services").json()["services"]
260+ services_compute = [x for x in services if x["binary"] == "nova-compute"]
261+ msg = ["nova-compute"]
262 status = []
263 hosts_checked = []
264 for agg in aggregates:
265 # skip the defined host aggregates to be skipped from the config
266 # making it case-insensitive
267- skipped_aggregates = [name.lower() for name in args.skip_aggregates.split(',')]
268- aggregate_name = agg['name'].lower()
269+ skipped_aggregates = [name.lower() for name in args.skip_aggregates.split(",")]
270+ aggregate_name = agg["name"].lower()
271 if aggregate_name in skipped_aggregates:
272 continue
273 # get a list of hosts, pass to the function
274- hosts = agg['hosts']
275+ hosts = agg["hosts"]
276 hosts_checked.append(hosts)
277- status.append(check_hosts_up(args, agg['name'], hosts,
278- services_compute))
279+ status.append(check_hosts_up(args, agg["name"], hosts, services_compute))
280 # find hosts that haven't been checked already
281 hosts_checked = [item for sublist in hosts_checked for item in sublist]
282- hosts_not_checked = [x['host'] for x in services_compute
283- if x['host'] not in hosts_checked]
284+ hosts_not_checked = [
285+ x["host"] for x in services_compute if x["host"] not in hosts_checked
286+ ]
287 if len(hosts_not_checked) > 0:
288- status.append(check_hosts_up(args, '(not-part-of-any-agg)', hosts_not_checked,
289- services_compute))
290- status_crit = len([agg['critical'] for agg in status
291- if agg['critical']])
292- status_warn = len([agg['warning'] for agg in status
293- if agg['warning']])
294- msg.extend([x['msg_text'] for x in status if x['msg_text'] != ''])
295+ status.append(
296+ check_hosts_up(
297+ args, "(not-part-of-any-agg)", hosts_not_checked, services_compute
298+ )
299+ )
300+ status_crit = len([agg["critical"] for agg in status if agg["critical"]])
301+ status_warn = len([agg["warning"] for agg in status if agg["warning"]])
302+ msg.extend([x["msg_text"] for x in status if x["msg_text"] != ""])
303 if status_crit:
304- output = 'CRITICAL: {}'.format(', '.join(msg))
305+ output = "CRITICAL: {}".format(", ".join(msg))
306 raise nagios_plugin3.CriticalError(output)
307 if status_warn:
308- output = 'WARNING: {}'.format(', '.join(msg))
309+ output = "WARNING: {}".format(", ".join(msg))
310 raise nagios_plugin3.WarnError(output)
311- print('OK: Nova-compute services happy')
312+ print("OK: Nova-compute services happy")
313
314
315-if __name__ == '__main__':
316- parser = argparse.ArgumentParser(description='Check Nova-compute status')
317- parser.add_argument('--warn', dest='warn', type=int, default=2,
318- help='Warn at this many hosts running')
319- parser.add_argument('--crit', dest='crit', type=int, default=1,
320- help='Critical at this many hosts running or less')
321- parser.add_argument('--skip-aggregates', dest='skip_aggregates', type=str,
322- default='', nargs='?',
323- help='Comma separated list of types of aggregates to skip.')
324- parser.add_argument('--env', dest='env',
325- default='/var/lib/nagios/nagios.novarc',
326- help='Novarc file to use for this check')
327- parser.add_argument('--skip-disabled', dest='skip_disabled',
328- help='Pass this flag not to alert on any disabled nova-compute services',
329- action='store_true')
330+if __name__ == "__main__":
331+ parser = argparse.ArgumentParser(description="Check Nova-compute status")
332+ parser.add_argument(
333+ "--warn",
334+ dest="warn",
335+ type=int,
336+ default=2,
337+ help="Warn at this many hosts running",
338+ )
339+ parser.add_argument(
340+ "--crit",
341+ dest="crit",
342+ type=int,
343+ default=1,
344+ help="Critical at this many hosts running or less",
345+ )
346+ parser.add_argument(
347+ "--skip-aggregates",
348+ dest="skip_aggregates",
349+ type=str,
350+ default="",
351+ nargs="?",
352+ help="Comma separated list of types of aggregates to skip.",
353+ )
354+ parser.add_argument(
355+ "--env",
356+ dest="env",
357+ default="/var/lib/nagios/nagios.novarc",
358+ help="Novarc file to use for this check",
359+ )
360+ parser.add_argument(
361+ "--skip-disabled",
362+ dest="skip_disabled",
363+ help="Pass this flag not to alert on any disabled nova-compute services",
364+ action="store_true",
365+ )
366 args = parser.parse_args()
367 # No arg was passed to --skip-aggregates (juju config is empty)
368 if args.skip_aggregates is None:
369- args.skip_aggregates = ''
370+ args.skip_aggregates = ""
371
372 # grab environment vars
373- command = ['/bin/bash', '-c', 'source {} && env'.format(args.env)]
374+ command = ["/bin/bash", "-c", "source {} && env".format(args.env)]
375 proc = subprocess.Popen(command, stdout=subprocess.PIPE)
376 for line in proc.stdout:
377- (key, _, value) = line.partition(b'=')
378- os.environ[key.decode('utf-8')] = value.rstrip().decode('utf-8')
379+ (key, _, value) = line.partition(b"=")
380+ os.environ[key.decode("utf-8")] = value.rstrip().decode("utf-8")
381 proc.communicate()
382- nova = os_client_config.session_client('compute', cloud='envvars')
383+ nova = os_client_config.session_client("compute", cloud="envvars")
384 nagios_plugin3.try_check(check_nova_services, args, nova)
385diff --git a/src/files/plugins/check_octavia.py b/src/files/plugins/check_octavia.py
386index bb6debc..c7e4d02 100755
387--- a/src/files/plugins/check_octavia.py
388+++ b/src/files/plugins/check_octavia.py
389@@ -12,18 +12,18 @@ import sys
390 import openstack
391
392
393-Alarm = collections.namedtuple('Alarm', 'lvl, desc')
394-DEFAULT_IGNORED = r''
395+Alarm = collections.namedtuple("Alarm", "lvl, desc")
396+DEFAULT_IGNORED = r""
397 NAGIOS_STATUS_OK = 0
398 NAGIOS_STATUS_WARNING = 1
399 NAGIOS_STATUS_CRITICAL = 2
400 NAGIOS_STATUS_UNKNOWN = 3
401
402 NAGIOS_STATUS = {
403- NAGIOS_STATUS_OK: 'OK',
404- NAGIOS_STATUS_WARNING: 'WARNING',
405- NAGIOS_STATUS_CRITICAL: 'CRITICAL',
406- NAGIOS_STATUS_UNKNOWN: 'UNKNOWN',
407+ NAGIOS_STATUS_OK: "OK",
408+ NAGIOS_STATUS_WARNING: "WARNING",
409+ NAGIOS_STATUS_CRITICAL: "CRITICAL",
410+ NAGIOS_STATUS_UNKNOWN: "UNKNOWN",
411 }
412
413
414@@ -52,22 +52,21 @@ def filter_checks(alarms, ignored=DEFAULT_IGNORED):
415 status = NAGIOS_STATUS_OK
416 msg = (
417 "total_alarms[{}], total_crit[{}], total_ignored[{}], "
418- "ignoring r'{}'\n"
419- .format(len(full), total_crit, len(ignoring), ignored)
420+ "ignoring r'{}'\n".format(len(full), total_crit, len(ignoring), ignored)
421 )
422- msg += '\n'.join(_.desc for _ in sorted(important))
423+ msg += "\n".join(_.desc for _ in sorted(important))
424 return status, msg
425
426
427 def nagios_exit(args, results):
428 # parse ignored list
429 unique = sorted(filter(None, set(args.ignored.split(","))))
430- ignored_re = r'|'.join('(?:{})'.format(_) for _ in unique)
431+ ignored_re = r"|".join("(?:{})".format(_) for _ in unique)
432
433 status, message = filter_checks(results, ignored=ignored_re)
434 assert status in NAGIOS_STATUS, "Invalid Nagios status code"
435 # prefix status name to message
436- output = '{}: {}'.format(NAGIOS_STATUS[status], message)
437+ output = "{}: {}".format(NAGIOS_STATUS[status], message)
438 return status, output
439
440
441@@ -81,18 +80,26 @@ def check_loadbalancers(connection):
442 lb_enabled = [lb for lb in lb_all if lb.is_admin_state_up]
443
444 # check provisioning_status is ACTIVE for each lb
445- bad_lbs = [(
446- NAGIOS_STATUS_CRITICAL,
447- 'loadbalancer {} provisioning_status is {}'.format(
448- lb.id, lb.provisioning_status)
449- ) for lb in lb_enabled if lb.provisioning_status != 'ACTIVE']
450+ bad_lbs = [
451+ (
452+ NAGIOS_STATUS_CRITICAL,
453+ "loadbalancer {} provisioning_status is {}".format(
454+ lb.id, lb.provisioning_status
455+ ),
456+ )
457+ for lb in lb_enabled
458+ if lb.provisioning_status != "ACTIVE"
459+ ]
460
461 # raise WARNING if operating_status is not ONLINE
462- bad_lbs += [(
463- NAGIOS_STATUS_CRITICAL,
464- 'loadbalancer {} operating_status is {}'.format(
465- lb.id, lb.operating_status)
466- ) for lb in lb_enabled if lb.operating_status != 'ONLINE']
467+ bad_lbs += [
468+ (
469+ NAGIOS_STATUS_CRITICAL,
470+ "loadbalancer {} operating_status is {}".format(lb.id, lb.operating_status),
471+ )
472+ for lb in lb_enabled
473+ if lb.operating_status != "ONLINE"
474+ ]
475
476 # check vip port exists for each lb
477 net_mgr = connection.network
478@@ -102,17 +109,20 @@ def check_loadbalancers(connection):
479 net_mgr.get_port(lb.vip_port_id)
480 except openstack.exceptions.NotFoundException:
481 vip_lbs.append(lb)
482- bad_lbs += [(
483- NAGIOS_STATUS_CRITICAL,
484- 'vip port {} for loadbalancer {} not found'.format(
485- lb.vip_port_id, lb.id)
486- ) for lb in vip_lbs]
487+ bad_lbs += [
488+ (
489+ NAGIOS_STATUS_CRITICAL,
490+ "vip port {} for loadbalancer {} not found".format(lb.vip_port_id, lb.id),
491+ )
492+ for lb in vip_lbs
493+ ]
494
495 # warn about disabled lbs if no other error found
496- bad_lbs += [(
497- NAGIOS_STATUS_WARNING,
498- 'loadbalancer {} admin_state_up is False'.format(lb.id)
499- ) for lb in lb_all if not lb.is_admin_state_up]
500+ bad_lbs += [
501+ (NAGIOS_STATUS_WARNING, "loadbalancer {} admin_state_up is False".format(lb.id))
502+ for lb in lb_all
503+ if not lb.is_admin_state_up
504+ ]
505
506 return bad_lbs
507
508@@ -126,25 +136,36 @@ def check_pools(connection):
509 pools_enabled = [pool for pool in pools_all if pool.is_admin_state_up]
510
511 # check provisioning_status is ACTIVE for each pool
512- bad_pools = [(
513- NAGIOS_STATUS_CRITICAL,
514- 'pool {} provisioning_status is {}'.format(
515- pool.id, pool.provisioning_status)
516- ) for pool in pools_enabled if pool.provisioning_status != 'ACTIVE']
517+ bad_pools = [
518+ (
519+ NAGIOS_STATUS_CRITICAL,
520+ "pool {} provisioning_status is {}".format(
521+ pool.id, pool.provisioning_status
522+ ),
523+ )
524+ for pool in pools_enabled
525+ if pool.provisioning_status != "ACTIVE"
526+ ]
527
528 # raise CRITICAL if operating_status is ERROR
529- bad_pools += [(
530- NAGIOS_STATUS_CRITICAL,
531- 'pool {} operating_status is {}'.format(
532- pool.id, pool.operating_status)
533- ) for pool in pools_enabled if pool.operating_status == 'ERROR']
534+ bad_pools += [
535+ (
536+ NAGIOS_STATUS_CRITICAL,
537+ "pool {} operating_status is {}".format(pool.id, pool.operating_status),
538+ )
539+ for pool in pools_enabled
540+ if pool.operating_status == "ERROR"
541+ ]
542
543 # raise WARNING if operating_status is NO_MONITOR
544- bad_pools += [(
545- NAGIOS_STATUS_WARNING,
546- 'pool {} operating_status is {}'.format(
547- pool.id, pool.operating_status)
548- ) for pool in pools_enabled if pool.operating_status == 'NO_MONITOR']
549+ bad_pools += [
550+ (
551+ NAGIOS_STATUS_WARNING,
552+ "pool {} operating_status is {}".format(pool.id, pool.operating_status),
553+ )
554+ for pool in pools_enabled
555+ if pool.operating_status == "NO_MONITOR"
556+ ]
557
558 return bad_pools
559
560@@ -154,29 +175,36 @@ def check_amphorae(connection):
561
562 lb_mgr = connection.load_balancer
563
564- resp = lb_mgr.get('/v2/octavia/amphorae')
565+ resp = lb_mgr.get("/v2/octavia/amphorae")
566 # python api is not available yet, use url
567 if resp.status_code != 200:
568- return [(NAGIOS_STATUS_WARNING, 'amphorae api not working')]
569+ return [(NAGIOS_STATUS_WARNING, "amphorae api not working")]
570
571 data = json.loads(resp.content)
572 # ouput is like {"amphorae": [{...}, {...}, ...]}
573- items = data.get('amphorae', [])
574+ items = data.get("amphorae", [])
575
576 # raise CRITICAL for ERROR status
577- bad_status_list = ('ERROR',)
578- bad_amp = [(
579- NAGIOS_STATUS_CRITICAL,
580- 'amphora {} status is {}'.format(item['id'], item['status'])
581- ) for item in items if item['status'] in bad_status_list]
582+ bad_status_list = ["ERROR"]
583+ bad_amp = [
584+ (
585+ NAGIOS_STATUS_CRITICAL,
586+ "amphora {} status is {}".format(item["id"], item["status"]),
587+ )
588+ for item in items
589+ if item["status"] in bad_status_list
590+ ]
591
592 # raise WARNING for these status
593- bad_status_list = (
594- 'PENDING_CREATE', 'PENDING_UPDATE', 'PENDING_DELETE', 'BOOTING')
595- bad_amp += [(
596- NAGIOS_STATUS_WARNING,
597- 'amphora {} status is {}'.format(item['id'], item['status'])
598- ) for item in items if item['status'] in bad_status_list]
599+ bad_status_list = ("PENDING_CREATE", "PENDING_UPDATE", "PENDING_DELETE", "BOOTING")
600+ bad_amp += [
601+ (
602+ NAGIOS_STATUS_WARNING,
603+ "amphora {} status is {}".format(item["id"], item["status"]),
604+ )
605+ for item in items
606+ if item["status"] in bad_status_list
607+ ]
608
609 return bad_amp
610
611@@ -186,15 +214,18 @@ def check_image(connection, tag, days):
612 images = list(img_mgr.images(tag=tag))
613
614 if not images:
615- message = ('Octavia requires image with tag {} to create amphora, '
616- 'but none exist').format(tag)
617+ message = (
618+ "Octavia requires image with tag {} to create amphora, but none exist"
619+ ).format(tag)
620 return [(NAGIOS_STATUS_CRITICAL, message)]
621
622- active_images = [image for image in images if image.status == 'active']
623+ active_images = [image for image in images if image.status == "active"]
624 if not active_images:
625- details = ['{}({})'.format(image.name, image.id) for image in images]
626- message = ('Octavia requires image with tag {} to create amphora, '
627- 'but none are active: {}').format(tag, ', '.join(details))
628+ details = ["{}({})".format(image.name, image.id) for image in images]
629+ message = (
630+ "Octavia requires image with tag {} to create amphora, "
631+ "but none are active: {}"
632+ ).format(tag, ", ".join(details))
633 return [(NAGIOS_STATUS_CRITICAL, message)]
634
635 # raise WARNING if image is too old
636@@ -202,10 +233,12 @@ def check_image(connection, tag, days):
637 # updated_at str format: '2019-12-05T18:21:25Z'
638 fresh_images = [image for image in active_images if image.updated_at > when]
639 if not fresh_images:
640- details = ['{}({})'.format(image.name, image.id) for image in images]
641- message = ('Octavia requires image with tag {} to create amphora, '
642- 'but all images are older than {} day(s): {}'
643- '').format(tag, days, ', '.join(details))
644+ details = ["{}({})".format(image.name, image.id) for image in images]
645+ message = (
646+ "Octavia requires image with tag {} to create amphora, "
647+ "but all images are older than {} day(s): {}"
648+ ""
649+ ).format(tag, days, ", ".join(details))
650 return [(NAGIOS_STATUS_WARNING, message)]
651
652 return []
653@@ -218,52 +251,69 @@ def process_checks(args):
654 return check_image(_connection, args.amp_image_tag, args.amp_image_days)
655
656 checks = {
657- 'loadbalancers': check_loadbalancers,
658- 'amphorae': check_amphorae,
659- 'pools': check_pools,
660- 'image': _check_image,
661+ "loadbalancers": check_loadbalancers,
662+ "amphorae": check_amphorae,
663+ "pools": check_pools,
664+ "image": _check_image,
665 }
666
667- connection = openstack.connect(cloud='envvars')
668+ connection = openstack.connect(cloud="envvars")
669 return nagios_exit(args, checks[args.check](connection))
670
671
672 def main():
673 parser = argparse.ArgumentParser(
674- description='Check Octavia status',
675+ description="Check Octavia status",
676 formatter_class=argparse.ArgumentDefaultsHelpFormatter,
677 )
678 parser.add_argument(
679- '--env', dest='env', default='/var/lib/nagios/nagios.novarc',
680- help='Novarc file to use for this check')
681+ "--env",
682+ dest="env",
683+ default="/var/lib/nagios/nagios.novarc",
684+ help="Novarc file to use for this check",
685+ )
686
687- check_choices = ['loadbalancers', 'amphorae', 'pools', 'image']
688+ check_choices = ["loadbalancers", "amphorae", "pools", "image"]
689 parser.add_argument(
690- '--check', dest='check', metavar='|'.join(check_choices),
691- type=str, choices=check_choices,
692+ "--check",
693+ dest="check",
694+ metavar="|".join(check_choices),
695+ type=str,
696+ choices=check_choices,
697 default=check_choices[0],
698- help='which check to run')
699+ help="which check to run",
700+ )
701
702 parser.add_argument(
703- '--ignored', dest="ignored", type=str,
704+ "--ignored",
705+ dest="ignored",
706+ type=str,
707 default=DEFAULT_IGNORED,
708- help='Comma separated list of alerts to ignore')
709+ help="Comma separated list of alerts to ignore",
710+ )
711
712 parser.add_argument(
713- '--amp-image-tag', dest='amp_image_tag', default='octavia-amphora',
714- help='amphora image tag for image check')
715+ "--amp-image-tag",
716+ dest="amp_image_tag",
717+ default="octavia-amphora",
718+ help="amphora image tag for image check",
719+ )
720
721 parser.add_argument(
722- '--amp-image-days', dest='amp_image_days', type=int, default=365,
723- help='raise warning if amphora image is older than these days')
724+ "--amp-image-days",
725+ dest="amp_image_days",
726+ type=int,
727+ default=365,
728+ help="raise warning if amphora image is older than these days",
729+ )
730
731 args = parser.parse_args()
732 # source environment vars
733- command = ['/bin/bash', '-c', 'source {} && env'.format(args.env)]
734+ command = ["/bin/bash", "-c", "source {} && env".format(args.env)]
735 proc = subprocess.Popen(command, stdout=subprocess.PIPE)
736 for line in proc.stdout:
737- (key, _, value) = line.partition(b'=')
738- os.environ[key.decode('utf-8')] = value.rstrip().decode('utf-8')
739+ (key, _, value) = line.partition(b"=")
740+ os.environ[key.decode("utf-8")] = value.rstrip().decode("utf-8")
741 proc.communicate()
742
743 status, message = process_checks(args)
744@@ -271,5 +321,5 @@ def main():
745 sys.exit(status)
746
747
748-if __name__ == '__main__':
749+if __name__ == "__main__":
750 main()
751diff --git a/src/files/plugins/check_rally.py b/src/files/plugins/check_rally.py
752index 62f1a7e..fac835b 100755
753--- a/src/files/plugins/check_rally.py
754+++ b/src/files/plugins/check_rally.py
755@@ -7,49 +7,54 @@ import sys
756 import json
757
758 # ie. {0} tempest.test.test1 ... success
759-TEMPEST_TEST_RE = r'{\d+} [.\w]+ ... (\w+)'
760-INPUT_FILE = '/home/nagiososc/rally.status'
761+TEMPEST_TEST_RE = r"{\d+} [.\w]+ ... (\w+)"
762+INPUT_FILE = "/home/nagiososc/rally.status"
763
764
765 def print_results(results):
766- status_message = collections.defaultdict(lambda: 'UNKNOWN') # 3
767- status_message.update({
768- 'success': 'OK', # 0
769- 'fail': 'CRITICAL', # 2
770- 'skip': 'WARNING', # 1
771- })
772- return_codes = {msg: code
773- for code, msg in enumerate(['OK', 'WARNING', 'CRITICAL', 'UNKNOWN'])}
774- rc = return_codes['OK']
775+ status_message = collections.defaultdict(lambda: "UNKNOWN") # 3
776+ status_message.update(
777+ {
778+ "success": "OK", # 0
779+ "fail": "CRITICAL", # 2
780+ "skip": "WARNING", # 1
781+ }
782+ )
783+ return_codes = {
784+ msg: code for code, msg in enumerate(["OK", "WARNING", "CRITICAL", "UNKNOWN"])
785+ }
786+ rc = return_codes["OK"]
787 summary = collections.defaultdict(lambda: 0)
788
789 output = []
790- for result in sorted(results, key=lambda result: result['message']):
791- if result.get('message', '').startswith('CRITICAL: '):
792+ for result in sorted(results, key=lambda result: result["message"]):
793+ if result.get("message", "").startswith("CRITICAL: "):
794 # Exception caused by run_rally.py, without running 'rally verify'
795- output.append(result['message'])
796- if 'verify' in result['message']:
797- summary['fail'] += 1
798+ output.append(result["message"])
799+ if "verify" in result["message"]:
800+ summary["fail"] += 1
801
802 continue
803- elif result.get('message', '').startswith('{'):
804+ elif result.get("message", "").startswith("{"):
805 # only parse json lines - rest, ignore
806- test_re = re.match(TEMPEST_TEST_RE, result.get('message', ''))
807+ test_re = re.match(TEMPEST_TEST_RE, result.get("message", ""))
808 if not test_re:
809 continue
810
811 test_status = test_re.groups()[0]
812- output.append('{}: {}'.format(status_message[test_status],
813- result['message']))
814+ output.append(
815+ "{}: {}".format(status_message[test_status], result["message"])
816+ )
817 summary[test_status] += 1
818
819 # make the first line carry the worst event out of all the parsed ones
820 # ie. all ok except one critical event will return the first line (and return code)
821 # as critical
822- nagios_status = 'OK'
823- for status_msg in ['CRITICAL', 'WARNING', 'UNKNOWN', 'OK']:
824- status = [msg for msg in status_message.keys()
825- if status_message[msg] == status_msg]
826+ nagios_status = "OK"
827+ for status_msg in ["CRITICAL", "WARNING", "UNKNOWN", "OK"]:
828+ status = [
829+ msg for msg in status_message.keys() if status_message[msg] == status_msg
830+ ]
831 if not status or status[0] not in summary:
832 continue
833
834@@ -60,43 +65,48 @@ def print_results(results):
835 break
836
837 if len(summary) > 0:
838- print('{}: '.format(nagios_status)
839- + ', '.join(['{}[{}]'.format(status_msg, summary[status_msg])
840- for status_msg in sorted(summary,
841- key=lambda status: summary[status],
842- reverse=True)
843- ]))
844- print('\n'.join(output))
845+ print(
846+ "{}: ".format(nagios_status)
847+ + ", ".join(
848+ [
849+ "{}[{}]".format(status_msg, summary[status_msg])
850+ for status_msg in sorted(
851+ summary, key=lambda status: summary[status], reverse=True
852+ )
853+ ]
854+ )
855+ )
856+ print("\n".join(output))
857 return rc
858
859
860 def main(results_filename):
861 if not os.path.exists(results_filename):
862- print('UNKNOWN: {} does not exist'.format(results_filename))
863+ print("UNKNOWN: {} does not exist".format(results_filename))
864 return 3
865
866 results = []
867- with open(results_filename, 'r') as fd:
868+ with open(results_filename, "r") as fd:
869 for line in fd.readlines():
870 line = line.strip()
871 if not line:
872 continue
873- elif len(line) > 5 and line[-5:] == '\x1b[00m':
874+ elif len(line) > 5 and line[-5:] == "\x1b[00m":
875 line = line[:-5]
876
877- if not line.startswith('{'):
878- results.append({'message': line})
879+ if not line.startswith("{"):
880+ results.append({"message": line})
881 continue
882
883 try:
884 results.append(json.loads(line))
885 except json.decoder.JSONDecodeError as error:
886- print('UNKNOWN: line[{}], error[{}]'.format(line, str(error)))
887+ print("UNKNOWN: line[{}], error[{}]".format(line, str(error)))
888 return 3
889
890 rc = print_results(results)
891 return rc
892
893
894-if __name__ == '__main__':
895+if __name__ == "__main__":
896 sys.exit(main(INPUT_FILE))
897diff --git a/src/files/run_rally.py b/src/files/run_rally.py
898index c0e5655..3f0802e 100755
899--- a/src/files/run_rally.py
900+++ b/src/files/run_rally.py
901@@ -8,8 +8,8 @@ import sys
902 import shutil
903 import tempfile
904
905-OUTPUT_FILE = '/home/nagiososc/rally.status'
906-HISTORY_FOLDER = '/home/nagiososc/rallystatuses'
907+OUTPUT_FILE = "/home/nagiososc/rally.status"
908+HISTORY_FOLDER = "/home/nagiososc/rallystatuses"
909
910
911 def get_backup_output_filename():
912@@ -18,65 +18,83 @@ def get_backup_output_filename():
913
914 weekday = datetime.datetime.today().weekday()
915 i = 0
916- statusfile = os.path.join(HISTORY_FOLDER, 'rally.status.{}.{}'.format(weekday, i))
917+ statusfile = os.path.join(HISTORY_FOLDER, "rally.status.{}.{}".format(weekday, i))
918 while os.path.exists(statusfile):
919 i += 1
920- statusfile = os.path.join(HISTORY_FOLDER, 'rally.status.{}.{}'.format(weekday, i))
921+ statusfile = os.path.join(
922+ HISTORY_FOLDER, "rally.status.{}.{}".format(weekday, i)
923+ )
924
925 return statusfile
926
927
928-def _load_envvars(novarc='/var/lib/nagios/nagios.novarc'):
929+def _load_envvars(novarc="/var/lib/nagios/nagios.novarc"):
930 if not os.path.exists(novarc):
931 return False
932
933- output = subprocess.check_output(['/bin/bash', '-c', 'source {} && env'.format(novarc)])
934+ output = subprocess.check_output(
935+ ["/bin/bash", "-c", "source {} && env".format(novarc)]
936+ )
937 i = 0
938- for line in output.decode('utf-8').splitlines():
939- key = line.split('=')[0]
940- if not (key.startswith('OS_') or key.count('proxy') > 0 or key.count('PROXY') > 0):
941+ for line in output.decode("utf-8").splitlines():
942+ key = line.split("=")[0]
943+ if not (
944+ key.startswith("OS_") or key.count("proxy") > 0 or key.count("PROXY") > 0
945+ ):
946 continue
947- key, value = line.split('=')
948+ key, value = line.split("=")
949 os.environ[key] = value
950 i += 1
951
952- os.environ['SHELL'] = '/bin/bash'
953- os.environ['HOME'] = '/home/nagiososc'
954- os.environ['PATH'] = '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin'
955+ os.environ["SHELL"] = "/bin/bash"
956+ os.environ["HOME"] = "/home/nagiososc"
957+ os.environ[
958+ "PATH"
959+ ] = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin"
960
961 return i >= 3
962
963
964-def main(testfile='/home/nagiososc/ostests.txt'):
965+def main(testfile="/home/nagiososc/ostests.txt"):
966 if not _load_envvars():
967- print('UNKNOWN: could not load OS_ envvars')
968+ print("UNKNOWN: could not load OS_ envvars")
969 sys.exit(3)
970
971 tempoutputfile = tempfile.mktemp()
972- cmd1 = ['fcbtest.rally', 'deployment', 'use', 'snap_generated']
973- cmd2 = ['fcbtest.rally', '--use-json', 'verify', 'start', '--load-list', testfile, '--detailed']
974+ cmd1 = ["fcbtest.rally", "deployment", "use", "snap_generated"]
975+ cmd2 = [
976+ "fcbtest.rally",
977+ "--use-json",
978+ "verify",
979+ "start",
980+ "--load-list",
981+ testfile,
982+ "--detailed",
983+ ]
984 try:
985 subprocess.check_output(cmd1, stderr=subprocess.STDOUT)
986 output = subprocess.check_output(cmd2, stderr=subprocess.STDOUT)
987- with open(tempoutputfile, 'w') as fd:
988- fd.write(output.decode('utf-8'))
989+ with open(tempoutputfile, "w") as fd:
990+ fd.write(output.decode("utf-8"))
991 shutil.copy2(tempoutputfile, OUTPUT_FILE)
992 shutil.copy2(OUTPUT_FILE, get_backup_output_filename())
993 os.unlink(tempoutputfile)
994 except subprocess.CalledProcessError as error:
995 msg = {
996- 'message': 'CRITICAL: fcbtest.rally command failed. {} - {}'.format(str(error), str(error.stdout)),
997+ "message": "CRITICAL: fcbtest.rally command failed. {} - {}".format(
998+ str(error), str(error.stdout)
999+ ),
1000 }
1001- with open(OUTPUT_FILE, 'w') as fd:
1002- fd.write('{}\n'.format(json.dumps(msg)))
1003+ with open(OUTPUT_FILE, "w") as fd:
1004+ fd.write("{}\n".format(json.dumps(msg)))
1005
1006 except IOError as error:
1007 msg = {
1008- 'message': 'CRITICAL: IOError. {}'.format(str(error)),
1009+ "message": "CRITICAL: IOError. {}".format(str(error)),
1010 }
1011- with open(OUTPUT_FILE, 'a') as fd:
1012- fd.write('{}\n'.format(json.dumps(msg)))
1013+ with open(OUTPUT_FILE, "a") as fd:
1014+ fd.write("{}\n".format(json.dumps(msg)))
1015
1016
1017-if __name__ == '__main__':
1018+if __name__ == "__main__":
1019 main()
1020diff --git a/src/lib/lib_openstack_service_checks.py b/src/lib/lib_openstack_service_checks.py
1021index ff4ac9f..405120d 100644
1022--- a/src/lib/lib_openstack_service_checks.py
1023+++ b/src/lib/lib_openstack_service_checks.py
1024@@ -31,215 +31,243 @@ class OSCKeystoneError(Exception):
1025 class OSCKeystoneServerError(OSCKeystoneError):
1026 @property
1027 def workload_status(self):
1028- return 'Keystone server error was encountered trying to list keystone '\
1029- 'resources. Check keystone server health. '\
1030- 'View juju logs for more info.'
1031+ return (
1032+ "Keystone server error was encountered trying to list keystone "
1033+ "resources. Check keystone server health. "
1034+ "View juju logs for more info."
1035+ )
1036
1037
1038 class OSCKeystoneClientError(OSCKeystoneError):
1039 @property
1040 def workload_status(self):
1041- return 'Keystone client request error was encountered trying to '\
1042- 'keystone resources. Check keystone auth creds and url.'\
1043- 'View juju logs for more info.'
1044+ return (
1045+ "Keystone client request error was encountered trying to "
1046+ "keystone resources. Check keystone auth creds and url."
1047+ "View juju logs for more info."
1048+ )
1049
1050
1051 class OSCSslError(OSCKeystoneError):
1052 @property
1053 def workload_status(self):
1054- return 'SSL error was encountered when requesting Keystone for ' \
1055- 'resource list. Check trusted_ssl_ca config option. ' \
1056- 'View juju logs for more info.'
1057+ return (
1058+ "SSL error was encountered when requesting Keystone for "
1059+ "resource list. Check trusted_ssl_ca config option. "
1060+ "View juju logs for more info."
1061+ )
1062
1063
1064-class OSCHelper():
1065+class OSCHelper:
1066 def __init__(self):
1067 self.charm_config = hookenv.config()
1068 self._keystone_client = None
1069
1070 def store_keystone_credentials(self, creds):
1071- '''store keystone credentials'''
1072+ """store keystone credentials"""
1073 kv = unitdata.kv()
1074- kv.set('keystonecreds', creds)
1075- kv.set('rallyinstalled', False)
1076+ kv.set("keystonecreds", creds)
1077+ kv.set("rallyinstalled", False)
1078
1079 @property
1080 def novarc(self):
1081- return '/var/lib/nagios/nagios.novarc'
1082+ return "/var/lib/nagios/nagios.novarc"
1083
1084 @property
1085 def contrail_analytics_vip(self):
1086- return self.charm_config['contrail_analytics_vip']
1087+ return self.charm_config["contrail_analytics_vip"]
1088
1089 @property
1090 def contrail_ignored(self):
1091- return self.charm_config['contrail_ignored_alarms']
1092+ return self.charm_config["contrail_ignored_alarms"]
1093
1094 @property
1095 def plugins_dir(self):
1096- return '/usr/local/lib/nagios/plugins/'
1097+ return "/usr/local/lib/nagios/plugins/"
1098
1099 @property
1100 def scripts_dir(self):
1101- return '/usr/local/bin/'
1102+ return "/usr/local/bin/"
1103
1104 @property
1105 def rally_cron_file(self):
1106- return '/etc/cron.d/osc_rally'
1107+ return "/etc/cron.d/osc_rally"
1108
1109 @property
1110 def is_rally_enabled(self):
1111- return self.charm_config['check-rally']
1112+ return self.charm_config["check-rally"]
1113
1114 @property
1115 def is_neutron_agents_check_enabled(self):
1116- return self.charm_config['check-neutron-agents']
1117+ return self.charm_config["check-neutron-agents"]
1118
1119 @property
1120 def is_octavia_check_enabled(self):
1121- return self.charm_config['check-octavia']
1122+ return self.charm_config["check-octavia"]
1123
1124 @property
1125 def octavia_amp_image_tag(self):
1126- return self.charm_config['octavia-amp-image-tag']
1127+ return self.charm_config["octavia-amp-image-tag"]
1128
1129 @property
1130 def octavia_amp_image_days(self):
1131- return self.charm_config['octavia-amp-image-days']
1132+ return self.charm_config["octavia-amp-image-days"]
1133
1134 @property
1135 def skipped_rally_checks(self):
1136- skipped_os_components = self.charm_config['skip-rally'].strip()
1137+ skipped_os_components = self.charm_config["skip-rally"].strip()
1138 if not skipped_os_components:
1139 return []
1140
1141 # filter skip-rally input to match available (or supported) components that
1142 # should be disabled
1143- available_os_components = 'cinder glance nova neutron'.split()
1144- return [comp.strip().lower() for comp in skipped_os_components.split(',')
1145- if comp.strip().lower() in available_os_components]
1146+ available_os_components = "cinder glance nova neutron".split()
1147+ return [
1148+ comp.strip().lower()
1149+ for comp in skipped_os_components.split(",")
1150+ if comp.strip().lower() in available_os_components
1151+ ]
1152
1153 @property
1154 def rally_cron_schedule(self):
1155- schedule = self.charm_config['rally-cron-schedule']
1156- if schedule.strip() == '' or len(schedule.strip().split()) != 5:
1157- return '*/15 * * * *'
1158+ schedule = self.charm_config["rally-cron-schedule"]
1159+ if schedule.strip() == "" or len(schedule.strip().split()) != 5:
1160+ return "*/15 * * * *"
1161 else:
1162 return schedule.strip()
1163
1164 def get_os_credentials(self):
1165- ident_creds = config_flags_parser(self.charm_config['os-credentials'])
1166- if not ident_creds.get('auth_url'):
1167- raise OSCCredentialsError('auth_url')
1168- elif '/v3' in ident_creds.get('auth_url'):
1169- extra_attrs = ['domain']
1170- creds = {'auth_version': 3}
1171+ ident_creds = config_flags_parser(self.charm_config["os-credentials"])
1172+ if not ident_creds.get("auth_url"):
1173+ raise OSCCredentialsError("auth_url")
1174+ elif "/v3" in ident_creds.get("auth_url"):
1175+ extra_attrs = ["domain"]
1176+ creds = {"auth_version": 3}
1177 else:
1178 extra_attrs = []
1179 creds = {}
1180
1181- common_attrs = ('username password region_name auth_url'
1182- ' credentials_project').split()
1183+ common_attrs = (
1184+ "username password region_name auth_url credentials_project"
1185+ ).split()
1186 all_attrs = common_attrs + extra_attrs
1187 missing = [k for k in all_attrs if k not in ident_creds]
1188 if missing:
1189- raise OSCCredentialsError(', '.join(missing))
1190-
1191- ident_creds['auth_url'] = ident_creds['auth_url'].strip('\"\'')
1192- creds.update(dict([(k, ident_creds.get(k))
1193- for k in all_attrs
1194- if k not in ('credentials_project', 'domain')]))
1195+ raise OSCCredentialsError(", ".join(missing))
1196+
1197+ ident_creds["auth_url"] = ident_creds["auth_url"].strip("\"'")
1198+ creds.update(
1199+ dict(
1200+ [
1201+ (k, ident_creds.get(k))
1202+ for k in all_attrs
1203+ if k not in ("credentials_project", "domain")
1204+ ]
1205+ )
1206+ )
1207 if extra_attrs:
1208- creds.update({'project_name': ident_creds['credentials_project'],
1209- 'user_domain_name': ident_creds['domain'],
1210- 'project_domain_name': ident_creds['domain'],
1211- })
1212+ creds.update(
1213+ {
1214+ "project_name": ident_creds["credentials_project"],
1215+ "user_domain_name": ident_creds["domain"],
1216+ "project_domain_name": ident_creds["domain"],
1217+ }
1218+ )
1219 else:
1220- creds['tenant_name'] = ident_creds['credentials_project']
1221+ creds["tenant_name"] = ident_creds["credentials_project"]
1222
1223 return creds
1224
1225 def get_keystone_credentials(self):
1226- '''retrieve keystone credentials from either config or relation data
1227+ """Retrieve keystone credentials from either config or relation data
1228
1229- If config 'os-crendentials' is set, return that info otherwise look for a keystonecreds relation data'
1230+ If config 'os-crendentials' is set, return that info otherwise look
1231+ for a keystonecreds relation data'
1232
1233 :return: dict of credential information for keystone
1234- '''
1235- return unitdata.kv().get('keystonecreds')
1236+ """
1237+ return unitdata.kv().get("keystonecreds")
1238
1239 @property
1240 def nova_warn(self):
1241- return self.charm_config.get('nova_warn')
1242+ return self.charm_config.get("nova_warn")
1243
1244 @property
1245 def nova_crit(self):
1246- return self.charm_config.get('nova_crit')
1247+ return self.charm_config.get("nova_crit")
1248
1249 @property
1250 def nova_skip_aggregates(self):
1251- skipped_aggregates = self.charm_config.get('skipped_host_aggregates')
1252+ skipped_aggregates = self.charm_config.get("skipped_host_aggregates")
1253 # We have to make sure there are no malicious injections in the code
1254 # as this gets passed to a python script via bash
1255- regex = r'([\w_-]+(?:,[\w_-]+)*)'
1256+ regex = r"([\w_-]+(?:,[\w_-]+)*)"
1257 sanitized = ",".join(re.findall(regex, skipped_aggregates))
1258- sanitized = [s for s in sanitized.split(',') if s != ""]
1259+ sanitized = [s for s in sanitized.split(",") if s != ""]
1260 sanitized = ",".join(sanitized)
1261 return sanitized
1262
1263 @property
1264 def skip_disabled(self):
1265- if self.charm_config.get('skip-disabled'):
1266- return '--skip-disabled'
1267+ if self.charm_config.get("skip-disabled"):
1268+ return "--skip-disabled"
1269 else:
1270- return ''
1271+ return ""
1272
1273 @property
1274 def check_dns(self):
1275- return self.charm_config.get('check-dns')
1276+ return self.charm_config.get("check-dns")
1277
1278 def update_plugins(self):
1279- charm_plugin_dir = os.path.join(hookenv.charm_dir(), 'files', 'plugins/')
1280- host.rsync(charm_plugin_dir, self.plugins_dir, options=['--executability'])
1281+ charm_plugin_dir = os.path.join(hookenv.charm_dir(), "files", "plugins/")
1282+ host.rsync(charm_plugin_dir, self.plugins_dir, options=["--executability"])
1283
1284 def _render_nova_checks(self, nrpe):
1285 """Nova services health."""
1286- nova_check_command = os.path.join(self.plugins_dir, 'check_nova_services.py')
1287- check_command = '{} --warn {} --crit {} --skip-aggregates {} {}'.format(
1288- nova_check_command, self.nova_warn, self.nova_crit, self.nova_skip_aggregates,
1289- self.skip_disabled).strip()
1290- nrpe.add_check(shortname='nova_services',
1291- description='Check that enabled Nova services are up',
1292- check_cmd=check_command,
1293- )
1294+ nova_check_command = os.path.join(self.plugins_dir, "check_nova_services.py")
1295+ check_command = "{} --warn {} --crit {} --skip-aggregates {} {}".format(
1296+ nova_check_command,
1297+ self.nova_warn,
1298+ self.nova_crit,
1299+ self.nova_skip_aggregates,
1300+ self.skip_disabled,
1301+ ).strip()
1302+ nrpe.add_check(
1303+ shortname="nova_services",
1304+ description="Check that enabled Nova services are up",
1305+ check_cmd=check_command,
1306+ )
1307
1308 def _render_neutron_checks(self, nrpe):
1309 """Neutron agents health."""
1310 if self.is_neutron_agents_check_enabled:
1311- nrpe.add_check(shortname='neutron_agents',
1312- description='Check that enabled Neutron agents are up',
1313- check_cmd=os.path.join(self.plugins_dir,
1314- 'check_neutron_agents.sh'),
1315- )
1316+ nrpe.add_check(
1317+ shortname="neutron_agents",
1318+ description="Check that enabled Neutron agents are up",
1319+ check_cmd=os.path.join(self.plugins_dir, "check_neutron_agents.sh"),
1320+ )
1321 else:
1322- nrpe.remove_check(shortname='neutron_agents')
1323+ nrpe.remove_check(shortname="neutron_agents")
1324
1325 def _render_cinder_checks(self, nrpe):
1326 # Cinder services health
1327- cinder_check_command = os.path.join(self.plugins_dir, 'check_cinder_services.py')
1328- check_command = '{} {}'.format(cinder_check_command, self.skip_disabled)
1329- nrpe.add_check(shortname='cinder_services',
1330- description='Check that enabled Cinder services are up',
1331- check_cmd=check_command,
1332- )
1333+ cinder_check_command = os.path.join(
1334+ self.plugins_dir, "check_cinder_services.py"
1335+ )
1336+ check_command = "{} {}".format(cinder_check_command, self.skip_disabled)
1337+ nrpe.add_check(
1338+ shortname="cinder_services",
1339+ description="Check that enabled Cinder services are up",
1340+ check_cmd=check_command,
1341+ )
1342
1343 def _remove_octavia_checks(self, nrpe):
1344- for check in ('loadbalancers', 'amphorae', 'pools', 'image'):
1345- nrpe.remove_check(shortname='octavia_{}'.format(check))
1346+ for check in ("loadbalancers", "amphorae", "pools", "image"):
1347+ nrpe.remove_check(shortname="octavia_{}".format(check))
1348
1349 def _render_octavia_checks(self, nrpe):
1350 # only care about octavia after 18.04
1351- if host.lsb_release()['DISTRIB_RELEASE'] < '18.04':
1352+ if host.lsb_release()["DISTRIB_RELEASE"] < "18.04":
1353 return
1354
1355 # if its not enabled in config, remove checks
1356@@ -248,59 +276,65 @@ class OSCHelper():
1357 return
1358
1359 # if its not listed as an endpoint, remove checks
1360- if 'octavia' not in self.endpoint_service_names.values():
1361+ if "octavia" not in self.endpoint_service_names.values():
1362 self._remove_octavia_checks(nrpe)
1363 return
1364
1365 # else, render the octavia service-specific checks
1366 fetch.apt_install(["python3-octaviaclient"], fatal=True)
1367- script = os.path.join(self.plugins_dir, 'check_octavia.py')
1368+ script = os.path.join(self.plugins_dir, "check_octavia.py")
1369
1370- for check in ('loadbalancers', 'amphorae', 'pools', 'image'):
1371- check_cmd = '{} --check {}'.format(script, check)
1372- if check == 'image':
1373+ for check in ("loadbalancers", "amphorae", "pools", "image"):
1374+ check_cmd = "{} --check {}".format(script, check)
1375+ if check == "image":
1376 check_cmd += " --amp-image-tag {}".format(self.octavia_amp_image_tag)
1377 check_cmd += " --amp-image-days {}".format(self.octavia_amp_image_days)
1378- ignore = self.charm_config.get('octavia-%s-ignored' % check)
1379+ ignore = self.charm_config.get("octavia-%s-ignored" % check)
1380 if ignore:
1381- check_cmd += ' --ignored {}'.format(ignore)
1382+ check_cmd += " --ignored {}".format(ignore)
1383 nrpe.add_check(
1384- shortname='octavia_{}'.format(check),
1385- description='Check octavia {} status'.format(check),
1386+ shortname="octavia_{}".format(check),
1387+ description="Check octavia {} status".format(check),
1388 check_cmd=check_cmd,
1389 )
1390
1391 def _render_contrail_checks(self, nrpe):
1392 if self.contrail_analytics_vip:
1393- contrail_check_command = '{} --host {}'.format(
1394- os.path.join(self.plugins_dir, 'check_contrail_analytics_alarms.py'),
1395- self.contrail_analytics_vip)
1396+ contrail_check_command = "{} --host {}".format(
1397+ os.path.join(self.plugins_dir, "check_contrail_analytics_alarms.py"),
1398+ self.contrail_analytics_vip,
1399+ )
1400 if self.contrail_ignored:
1401- contrail_check_command += ' --ignored {}'.format(
1402- self.contrail_ignored
1403- )
1404- nrpe.add_check(shortname='contrail_analytics_alarms',
1405- description='Check Contrail Analytics alarms',
1406- check_cmd=contrail_check_command,
1407- )
1408+ contrail_check_command += " --ignored {}".format(self.contrail_ignored)
1409+ nrpe.add_check(
1410+ shortname="contrail_analytics_alarms",
1411+ description="Check Contrail Analytics alarms",
1412+ check_cmd=contrail_check_command,
1413+ )
1414 else:
1415- nrpe.remove_check(shortname='contrail_analytics_alarms')
1416+ nrpe.remove_check(shortname="contrail_analytics_alarms")
1417
1418 def _render_dns_checks(self, nrpe):
1419 if len(self.check_dns):
1420- nrpe.add_check(shortname='dns_multi',
1421- description='Check DNS names are resolvable',
1422- check_cmd='{} {}'.format(
1423- os.path.join(self.plugins_dir,
1424- 'check_dns_multi.sh'),
1425- ' '.join(self.check_dns.split())),
1426- )
1427+ nrpe.add_check(
1428+ shortname="dns_multi",
1429+ description="Check DNS names are resolvable",
1430+ check_cmd="{} {}".format(
1431+ os.path.join(self.plugins_dir, "check_dns_multi.sh"),
1432+ " ".join(self.check_dns.split()),
1433+ ),
1434+ )
1435 else:
1436- nrpe.remove_check(shortname='dns_multi')
1437+ nrpe.remove_check(shortname="dns_multi")
1438
1439 def render_checks(self, creds):
1440- render(source='nagios.novarc', target=self.novarc, context=creds,
1441- owner='nagios', group='nagios')
1442+ render(
1443+ source="nagios.novarc",
1444+ target=self.novarc,
1445+ context=creds,
1446+ owner="nagios",
1447+ group="nagios",
1448+ )
1449
1450 nrpe = NRPE()
1451 if not os.path.exists(self.plugins_dir):
1452@@ -333,12 +367,12 @@ class OSCHelper():
1453 :returns: str
1454 :rtype: Tuple[str, str]
1455 """
1456- if netloc.find(':') == -1:
1457+ if netloc.find(":") == -1:
1458 # no port specified
1459 host = netloc
1460- port = 80 if scheme == 'http' else 443
1461+ port = 80 if scheme == "http" else 443
1462 else:
1463- host, port = netloc.split(':')
1464+ host, port = netloc.split(":")
1465
1466 return host, port
1467
1468@@ -352,31 +386,32 @@ class OSCHelper():
1469 If SSL, add a check for the cert.
1470
1471 v2 endpoint needs the 'interface' attribute:
1472- <Endpoint {'id': 'XXXXX', 'region': 'RegionOne', 'publicurl': 'http://10.x.x.x:9696',
1473- 'service_id': 'YYY', 'internalurl': 'http://10.x.x.x:9696', 'enabled': True,
1474+ <Endpoint {'id': 'XXXXX', 'region': 'RegionOne',
1475+ 'publicurl': 'http://10.x.x.x:9696', 'service_id': 'YYY',
1476+ 'internalurl': 'http://10.x.x.x:9696', 'enabled': True,
1477 'adminurl': 'http://10.x.x.x:9696'}>
1478 """
1479 # provide URLs that can be used for healthcheck for some services
1480 # This also provides a nasty hack-ish way to add switches if we need
1481 # for some services.
1482 health_check_params = {
1483- 'aodh': '/healthcheck',
1484- 'barbican': '/v1 -e Unauthorized',
1485- 'ceilometer': '/ -e Unauthorized -d x-openstack-request-id',
1486- 'cinderv1': '/v1 -e Unauthorized -d x-openstack-request-id',
1487- 'cinderv2': '/v2 -e Unauthorized',
1488- 'cinderv3': '/v3 -e Unauthorized -d x-openstack-request-id',
1489- 'designate': '/v2 -e Unauthorized',
1490- 'glance': '/healthcheck',
1491- 'gnocchi': '/v1 -e Unauthorized',
1492- 'heat': '/v1 -e Unauthorized',
1493- 'keystone': '/healthcheck',
1494- 'nova': '/healthcheck',
1495- 'octavia': '/v2 -e Unauthorized',
1496- 'placement': '/healthcheck -e Unauthorized -d x-openstack-request-id',
1497- 's3': self.charm_config.get('s3_check_params', '/'),
1498- 'swift': self.charm_config.get('swift_check_params', '/'),
1499- }
1500+ "aodh": "/healthcheck",
1501+ "barbican": "/v1 -e Unauthorized",
1502+ "ceilometer": "/ -e Unauthorized -d x-openstack-request-id",
1503+ "cinderv1": "/v1 -e Unauthorized -d x-openstack-request-id",
1504+ "cinderv2": "/v2 -e Unauthorized",
1505+ "cinderv3": "/v3 -e Unauthorized -d x-openstack-request-id",
1506+ "designate": "/v2 -e Unauthorized",
1507+ "glance": "/healthcheck",
1508+ "gnocchi": "/v1 -e Unauthorized",
1509+ "heat": "/v1 -e Unauthorized",
1510+ "keystone": "/healthcheck",
1511+ "nova": "/healthcheck",
1512+ "octavia": "/v2 -e Unauthorized",
1513+ "placement": "/healthcheck -e Unauthorized -d x-openstack-request-id",
1514+ "s3": self.charm_config.get("s3_check_params", "/"),
1515+ "swift": self.charm_config.get("swift_check_params", "/"),
1516+ }
1517
1518 self.get_keystone_client(creds)
1519 nrpe = NRPE()
1520@@ -384,19 +419,19 @@ class OSCHelper():
1521
1522 for endpoint in self.keystone_endpoints:
1523 service_name = self.endpoint_service_names[endpoint.id]
1524- endpoint.healthcheck_url = health_check_params.get(service_name, '/')
1525+ endpoint.healthcheck_url = health_check_params.get(service_name, "/")
1526
1527 # Note(aluria): glance-simplestreams-sync does not provide an API to check
1528- if service_name == 'image-stream':
1529+ if service_name == "image-stream":
1530 continue
1531
1532- if not hasattr(endpoint, 'interface'):
1533+ if not hasattr(endpoint, "interface"):
1534 # Note(aluria): filter:healthcheck is not configured in Keystone v2
1535 # https://docs.openstack.org/keystone/pike/configuration.html#health-check-middleware
1536- if service_name == 'keystone':
1537+ if service_name == "keystone":
1538 continue
1539- for interface in 'admin internal public'.split():
1540- old_interface_name = '{}url'.format(interface)
1541+ for interface in "admin internal public".split():
1542+ old_interface_name = "{}url".format(interface)
1543 if not hasattr(endpoint, old_interface_name):
1544 continue
1545 endpoint.interface = interface
1546@@ -404,51 +439,70 @@ class OSCHelper():
1547 break
1548
1549 check_url = urlparse(endpoint.url)
1550- if not self.charm_config.get('check_{}_urls'.format(endpoint.interface)):
1551- nrpe.remove_check(shortname='{}_{}'.format(service_name, endpoint.interface))
1552- if check_url.scheme == 'https':
1553- nrpe.remove_check(shortname='{}_{}_cert'.format(service_name, endpoint.interface))
1554+ if not self.charm_config.get("check_{}_urls".format(endpoint.interface)):
1555+ nrpe.remove_check(
1556+ shortname="{}_{}".format(service_name, endpoint.interface)
1557+ )
1558+ if check_url.scheme == "https":
1559+ nrpe.remove_check(
1560+ shortname="{}_{}_cert".format(service_name, endpoint.interface)
1561+ )
1562 continue
1563
1564- cmd_params = ['/usr/lib/nagios/plugins/check_http']
1565+ cmd_params = ["/usr/lib/nagios/plugins/check_http"]
1566 host, port = self._split_url(check_url.netloc, check_url.scheme)
1567- cmd_params.append('-H {} -p {}'.format(host, port))
1568- cmd_params.append('-u {}'.format(endpoint.healthcheck_url))
1569+ cmd_params.append("-H {} -p {}".format(host, port))
1570+ cmd_params.append("-u {}".format(endpoint.healthcheck_url))
1571
1572 # if this is https, we want to add a check for cert expiry
1573 # also need to tell check_http use use TLS
1574- if check_url.scheme == 'https':
1575- cmd_params.append('-S')
1576+ if check_url.scheme == "https":
1577+ cmd_params.append("-S")
1578 # Add an extra check for TLS cert expiry
1579 cmd_params_cert = cmd_params.copy()
1580- cmd_params_cert.append('-C {},{}'.format(self.charm_config['tls_warn_days'] or 30,
1581- self.charm_config['tls_crit_days'] or 14))
1582- nrpe.add_check(shortname='{}_{}_cert'.format(service_name, endpoint.interface),
1583- description='Certificate expiry check for {} {}'.format(service_name,
1584- endpoint.interface),
1585- check_cmd=' '.join(cmd_params_cert))
1586- hookenv.log("Added cert expiry check for: {}, {}".format(service_name, endpoint.interface))
1587+ cmd_params_cert.append(
1588+ "-C {},{}".format(
1589+ self.charm_config["tls_warn_days"] or 30,
1590+ self.charm_config["tls_crit_days"] or 14,
1591+ )
1592+ )
1593+ nrpe.add_check(
1594+ shortname="{}_{}_cert".format(service_name, endpoint.interface),
1595+ description="Certificate expiry check for {} {}".format(
1596+ service_name, endpoint.interface
1597+ ),
1598+ check_cmd=" ".join(cmd_params_cert),
1599+ )
1600+ hookenv.log(
1601+ "Added cert expiry check for: {}, {}".format(
1602+ service_name, endpoint.interface
1603+ )
1604+ )
1605
1606 # Add the actual health check for the URL
1607- nrpe_shortname = '{}_{}'.format(service_name, endpoint.interface)
1608- nrpe.add_check(shortname=nrpe_shortname,
1609- description='Endpoint url check for {} {}'.format(service_name, endpoint.interface),
1610- check_cmd=' '.join(cmd_params))
1611+ nrpe_shortname = "{}_{}".format(service_name, endpoint.interface)
1612+ nrpe.add_check(
1613+ shortname=nrpe_shortname,
1614+ description="Endpoint url check for {} {}".format(
1615+ service_name, endpoint.interface
1616+ ),
1617+ check_cmd=" ".join(cmd_params),
1618+ )
1619 configured_endpoint_checks[nrpe_shortname] = True
1620- hookenv.log("Added nrpe check {}: {}".format(nrpe_shortname, ' '.join(cmd_params)))
1621+ hookenv.log(
1622+ "Added nrpe check {}: {}".format(nrpe_shortname, " ".join(cmd_params))
1623+ )
1624 nrpe.write()
1625 self._remove_old_nrpe_endpoint_checks(nrpe, configured_endpoint_checks)
1626
1627 def _remove_old_nrpe_endpoint_checks(self, nrpe, configured_endpoint_checks):
1628- """Loop through the old and new endpoint checks, if there are checks that aren't needed any more,
1629- remove them.
1630- """
1631+ """Remove old endpoint checks that are no longer currently defined."""
1632 kv = unitdata.kv()
1633- endpoint_delta = kv.delta(configured_endpoint_checks, 'endpoint_checks')
1634- kv.update(configured_endpoint_checks, 'endpoint_checks')
1635+ endpoint_delta = kv.delta(configured_endpoint_checks, "endpoint_checks")
1636+ kv.update(configured_endpoint_checks, "endpoint_checks")
1637 for nrpe_shortname in endpoint_delta.items():
1638- # generates tuples of the format ('heat_public', Delta(previous=None, current=True))
1639- # remove any that are not current
1640+ # generates tuples of below format, remove any that are not current
1641+ # ('heat_public', Delta(previous=None, current=True))
1642 if not nrpe_shortname[1].current:
1643 nrpe.remove_check(shortname=nrpe_shortname[0])
1644 nrpe.write()
1645@@ -468,17 +522,23 @@ class OSCHelper():
1646
1647 # don't try to initialize a client without credentials
1648 if creds is None:
1649- raise OSCKeystoneServerError('Unable to list the endpoints yet: '
1650- 'no credentials provided.')
1651+ raise OSCKeystoneServerError(
1652+ "Unable to list the endpoints yet: no credentials provided."
1653+ )
1654
1655- if int(creds.get('auth_version', 0)) >= 3:
1656+ if int(creds.get("auth_version", 0)) >= 3:
1657 from keystoneclient.v3 import client
1658 from keystoneclient.auth.identity import v3 as kst_version
1659- auth_fields = 'username password auth_url user_domain_name project_domain_name project_name'.split()
1660+
1661+ auth_fields = (
1662+ "username password auth_url user_domain_name "
1663+ "project_domain_name project_name"
1664+ ).split()
1665 else:
1666 from keystoneclient.v2_0 import client
1667 from keystoneclient.auth.identity import v2 as kst_version
1668- auth_fields = 'username password auth_url tenant_name'.split()
1669+
1670+ auth_fields = "username password auth_url tenant_name".split()
1671
1672 auth_creds = dict([(key, creds.get(key)) for key in auth_fields])
1673 auth = kst_version.Password(**auth_creds)
1674@@ -486,18 +546,20 @@ class OSCHelper():
1675 self._keystone_client = client.Client(session=sess)
1676
1677 if self._keystone_client is None:
1678- raise OSCKeystoneServerError('Unable to list the endpoints yet: '
1679- 'could not connect to the Identity Service')
1680+ raise OSCKeystoneServerError(
1681+ "Unable to list the endpoints yet: "
1682+ "could not connect to the Identity Service"
1683+ )
1684
1685 @property
1686 def keystone_endpoints(self):
1687- endpoints = self._safe_keystone_client_list('endpoints')
1688+ endpoints = self._safe_keystone_client_list("endpoints")
1689 hookenv.log("Endpoints from keystone: {}".format(endpoints))
1690 return endpoints
1691
1692 @property
1693 def keystone_services(self):
1694- services = self._safe_keystone_client_list('services')
1695+ services = self._safe_keystone_client_list("services")
1696 hookenv.log("Services from keystone: {}".format(services))
1697 return services
1698
1699@@ -520,28 +582,40 @@ class OSCHelper():
1700 list_command = getattr(self._keystone_client, object_type).list
1701 try:
1702 response = list_command()
1703- except (keystoneauth1.exceptions.http.InternalServerError,
1704- keystoneauth1.exceptions.connection.ConnectFailure) as server_error:
1705+ except (
1706+ keystoneauth1.exceptions.http.InternalServerError,
1707+ keystoneauth1.exceptions.connection.ConnectFailure,
1708+ ) as server_error:
1709 raise OSCKeystoneServerError(
1710- 'Keystone server unable to list keystone {}: {}'.format(server_error, object_type))
1711+ "Keystone server unable to list keystone {}: {}".format(
1712+ server_error, object_type
1713+ )
1714+ )
1715 except keystoneauth1.exceptions.http.BadRequest as client_error:
1716 raise OSCKeystoneClientError(
1717- 'Keystone client error when listing {}: {}'.format(client_error, object_type))
1718+ "Keystone client error when listing {}: {}".format(
1719+ client_error, object_type
1720+ )
1721+ )
1722 except keystoneauth1.exceptions.connection.SSLError as ssl_error:
1723- raise OSCSslError('Keystone ssl error when listing {}: {}'.format(ssl_error, object_type))
1724+ raise OSCSslError(
1725+ "Keystone ssl error when listing {}: {}".format(ssl_error, object_type)
1726+ )
1727 return response
1728
1729 @property
1730- def _load_envvars(self, novarc='/var/lib/nagios/nagios.novarc'):
1731+ def _load_envvars(self, novarc="/var/lib/nagios/nagios.novarc"):
1732 if not os.path.exists(novarc):
1733 return False
1734
1735- output = subprocess.check_output(['/bin/bash', '-c', 'source {} && env'.format(novarc)])
1736+ output = subprocess.check_output(
1737+ ["/bin/bash", "-c", "source {} && env".format(novarc)]
1738+ )
1739 i = 0
1740- for line in output.decode('utf-8').splitlines():
1741- if not line.startswith('OS_'):
1742+ for line in output.decode("utf-8").splitlines():
1743+ if not line.startswith("OS_"):
1744 continue
1745- key, value = line.split('=')
1746+ key, value = line.split("=")
1747 os.environ[key] = value
1748 i += 1
1749
1750@@ -551,7 +625,7 @@ class OSCHelper():
1751 try:
1752 pwd.getpwnam(user)
1753 # preserve envvars and run as `user`
1754- cmd = ['sudo', '-Eu', user]
1755+ cmd = ["sudo", "-Eu", user]
1756
1757 # convert command into a list
1758 if isinstance(user_cmd, str):
1759@@ -560,48 +634,58 @@ class OSCHelper():
1760 elif isinstance(user_cmd, list):
1761 cmd.extend(user_cmd)
1762 else:
1763- hookenv.log("_run_as - can't run as user {} the command: {}".format(user, user_cmd))
1764+ hookenv.log(
1765+ "_run_as - can't run as user {} the command: {}".format(
1766+ user, user_cmd
1767+ )
1768+ )
1769 return False
1770
1771 subprocess.check_call(cmd)
1772 return True
1773
1774 except KeyError as error:
1775- hookenv.log('_run_as - user does not exist => {}'.format(str(error)))
1776+ hookenv.log("_run_as - user does not exist => {}".format(str(error)))
1777 return False
1778 except subprocess.CalledProcessError as error:
1779- hookenv.log('_run_as - cmd failed => {}'.format(str(error)))
1780+ hookenv.log("_run_as - cmd failed => {}".format(str(error)))
1781 if error.stderr:
1782- hookenv.log('_run_as stderr => {}'.format(error.stderr))
1783+ hookenv.log("_run_as stderr => {}".format(error.stderr))
1784 if error.stdout:
1785- hookenv.log('_run_as stderr => {}'.format(error.stdout))
1786+ hookenv.log("_run_as stderr => {}".format(error.stdout))
1787 return False
1788
1789 @property
1790 def _rallyuser(self):
1791- return 'nagiososc'
1792+ return "nagiososc"
1793
1794 def install_rally(self):
1795 kv = unitdata.kv()
1796- if kv.get('rallyinstalled', False):
1797+ if kv.get("rallyinstalled", False):
1798 return True
1799
1800 if not self._load_envvars:
1801- hookenv.log('install_rally - could not load nagios.novarc')
1802+ hookenv.log("install_rally - could not load nagios.novarc")
1803 return False
1804
1805 user = self._rallyuser
1806 host.adduser(user)
1807- host.mkdir(os.path.join('/home', user), owner=user, group=user, perms=0o755, force=False)
1808-
1809- for tool in ['rally', 'tempest']:
1810- toolname = 'fcbtest.{}init'.format(tool)
1811+ host.mkdir(
1812+ os.path.join("/home", user),
1813+ owner=user,
1814+ group=user,
1815+ perms=0o755,
1816+ force=False,
1817+ )
1818+
1819+ for tool in ["rally", "tempest"]:
1820+ toolname = "fcbtest.{}init".format(tool)
1821 installed = self._run_as(user, [toolname])
1822 if not installed:
1823- hookenv.log('install_rally - could not initialize {}'.format(tool))
1824+ hookenv.log("install_rally - could not initialize {}".format(tool))
1825 return False
1826
1827- kv.set('rallyinstalled', True)
1828+ kv.set("rallyinstalled", True)
1829 return True
1830
1831 def _regenerate_tempest_conf(self, tempestfile):
1832@@ -610,18 +694,18 @@ class OSCHelper():
1833 for section in config.keys():
1834 for key, value in config[section].items():
1835 try:
1836- if section != 'DEFAULT' and key in config['DEFAULT'].keys():
1837- # avoid copying the DEFAULT config options to the rest of sections
1838+ if section != "DEFAULT" and key in config["DEFAULT"].keys():
1839+ # avoid copying the DEFAULT config options to remaining sections
1840 continue
1841 except KeyError:
1842 # DEFAULT section does not exist
1843 pass
1844
1845 # Enable Cinder, which is a default OpenStack service
1846- if section == 'service_available' and key == 'cinder':
1847- config[section][key] = 'True'
1848+ if section == "service_available" and key == "cinder":
1849+ config[section][key] = "True"
1850
1851- with open(tempestfile, 'w') as fd:
1852+ with open(tempestfile, "w") as fd:
1853 config.write(fd)
1854
1855 def reconfigure_tempest(self):
1856@@ -633,22 +717,25 @@ class OSCHelper():
1857 RALLY_DEPLOYMENT=a75657c6-9eea-4f00-9117-2580fe056a80
1858 RALLY_ENV=a75657c6-9eea-4f00-9117-2580fe056a80
1859 """
1860- RALLY_CONF = ['/home', self._rallyuser, 'snap', 'fcbtest', 'current', '.rally']
1861- rally_globalconfig = os.path.join(*RALLY_CONF, 'globals')
1862+ RALLY_CONF = ["/home", self._rallyuser, "snap", "fcbtest", "current", ".rally"]
1863+ rally_globalconfig = os.path.join(*RALLY_CONF, "globals")
1864 if not os.path.isfile(rally_globalconfig):
1865 return False
1866
1867- uuids = collections.defaultdict(lambda: '*')
1868- with open(rally_globalconfig, 'r') as fd:
1869+ uuids = collections.defaultdict(lambda: "*")
1870+ with open(rally_globalconfig, "r") as fd:
1871 for line in fd.readlines():
1872- key, value = line.strip().split('=')
1873- if key in ['RALLY_VERIFIER', 'RALLY_DEPLOYMENT']:
1874+ key, value = line.strip().split("=")
1875+ if key in ["RALLY_VERIFIER", "RALLY_DEPLOYMENT"]:
1876 uuids[key] = value
1877
1878- tempest_path = os.path.join(*RALLY_CONF, 'verification',
1879- 'verifier-{RALLY_VERIFIER}'.format(**uuids),
1880- 'for-deployment-{RALLY_DEPLOYMENT}'.format(**uuids),
1881- 'tempest.conf')
1882+ tempest_path = os.path.join(
1883+ *RALLY_CONF,
1884+ "verification",
1885+ "verifier-{RALLY_VERIFIER}".format(**uuids),
1886+ "for-deployment-{RALLY_DEPLOYMENT}".format(**uuids),
1887+ "tempest.conf"
1888+ )
1889 tempestfile = glob.glob(tempest_path)
1890 if len(tempestfile) == 0:
1891 # No tempest.conf file generated, yet
1892@@ -663,7 +750,7 @@ class OSCHelper():
1893 def _get_rally_checks_context(self):
1894 os_components_skip_list = self.skipped_rally_checks
1895 ctxt = {}
1896- for comp in 'cinder glance nova neutron'.split():
1897+ for comp in "cinder glance nova neutron".split():
1898 ctxt.update({comp: comp not in os_components_skip_list})
1899 return ctxt
1900
1901@@ -672,53 +759,66 @@ class OSCHelper():
1902 return
1903
1904 # Copy run_rally.sh to /usr/local/bin
1905- rally_script = os.path.join(hookenv.charm_dir(), 'files', 'run_rally.py')
1906- host.rsync(rally_script, self.scripts_dir, options=['--executability'])
1907-
1908- ostestsfile = os.path.join('/home', self._rallyuser, 'ostests.txt')
1909- render(source='ostests.txt.j2', target=ostestsfile,
1910- context=self._get_rally_checks_context(),
1911- owner=self._rallyuser, group=self._rallyuser)
1912+ rally_script = os.path.join(hookenv.charm_dir(), "files", "run_rally.py")
1913+ host.rsync(rally_script, self.scripts_dir, options=["--executability"])
1914+
1915+ ostestsfile = os.path.join("/home", self._rallyuser, "ostests.txt")
1916+ render(
1917+ source="ostests.txt.j2",
1918+ target=ostestsfile,
1919+ context=self._get_rally_checks_context(),
1920+ owner=self._rallyuser,
1921+ group=self._rallyuser,
1922+ )
1923
1924 proxy_settings = hookenv.env_proxy_settings()
1925 if proxy_settings:
1926- content = '\n'.join(['{}={}'.format(proxy_var, proxy_var_val)
1927- for proxy_var, proxy_var_val in proxy_settings.items()])
1928+ content = "\n".join(
1929+ [
1930+ "{}={}".format(proxy_var, proxy_var_val)
1931+ for proxy_var, proxy_var_val in proxy_settings.items()
1932+ ]
1933+ )
1934 else:
1935- content = ''
1936+ content = ""
1937
1938 context = {
1939- 'schedule': self.rally_cron_schedule,
1940- 'user': self._rallyuser,
1941- 'cmd': os.path.join(self.scripts_dir, 'run_rally.py'),
1942+ "schedule": self.rally_cron_schedule,
1943+ "user": self._rallyuser,
1944+ "cmd": os.path.join(self.scripts_dir, "run_rally.py"),
1945 }
1946- content += '\n#\n{schedule} {user} timeout -k 840s -s SIGTERM 780s {cmd}'.format(**context)
1947- with open(self.rally_cron_file, 'w') as fd:
1948- fd.write('# Juju generated - DO NOT EDIT\n{}\n\n'.format(content))
1949+ content += (
1950+ "\n#\n{schedule} {user} timeout -k 840s -s SIGTERM 780s {cmd}".format(
1951+ **context
1952+ )
1953+ )
1954+ with open(self.rally_cron_file, "w") as fd:
1955+ fd.write("# Juju generated - DO NOT EDIT\n{}\n\n".format(content))
1956
1957 def configure_rally_check(self):
1958 kv = unitdata.kv()
1959- if kv.get('rallyconfigured', False):
1960+ if kv.get("rallyconfigured", False):
1961 return
1962
1963 self.update_rally_checkfiles()
1964- rally_check = os.path.join(self.plugins_dir, 'check_rally.py')
1965+ rally_check = os.path.join(self.plugins_dir, "check_rally.py")
1966 nrpe = NRPE()
1967- nrpe.add_check(shortname='rally',
1968- description='Check that all rally tests pass',
1969- check_cmd=rally_check,
1970- )
1971+ nrpe.add_check(
1972+ shortname="rally",
1973+ description="Check that all rally tests pass",
1974+ check_cmd=rally_check,
1975+ )
1976 nrpe.write()
1977- kv.set('rallyconfigured', True)
1978+ kv.set("rallyconfigured", True)
1979
1980 def remove_rally_check(self):
1981 filename = self.rally_cron_file
1982 if os.path.exists(filename):
1983 os.unlink(filename)
1984
1985- if os.path.exists('/etc/nagios/nrpe.d/check_rally.cfg'):
1986+ if os.path.exists("/etc/nagios/nrpe.d/check_rally.cfg"):
1987 nrpe = NRPE()
1988- nrpe.remove_check(shortname='rally')
1989+ nrpe.remove_check(shortname="rally")
1990 nrpe.write()
1991
1992 def deploy_rally(self):
1993@@ -729,5 +829,5 @@ class OSCHelper():
1994 self.configure_rally_check()
1995 else:
1996 self.remove_rally_check()
1997- unitdata.kv().set('rallyconfigured', False)
1998+ unitdata.kv().set("rallyconfigured", False)
1999 return True
2000diff --git a/src/reactive/openstack_service_checks.py b/src/reactive/openstack_service_checks.py
2001index f8d5a77..ede8c79 100644
2002--- a/src/reactive/openstack_service_checks.py
2003+++ b/src/reactive/openstack_service_checks.py
2004@@ -19,25 +19,32 @@ import base64
2005 import subprocess
2006
2007 from charmhelpers.core import hookenv, host, unitdata
2008-from charms.reactive import any_flags_set, clear_flag, is_flag_set, set_flag, when, when_not
2009+from charms.reactive import (
2010+ any_flags_set,
2011+ clear_flag,
2012+ is_flag_set,
2013+ set_flag,
2014+ when,
2015+ when_not,
2016+)
2017
2018 from lib_openstack_service_checks import (
2019 OSCHelper,
2020 OSCCredentialsError,
2021- OSCKeystoneError
2022+ OSCKeystoneError,
2023 )
2024
2025-CERT_FILE = '/usr/local/share/ca-certificates/openstack-service-checks.crt'
2026+CERT_FILE = "/usr/local/share/ca-certificates/openstack-service-checks.crt"
2027 helper = OSCHelper()
2028
2029
2030-@when('config.changed')
2031+@when("config.changed")
2032 def config_changed():
2033- clear_flag('openstack-service-checks.configured')
2034+ clear_flag("openstack-service-checks.configured")
2035
2036
2037-@when_not('openstack-service-checks.installed')
2038-@when('nrpe-external-master.available')
2039+@when_not("openstack-service-checks.installed")
2040+@when("nrpe-external-master.available")
2041 def install_openstack_service_checks():
2042 """Entry point to start configuring the unit
2043
2044@@ -45,22 +52,21 @@ def install_openstack_service_checks():
2045 Some relation data can be initialized if the application is related to
2046 keystone.
2047 """
2048- set_flag('openstack-service-checks.installed')
2049- clear_flag('openstack-service-checks.configured')
2050+ set_flag("openstack-service-checks.installed")
2051+ clear_flag("openstack-service-checks.configured")
2052
2053
2054-@when_not('identity-credentials.available')
2055-@when('identity-credentials.connected')
2056+@when_not("identity-credentials.available")
2057+@when("identity-credentials.connected")
2058 def configure_ident_username(keystone):
2059- """Requests a user to the Identity Service
2060- """
2061- username = 'nagios'
2062+ """Requests a user to the Identity Service"""
2063+ username = "nagios"
2064 keystone.request_credentials(username)
2065- clear_flag('openstack-service-checks.stored-creds')
2066+ clear_flag("openstack-service-checks.stored-creds")
2067
2068
2069-@when_not('openstack-service-checks.stored-creds')
2070-@when('identity-credentials.available')
2071+@when_not("openstack-service-checks.stored-creds")
2072+@when("identity-credentials.available")
2073 def save_creds(keystone):
2074 """Collect and save credentials from Keystone relation.
2075
2076@@ -68,47 +74,53 @@ def save_creds(keystone):
2077 reformat them into something the Keystone client can use, and
2078 save them into the unitdata.
2079 """
2080- creds = {'username': keystone.credentials_username(),
2081- 'password': keystone.credentials_password(),
2082- 'region': keystone.region(),
2083- }
2084- if keystone.api_version() == '3':
2085- api_url = 'v3'
2086+ creds = {
2087+ "username": keystone.credentials_username(),
2088+ "password": keystone.credentials_password(),
2089+ "region": keystone.region(),
2090+ }
2091+ if keystone.api_version() == "3":
2092+ api_url = "v3"
2093 try:
2094 domain = keystone.domain()
2095 except AttributeError:
2096- domain = 'service_domain'
2097+ domain = "service_domain"
2098 # keystone relation sends info back with funny names, fix here
2099- creds.update({'project_name': keystone.credentials_project(),
2100- 'auth_version': '3',
2101- 'user_domain_name': domain,
2102- 'project_domain_name': domain})
2103+ creds.update(
2104+ {
2105+ "project_name": keystone.credentials_project(),
2106+ "auth_version": "3",
2107+ "user_domain_name": domain,
2108+ "project_domain_name": domain,
2109+ }
2110+ )
2111 else:
2112- api_url = 'v2.0'
2113- creds['tenant_name'] = keystone.credentials_project()
2114+ api_url = "v2.0"
2115+ creds["tenant_name"] = keystone.credentials_project()
2116
2117- creds['auth_url'] = '{proto}://{host}:{port}/{api_url}'.format(
2118- proto=keystone.auth_protocol(), host=keystone.auth_host(),
2119- port=keystone.auth_port(), api_url=api_url)
2120+ creds["auth_url"] = "{proto}://{host}:{port}/{api_url}".format(
2121+ proto=keystone.auth_protocol(),
2122+ host=keystone.auth_host(),
2123+ port=keystone.auth_port(),
2124+ api_url=api_url,
2125+ )
2126
2127 helper.store_keystone_credentials(creds)
2128- set_flag('openstack-service-checks.stored-creds')
2129- clear_flag('openstack-service-checks.configured')
2130+ set_flag("openstack-service-checks.stored-creds")
2131+ clear_flag("openstack-service-checks.configured")
2132
2133
2134-@when_not('identity-credentials.connected')
2135-@when_not('identity-credentials.available')
2136-@when('openstack-service-checks.stored-creds')
2137+@when_not("identity-credentials.connected")
2138+@when_not("identity-credentials.available")
2139+@when("openstack-service-checks.stored-creds")
2140 def allow_keystone_store_overwrite():
2141- """Allow unitdata overwrite if keystone relation is recycled.
2142- """
2143- clear_flag('openstack-service-checks.stored-creds')
2144+ """Allow unitdata overwrite if keystone relation is recycled."""
2145+ clear_flag("openstack-service-checks.stored-creds")
2146
2147
2148-@when('identity-credentials.available.updated')
2149+@when("identity-credentials.available.updated")
2150 def update_keystone_store():
2151- """when identity-service-relation-changed is triggered, update the stored credentials
2152- """
2153+ """Update stored credentials when identity-service-relation-changed is triggered."""
2154 allow_keystone_store_overwrite()
2155
2156
2157@@ -123,15 +135,16 @@ def get_credentials():
2158 except OSCCredentialsError as error:
2159 creds = helper.get_keystone_credentials()
2160 if not creds:
2161- hookenv.log('render_config: No credentials yet, skipping')
2162- hookenv.status_set('blocked',
2163- 'Missing os-credentials vars: {}'.format(error))
2164+ hookenv.log("render_config: No credentials yet, skipping")
2165+ hookenv.status_set(
2166+ "blocked", "Missing os-credentials vars: {}".format(error)
2167+ )
2168 return
2169 return creds
2170
2171
2172-@when('openstack-service-checks.installed')
2173-@when_not('openstack-service-checks.configured')
2174+@when("openstack-service-checks.installed")
2175+@when_not("openstack-service-checks.configured")
2176 def render_config():
2177 """Render nrpe checks from the templates
2178
2179@@ -142,11 +155,10 @@ def render_config():
2180 Furthermore, juju config os-credentials take precedence over keystone
2181 related data.
2182 """
2183+
2184 def block_tls_failure(error):
2185- hookenv.log('update-ca-certificates failed: {}'.format(error),
2186- hookenv.ERROR)
2187- hookenv.status_set('blocked',
2188- 'update-ca-certificates error. check logs')
2189+ hookenv.log("update-ca-certificates failed: {}".format(error), hookenv.ERROR)
2190+ hookenv.status_set("blocked", "update-ca-certificates error. check logs")
2191 return
2192
2193 creds = get_credentials()
2194@@ -154,14 +166,14 @@ def render_config():
2195 return
2196
2197 # Fix TLS
2198- if helper.charm_config['trusted_ssl_ca'].strip():
2199- trusted_ssl_ca = helper.charm_config['trusted_ssl_ca'].strip()
2200- hookenv.log('Writing ssl ca cert:{}'.format(trusted_ssl_ca))
2201+ if helper.charm_config["trusted_ssl_ca"].strip():
2202+ trusted_ssl_ca = helper.charm_config["trusted_ssl_ca"].strip()
2203+ hookenv.log("Writing ssl ca cert:{}".format(trusted_ssl_ca))
2204 cert_content = base64.b64decode(trusted_ssl_ca).decode()
2205 try:
2206- with open(CERT_FILE, 'w') as fd:
2207+ with open(CERT_FILE, "w") as fd:
2208 fd.write(cert_content)
2209- subprocess.call(['/usr/sbin/update-ca-certificates'])
2210+ subprocess.call(["/usr/sbin/update-ca-certificates"])
2211
2212 except subprocess.CalledProcessError as error:
2213 block_tls_failure(error)
2214@@ -170,12 +182,14 @@ def render_config():
2215 block_tls_failure(error)
2216 return
2217
2218- hookenv.log('render_config: Got credentials for'
2219- ' username={}'.format(creds.get('username')))
2220+ hookenv.log(
2221+ "render_config: Got credentials for"
2222+ " username={}".format(creds.get("username"))
2223+ )
2224
2225 try:
2226 helper.render_checks(creds)
2227- set_flag('openstack-service-checks.endpoints.configured')
2228+ set_flag("openstack-service-checks.endpoints.configured")
2229 except OSCKeystoneError as keystone_error:
2230 _set_keystone_error_workload_status(keystone_error)
2231
2232@@ -183,13 +197,13 @@ def render_config():
2233 # Rally could not be installed (if enabled). No further actions taken
2234 return
2235
2236- set_flag('openstack-service-checks.configured')
2237- clear_flag('openstack-service-checks.started')
2238+ set_flag("openstack-service-checks.configured")
2239+ clear_flag("openstack-service-checks.started")
2240
2241
2242-@when('openstack-service-checks.installed')
2243-@when('openstack-service-checks.configured')
2244-@when_not('openstack-service-checks.endpoints.configured')
2245+@when("openstack-service-checks.installed")
2246+@when("openstack-service-checks.configured")
2247+@when_not("openstack-service-checks.endpoints.configured")
2248 def configure_nrpe_endpoints():
2249 """Create an NRPE check for each Keystone catalog endpoint.
2250
2251@@ -205,94 +219,101 @@ def configure_nrpe_endpoints():
2252
2253 try:
2254 helper.create_endpoint_checks(creds)
2255- set_flag('openstack-service-checks.endpoints.configured')
2256- clear_flag('openstack-service-checks.started')
2257+ set_flag("openstack-service-checks.endpoints.configured")
2258+ clear_flag("openstack-service-checks.started")
2259 except OSCKeystoneError as keystone_error:
2260 _set_keystone_error_workload_status(keystone_error)
2261
2262
2263-@when('identity-notifications.available.updated')
2264+@when("identity-notifications.available.updated")
2265 def endpoints_changed():
2266- clear_flag('openstack-service-checks.endpoints.configured')
2267+ clear_flag("openstack-service-checks.endpoints.configured")
2268
2269
2270-@when('openstack-service-checks.configured')
2271-@when_not('openstack-service-checks.started')
2272+@when("openstack-service-checks.configured")
2273+@when_not("openstack-service-checks.started")
2274 def do_restart():
2275- hookenv.log('Reloading nagios-nrpe-server')
2276- host.service_restart('nagios-nrpe-server')
2277- set_flag('openstack-service-checks.started')
2278+ hookenv.log("Reloading nagios-nrpe-server")
2279+ host.service_restart("nagios-nrpe-server")
2280+ set_flag("openstack-service-checks.started")
2281
2282
2283-@when('openstack-service-checks.started')
2284-@when('openstack-service-checks.endpoints.configured')
2285+@when("openstack-service-checks.started")
2286+@when("openstack-service-checks.endpoints.configured")
2287 def set_active():
2288- hookenv.status_set('active', 'Unit is ready')
2289+ hookenv.status_set("active", "Unit is ready")
2290
2291
2292-@when('nrpe-external-master.available')
2293+@when("nrpe-external-master.available")
2294 def do_reconfigure_nrpe():
2295- os_credentials_flag = 'config.changed.os-credentials'
2296- flags = ['config.changed.check_{}_urls'.format(interface) for interface in ['admin', 'internal', 'public']]
2297+ os_credentials_flag = "config.changed.os-credentials"
2298+ flags = [
2299+ "config.changed.check_{}_urls".format(interface)
2300+ for interface in ["admin", "internal", "public"]
2301+ ]
2302 flags.extend(os_credentials_flag)
2303
2304- if is_flag_set('config.changed'):
2305- clear_flag('openstack-service-checks.configured')
2306+ if is_flag_set("config.changed"):
2307+ clear_flag("openstack-service-checks.configured")
2308
2309 if any_flags_set(*flags):
2310 if is_flag_set(os_credentials_flag):
2311- clear_flag('openstack-service-checks.configured')
2312- clear_flag('openstack-service-checks.endpoints.configured')
2313+ clear_flag("openstack-service-checks.configured")
2314+ clear_flag("openstack-service-checks.endpoints.configured")
2315
2316 if helper.is_rally_enabled:
2317 helper.reconfigure_tempest()
2318
2319- if is_flag_set('config.changed.skip-rally'):
2320+ if is_flag_set("config.changed.skip-rally"):
2321 helper.update_rally_checkfiles()
2322
2323
2324-@when_not('nrpe-external-master.available')
2325+@when_not("nrpe-external-master.available")
2326 def missing_nrpe():
2327- """Avoid a user action to be missed or overwritten by another hook
2328- """
2329- if hookenv.hook_name() != 'update-status':
2330- hookenv.status_set('blocked', 'Missing relations: nrpe')
2331+ """Avoid a user action to be missed or overwritten by another hook"""
2332+ if hookenv.hook_name() != "update-status":
2333+ hookenv.status_set("blocked", "Missing relations: nrpe")
2334
2335
2336-@when('openstack-service-checks.installed')
2337-@when('nrpe-external-master.available')
2338+@when("openstack-service-checks.installed")
2339+@when("nrpe-external-master.available")
2340 def parse_hooks():
2341- if hookenv.hook_name() == 'upgrade-charm':
2342+ if hookenv.hook_name() == "upgrade-charm":
2343 # Check if creds storage needs to be migrated
2344 # Old key: keystone-relation-creds
2345 # New key: keystonecreds
2346 kv = unitdata.kv()
2347- creds = kv.get('keystonecreds')
2348- old_creds = kv.get('keystone-relation-creds')
2349+ creds = kv.get("keystonecreds")
2350+ old_creds = kv.get("keystone-relation-creds")
2351 if old_creds and not creds:
2352 # This set of creds needs an update to a newer format
2353 creds = {
2354- 'username': old_creds['credentials_username'],
2355- 'password': old_creds['credentials_password'],
2356- 'project_name': old_creds['credentials_project'],
2357- 'tenant_name': old_creds['credentials_project'],
2358- 'user_domain_name': old_creds.get('credentials_user_domain'),
2359- 'project_domain_name': old_creds.get('credentials_project_domain'),
2360- }
2361- kv.set('keystonecreds', creds)
2362+ "username": old_creds["credentials_username"],
2363+ "password": old_creds["credentials_password"],
2364+ "project_name": old_creds["credentials_project"],
2365+ "tenant_name": old_creds["credentials_project"],
2366+ "user_domain_name": old_creds.get("credentials_user_domain"),
2367+ "project_domain_name": old_creds.get("credentials_project_domain"),
2368+ }
2369+ kv.set("keystonecreds", creds)
2370
2371 if old_creds:
2372- kv.unset('keystone-relation-creds')
2373+ kv.unset("keystone-relation-creds")
2374
2375 # update rally check files and plugins, which may have changed
2376 helper.update_plugins()
2377 helper.update_rally_checkfiles()
2378
2379 # render configs again
2380- clear_flag('openstack-service-checks.configured')
2381+ clear_flag("openstack-service-checks.configured")
2382
2383
2384 def _set_keystone_error_workload_status(keystone_error):
2385- error_status_message = 'Failed to create endpoint checks due issue communicating with Keystone'
2386- hookenv.log('{}. Error:\n{}'.format(error_status_message, keystone_error), level=hookenv.ERROR)
2387- hookenv.status_set('blocked', keystone_error.workload_status)
2388+ error_status_message = (
2389+ "Failed to create endpoint checks due issue communicating with Keystone"
2390+ )
2391+ hookenv.log(
2392+ "{}. Error:\n{}".format(error_status_message, keystone_error),
2393+ level=hookenv.ERROR,
2394+ )
2395+ hookenv.status_set("blocked", keystone_error.workload_status)
2396diff --git a/src/tests/functional/conftest.py b/src/tests/functional/conftest.py
2397index 41b4b5f..948059b 100644
2398--- a/src/tests/functional/conftest.py
2399+++ b/src/tests/functional/conftest.py
2400@@ -1,4 +1,4 @@
2401-'''
2402+"""
2403 Reusable pytest fixtures for functional testing
2404
2405 Environment variables
2406@@ -6,7 +6,7 @@ Environment variables
2407
2408 test_preserve_model:
2409 if set, the testing model won't be torn down at the end of the testing session
2410-'''
2411+"""
2412
2413 import asyncio
2414 import json
2415@@ -19,7 +19,7 @@ import juju
2416 from juju.controller import Controller
2417 from juju.errors import JujuError
2418
2419-STAT_CMD = '''python3 - <<EOF
2420+STAT_CMD = """python3 - <<EOF
2421 import json
2422 import os
2423
2424@@ -34,13 +34,13 @@ stat_json = json.dumps(stat_hash)
2425 print(stat_json)
2426
2427 EOF
2428-'''
2429+"""
2430
2431
2432-@pytest.fixture(scope='module')
2433+@pytest.fixture(scope="module")
2434 def event_loop():
2435- '''Override the default pytest event loop to allow for fixtures using a
2436- broader scope'''
2437+ """Override the default pytest event loop to allow for fixtures using a
2438+ broader scope"""
2439 loop = asyncio.get_event_loop_policy().new_event_loop()
2440 asyncio.set_event_loop(loop)
2441 loop.set_debug(True)
2442@@ -49,37 +49,38 @@ def event_loop():
2443 asyncio.set_event_loop(None)
2444
2445
2446-@pytest.fixture(scope='module')
2447+@pytest.fixture(scope="module")
2448 async def controller():
2449- '''Connect to the current controller'''
2450+ """Connect to the current controller"""
2451 _controller = Controller()
2452 await _controller.connect_current()
2453 yield _controller
2454 await _controller.disconnect()
2455
2456
2457-@pytest.fixture(scope='module')
2458+@pytest.fixture(scope="module")
2459 async def model(controller):
2460- '''This model lives only for the duration of the test'''
2461- model_name = os.getenv('PYTEST_MODEL')
2462+ """This model lives only for the duration of the test"""
2463+ model_name = os.getenv("PYTEST_MODEL")
2464 if model_name is None:
2465 model_name = "functest-{}".format(str(uuid.uuid4())[-12:])
2466
2467 if model_name not in await controller.list_models():
2468- _model = await controller.add_model(model_name,
2469- cloud_name=os.getenv('PYTEST_CLOUD_NAME'),
2470- region=os.getenv('PYTEST_CLOUD_REGION'),
2471- )
2472+ _model = await controller.add_model(
2473+ model_name,
2474+ cloud_name=os.getenv("PYTEST_CLOUD_NAME"),
2475+ region=os.getenv("PYTEST_CLOUD_REGION"),
2476+ )
2477 else:
2478 _model = await controller.get_model(model_name)
2479
2480 # https://github.com/juju/python-libjuju/issues/267
2481- subprocess.check_call(['juju', 'models'])
2482+ subprocess.check_call(["juju", "models"])
2483 while model_name not in await controller.list_models():
2484 await asyncio.sleep(1)
2485 yield _model
2486 await _model.disconnect()
2487- if not os.getenv('PYTEST_KEEP_MODEL'):
2488+ if not os.getenv("PYTEST_KEEP_MODEL"):
2489 await controller.destroy_model(model_name)
2490 while model_name in await controller.list_models():
2491 await asyncio.sleep(1)
2492@@ -87,30 +88,35 @@ async def model(controller):
2493
2494 @pytest.fixture
2495 async def get_app(model):
2496- '''Returns the application requested'''
2497+ """Returns the application requested"""
2498+
2499 async def _get_app(name):
2500 try:
2501 return model.applications[name]
2502 except KeyError:
2503 raise JujuError("Cannot find application {}".format(name))
2504+
2505 return _get_app
2506
2507
2508 @pytest.fixture
2509 async def get_unit(model):
2510- '''Returns the requested <app_name>/<unit_number> unit'''
2511+ """Returns the requested <app_name>/<unit_number> unit"""
2512+
2513 async def _get_unit(name):
2514 try:
2515- (app_name, unit_number) = name.split('/')
2516+ (app_name, unit_number) = name.split("/")
2517 return model.applications[app_name].units[unit_number]
2518 except (KeyError, ValueError):
2519 raise JujuError("Cannot find unit {}".format(name))
2520+
2521 return _get_unit
2522
2523
2524 @pytest.fixture
2525 async def get_entity(get_unit, get_app):
2526- '''Returns a unit or an application'''
2527+ """Returns a unit or an application"""
2528+
2529 async def _get_entity(name):
2530 try:
2531 return await get_unit(name)
2532@@ -119,63 +125,68 @@ async def get_entity(get_unit, get_app):
2533 return await get_app(name)
2534 except JujuError:
2535 raise JujuError("Cannot find entity {}".format(name))
2536+
2537 return _get_entity
2538
2539
2540 @pytest.fixture
2541 async def run_command(get_unit):
2542- '''
2543+ """
2544 Runs a command on a unit.
2545
2546 :param cmd: Command to be run
2547 :param target: Unit object or unit name string
2548- '''
2549+ """
2550+
2551 async def _run_command(cmd, target):
2552- unit = (
2553- target
2554- if isinstance(target, juju.unit.Unit)
2555- else await get_unit(target)
2556- )
2557+ unit = target if isinstance(target, juju.unit.Unit) else await get_unit(target)
2558 action = await unit.run(cmd)
2559 return action.results
2560+
2561 return _run_command
2562
2563
2564 @pytest.fixture
2565 async def file_stat(run_command):
2566- '''
2567+ """
2568 Runs stat on a file
2569
2570 :param path: File path
2571 :param target: Unit object or unit name string
2572- '''
2573+ """
2574+
2575 async def _file_stat(path, target):
2576 cmd = STAT_CMD % path
2577 results = await run_command(cmd, target)
2578 assert results["Code"] == "0", "Error stat {} on {}: {}".format(
2579- path, target, results.get("Stderr", "?"))
2580- return json.loads(results['Stdout'])
2581+ path, target, results.get("Stderr", "?")
2582+ )
2583+ return json.loads(results["Stdout"])
2584+
2585 return _file_stat
2586
2587
2588 @pytest.fixture
2589 async def file_contents(run_command):
2590- '''
2591+ """
2592 Returns the contents of a file
2593
2594 :param path: File path
2595 :param target: Unit object or unit name string
2596- '''
2597+ """
2598+
2599 async def _file_contents(path, target):
2600- cmd = 'cat {}'.format(path)
2601+ cmd = "cat {}".format(path)
2602 results = await run_command(cmd, target)
2603- return results['Stdout']
2604+ return results["Stdout"]
2605+
2606 return _file_contents
2607
2608
2609 @pytest.fixture
2610 async def reconfigure_app(get_app, model):
2611- '''Applies a different config to the requested app'''
2612+ """Applies a different config to the requested app"""
2613+
2614 async def _reconfigure_app(cfg, target):
2615 application = (
2616 target
2617@@ -184,5 +195,6 @@ async def reconfigure_app(get_app, model):
2618 )
2619 await application.set_config(cfg)
2620 await application.get_config()
2621- await model.block_until(lambda: application.status == 'active')
2622+ await model.block_until(lambda: application.status == "active")
2623+
2624 return _reconfigure_app
2625diff --git a/src/tests/functional/test_deploy.py b/src/tests/functional/test_deploy.py
2626index c14ff02..e7d5782 100644
2627--- a/src/tests/functional/test_deploy.py
2628+++ b/src/tests/functional/test_deploy.py
2629@@ -7,19 +7,20 @@ import pytest
2630 pytestmark = pytest.mark.asyncio
2631
2632 SERIES = [
2633- 'xenial',
2634- 'bionic',
2635- 'focal',
2636+ "xenial",
2637+ "bionic",
2638+ "focal",
2639 ]
2640-CHARM_BUILD_DIR = os.getenv('CHARM_BUILD_DIR', '.').rstrip('/')
2641+CHARM_BUILD_DIR = os.getenv("CHARM_BUILD_DIR", ".").rstrip("/")
2642
2643
2644 # Custom fixtures
2645
2646-@pytest.fixture(scope='module', params=SERIES)
2647+
2648+@pytest.fixture(scope="module", params=SERIES)
2649 async def osc_apps(request, model):
2650 series = request.param
2651- app = model.applications.get('openstack-service-checks-{}'.format(series))
2652+ app = model.applications.get("openstack-service-checks-{}".format(series))
2653 return app
2654
2655
2656@@ -28,15 +29,26 @@ class ActionFailed(Exception):
2657
2658 def __init__(self, action):
2659 """Set information about action failure in message and raise."""
2660- params = {key: getattr(action, key, "<not-set>")
2661- for key in ['name', 'parameters', 'receiver',
2662- 'message', 'id', 'status',
2663- 'enqueued', 'started', 'completed']}
2664- message = ('Run of action "{name}" with parameters "{parameters}" on '
2665- '"{receiver}" failed with "{message}" (id={id} '
2666- 'status={status} enqueued={enqueued} started={started} '
2667- 'completed={completed})'
2668- .format(**params))
2669+ params = {
2670+ key: getattr(action, key, "<not-set>")
2671+ for key in [
2672+ "name",
2673+ "parameters",
2674+ "receiver",
2675+ "message",
2676+ "id",
2677+ "status",
2678+ "enqueued",
2679+ "started",
2680+ "completed",
2681+ ]
2682+ }
2683+ message = (
2684+ 'Run of action "{name}" with parameters "{parameters}" on '
2685+ '"{receiver}" failed with "{message}" (id={id} '
2686+ "status={status} enqueued={enqueued} started={started} "
2687+ "completed={completed})".format(**params)
2688+ )
2689 super(ActionFailed, self).__init__(message)
2690
2691
2692@@ -47,18 +59,17 @@ class Agent:
2693 async def _act(self, action, **kwargs):
2694 action_obj = await self.unit.run_action(action, **kwargs)
2695 await action_obj.wait()
2696- if action_obj.status != 'completed':
2697+ if action_obj.status != "completed":
2698 raise ActionFailed(action_obj)
2699
2700 def status(self, status):
2701- return (self.unit.workload_status == status and
2702- self.unit.agent_status == 'idle')
2703+ return self.unit.workload_status == status and self.unit.agent_status == "idle"
2704
2705 async def pause(self):
2706- await self._act('pause')
2707+ await self._act("pause")
2708
2709 async def resume(self):
2710- await self._act('resume')
2711+ await self._act("resume")
2712
2713 async def block_until(self, lambda_f, timeout=600, wait_period=1):
2714 await self.unit.model.block_until(
2715@@ -68,21 +79,28 @@ class Agent:
2716
2717 def app_names(series=None):
2718 apps = {
2719- app: app for app in
2720- ['keystone', 'neutron-api', 'nova-cloud-controller',
2721- 'percona-cluster', 'rabbitmq-server', 'nagios', 'ceph-radosgw']
2722+ app: app
2723+ for app in [
2724+ "keystone",
2725+ "neutron-api",
2726+ "nova-cloud-controller",
2727+ "percona-cluster",
2728+ "rabbitmq-server",
2729+ "nagios",
2730+ "ceph-radosgw",
2731+ ]
2732 }
2733 if not series:
2734 return apps
2735
2736- for app in ['openstack-service-checks', 'nrpe']:
2737- apps[app] = '{}-{}'.format(app, series)
2738+ for app in ["openstack-service-checks", "nrpe"]:
2739+ apps[app] = "{}-{}".format(app, series)
2740 return apps
2741
2742
2743-@pytest.fixture(scope='module')
2744+@pytest.fixture(scope="module")
2745 async def deploy_openstack(model):
2746- blocking_apps = {'nova-cloud-controller', 'ceph-radosgw'}
2747+ blocking_apps = {"nova-cloud-controller", "ceph-radosgw"}
2748 apps = app_names()
2749 active_apps = []
2750 is_deployed = False
2751@@ -92,8 +110,9 @@ async def deploy_openstack(model):
2752 active_apps.append(model.applications[app])
2753 is_deployed = True
2754 continue
2755- app_deploy = await model.deploy('cs:{}'.format(app), series='bionic',
2756- application_name=app, num_units=1)
2757+ app_deploy = await model.deploy(
2758+ "cs:{}".format(app), series="bionic", application_name=app, num_units=1
2759+ )
2760 if app not in blocking_apps:
2761 # we don't expect blocking apps to become active as we don't
2762 # configure them fully for this test
2763@@ -103,49 +122,71 @@ async def deploy_openstack(model):
2764 yield active_apps
2765 return
2766
2767- await model.add_relation('{}:shared-db'.format(apps['keystone']),
2768- '{}:shared-db'.format(apps['percona-cluster']))
2769+ await model.add_relation(
2770+ "{}:shared-db".format(apps["keystone"]),
2771+ "{}:shared-db".format(apps["percona-cluster"]),
2772+ )
2773
2774- for app in 'neutron-api nova-cloud-controller'.split():
2775+ for app in "neutron-api nova-cloud-controller".split():
2776 # Note(aluria): Both neutron/nova APIs needs rmq, mysql, keystone
2777- await model.add_relation('{}:amqp'.format(apps[app]),
2778- '{}:amqp'.format(apps['rabbitmq-server']))
2779- await model.add_relation('{}:shared-db'.format(apps[app]),
2780- '{}:shared-db'.format(apps['percona-cluster']))
2781- await model.add_relation('{}:identity-service'.format(apps[app]),
2782- '{}:identity-service'.format(apps['keystone']))
2783- await model.add_relation('{}:identity-service'.format(apps['ceph-radosgw']),
2784- '{}:identity-service'.format(apps['keystone']))
2785+ await model.add_relation(
2786+ "{}:amqp".format(apps[app]), "{}:amqp".format(apps["rabbitmq-server"])
2787+ )
2788+ await model.add_relation(
2789+ "{}:shared-db".format(apps[app]),
2790+ "{}:shared-db".format(apps["percona-cluster"]),
2791+ )
2792+ await model.add_relation(
2793+ "{}:identity-service".format(apps[app]),
2794+ "{}:identity-service".format(apps["keystone"]),
2795+ )
2796+ await model.add_relation(
2797+ "{}:identity-service".format(apps["ceph-radosgw"]),
2798+ "{}:identity-service".format(apps["keystone"]),
2799+ )
2800 yield active_apps
2801
2802
2803-@pytest.fixture(scope='module', params=SERIES)
2804+@pytest.fixture(scope="module", params=SERIES)
2805 async def deploy_app(request, deploy_openstack, model):
2806- await model.block_until(lambda: all([app.status == 'active' for app in deploy_openstack]),
2807- timeout=1200)
2808+ await model.block_until(
2809+ lambda: all([app.status == "active" for app in deploy_openstack]), timeout=1200
2810+ )
2811 series = request.param
2812 apps = app_names(series)
2813
2814 # Starts a deploy for each series
2815- if (apps['nrpe'] in model.applications
2816- and apps['openstack-service-checks'] in model.applications):
2817- yield model.applications[apps['openstack-service-checks']]
2818+ if (
2819+ apps["nrpe"] in model.applications
2820+ and apps["openstack-service-checks"] in model.applications
2821+ ):
2822+ yield model.applications[apps["openstack-service-checks"]]
2823 return
2824
2825- await model.deploy('cs:nrpe', series=series, application_name=apps['nrpe'], num_units=0)
2826- osc_app = await model.deploy(os.path.join(CHARM_BUILD_DIR, 'openstack-service-checks'),
2827- series=series, application_name=apps['openstack-service-checks'])
2828+ await model.deploy(
2829+ "cs:nrpe", series=series, application_name=apps["nrpe"], num_units=0
2830+ )
2831+ osc_app = await model.deploy(
2832+ os.path.join(CHARM_BUILD_DIR, "openstack-service-checks"),
2833+ series=series,
2834+ application_name=apps["openstack-service-checks"],
2835+ )
2836
2837 # Add relations: nagios/nrpe, keystone/osc, nrpe/osc
2838- await model.add_relation('{}:monitors'.format(apps['nrpe']),
2839- '{}:monitors'.format(apps['nagios']))
2840- await model.add_relation(apps['nrpe'], apps['openstack-service-checks'])
2841+ await model.add_relation(
2842+ "{}:monitors".format(apps["nrpe"]), "{}:monitors".format(apps["nagios"])
2843+ )
2844+ await model.add_relation(apps["nrpe"], apps["openstack-service-checks"])
2845 credrel = "{}:identity-credentials"
2846- await model.add_relation(credrel.format(apps['keystone']),
2847- credrel.format(apps['openstack-service-checks']))
2848+ await model.add_relation(
2849+ credrel.format(apps["keystone"]),
2850+ credrel.format(apps["openstack-service-checks"]),
2851+ )
2852 notifrel = "{}:identity-notifications"
2853- await model.add_relation(notifrel.format(apps['keystone']),
2854- notifrel.format(apps['openstack-service-checks']))
2855+ await model.add_relation(
2856+ notifrel.format(apps["keystone"]),
2857+ notifrel.format(apps["openstack-service-checks"]),
2858+ )
2859 yield osc_app
2860
2861
2862@@ -157,107 +198,142 @@ def unit_from(model, name):
2863
2864 # Tests
2865 async def test_openstackservicechecks_deploy_openstack(deploy_openstack, model):
2866- await model.block_until(lambda: all([app.status == 'active' for app in deploy_openstack]),
2867- timeout=1200)
2868+ await model.block_until(
2869+ lambda: all([app.status == "active" for app in deploy_openstack]), timeout=1200
2870+ )
2871
2872
2873 async def test_openstackservicechecks_deploy(deploy_app, model):
2874- await model.block_until(lambda: deploy_app.status == 'active', timeout=1200)
2875+ await model.block_until(lambda: deploy_app.status == "active", timeout=1200)
2876
2877
2878-async def test_openstackservicechecks_verify_default_nrpe_checks(deploy_app, model, file_stat):
2879+async def test_openstackservicechecks_verify_default_nrpe_checks(
2880+ deploy_app, model, file_stat
2881+):
2882 unit = unit_from(model, deploy_app.name)
2883- endpoint_checks_config = ['check_{endpoint}_urls'.format(endpoint=endpoint)
2884- for endpoint in 'admin internal public'.split()]
2885+ endpoint_checks_config = [
2886+ "check_{endpoint}_urls".format(endpoint=endpoint)
2887+ for endpoint in "admin internal public".split()
2888+ ]
2889 await deploy_app.reset_config(endpoint_checks_config)
2890 # Wait until nrpe checks are created
2891- await model.block_until(lambda: deploy_app.status == 'active' and unit.agent_status == 'idle',
2892- timeout=600)
2893+ await model.block_until(
2894+ lambda: deploy_app.status == "active" and unit.agent_status == "idle",
2895+ timeout=600,
2896+ )
2897 filenames = [
2898- '/etc/nagios/nrpe.d/check_{service}_{endpoint}.cfg'.format(service=service, endpoint=endpoint)
2899- for service in 'keystone neutron nova placement swift'.split()
2900- for endpoint in 'admin internal public'.split()
2901+ "/etc/nagios/nrpe.d/check_{service}_{endpoint}.cfg".format(
2902+ service=service, endpoint=endpoint
2903+ )
2904+ for service in "keystone neutron nova placement swift".split()
2905+ for endpoint in "admin internal public".split()
2906 ]
2907- filenames.extend([
2908- '/etc/nagios/nrpe.d/check_cinder_services.cfg',
2909- '/etc/nagios/nrpe.d/check_neutron_agents.cfg',
2910- '/etc/nagios/nrpe.d/check_nova_services.cfg',
2911- ])
2912+ filenames.extend(
2913+ [
2914+ "/etc/nagios/nrpe.d/check_cinder_services.cfg",
2915+ "/etc/nagios/nrpe.d/check_neutron_agents.cfg",
2916+ "/etc/nagios/nrpe.d/check_nova_services.cfg",
2917+ ]
2918+ )
2919 for filename in filenames:
2920 test_stat = await file_stat(filename, unit)
2921- assert test_stat['size'] > 0
2922+ assert test_stat["size"] > 0
2923
2924
2925 async def test_openstackservicechecks_update_endpoint(deploy_app, model, file_stat):
2926 unit = unit_from(model, deploy_app.name)
2927- keystone = model.applications['keystone']
2928+ keystone = model.applications["keystone"]
2929 assert len(keystone.units) == 1
2930 kst_unit = keystone.units[0]
2931- rgw = model.applications['ceph-radosgw']
2932+ rgw = model.applications["ceph-radosgw"]
2933 assert len(rgw.units) == 1
2934- expect_port = '8080'
2935- await rgw.set_config({'port': expect_port})
2936+ expect_port = "8080"
2937+ await rgw.set_config({"port": expect_port})
2938 # avoid jumping over the config change (test script faster than Juju controller)
2939 await asyncio.sleep(2)
2940- await model.block_until(lambda: rgw.units[0].agent_status == 'idle',
2941- timeout=600, wait_period=1)
2942- await model.block_until(lambda: keystone.status == 'active' and kst_unit.agent_status == 'idle',
2943- timeout=600, wait_period=1)
2944- await model.block_until(lambda: deploy_app.status == 'active' and unit.agent_status == 'idle',
2945- timeout=600, wait_period=1)
2946+ await model.block_until(
2947+ lambda: rgw.units[0].agent_status == "idle", timeout=600, wait_period=1
2948+ )
2949+ await model.block_until(
2950+ lambda: keystone.status == "active" and kst_unit.agent_status == "idle",
2951+ timeout=600,
2952+ wait_period=1,
2953+ )
2954+ await model.block_until(
2955+ lambda: deploy_app.status == "active" and unit.agent_status == "idle",
2956+ timeout=600,
2957+ wait_period=1,
2958+ )
2959 for _ in range(10):
2960 # Need to retry this as endpoint update takes some time to propagate
2961 check_configs = []
2962- for endpoint in 'admin internal public'.split():
2963- filename = '/etc/nagios/nrpe.d/check_swift_{}.cfg'.format(endpoint)
2964- action = await unit.run('cat {}'.format(filename))
2965+ for endpoint in "admin internal public".split():
2966+ filename = "/etc/nagios/nrpe.d/check_swift_{}.cfg".format(endpoint)
2967+ action = await unit.run("cat {}".format(filename))
2968 result = action.results
2969- assert result["Code"] == "0", "Error {}: {}".format(filename, result["Stderr"])
2970+ assert result["Code"] == "0", "Error {}: {}".format(
2971+ filename, result["Stderr"]
2972+ )
2973 check_configs.append(result["Stdout"])
2974 if all([" -p {} ".format(expect_port) in s for s in check_configs]):
2975 break
2976 await asyncio.sleep(4)
2977 else:
2978 assert False, "Port {} not in all endpoints: {}".format(
2979- expect_port, check_configs)
2980+ expect_port, check_configs
2981+ )
2982
2983
2984-async def test_openstackservicechecks_remove_endpoint_checks(deploy_app, model, file_stat):
2985+async def test_openstackservicechecks_remove_endpoint_checks(
2986+ deploy_app, model, file_stat
2987+):
2988 unit = unit_from(model, deploy_app.name)
2989- endpoint_checks_config = {'check_{endpoint}_urls'.format(endpoint=endpoint): 'false'
2990- for endpoint in 'admin internal public'.split()}
2991+ endpoint_checks_config = {
2992+ "check_{endpoint}_urls".format(endpoint=endpoint): "false"
2993+ for endpoint in "admin internal public".split()
2994+ }
2995 await deploy_app.set_config(endpoint_checks_config)
2996 # Wait until nrpe checks are removed
2997- await model.block_until(lambda: deploy_app.status == 'active' and unit.agent_status == 'idle',
2998- timeout=600)
2999+ await model.block_until(
3000+ lambda: deploy_app.status == "active" and unit.agent_status == "idle",
3001+ timeout=600,
3002+ )
3003 filenames = [
3004- '/etc/nagios/nrpe.d/check_{service}_{endpoint}.cfg'.format(service=service, endpoint=endpoint)
3005- for service in 'keystone neutron nova placement'.split()
3006- for endpoint in 'admin internal public'.split()
3007+ "/etc/nagios/nrpe.d/check_{service}_{endpoint}.cfg".format(
3008+ service=service, endpoint=endpoint
3009+ )
3010+ for service in "keystone neutron nova placement".split()
3011+ for endpoint in "admin internal public".split()
3012 ]
3013 for filename in filenames:
3014 # raises exception because filename does not exist
3015 with pytest.raises(AssertionError):
3016 await file_stat(filename, unit)
3017 # re-enable endpoint checks
3018- endpoint_checks_config = ['check_{endpoint}_urls'.format(endpoint=endpoint)
3019- for endpoint in 'admin internal public'.split()]
3020+ endpoint_checks_config = [
3021+ "check_{endpoint}_urls".format(endpoint=endpoint)
3022+ for endpoint in "admin internal public".split()
3023+ ]
3024 await deploy_app.reset_config(endpoint_checks_config)
3025- await model.block_until(lambda: deploy_app.status == 'active' and unit.agent_status == 'idle',
3026- timeout=600)
3027+ await model.block_until(
3028+ lambda: deploy_app.status == "active" and unit.agent_status == "idle",
3029+ timeout=600,
3030+ )
3031
3032
3033 async def test_openstackservicechecks_enable_rally(deploy_app, model, file_stat):
3034 unit = unit_from(model, deploy_app.name)
3035- filenames = ['/etc/cron.d/osc_rally', '/etc/nagios/nrpe.d/check_rally.cfg']
3036+ filenames = ["/etc/cron.d/osc_rally", "/etc/nagios/nrpe.d/check_rally.cfg"]
3037
3038 # disable rally nrpe check if it was enabled (ie. from a previous run of functests)
3039 config = await deploy_app.get_config()
3040- if config['check-rally']['value']:
3041- await deploy_app.set_config({'check-rally': 'false'})
3042+ if config["check-rally"]["value"]:
3043+ await deploy_app.set_config({"check-rally": "false"})
3044 # Wait until nrpe check is set
3045- await model.block_until(lambda: deploy_app.status == 'active' and unit.agent_status == 'idle',
3046- timeout=600)
3047+ await model.block_until(
3048+ lambda: deploy_app.status == "active" and unit.agent_status == "idle",
3049+ timeout=600,
3050+ )
3051
3052 # Check BEFORE enabling check-rally
3053 for filename in filenames:
3054@@ -265,116 +341,140 @@ async def test_openstackservicechecks_enable_rally(deploy_app, model, file_stat)
3055 with pytest.raises(AssertionError):
3056 await file_stat(filename, unit)
3057
3058- await deploy_app.set_config({'check-rally': 'true'})
3059+ await deploy_app.set_config({"check-rally": "true"})
3060 # Wait until nrpe check is set
3061- await model.block_until(lambda: deploy_app.status == 'active' and unit.agent_status == 'idle',
3062- timeout=600)
3063+ await model.block_until(
3064+ lambda: deploy_app.status == "active" and unit.agent_status == "idle",
3065+ timeout=600,
3066+ )
3067
3068 # Check AFTER enabling check-rally
3069 for filename in filenames:
3070 test_stat = await file_stat(filename, unit)
3071- assert test_stat['size'] > 0
3072+ assert test_stat["size"] > 0
3073
3074
3075-async def test_openstackservicechecks_enable_contrail_analytics_vip(deploy_app, model, file_stat, file_contents):
3076+async def test_openstackservicechecks_enable_contrail_analytics_vip(
3077+ deploy_app, model, file_stat, file_contents
3078+):
3079 unit = unit_from(model, deploy_app.name)
3080- filename = '/etc/nagios/nrpe.d/check_contrail_analytics_alarms.cfg'
3081+ filename = "/etc/nagios/nrpe.d/check_contrail_analytics_alarms.cfg"
3082
3083 # disable contrail nrpe check if it was enabled
3084 # (ie. from a previous run of functests)
3085 config = await deploy_app.get_config()
3086- if config['contrail_analytics_vip']['value']:
3087- await deploy_app.set_config({'contrail_analytics_vip': ''})
3088+ if config["contrail_analytics_vip"]["value"]:
3089+ await deploy_app.set_config({"contrail_analytics_vip": ""})
3090 # Wait until nrpe check is set
3091- await model.block_until(lambda: deploy_app.status == 'active' and unit.agent_status == 'idle',
3092- timeout=600)
3093+ await model.block_until(
3094+ lambda: deploy_app.status == "active" and unit.agent_status == "idle",
3095+ timeout=600,
3096+ )
3097
3098 # Check BEFORE enabling contrail_analytics_vip
3099 # raises exception because filename does not exist
3100 with pytest.raises(AssertionError):
3101 await file_stat(filename, unit)
3102
3103- await deploy_app.set_config({
3104- 'contrail_analytics_vip': '127.0.0.1',
3105- 'contrail_ignored_alarms': 'vrouter,testable'
3106- })
3107+ await deploy_app.set_config(
3108+ {
3109+ "contrail_analytics_vip": "127.0.0.1",
3110+ "contrail_ignored_alarms": "vrouter,testable",
3111+ }
3112+ )
3113 # Wait until nrpe check is set
3114- await model.block_until(lambda: deploy_app.status == 'active' and unit.agent_status == 'idle',
3115- timeout=600)
3116+ await model.block_until(
3117+ lambda: deploy_app.status == "active" and unit.agent_status == "idle",
3118+ timeout=600,
3119+ )
3120
3121 # Check AFTER enabling contrail_analytics_vip
3122 test_stat = await file_stat(filename, unit)
3123- assert test_stat['size'] > 0
3124+ assert test_stat["size"] > 0
3125
3126 # Get Contents after enabling contrail_analytics_vip
3127 test_content = await file_contents(filename, unit)
3128 assert "--ignored vrouter,testable" in test_content
3129
3130
3131-async def test_openstackservicechecks_disable_check_neutron_agents(deploy_app, model, file_stat):
3132+async def test_openstackservicechecks_disable_check_neutron_agents(
3133+ deploy_app, model, file_stat
3134+):
3135 unit = unit_from(model, deploy_app.name)
3136- filename = '/etc/nagios/nrpe.d/check_neutron_agents.cfg'
3137+ filename = "/etc/nagios/nrpe.d/check_neutron_agents.cfg"
3138
3139- # disable neutron_agents nrpe check if it was enabled (ie. from a previous run of functests)
3140+ # disable neutron_agents nrpe check if it was enabled
3141+ # i.e. from a previous run of functests
3142 config = await deploy_app.get_config()
3143- if config['check-neutron-agents']['value']:
3144- await deploy_app.set_config({'check-neutron-agents': 'false'})
3145+ if config["check-neutron-agents"]["value"]:
3146+ await deploy_app.set_config({"check-neutron-agents": "false"})
3147 # Wait until nrpe check is set
3148- await model.block_until(lambda: deploy_app.status == 'active' and unit.agent_status == 'idle',
3149- timeout=600)
3150+ await model.block_until(
3151+ lambda: deploy_app.status == "active" and unit.agent_status == "idle",
3152+ timeout=600,
3153+ )
3154
3155 # Check BEFORE enabling neutron_agents check
3156 # raises exception because filename does not exist
3157 with pytest.raises(AssertionError):
3158 await file_stat(filename, unit)
3159
3160- await deploy_app.set_config({'check-neutron-agents': 'true'})
3161+ await deploy_app.set_config({"check-neutron-agents": "true"})
3162 # Wait until nrpe check is set
3163- await model.block_until(lambda: deploy_app.status == 'active' and unit.agent_status == 'idle',
3164- timeout=600)
3165+ await model.block_until(
3166+ lambda: deploy_app.status == "active" and unit.agent_status == "idle",
3167+ timeout=600,
3168+ )
3169
3170 # Check AFTER enabling neutron_agents check
3171 test_stat = await file_stat(filename, unit)
3172- assert test_stat['size'] > 0
3173+ assert test_stat["size"] > 0
3174
3175
3176-@pytest.fixture(scope='module')
3177+@pytest.fixture(scope="module")
3178 async def paused_keystone(deploy_app, deploy_openstack, model):
3179- await model.block_until(lambda: all([app.status == 'active' for app in deploy_openstack]),
3180- timeout=1200)
3181- keystone = model.applications['keystone']
3182- agent = Agent(unit_from(model, 'keystone'))
3183+ await model.block_until(
3184+ lambda: all([app.status == "active" for app in deploy_openstack]), timeout=1200
3185+ )
3186+ keystone = model.applications["keystone"]
3187+ agent = Agent(unit_from(model, "keystone"))
3188
3189 # get default port
3190 kst_cfg = await keystone.get_config()
3191- default_port = kst_cfg['service-port'].get('value') or kst_cfg['service-port'].get('default')
3192+ default_port = kst_cfg["service-port"].get("value") or kst_cfg["service-port"].get(
3193+ "default"
3194+ )
3195 new_svc_port = int(default_port) + 1
3196
3197 # adjust keystone config service-port
3198- await keystone.set_config({'service-port': str(new_svc_port)})
3199- await agent.block_until(lambda: agent.status('active'))
3200+ await keystone.set_config({"service-port": str(new_svc_port)})
3201+ await agent.block_until(lambda: agent.status("active"))
3202
3203 # pause keystone
3204 await agent.pause()
3205- await agent.block_until(lambda: agent.status('maintenance'))
3206+ await agent.block_until(lambda: agent.status("maintenance"))
3207
3208 yield keystone
3209
3210 # resume keystone
3211 await agent.resume()
3212- await agent.block_until(lambda: agent.status('active'))
3213+ await agent.block_until(lambda: agent.status("active"))
3214
3215 # restore service-port
3216- await keystone.set_config({'service-port': str(default_port)})
3217- await agent.block_until(lambda: agent.status('active'))
3218+ await keystone.set_config({"service-port": str(default_port)})
3219+ await agent.block_until(lambda: agent.status("active"))
3220
3221
3222 @pytest.mark.usefixtures("paused_keystone")
3223-async def test_openstackservicechecks_invalid_keystone_workload_status(model, deploy_app):
3224+async def test_openstackservicechecks_invalid_keystone_workload_status(
3225+ model, deploy_app
3226+):
3227 agent = Agent(unit_from(model, deploy_app.name))
3228
3229 # Wait for osc app to block with expected workload-status
3230- await agent.block_until(lambda: agent.status('blocked'))
3231- assert agent.unit.workload_status_message == \
3232- 'Keystone server error was encountered trying to list keystone ' \
3233- 'resources. Check keystone server health. View juju logs for more info.'
3234+ await agent.block_until(lambda: agent.status("blocked"))
3235+ assert (
3236+ agent.unit.workload_status_message
3237+ == "Keystone server error was encountered trying to list keystone "
3238+ "resources. Check keystone server health. View juju logs for more info."
3239+ )
3240diff --git a/src/tests/nagios_plugin/setup.py b/src/tests/nagios_plugin/setup.py
3241index e0301bb..90f14d5 100644
3242--- a/src/tests/nagios_plugin/setup.py
3243+++ b/src/tests/nagios_plugin/setup.py
3244@@ -5,36 +5,36 @@ import urllib.request
3245
3246
3247 with TemporaryDirectory() as tempd:
3248- URL = 'https://git.launchpad.net/nrpe-charm/plain/files/nagios_plugin3.py'
3249+ URL = "https://git.launchpad.net/nrpe-charm/plain/files/nagios_plugin3.py"
3250 script = os.path.join(tempd, os.path.basename(URL))
3251- with open(script, 'wb') as dest_f:
3252+ with open(script, "wb") as dest_f:
3253 print("downloading {}".format(URL))
3254 dest_f.write(urllib.request.urlopen(URL).read())
3255 print("writing {}".format(script))
3256 setup(
3257- name='nagios_plugin3',
3258- description='nagios plugin from the NRPE charm',
3259+ name="nagios_plugin3",
3260+ description="nagios plugin from the NRPE charm",
3261 download_url=URL,
3262 project_urls={
3263- 'nrpe source': 'https://git.launchpad.net/nrpe-charm/',
3264- 'nrpe issues': 'https://bugs.launchpad.net/charm-nrpe',
3265+ "nrpe source": "https://git.launchpad.net/nrpe-charm/",
3266+ "nrpe issues": "https://bugs.launchpad.net/charm-nrpe",
3267 },
3268 classifiers=[
3269- 'Environment :: Plugins',
3270- 'Intended Audience :: Developers',
3271- 'Intended Audience :: System Administrators',
3272- 'Operating System :: POSIX',
3273- 'Programming Language :: Python :: 2.7',
3274- 'Programming Language :: Python :: 3.4',
3275- 'Programming Language :: Python :: 3.5',
3276- 'Programming Language :: Python :: 3.6',
3277- 'Programming Language :: Python :: 3.7',
3278- 'Topic :: Software Development :: Libraries :: Python Modules',
3279- 'Topic :: System :: Monitoring',
3280+ "Environment :: Plugins",
3281+ "Intended Audience :: Developers",
3282+ "Intended Audience :: System Administrators",
3283+ "Operating System :: POSIX",
3284+ "Programming Language :: Python :: 2.7",
3285+ "Programming Language :: Python :: 3.4",
3286+ "Programming Language :: Python :: 3.5",
3287+ "Programming Language :: Python :: 3.6",
3288+ "Programming Language :: Python :: 3.7",
3289+ "Topic :: Software Development :: Libraries :: Python Modules",
3290+ "Topic :: System :: Monitoring",
3291 ],
3292- keywords='nrpe nagios plugin check monitoring',
3293- author='Llama Charmers',
3294- author_email='llama-charmers@lists.ubuntu.com ',
3295- package_dir={'': tempd},
3296- packages=['']
3297+ keywords="nrpe nagios plugin check monitoring",
3298+ author="Llama Charmers",
3299+ author_email="llama-charmers@lists.ubuntu.com ",
3300+ package_dir={"": tempd},
3301+ packages=[""],
3302 )
3303diff --git a/src/tests/unit/conftest.py b/src/tests/unit/conftest.py
3304index 9266259..e379711 100644
3305--- a/src/tests/unit/conftest.py
3306+++ b/src/tests/unit/conftest.py
3307@@ -7,7 +7,7 @@ import pytest
3308 TEST_DIR = dirname(abspath(__file__))
3309 REACTIVE_DIR = dirname(dirname(TEST_DIR))
3310 CHARM_DIR = REACTIVE_DIR
3311-CHECKS_DIR = join(CHARM_DIR, 'files', 'plugins')
3312+CHECKS_DIR = join(CHARM_DIR, "files", "plugins")
3313 sys.path.append(CHECKS_DIR)
3314
3315
3316@@ -16,19 +16,20 @@ sys.path.append(CHECKS_DIR)
3317 @pytest.fixture
3318 def mock_layers(monkeypatch):
3319 import sys
3320- sys.modules['charms.layer'] = mock.Mock()
3321- sys.modules['reactive'] = mock.Mock()
3322+
3323+ sys.modules["charms.layer"] = mock.Mock()
3324+ sys.modules["reactive"] = mock.Mock()
3325 # Mock any functions in layers that need to be mocked here
3326
3327 def options(layer):
3328 # mock options for layers here
3329- if layer == 'example-layer':
3330- options = {'port': 9999}
3331+ if layer == "example-layer":
3332+ options = {"port": 9999}
3333 return options
3334 else:
3335 return None
3336
3337- monkeypatch.setattr('lib_openstack_service_checks.layer.options', options)
3338+ monkeypatch.setattr("lib_openstack_service_checks.layer.options", options)
3339
3340
3341 @pytest.fixture
3342@@ -37,49 +38,58 @@ def mock_hookenv_config(monkeypatch):
3343
3344 def mock_config():
3345 cfg = {}
3346- yml = yaml.safe_load(open('./config.yaml'))
3347+ yml = yaml.safe_load(open("./config.yaml"))
3348
3349 # Load all defaults
3350- for key, value in yml['options'].items():
3351- cfg[key] = value['default']
3352+ for key, value in yml["options"].items():
3353+ cfg[key] = value["default"]
3354
3355 # Manually add cfg from other layers
3356 # cfg['my-other-layer'] = 'mock'
3357 return cfg
3358
3359- monkeypatch.setattr('lib_openstack_service_checks.hookenv.config', mock_config)
3360+ monkeypatch.setattr("lib_openstack_service_checks.hookenv.config", mock_config)
3361
3362
3363 @pytest.fixture
3364 def mock_remote_unit(monkeypatch):
3365- monkeypatch.setattr('lib_openstack_service_checks.hookenv.remote_unit', lambda: 'unit-mock/0')
3366+ monkeypatch.setattr(
3367+ "lib_openstack_service_checks.hookenv.remote_unit", lambda: "unit-mock/0"
3368+ )
3369
3370
3371 @pytest.fixture
3372 def mock_charm_dir(monkeypatch):
3373- monkeypatch.setattr('lib_openstack_service_checks.hookenv.charm_dir', lambda: '/mock/charm/dir')
3374+ monkeypatch.setattr(
3375+ "lib_openstack_service_checks.hookenv.charm_dir", lambda: "/mock/charm/dir"
3376+ )
3377
3378
3379 @pytest.fixture
3380 def mock_unitdata_keystonecreds(monkeypatch):
3381- creds = {'keystonecreds': {'username': 'nagios',
3382- 'password': 'password',
3383- 'project_name': 'services',
3384- 'tenant_name': 'services',
3385- 'user_domain_name': 'service_domain',
3386- 'project_domain_name': 'service_domain',
3387- }
3388- }
3389- monkeypatch.setattr('lib_openstack_service_checks.unitdata.kv', lambda: creds)
3390+ creds = {
3391+ "keystonecreds": {
3392+ "username": "nagios",
3393+ "password": "password",
3394+ "project_name": "services",
3395+ "tenant_name": "services",
3396+ "user_domain_name": "service_domain",
3397+ "project_domain_name": "service_domain",
3398+ }
3399+ }
3400+ monkeypatch.setattr("lib_openstack_service_checks.unitdata.kv", lambda: creds)
3401
3402
3403 @pytest.fixture
3404 def openstackservicechecks(tmpdir, mock_hookenv_config, mock_charm_dir, monkeypatch):
3405 from lib_openstack_service_checks import OSCHelper
3406+
3407 helper = OSCHelper()
3408
3409 # Any other functions that load helper will get this version
3410- monkeypatch.setattr('lib_openstack_service_checks.hookenv.log', lambda msg, level='INFO': None)
3411- monkeypatch.setattr('lib_openstack_service_checks.OSCHelper', lambda: helper)
3412+ monkeypatch.setattr(
3413+ "lib_openstack_service_checks.hookenv.log", lambda msg, level="INFO": None
3414+ )
3415+ monkeypatch.setattr("lib_openstack_service_checks.OSCHelper", lambda: helper)
3416
3417 return helper
3418diff --git a/src/tests/unit/test_check_contrail_analytics_alarms.py b/src/tests/unit/test_check_contrail_analytics_alarms.py
3419index d397bc9..663814a 100644
3420--- a/src/tests/unit/test_check_contrail_analytics_alarms.py
3421+++ b/src/tests/unit/test_check_contrail_analytics_alarms.py
3422@@ -7,10 +7,12 @@ TEST_DIR = dirname(abspath(__file__))
3423
3424
3425 def test_parse_contrail_alarms():
3426- with open(join(TEST_DIR, 'contrail_alert_data.json')) as f:
3427+ with open(join(TEST_DIR, "contrail_alert_data.json")) as f:
3428 data = json.load(f)
3429 parsed = check_contrail_analytics_alarms.parse_contrail_alarms(data)
3430- assert parsed in """
3431+ assert (
3432+ parsed
3433+ in """
3434 CRITICAL: total_alarms[11], unacked_or_sev_gt_0[10], total_ignored[0], ignoring r''
3435 CRITICAL: vrouter{compute-10.maas, sev=1, ts[2020-06-25 18:29:23.149146]} Vrouter interface(s) down.
3436 WARNING: control-node{control-8-contrail-rmq, sev=0, ts[2020-06-25 18:29:23.684803]} Node Failure. NodeStatus UVE not present.
3437@@ -23,46 +25,67 @@ CRITICAL: control-node{control-9.maas, sev=1, ts[2020-06-25 18:29:25.183842]} BG
3438 CRITICAL: vrouter{compute-3.maas, sev=1, ts[2020-06-26 12:20:58.955855]} Vrouter interface(s) down.
3439 CRITICAL: vrouter{compute-1.maas, sev=1, ts[2020-06-29 13:01:53.459050]} Vrouter interface(s) down.
3440 CRITICAL: vrouter{compute-7.maas, sev=1, ts[2020-07-03 18:30:32.481386]} Vrouter interface(s) down.
3441-""" # noqa: ignore=F501
3442+""" # noqa:E501
3443+ )
3444
3445
3446 def test_parse_contrail_alarms_filter_vrouter_control_9():
3447- with open(join(TEST_DIR, 'contrail_alert_data.json')) as f:
3448+ with open(join(TEST_DIR, "contrail_alert_data.json")) as f:
3449 data = json.load(f)
3450- ignored_re = r'(?:vrouter)|(?:control-9)'
3451- parsed = check_contrail_analytics_alarms.parse_contrail_alarms(data, ignored=ignored_re)
3452- assert parsed in """
3453+ ignored_re = r"(?:vrouter)|(?:control-9)"
3454+ parsed = check_contrail_analytics_alarms.parse_contrail_alarms(
3455+ data, ignored=ignored_re
3456+ )
3457+ assert (
3458+ parsed
3459+ in """
3460 CRITICAL: total_alarms[11], unacked_or_sev_gt_0[10], total_ignored[8], ignoring r'(?:vrouter)|(?:control-9)'
3461 WARNING: control-node{control-8-contrail-rmq, sev=0, ts[2020-06-25 18:29:23.684803]} Node Failure. NodeStatus UVE not present.
3462 CRITICAL: control-node{control-8.maas, sev=1, ts[2020-06-25 18:29:24.293341]} BGP peer mismatch. Not enough BGP peers are up.
3463 CRITICAL: control-node{control-7-contrail-rmq, sev=1, ts[2020-06-25 18:29:24.377040]} BGP peer mismatch. Not enough BGP peers are up.
3464-""" # noqa: ignore=F501
3465+""" # noqa:E501
3466+ )
3467
3468
3469 def test_parse_contrail_alarms_filter_critical():
3470- with open(join(TEST_DIR, 'contrail_alert_data.json')) as f:
3471+ with open(join(TEST_DIR, "contrail_alert_data.json")) as f:
3472 data = json.load(f)
3473- ignored_re = r'(?:CRITICAL)'
3474- parsed = check_contrail_analytics_alarms.parse_contrail_alarms(data, ignored=ignored_re)
3475- assert parsed in """
3476+ ignored_re = r"(?:CRITICAL)"
3477+ parsed = check_contrail_analytics_alarms.parse_contrail_alarms(
3478+ data, ignored=ignored_re
3479+ )
3480+ assert (
3481+ parsed
3482+ in """
3483 WARNING: total_alarms[11], unacked_or_sev_gt_0[10], total_ignored[10], ignoring r'(?:CRITICAL)'
3484 WARNING: control-node{control-8-contrail-rmq, sev=0, ts[2020-06-25 18:29:23.684803]} Node Failure. NodeStatus UVE not present.
3485-""" # noqa: ignore=F501
3486+""" # noqa: E501
3487+ )
3488
3489
3490 def test_parse_contrail_alarms_all_ignored():
3491- with open(join(TEST_DIR, 'contrail_alert_data.json')) as f:
3492+ with open(join(TEST_DIR, "contrail_alert_data.json")) as f:
3493 data = json.load(f)
3494- ignored_re = r'(?:CRITICAL)|(?:WARNING)'
3495- parsed = check_contrail_analytics_alarms.parse_contrail_alarms(data, ignored=ignored_re)
3496- assert parsed in """
3497+ ignored_re = r"(?:CRITICAL)|(?:WARNING)"
3498+ parsed = check_contrail_analytics_alarms.parse_contrail_alarms(
3499+ data, ignored=ignored_re
3500+ )
3501+ assert (
3502+ parsed
3503+ in """
3504 OK: total_alarms[11], unacked_or_sev_gt_0[10], total_ignored[11], ignoring r'(?:CRITICAL)|(?:WARNING)'
3505-""" # noqa: ignore=F501
3506+""" # noqa:E501
3507+ )
3508
3509
3510 def test_parse_contrail_alarms_no_alarms():
3511- ignored_re = r''
3512- parsed = check_contrail_analytics_alarms.parse_contrail_alarms({}, ignored=ignored_re)
3513- assert parsed in """
3514+ ignored_re = r""
3515+ parsed = check_contrail_analytics_alarms.parse_contrail_alarms(
3516+ {}, ignored=ignored_re
3517+ )
3518+ assert (
3519+ parsed
3520+ in """
3521 OK: total_alarms[0], unacked_or_sev_gt_0[0], total_ignored[0], ignoring r''
3522 """
3523+ )
3524diff --git a/src/tests/unit/test_check_nova_services.py b/src/tests/unit/test_check_nova_services.py
3525index dad32a6..816ec73 100644
3526--- a/src/tests/unit/test_check_nova_services.py
3527+++ b/src/tests/unit/test_check_nova_services.py
3528@@ -4,13 +4,15 @@ import nagios_plugin3
3529 import check_nova_services
3530
3531
3532-@pytest.mark.parametrize('is_skip_disabled,num_nodes',
3533- [
3534- (True, 5),
3535- (False, 5),
3536- (True, 2),
3537- (False, 2),
3538- ])
3539+@pytest.mark.parametrize(
3540+ "is_skip_disabled,num_nodes",
3541+ [
3542+ (True, 5),
3543+ (False, 5),
3544+ (True, 2),
3545+ (False, 2),
3546+ ],
3547+)
3548 def test_check_hosts_up(is_skip_disabled, num_nodes):
3549 class _TestArgs(object):
3550 warn = 2
3551@@ -18,42 +20,46 @@ def test_check_hosts_up(is_skip_disabled, num_nodes):
3552 skip_disabled = is_skip_disabled
3553
3554 args = _TestArgs()
3555- aggregate = '(not-part-of-any-agg)'
3556+ aggregate = "(not-part-of-any-agg)"
3557 services_compute = [
3558- {u'status': (u'disabled' if id == 0 else u'enabled'),
3559- u'binary': u'nova-compute',
3560- u'zone': u'nova',
3561- u'state': u'up',
3562- u'updated_at': u'2019-07-04T09:23:06.000000',
3563- u'host': u'juju-3efade-{}'.format(id),
3564- u'disabled_reason': None,
3565- u'id': id,
3566- }
3567+ {
3568+ u"status": (u"disabled" if id == 0 else u"enabled"),
3569+ u"binary": u"nova-compute",
3570+ u"zone": u"nova",
3571+ u"state": u"up",
3572+ u"updated_at": u"2019-07-04T09:23:06.000000",
3573+ u"host": u"juju-3efade-{}".format(id),
3574+ u"disabled_reason": None,
3575+ u"id": id,
3576+ }
3577 for id in range(num_nodes)
3578 ]
3579- hosts = [svc['host'] for svc in services_compute]
3580+ hosts = [svc["host"] for svc in services_compute]
3581
3582- msg_text = 'Host juju-3efade-0 disabled'
3583+ msg_text = "Host juju-3efade-0 disabled"
3584 if num_nodes <= 2:
3585 # 1 host enabled + 1 host disabled == 1 host alive (<=1)
3586 status_critical = True
3587- msg_text = ('{}, Host Aggregate (not-part-of-any-agg) has 1 hosts alive'
3588- .format(msg_text))
3589+ msg_text = "{}, Host Aggregate (not-part-of-any-agg) has 1 hosts alive".format(
3590+ msg_text
3591+ )
3592 else:
3593 # more than args.crit (1) hosts alive (4)
3594 status_critical = False
3595
3596 expected = {
3597- 'agg_name': aggregate,
3598- 'msg_text': msg_text,
3599- 'critical': status_critical,
3600- 'warning': not is_skip_disabled or num_nodes <= args.warn,
3601+ "agg_name": aggregate,
3602+ "msg_text": msg_text,
3603+ "critical": status_critical,
3604+ "warning": not is_skip_disabled or num_nodes <= args.warn,
3605 }
3606- actual = check_nova_services.check_hosts_up(args, aggregate, hosts, services_compute)
3607+ actual = check_nova_services.check_hosts_up(
3608+ args, aggregate, hosts, services_compute
3609+ )
3610 assert actual == expected
3611
3612
3613-@pytest.mark.parametrize('is_skip_disabled', [True, False])
3614+@pytest.mark.parametrize("is_skip_disabled", [True, False])
3615 def test_check_nova_services(is_skip_disabled, monkeypatch):
3616 class _TestArgs(object):
3617 warn = 2
3618@@ -66,34 +72,41 @@ def test_check_nova_services(is_skip_disabled, monkeypatch):
3619
3620 class _TestNovaJson(object):
3621 def json(cls):
3622- return {'aggregates': [],
3623- 'services': [
3624- {u'status': (u'disabled' if id == 0 else u'enabled'),
3625- u'binary': u'nova-compute',
3626- u'zone': u'nova',
3627- u'state': u'up',
3628- u'updated_at': u'2019-07-04T09:23:06.000000',
3629- u'host': u'juju-3efade-{}'.format(id),
3630- u'disabled_reason': None,
3631- u'id': id,
3632- }
3633- for id in range(5)]
3634+ return {
3635+ "aggregates": [],
3636+ "services": [
3637+ {
3638+ u"status": (u"disabled" if id == 0 else u"enabled"),
3639+ u"binary": u"nova-compute",
3640+ u"zone": u"nova",
3641+ u"state": u"up",
3642+ u"updated_at": u"2019-07-04T09:23:06.000000",
3643+ u"host": u"juju-3efade-{}".format(id),
3644+ u"disabled_reason": None,
3645+ u"id": id,
3646 }
3647+ for id in range(5)
3648+ ],
3649+ }
3650
3651 args = _TestArgs()
3652 nova = _TestNova()
3653 check_hosts_up_expected = {
3654- 'agg_name': '(not-part-of-any-agg)',
3655- 'msg_text': 'Host juju-3efade-0 disabled',
3656- 'critical': False,
3657- 'warning': not is_skip_disabled,
3658+ "agg_name": "(not-part-of-any-agg)",
3659+ "msg_text": "Host juju-3efade-0 disabled",
3660+ "critical": False,
3661+ "warning": not is_skip_disabled,
3662 }
3663- monkeypatch.setattr('check_nova_services.check_hosts_up',
3664- lambda args, aggregate, hosts, svcs_compute: check_hosts_up_expected)
3665+ monkeypatch.setattr(
3666+ "check_nova_services.check_hosts_up",
3667+ lambda args, aggregate, hosts, svcs_compute: check_hosts_up_expected,
3668+ )
3669
3670 if is_skip_disabled:
3671 assert check_nova_services.check_nova_services(args, nova) is None
3672 else:
3673 with pytest.raises(nagios_plugin3.WarnError) as excinfo:
3674 check_nova_services.check_nova_services(args, nova)
3675- assert str(excinfo.value) == 'WARNING: nova-compute, Host juju-3efade-0 disabled'
3676+ assert (
3677+ str(excinfo.value) == "WARNING: nova-compute, Host juju-3efade-0 disabled"
3678+ )
3679diff --git a/src/tests/unit/test_check_octavia.py b/src/tests/unit/test_check_octavia.py
3680index 08c9357..5f871e8 100644
3681--- a/src/tests/unit/test_check_octavia.py
3682+++ b/src/tests/unit/test_check_octavia.py
3683@@ -7,111 +7,128 @@ import check_octavia
3684 import pytest
3685
3686
3687-@mock.patch('check_octavia.openstack.connect')
3688-@pytest.mark.parametrize('check', [
3689- 'loadbalancers', 'pools', "amphorae", "image"
3690-])
3691+@mock.patch("check_octavia.openstack.connect")
3692+@pytest.mark.parametrize("check", ["loadbalancers", "pools", "amphorae", "image"])
3693 def test_stable_alarms(connect, check):
3694 args = mock.MagicMock()
3695- args.ignored = r''
3696+ args.ignored = r""
3697 args.check = check
3698 if check == "amphorae":
3699 # Present 0 Amphora instances
3700 resp = connect().load_balancer.get()
3701 resp.status_code = 200
3702- resp.content = json.dumps({'amphora': []})
3703+ resp.content = json.dumps({"amphora": []})
3704 elif check == "image":
3705 # Present 1 Active Fresh Amphora image
3706- args.amp_image_tag = 'octavia'
3707+ args.amp_image_tag = "octavia"
3708 args.amp_image_days = 1
3709 amp_image = mock.MagicMock()
3710- amp_image.status = 'active'
3711+ amp_image.status = "active"
3712 amp_image.updated_at = datetime.now().isoformat()
3713 connect().image.images.return_value = [amp_image]
3714
3715 status, message = check_octavia.process_checks(args)
3716- assert message in """
3717+ assert (
3718+ message
3719+ in """
3720 OK: total_alarms[0], total_crit[0], total_ignored[0], ignoring r''
3721 """
3722+ )
3723 assert status == check_octavia.NAGIOS_STATUS_OK
3724
3725
3726-@mock.patch('check_octavia.openstack.connect')
3727+@mock.patch("check_octavia.openstack.connect")
3728 def test_no_images_is_ignorable(connect):
3729 args = mock.MagicMock()
3730- args.ignored = 'none exist'
3731+ args.ignored = "none exist"
3732 args.check = "image"
3733 # Present 1 Active Fresh Amphora image
3734- args.amp_image_tag = 'octavia'
3735+ args.amp_image_tag = "octavia"
3736 args.amp_image_days = 1
3737 connect().image.images.return_value = []
3738
3739 status, message = check_octavia.process_checks(args)
3740- assert message in """
3741+ assert (
3742+ message
3743+ in """
3744 OK: total_alarms[1], total_crit[1], total_ignored[1], ignoring r'(?:none exist)'
3745 """
3746+ )
3747 assert status == check_octavia.NAGIOS_STATUS_OK
3748
3749
3750-@mock.patch('check_octavia.openstack.connect')
3751+@mock.patch("check_octavia.openstack.connect")
3752 def test_no_images(connect):
3753 args = mock.MagicMock()
3754- args.ignored = r''
3755+ args.ignored = r""
3756 args.check = "image"
3757 # Present 1 Active Fresh Amphora image
3758- args.amp_image_tag = 'octavia'
3759+ args.amp_image_tag = "octavia"
3760 args.amp_image_days = 1
3761 connect().image.images.return_value = []
3762
3763 status, message = check_octavia.process_checks(args)
3764- assert message in """
3765+ assert (
3766+ message
3767+ in """
3768 CRITICAL: total_alarms[1], total_crit[1], total_ignored[0], ignoring r''
3769 Octavia requires image with tag octavia to create amphora, but none exist
3770 """
3771+ )
3772 assert status == check_octavia.NAGIOS_STATUS_CRITICAL
3773
3774
3775-@mock.patch('check_octavia.openstack.connect')
3776+@mock.patch("check_octavia.openstack.connect")
3777 def test_no_active_images(connect):
3778 args = mock.MagicMock()
3779- args.ignored = r''
3780+ args.ignored = r""
3781 args.check = "image"
3782 # Present 1 Active Fresh Amphora image
3783- args.amp_image_tag = 'octavia'
3784+ args.amp_image_tag = "octavia"
3785 args.amp_image_days = 1
3786 amp_image = mock.MagicMock()
3787 amp_image.name = "bob-the-image"
3788 amp_image.id = str(uuid4())
3789- amp_image.status = 'inactive'
3790+ amp_image.status = "inactive"
3791 amp_image.updated_at = datetime.now().isoformat()
3792 connect().image.images.return_value = [amp_image]
3793
3794 status, message = check_octavia.process_checks(args)
3795- assert message in """
3796+ assert (
3797+ message
3798+ in """
3799 CRITICAL: total_alarms[1], total_crit[1], total_ignored[0], ignoring r''
3800 Octavia requires image with tag octavia to create amphora, but none are active: bob-the-image({})
3801-""".format(amp_image.id)
3802+""".format( # noqa:E501
3803+ amp_image.id
3804+ )
3805+ )
3806 assert status == check_octavia.NAGIOS_STATUS_CRITICAL
3807
3808
3809-@mock.patch('check_octavia.openstack.connect')
3810+@mock.patch("check_octavia.openstack.connect")
3811 def test_no_fresh_images(connect):
3812 args = mock.MagicMock()
3813- args.ignored = r''
3814+ args.ignored = r""
3815 args.check = "image"
3816 # Present 1 Active Fresh Amphora image
3817- args.amp_image_tag = 'octavia'
3818+ args.amp_image_tag = "octavia"
3819 args.amp_image_days = 1
3820 amp_image = mock.MagicMock()
3821 amp_image.name = "bob-the-image"
3822 amp_image.id = str(uuid4())
3823- amp_image.status = 'active'
3824+ amp_image.status = "active"
3825 amp_image.updated_at = (datetime.now() - timedelta(days=2)).isoformat()
3826 connect().image.images.return_value = [amp_image]
3827
3828 status, message = check_octavia.process_checks(args)
3829- assert message in """
3830+ assert (
3831+ message
3832+ in """
3833 WARNING: total_alarms[1], total_crit[0], total_ignored[0], ignoring r''
3834 Octavia requires image with tag octavia to create amphora, but all images are older than 1 day(s): bob-the-image({})
3835-""".format(amp_image.id)
3836+""".format( # noqa:E501
3837+ amp_image.id
3838+ )
3839+ )
3840 assert status == check_octavia.NAGIOS_STATUS_WARNING
3841diff --git a/src/tests/unit/test_lib.py b/src/tests/unit/test_lib.py
3842index 5d4767a..674285d 100644
3843--- a/src/tests/unit/test_lib.py
3844+++ b/src/tests/unit/test_lib.py
3845@@ -3,86 +3,122 @@ from unittest.mock import MagicMock
3846 import pytest
3847 import keystoneauth1
3848
3849-from lib_openstack_service_checks import OSCKeystoneServerError, OSCKeystoneClientError, OSCSslError
3850+from lib_openstack_service_checks import (
3851+ OSCKeystoneServerError,
3852+ OSCKeystoneClientError,
3853+ OSCSslError,
3854+)
3855
3856
3857 def test_openstackservicechecks_common_properties(openstackservicechecks):
3858- '''Verify the most common properties from the class or default config.yaml'''
3859+ """Verify the most common properties from the class or default config.yaml"""
3860 assert isinstance(openstackservicechecks.charm_config, dict)
3861- assert openstackservicechecks.check_dns == ''
3862- assert openstackservicechecks.contrail_analytics_vip == ''
3863+ assert openstackservicechecks.check_dns == ""
3864+ assert openstackservicechecks.contrail_analytics_vip == ""
3865 assert openstackservicechecks.is_neutron_agents_check_enabled
3866 assert not openstackservicechecks.is_rally_enabled
3867- assert openstackservicechecks.novarc == '/var/lib/nagios/nagios.novarc'
3868+ assert openstackservicechecks.novarc == "/var/lib/nagios/nagios.novarc"
3869 assert openstackservicechecks.nova_crit == 1
3870 assert openstackservicechecks.nova_warn == 2
3871- assert openstackservicechecks.plugins_dir == '/usr/local/lib/nagios/plugins/'
3872- assert openstackservicechecks.rally_cron_schedule == '*/15 * * * *'
3873- assert openstackservicechecks.skip_disabled == ''
3874+ assert openstackservicechecks.plugins_dir == "/usr/local/lib/nagios/plugins/"
3875+ assert openstackservicechecks.rally_cron_schedule == "*/15 * * * *"
3876+ assert openstackservicechecks.skip_disabled == ""
3877 assert not openstackservicechecks.skipped_rally_checks
3878
3879
3880 def test_openstackservicechecks_get_keystone_credentials_unitdata(
3881- openstackservicechecks, mock_unitdata_keystonecreds):
3882- """Checks the expected behavior when 'os-credentials' are not shared, but the application is related to keystone.
3883- """
3884+ openstackservicechecks, mock_unitdata_keystonecreds
3885+):
3886+ """Check expected behavior when 'os-credentials' not shared, but related to ks."""
3887 assert openstackservicechecks.get_keystone_credentials() == {
3888- 'username': 'nagios', 'password': 'password', 'project_name': 'services',
3889- 'tenant_name': 'services', 'user_domain_name': 'service_domain',
3890- 'project_domain_name': 'service_domain'
3891- }
3892+ "username": "nagios",
3893+ "password": "password",
3894+ "project_name": "services",
3895+ "tenant_name": "services",
3896+ "user_domain_name": "service_domain",
3897+ "project_domain_name": "service_domain",
3898+ }
3899
3900
3901-@pytest.mark.parametrize('os_credentials,expected', [
3902- (('username=nagios, password=password, region_name=RegionOne, auth_url="http://XX.XX.XX.XX:5000/v3",'
3903- 'credentials_project=services, domain=service_domain'),
3904- {'username': 'nagios', 'password': 'password', 'project_name': 'services', 'auth_version': 3,
3905- 'user_domain_name': 'service_domain', 'project_domain_name': 'service_domain', 'region_name': 'RegionOne',
3906- 'auth_url': 'http://XX.XX.XX.XX:5000/v3'},
3907- ),
3908- (('username=nagios, password=password, region_name=RegionOne, auth_url="http://XX.XX.XX.XX:5000/v2.0",'
3909- 'credentials_project=services'),
3910- {'username': 'nagios', 'password': 'password', 'tenant_name': 'services', 'region_name': 'RegionOne',
3911- 'auth_url': 'http://XX.XX.XX.XX:5000/v2.0'},
3912- )
3913-])
3914+@pytest.mark.parametrize(
3915+ "os_credentials,expected",
3916+ [
3917+ (
3918+ (
3919+ 'username=nagios, password=password, region_name=RegionOne, auth_url="http://XX.XX.XX.XX:5000/v3",' # noqa:E501
3920+ "credentials_project=services, domain=service_domain"
3921+ ),
3922+ {
3923+ "username": "nagios",
3924+ "password": "password",
3925+ "project_name": "services",
3926+ "auth_version": 3,
3927+ "user_domain_name": "service_domain",
3928+ "project_domain_name": "service_domain",
3929+ "region_name": "RegionOne",
3930+ "auth_url": "http://XX.XX.XX.XX:5000/v3",
3931+ },
3932+ ),
3933+ (
3934+ (
3935+ 'username=nagios, password=password, region_name=RegionOne, auth_url="http://XX.XX.XX.XX:5000/v2.0",' # noqa:E501
3936+ "credentials_project=services"
3937+ ),
3938+ {
3939+ "username": "nagios",
3940+ "password": "password",
3941+ "tenant_name": "services",
3942+ "region_name": "RegionOne",
3943+ "auth_url": "http://XX.XX.XX.XX:5000/v2.0",
3944+ },
3945+ ),
3946+ ],
3947+)
3948 def test_openstackservicechecks_get_keystone_credentials_oscredentials(
3949- os_credentials, expected, openstackservicechecks, mock_unitdata_keystonecreds):
3950- """Checks the expected behavior when keystone v2 and v3 data is shared via the 'os-credentials' config parameter.
3951- """
3952- openstackservicechecks.charm_config['os-credentials'] = os_credentials
3953+ os_credentials, expected, openstackservicechecks, mock_unitdata_keystonecreds
3954+):
3955+ """Check the expected behavior when keystone v2 and v3 data is set via config."""
3956+ openstackservicechecks.charm_config["os-credentials"] = os_credentials
3957 assert openstackservicechecks.get_os_credentials() == expected
3958
3959
3960-@pytest.mark.parametrize('skip_rally,result', [
3961- ('nova,neutron', [True, True, False, False]),
3962- ('cinder,neutron', [False, True, True, False]),
3963- ('glance', [True, False, True, True]),
3964- ('nova neutron', [True, True, True, True]), # needs to be comma-separated
3965- ('', [True, True, True, True]),
3966-])
3967+@pytest.mark.parametrize(
3968+ "skip_rally,result",
3969+ [
3970+ ("nova,neutron", [True, True, False, False]),
3971+ ("cinder,neutron", [False, True, True, False]),
3972+ ("glance", [True, False, True, True]),
3973+ ("nova neutron", [True, True, True, True]), # needs to be comma-separated
3974+ ("", [True, True, True, True]),
3975+ ],
3976+)
3977 def test_get_rally_checks_context(skip_rally, result, openstackservicechecks):
3978- openstackservicechecks.charm_config['skip-rally'] = skip_rally
3979- expected = {comp: result[num]
3980- for num, comp in enumerate('cinder glance nova neutron'.split())}
3981+ openstackservicechecks.charm_config["skip-rally"] = skip_rally
3982+ expected = {
3983+ comp: result[num]
3984+ for num, comp in enumerate("cinder glance nova neutron".split())
3985+ }
3986 assert openstackservicechecks._get_rally_checks_context() == expected
3987
3988
3989-@pytest.mark.parametrize('keystone_auth_exception,expected_raised_exception', [
3990- (keystoneauth1.exceptions.http.InternalServerError, OSCKeystoneServerError),
3991- (keystoneauth1.exceptions.connection.ConnectFailure, OSCKeystoneServerError),
3992- (keystoneauth1.exceptions.http.BadRequest, OSCKeystoneClientError),
3993- (keystoneauth1.exceptions.connection.SSLError, OSCSslError),
3994-])
3995-@pytest.mark.parametrize('source', ["endpoints", "services"])
3996+@pytest.mark.parametrize(
3997+ "keystone_auth_exception,expected_raised_exception",
3998+ [
3999+ (keystoneauth1.exceptions.http.InternalServerError, OSCKeystoneServerError),
4000+ (keystoneauth1.exceptions.connection.ConnectFailure, OSCKeystoneServerError),
4001+ (keystoneauth1.exceptions.http.BadRequest, OSCKeystoneClientError),
4002+ (keystoneauth1.exceptions.connection.SSLError, OSCSslError),
4003+ ],
4004+)
4005+@pytest.mark.parametrize("source", ["endpoints", "services"])
4006 def test_keystone_client_exceptions(
4007- keystone_auth_exception, expected_raised_exception,
4008- openstackservicechecks, source):
4009+ keystone_auth_exception, expected_raised_exception, openstackservicechecks, source
4010+):
4011 mock_keystone_client = MagicMock()
4012 getattr(mock_keystone_client, source).list.side_effect = keystone_auth_exception
4013 openstackservicechecks._keystone_client = mock_keystone_client
4014 with pytest.raises(expected_raised_exception):
4015- if source == 'endpoints':
4016+ if source == "endpoints":
4017 openstackservicechecks.keystone_endpoints
4018 else:
4019 openstackservicechecks.keystone_services
4020diff --git a/src/tox.ini b/src/tox.ini
4021index 4d8ee9d..e00666c 100644
4022--- a/src/tox.ini
4023+++ b/src/tox.ini
4024@@ -25,7 +25,7 @@ passenv =
4025 [testenv:lint]
4026 commands =
4027 flake8
4028- #TODO black --check --exclude "/(\.eggs|\.git|\.tox|\.venv|\.build|dist|charmhelpers|mod)/" .
4029+ black --check --exclude "/(\.eggs|\.git|\.tox|\.venv|\.build|dist|charmhelpers|mod)/" .
4030 deps =
4031 black
4032 flake8
4033@@ -49,8 +49,7 @@ exclude =
4034 mod,
4035 .build
4036
4037-max-line-length = 120
4038-#TODO max-line-length = 88
4039+max-line-length = 88
4040 max-complexity = 10
4041
4042 [testenv:black]

Subscribers

People subscribed via source and target branches