Merge ~xavpaice/charm-telegraf:blacken-20.08 into charm-telegraf:master

Proposed by Xav Paice
Status: Merged
Approved by: Alvaro Uria
Approved revision: 29b50c584187bd1f687e49ffee321d5eda0d3ca4
Merged at revision: 7a23dee3004cf081dbf37a2b5ac365bdf1e8671f
Proposed branch: ~xavpaice/charm-telegraf:blacken-20.08
Merge into: charm-telegraf:master
Prerequisite: ~xavpaice/charm-telegraf:makefile-20.08
Diff against target: 4403 lines (+1427/-1179)
11 files modified
src/files/telegraf_exec_metrics.py (+135/-104)
src/hooks/relations/apache-website/requires.py (+4/-4)
src/hooks/relations/statistics/requires.py (+6/-6)
src/hooks/relations/telegraf-exec/requires.py (+15/-15)
src/reactive/telegraf.py (+549/-450)
src/tests/functional/tests/test_telegraf.py (+46/-24)
src/tests/unit/__init__.py (+2/-1)
src/tests/unit/test_mysql.py (+55/-50)
src/tests/unit/test_postgresql.py (+89/-68)
src/tests/unit/test_telegraf.py (+524/-455)
src/tox.ini (+2/-2)
Reviewer Review Type Date Requested Status
Alvaro Uria (community) Approve
Celia Wang Approve
Canonical IS Reviewers Pending
Review via email: mp+388542@code.launchpad.net

Commit message

Blackened repository to 88 lines

To post a comment you must log in.
Revision history for this message
🤖 Canonical IS Merge Bot (canonical-is-mergebot) wrote :

This merge proposal is being monitored by mergebot. Change the status to Approved to merge.

Revision history for this message
🤖 Canonical IS Merge Bot (canonical-is-mergebot) wrote :

Unable to determine commit message from repository - please click "Set commit message" and enter the commit message manually.

Revision history for this message
Celia Wang (ziyiwang) wrote :

LGTM

review: Approve
Revision history for this message
Alvaro Uria (aluria) wrote :

+1 to this and the other 2 related MPs (makefile and linting)

review: Approve
Revision history for this message
🤖 Canonical IS Merge Bot (canonical-is-mergebot) wrote :

Change has no commit message, setting status to needs review.

Revision history for this message
🤖 Canonical IS Merge Bot (canonical-is-mergebot) wrote :

Change successfully merged at revision 7a23dee3004cf081dbf37a2b5ac365bdf1e8671f

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/src/files/telegraf_exec_metrics.py b/src/files/telegraf_exec_metrics.py
2index 6922e01..f03e23a 100755
3--- a/src/files/telegraf_exec_metrics.py
4+++ b/src/files/telegraf_exec_metrics.py
5@@ -27,89 +27,91 @@ def register_metric(MetricClass):
6
7
8 class FileMetric:
9- name = ''
10- input_file = ''
11- config_template = dedent('''
12+ name = ""
13+ input_file = ""
14+ config_template = dedent(
15+ """
16 [[inputs.exec]]
17 commands = ["{python} {script} --metric {name}"]
18 name_override = "{name}"
19 data_format = "json"
20- ''')
21+ """
22+ )
23
24 def config_path(self, configs_dir):
25- return os.path.join(configs_dir, '{}.conf'.format(self.name))
26+ return os.path.join(configs_dir, "{}.conf".format(self.name))
27
28 def render_config(self, configs_dir, python, dry_run=False):
29 config_path = self.config_path(configs_dir)
30- LOG.info('rendering config to %s', config_path)
31+ LOG.info("rendering config to %s", config_path)
32 script = os.path.abspath(__file__)
33 output = self.config_template.format(
34- python=python or sys.executable,
35- script=script,
36- name=self.name,
37+ python=python or sys.executable, script=script, name=self.name,
38 )
39 LOG.debug(output)
40 if not dry_run:
41- with open(config_path, mode='w', encoding='utf8') as f:
42+ with open(config_path, mode="w", encoding="utf8") as f:
43 f.write(output)
44 return output
45
46 def remove_config(self, configs_dir, dry_run=False):
47 config_path = self.config_path(configs_dir)
48 if os.path.isfile(config_path):
49- LOG.info('removing %s', config_path)
50+ LOG.info("removing %s", config_path)
51 if not dry_run:
52 os.remove(config_path)
53 else:
54- LOG.info('config file %s is absent, skip removing', config_path)
55+ LOG.info("config file %s is absent, skip removing", config_path)
56
57 def get_input_content(self):
58- with open(self.input_file, mode='r', encoding='utf8') as f:
59+ with open(self.input_file, mode="r", encoding="utf8") as f:
60 return f.read()
61
62 def parse(self, input_content):
63- raise NotImplementedError('parse method not implemented for this metric')
64+ raise NotImplementedError("parse method not implemented for this metric")
65
66
67 @register_metric
68 class SockStatFileMetric(FileMetric):
69- name = 'sockstat'
70- input_file = '/proc/net/sockstat'
71+ name = "sockstat"
72+ input_file = "/proc/net/sockstat"
73
74 def parse(self, content):
75 results = {}
76 for line in content.splitlines():
77- LOG.debug('parsing line: %s', line)
78+ LOG.debug("parsing line: %s", line)
79 # line example: TCP: inuse 62 orphan 0 tw 5 alloc 222 mem 20
80- key, value = line.split(':', maxsplit=1)
81+ key, value = line.split(":", maxsplit=1)
82 items = value.strip().split()
83 count = len(items)
84 assert count % 2 == 0
85 group = {}
86 for i in range(0, count, 2):
87- group[items[i]] = int(items[i+1])
88+ group[items[i]] = int(items[i + 1])
89 results[key.strip()] = group
90 return results
91
92
93 @register_metric
94 class SockStat6FileMetric(SockStatFileMetric):
95- name = 'sockstat6'
96- input_file = '/proc/net/sockstat6'
97+ name = "sockstat6"
98+ input_file = "/proc/net/sockstat6"
99
100
101 @register_metric
102 class SoftNetStatFileMetric(FileMetric):
103- name = 'softnet_stat'
104- input_file = '/proc/net/softnet_stat'
105+ name = "softnet_stat"
106+ input_file = "/proc/net/softnet_stat"
107 # customize config template with tag_keys
108- config_template = dedent('''
109+ config_template = dedent(
110+ """
111 [[inputs.exec]]
112 commands = ["{python} {script} --metric {name}"]
113 name_override = "{name}"
114 data_format = "json"
115 tag_keys = ["cpu"]
116- ''')
117+ """
118+ )
119
120 def parse(self, input_content):
121 """Use package `insights` to parse /proc/net/softnet_stat file content.
122@@ -133,85 +135,98 @@ class SoftNetStatFileMetric(FileMetric):
123 cpu_nstats = softnet_stats.cpu_nstats
124
125 for i, cpu_nstat in enumerate(cpu_nstats):
126- cpu_nstat['cpu'] = 'cpu{}'.format(i)
127+ cpu_nstat["cpu"] = "cpu{}".format(i)
128
129 return cpu_nstats
130
131
132 @register_metric
133 class BuddyinfoFileMetric(FileMetric):
134- name = 'buddyinfo'
135- input_file = '/proc/buddyinfo'
136+ name = "buddyinfo"
137+ input_file = "/proc/buddyinfo"
138 # customize config template with tag_keys
139- config_template = dedent('''
140+ config_template = dedent(
141+ """
142 [[inputs.exec]]
143 commands = ["{python} {script} --metric {name}"]
144 name_override = "{name}"
145 data_format = "json"
146 tag_keys = ["node", "zone", "size"]
147- ''')
148+ """
149+ )
150
151 def _get_human_size(self, num):
152 """Convert num in bytes to human size."""
153- for unit in ['B', 'K', 'M', 'G']:
154+ for unit in ["B", "K", "M", "G"]:
155 if num < 1024:
156- return '{}{}'.format(num, unit)
157+ return "{}{}".format(num, unit)
158 else:
159 num = num // 1024
160
161 def parse(self, content):
162 page_size = os.sysconf("SC_PAGE_SIZE") # normally 4096, should be 2^N
163- LOG.info('SC_PAGE_SIZE: %s', page_size)
164+ LOG.info("SC_PAGE_SIZE: %s", page_size)
165 human_sizes = None
166
167 # in telegraf.conf:
168 # name_override = "buddyinfo"
169 # tag_keys = ["node", "zone", "size"]
170 items = []
171- re_line = re.compile(r"Node\s+(?P<node>\d+).*zone\s+(?P<zone>\w+)\s+(?P<pages>.*)")
172+ re_line = re.compile(
173+ r"Node\s+(?P<node>\d+).*zone\s+(?P<zone>\w+)\s+(?P<pages>.*)"
174+ )
175 for line in content.splitlines():
176 LOG.debug(line)
177 match = re_line.match(line)
178 if match:
179 data = match.groupdict()
180 LOG.debug(data)
181- pages = data['pages'].split()
182+ pages = data["pages"].split()
183 if not human_sizes:
184- human_sizes = [self._get_human_size(page_size * 2 ** i) for i, _ in enumerate(pages)]
185+ human_sizes = [
186+ self._get_human_size(page_size * 2 ** i)
187+ for i, _ in enumerate(pages)
188+ ]
189 for k, v in zip(human_sizes, pages):
190- items.append({
191- 'node': data['node'],
192- 'zone': data['zone'],
193- 'size': k,
194- 'count': int(v),
195- })
196+ items.append(
197+ {
198+ "node": data["node"],
199+ "zone": data["zone"],
200+ "size": k,
201+ "count": int(v),
202+ }
203+ )
204 return items
205
206
207 @register_metric
208 class ZoneinfoFileMetric(FileMetric):
209- name = 'zoneinfo'
210- input_file = '/proc/zoneinfo'
211+ name = "zoneinfo"
212+ input_file = "/proc/zoneinfo"
213 # customize config template with tag_keys
214- config_template = dedent('''
215+ config_template = dedent(
216+ """
217 [[inputs.exec]]
218 commands = ["{python} {script} --metric {name}"]
219 name_override = "{name}"
220 data_format = "json"
221 tag_keys = ["node", "zone"]
222- ''')
223+ """
224+ )
225
226 def parse(self, content):
227- pattern = re.compile(r'^Node\s+(?P<node>\d+),\s+zone\s+(?P<zone>\S+)\n'
228- r'+.*?' # match anything in between non-greedy
229- r'^\s+pages free\s+(?P<pages_free>\d+)\n'
230- r'^\s+min\s+(?P<min>\d+)\n'
231- r'^\s+low\s+(?P<low>\d+)\n'
232- r'^\s+high\s+(?P<high>\d+)\n'
233- r'^\s+spanned\s+(?P<spanned>\d+)\n'
234- r'^\s+present\s+(?P<present>\d+)\n'
235- r'^\s+managed\s+(?P<managed>\d+)',
236- re.MULTILINE + re.DOTALL)
237+ pattern = re.compile(
238+ r"^Node\s+(?P<node>\d+),\s+zone\s+(?P<zone>\S+)\n"
239+ r"+.*?" # match anything in between non-greedy
240+ r"^\s+pages free\s+(?P<pages_free>\d+)\n"
241+ r"^\s+min\s+(?P<min>\d+)\n"
242+ r"^\s+low\s+(?P<low>\d+)\n"
243+ r"^\s+high\s+(?P<high>\d+)\n"
244+ r"^\s+spanned\s+(?P<spanned>\d+)\n"
245+ r"^\s+present\s+(?P<present>\d+)\n"
246+ r"^\s+managed\s+(?P<managed>\d+)",
247+ re.MULTILINE + re.DOTALL,
248+ )
249 items = []
250 for match in pattern.finditer(content):
251 data = match.groupdict()
252@@ -229,8 +244,8 @@ class CmdMetric(FileMetric):
253 cmd = []
254
255 def get_cmd_output(self, cmd, is_json=False):
256- LOG.debug('running cmd: %s', ' '.join(cmd))
257- output = subprocess.check_output(cmd).decode('utf8').strip()
258+ LOG.debug("running cmd: %s", " ".join(cmd))
259+ output = subprocess.check_output(cmd).decode("utf8").strip()
260 return json.loads(output) if is_json else output
261
262 def get_input_content(self):
263@@ -243,52 +258,53 @@ class CmdMetric(FileMetric):
264
265 @register_metric
266 class NetNSCmdMetric(CmdMetric):
267- name = 'netns'
268- cmd = ['ip', 'netns', 'list']
269+ name = "netns"
270+ cmd = ["ip", "netns", "list"]
271 # customize config template with tag_keys and interval
272 # the output could be huge, so increase the interval
273- config_template = dedent('''
274+ config_template = dedent(
275+ """
276 [[inputs.exec]]
277 commands = ["{python} {script} --metric {name}"]
278 name_override = "{name}"
279 data_format = "json"
280 tag_keys = ["namespace", "id"]
281 interval = "600s"
282- ''')
283+ """
284+ )
285
286 def parse(self, content):
287 items = []
288 # find openstack/neutron netns list pattern
289 pattern = re.compile(r"^([\w-]+)\s+\(id:\s+(\d+)\)", flags=re.M)
290 for match in pattern.finditer(content):
291- items.append({
292- 'namespace': match.group(1),
293- 'id': match.group(2),
294- 'state': 1,
295- })
296+ items.append(
297+ {"namespace": match.group(1), "id": match.group(2), "state": 1,}
298+ )
299
300 # no re matches, should be in simple list format
301 if not items:
302 for line in content.splitlines():
303- items.append({
304- 'namespace': line.strip(),
305- 'state': 1,
306- })
307+ items.append(
308+ {"namespace": line.strip(), "state": 1,}
309+ )
310 return items
311
312
313 @register_metric
314 class OvsDumpFlowsCmdMetric(CmdMetric):
315- name = 'ovs_dump_flows'
316+ name = "ovs_dump_flows"
317 # customize config template with tag_keys and interval
318 # the output could be huge, so increase the interval
319- config_template = dedent('''
320+ config_template = dedent(
321+ """
322 [[inputs.exec]]
323 commands = ["{python} {script} --metric {name}"]
324 name_override = "{name}"
325 data_format = "json"
326 tag_keys = ["bridge"]
327- ''')
328+ """
329+ )
330
331 def get_input_content(self):
332 """Get ovs dump-flows output for each bridge in a dict.
333@@ -304,13 +320,13 @@ class OvsDumpFlowsCmdMetric(CmdMetric):
334 """
335 flows = {}
336
337- ovs_cmd = 'ovs-ofctl'
338+ ovs_cmd = "ovs-ofctl"
339 if not shutil.which(ovs_cmd):
340 LOG.error('openvswitch command "%s" is not available, exit', ovs_cmd)
341 return flows
342
343- for bridge in ['br-int', 'br-tun', 'br-data']:
344- cmd = ['sudo', ovs_cmd, 'dump-flows', bridge]
345+ for bridge in ["br-int", "br-tun", "br-data"]:
346+ cmd = ["sudo", ovs_cmd, "dump-flows", bridge]
347 output = self.get_cmd_output(cmd)
348 flows[bridge] = output
349
350@@ -351,16 +367,18 @@ class OvsDumpFlowsCmdMetric(CmdMetric):
351
352 @register_metric
353 class OvsDpCtlCmdMetric(CmdMetric):
354- name = 'ovs_dpctl'
355- cmd = ['sudo', 'ovs-appctl', 'dpctl/show', '-s']
356+ name = "ovs_dpctl"
357+ cmd = ["sudo", "ovs-appctl", "dpctl/show", "-s"]
358 # customize tag_keys
359- config_template = dedent('''
360+ config_template = dedent(
361+ """
362 [[inputs.exec]]
363 commands = ["{python} {script} --metric {name}"]
364 name_override = "{name}"
365 data_format = "json"
366 tag_keys = ["datapath", "portname", "port"]
367- ''')
368+ """
369+ )
370
371 def parse_fields(self, text):
372 """
373@@ -443,15 +461,17 @@ class OvsDpCtlCmdMetric(CmdMetric):
374 return result
375
376
377-def render_config_files(configs_dir, python, disabled_metrics='', dry_run=False):
378+def render_config_files(configs_dir, python, disabled_metrics="", dry_run=False):
379 """Render config files for any metrics not disabled, and remove any disabled"""
380
381- disabled_metrics_set = set(disabled_metrics.split(':')) if disabled_metrics else set([])
382+ disabled_metrics_set = (
383+ set(disabled_metrics.split(":")) if disabled_metrics else set([])
384+ )
385 for metric in disabled_metrics_set:
386 try:
387 METRICS[metric].remove_config(configs_dir, dry_run=dry_run)
388 except KeyError:
389- LOG.warning('metric name %s not in %s', metric, ','.join(METRICS))
390+ LOG.warning("metric name %s not in %s", metric, ",".join(METRICS))
391 enabled_metrics_set = set(METRICS.keys()) - disabled_metrics_set
392 for metric in enabled_metrics_set:
393 METRICS[metric].render_config(configs_dir, python, dry_run=dry_run)
394@@ -459,56 +479,67 @@ def render_config_files(configs_dir, python, disabled_metrics='', dry_run=False)
395
396 def main():
397 argparser = argparse.ArgumentParser(
398- description='Telegraf exec metrics',
399+ description="Telegraf exec metrics",
400 formatter_class=argparse.ArgumentDefaultsHelpFormatter,
401 )
402 choices = list(METRICS) # sorted dict
403 argparser.add_argument(
404- '--metric', choices=choices,
405+ "--metric",
406+ choices=choices,
407 default=choices[0],
408- help='which metric to execuate',
409+ help="which metric to execuate",
410 )
411 argparser.add_argument(
412- '-f', '--input-file', dest='input_file',
413- help='read input content from this file',
414+ "-f",
415+ "--input-file",
416+ dest="input_file",
417+ help="read input content from this file",
418 )
419 argparser.add_argument(
420- '--render-config-files', dest='render_config_files', action='store_true',
421- help='render config files for all metrics, use --disabled-metrics to exclude specific ones',
422+ "--render-config-files",
423+ dest="render_config_files",
424+ action="store_true",
425+ help="render config files for all metrics, use --disabled-metrics to exclude specific ones",
426 )
427 argparser.add_argument(
428- '--disabled-metrics', dest='disabled_metrics', default='',
429- help='colon separated metric names to disable, e.g.: buddyinfo:zoneinfo',
430+ "--disabled-metrics",
431+ dest="disabled_metrics",
432+ default="",
433+ help="colon separated metric names to disable, e.g.: buddyinfo:zoneinfo",
434 )
435 argparser.add_argument(
436- '--python', dest='python', default=sys.executable,
437- help='python interperter path in config file to execute this script, required for venv',
438+ "--python",
439+ dest="python",
440+ default=sys.executable,
441+ help="python interperter path in config file to execute this script, required for venv",
442 )
443 # useful for testing
444 argparser.add_argument(
445- '--configs-dir', dest='configs_dir', default='/etc/telegraf/telegraf.d/',
446- help='telegraf configs dir for exec metrics',
447+ "--configs-dir",
448+ dest="configs_dir",
449+ default="/etc/telegraf/telegraf.d/",
450+ help="telegraf configs dir for exec metrics",
451 )
452 argparser.add_argument(
453- '--dry-run', action='store_true',
454- help='dry run without real actions',
455+ "--dry-run", action="store_true", help="dry run without real actions",
456 )
457 argparser.add_argument(
458- '-v', '--verbose', action='store_true',
459- help='be verbose in log',
460+ "-v", "--verbose", action="store_true", help="be verbose in log",
461 )
462
463 cli = argparser.parse_args()
464 logging.basicConfig(
465 level=logging.DEBUG if cli.verbose else logging.WARNING,
466- format='%(asctime)s %(levelname)s: %(message)s')
467+ format="%(asctime)s %(levelname)s: %(message)s",
468+ )
469
470 if cli.render_config_files:
471 render_config_files(
472 cli.configs_dir,
473 cli.python,
474 disabled_metrics=cli.disabled_metrics,
475- dry_run=cli.dry_run)
476+ dry_run=cli.dry_run,
477+ )
478 else:
479 metric = METRICS[cli.metric]
480 if cli.input_file:
481@@ -517,5 +548,5 @@ def main():
482 print(json.dumps(output, indent=4))
483
484
485-if __name__ == '__main__':
486+if __name__ == "__main__":
487 main()
488diff --git a/src/hooks/relations/apache-website/requires.py b/src/hooks/relations/apache-website/requires.py
489index 0423c2d..ecb663a 100644
490--- a/src/hooks/relations/apache-website/requires.py
491+++ b/src/hooks/relations/apache-website/requires.py
492@@ -22,12 +22,12 @@ from charms.reactive import scopes
493 class WSGIRequires(RelationBase):
494 scope = scopes.UNIT
495
496- @hook('{requires:apache-website}-relation-{joined,changed}')
497+ @hook("{requires:apache-website}-relation-{joined,changed}")
498 def changed(self):
499 conv = self.conversation()
500- conv.set_state('{relation_name}.available')
501+ conv.set_state("{relation_name}.available")
502
503- @hook('{requires:apache-website}-relation-{departed,broken}')
504+ @hook("{requires:apache-website}-relation-{departed,broken}")
505 def broken(self):
506 conv = self.conversation()
507- conv.remove_state('{relation_name}.available')
508+ conv.remove_state("{relation_name}.available")
509diff --git a/src/hooks/relations/statistics/requires.py b/src/hooks/relations/statistics/requires.py
510index 284b671..4aafb2a 100644
511--- a/src/hooks/relations/statistics/requires.py
512+++ b/src/hooks/relations/statistics/requires.py
513@@ -22,16 +22,16 @@ from charms.reactive import scopes
514 class WSGIRequires(RelationBase):
515 scope = scopes.UNIT
516
517- @hook('{requires:statistics}-relation-{joined,changed}')
518+ @hook("{requires:statistics}-relation-{joined,changed}")
519 def changed(self):
520 conv = self.conversation()
521- conv.set_state('{relation_name}.connected')
522- if conv.get_remote('enabled'):
523+ conv.set_state("{relation_name}.connected")
524+ if conv.get_remote("enabled"):
525 # this unit's conversation has a port, so
526 # it is part of the set of available units
527- conv.set_state('{relation_name}.available')
528+ conv.set_state("{relation_name}.available")
529
530- @hook('{requires:statistics}-relation-{departed,broken}')
531+ @hook("{requires:statistics}-relation-{departed,broken}")
532 def broken(self):
533 conv = self.conversation()
534- conv.remove_state('{relation_name}.available')
535+ conv.remove_state("{relation_name}.available")
536diff --git a/src/hooks/relations/telegraf-exec/requires.py b/src/hooks/relations/telegraf-exec/requires.py
537index 6582ebb..42bb783 100644
538--- a/src/hooks/relations/telegraf-exec/requires.py
539+++ b/src/hooks/relations/telegraf-exec/requires.py
540@@ -24,37 +24,37 @@ from charms.reactive import scopes
541 class ExecRequires(RelationBase):
542 scope = scopes.UNIT
543
544- @hook('{requires:telegraf-exec}-relation-{joined,changed}')
545+ @hook("{requires:telegraf-exec}-relation-{joined,changed}")
546 def changed(self):
547 conv = self.conversation()
548- conv.set_state('{relation_name}.connected')
549- commands_json_dict = conv.get_remote('commands') # list of commands to run
550+ conv.set_state("{relation_name}.connected")
551+ commands_json_dict = conv.get_remote("commands") # list of commands to run
552 if commands_json_dict is not None and json.loads(commands_json_dict):
553- conv.set_state('{relation_name}.available')
554+ conv.set_state("{relation_name}.available")
555
556- @hook('{requires:telegraf-exec}-relation-{departed,broken}')
557+ @hook("{requires:telegraf-exec}-relation-{departed,broken}")
558 def broken(self):
559 conv = self.conversation()
560- conv.remove_state('{relation_name}.connected')
561- conv.remove_state('{relation_name}.available')
562+ conv.remove_state("{relation_name}.connected")
563+ conv.remove_state("{relation_name}.available")
564
565 def commands(self):
566 cmds = []
567 for conv in self.conversations():
568- commands_json_dict = conv.get_remote('commands') # list of commands dicts
569+ commands_json_dict = conv.get_remote("commands") # list of commands dicts
570 for cmd_info in json.loads(commands_json_dict):
571- commands = cmd_info.pop('commands', []) # list of commands
572- if commands is None and 'command' in cmd_info:
573- commands = [cmd_info.pop('command')]
574+ commands = cmd_info.pop("commands", []) # list of commands
575+ if commands is None and "command" in cmd_info:
576+ commands = [cmd_info.pop("command")]
577 if not commands:
578 continue
579- data_format = cmd_info.pop('data_format') # json, graphite, influx
580- cmd = {'commands': commands, 'data_format': data_format}
581+ data_format = cmd_info.pop("data_format") # json, graphite, influx
582+ cmd = {"commands": commands, "data_format": data_format}
583 # timeout is otional because we have telegraf 0.12.1 around
584- cmd['timeout'] = cmd_info.pop('timeout', '5s')
585+ cmd["timeout"] = cmd_info.pop("timeout", "5s")
586 # by default run_on_this_unit is True, we risk to run the command
587 # everywhere than not running it at all
588- cmd['run_on_this_unit'] = cmd_info.pop('run_on_this_unit', True)
589+ cmd["run_on_this_unit"] = cmd_info.pop("run_on_this_unit", True)
590 cmd.update(cmd_info)
591 cmds.append(cmd)
592 return cmds
593diff --git a/src/reactive/telegraf.py b/src/reactive/telegraf.py
594index 83264e7..ba47505 100644
595--- a/src/reactive/telegraf.py
596+++ b/src/reactive/telegraf.py
597@@ -51,20 +51,20 @@ from charmhelpers.contrib.charmsupport import nrpe
598 import charms.promreg
599 from jinja2 import Template, Environment, FileSystemLoader, exceptions
600
601-DEB_BASE_DIR = '/etc/telegraf'
602-SNAP_BASE_DIR = '/var/snap/telegraf/current'
603-SUDOERS_DIR = '/etc/sudoers.d'
604+DEB_BASE_DIR = "/etc/telegraf"
605+SNAP_BASE_DIR = "/var/snap/telegraf/current"
606+SUDOERS_DIR = "/etc/sudoers.d"
607
608-CONFIG_FILE = 'telegraf.conf'
609+CONFIG_FILE = "telegraf.conf"
610
611-CONFIG_DIR = 'telegraf.d'
612+CONFIG_DIR = "telegraf.d"
613
614-GRAFANA_DASHBOARD_TELEGRAF_FILE_NAME = 'Telegraf.json.j2'
615+GRAFANA_DASHBOARD_TELEGRAF_FILE_NAME = "Telegraf.json.j2"
616
617-GRAFANA_DASHBOARD_NAME = 'telegraf'
618+GRAFANA_DASHBOARD_NAME = "telegraf"
619
620-SNAP_SERVICE = 'snap.telegraf.telegraf'
621-DEB_SERVICE = 'telegraf'
622+SNAP_SERVICE = "snap.telegraf.telegraf"
623+DEB_SERVICE = "telegraf"
624
625 # Utilities #
626
627@@ -75,43 +75,46 @@ class InvalidInstallMethod(Exception):
628
629 def get_install_method():
630 config = hookenv.config()
631- if config['install_method'] in ['deb', 'snap']:
632- return config['install_method']
633+ if config["install_method"] in ["deb", "snap"]:
634+ return config["install_method"]
635 else:
636 hookenv.log(
637- "Invalid install_method for telegraf: {}".format(config['install_method']),
638- level=hookenv.ERROR)
639+ "Invalid install_method for telegraf: {}".format(config["install_method"]),
640+ level=hookenv.ERROR,
641+ )
642 raise InvalidInstallMethod()
643
644
645 def get_base_dir():
646 config = hookenv.config()
647- if config['install_method'] == 'deb':
648+ if config["install_method"] == "deb":
649 return DEB_BASE_DIR
650- elif config['install_method'] == 'snap':
651+ elif config["install_method"] == "snap":
652 return SNAP_BASE_DIR
653 else:
654 hookenv.log(
655- "Invalid install_method for telegraf: {}".format(config['install_method']),
656- level=hookenv.ERROR)
657+ "Invalid install_method for telegraf: {}".format(config["install_method"]),
658+ level=hookenv.ERROR,
659+ )
660 raise InvalidInstallMethod()
661
662
663 def get_service():
664 config = hookenv.config()
665- if config['install_method'] == 'deb':
666+ if config["install_method"] == "deb":
667 return DEB_SERVICE
668- elif config['install_method'] == 'snap':
669+ elif config["install_method"] == "snap":
670 return SNAP_SERVICE
671 else:
672 hookenv.log(
673- "Invalid install_method for telegraf: {}".format(config['install_method']),
674- level=hookenv.ERROR)
675+ "Invalid install_method for telegraf: {}".format(config["install_method"]),
676+ level=hookenv.ERROR,
677+ )
678 raise InvalidInstallMethod()
679
680
681 def get_templates_dir():
682- return os.path.join(hookenv.charm_dir(), 'templates')
683+ return os.path.join(hookenv.charm_dir(), "templates")
684
685
686 def get_main_config_path():
687@@ -123,14 +126,13 @@ def get_configs_dir():
688
689
690 def get_files_dir():
691- return os.path.join(hookenv.charm_dir(), 'files')
692+ return os.path.join(hookenv.charm_dir(), "files")
693
694
695 def list_supported_plugins():
696- return [k for k in hookenv.metadata()['requires'].keys()
697- if k != 'juju-info'] + \
698- [k for k in hookenv.metadata()['provides'].keys()
699- if k != 'juju-info']
700+ return [k for k in hookenv.metadata()["requires"].keys() if k != "juju-info"] + [
701+ k for k in hookenv.metadata()["provides"].keys() if k != "juju-info"
702+ ]
703
704
705 def list_config_files():
706@@ -138,27 +140,26 @@ def list_config_files():
707 # only include config files for configured plugins
708 current_states = get_states()
709 for plugin in list_supported_plugins():
710- if 'plugins.{}.configured'.format(plugin) in current_states.keys():
711- config_path = '{}/{}.conf'.format(get_configs_dir(), plugin)
712+ if "plugins.{}.configured".format(plugin) in current_states.keys():
713+ config_path = "{}/{}.conf".format(get_configs_dir(), plugin)
714 config_files.append(config_path)
715- if 'extra_plugins.configured' in current_states.keys():
716- config_files.append('{}/extra_plugins.conf'.format(get_configs_dir()))
717- config_files.append('{}/socket_listener.conf'.format(get_configs_dir()))
718+ if "extra_plugins.configured" in current_states.keys():
719+ config_files.append("{}/extra_plugins.conf".format(get_configs_dir()))
720+ config_files.append("{}/socket_listener.conf".format(get_configs_dir()))
721 return config_files
722
723
724 def get_hostname_label():
725 config = hookenv.config()
726- hostname_fmt = config['hostname']
727- unit = get_remote_unit_name().replace('/', '-') # / is invalid in labels.
728- if hostname_fmt == 'UNIT_NAME': # Deprecated
729+ hostname_fmt = config["hostname"]
730+ unit = get_remote_unit_name().replace("/", "-") # / is invalid in labels.
731+ if hostname_fmt == "UNIT_NAME": # Deprecated
732 return unit
733 env = os.environ
734- model = env.get('JUJU_ENV_NAME') or env.get('JUJU_MODEL_NAME', '')
735- uuid = env.get('JUJU_ENV_UUID') or env.get('JUJU_MODEL_UUID', '')
736+ model = env.get("JUJU_ENV_NAME") or env.get("JUJU_MODEL_NAME", "")
737+ uuid = env.get("JUJU_ENV_UUID") or env.get("JUJU_MODEL_UUID", "")
738 syshost = socket.gethostname()
739- return hostname_fmt.format(unit=unit, model=model, uuid=uuid,
740- host=syshost)
741+ return hostname_fmt.format(unit=unit, model=model, uuid=uuid, host=syshost)
742
743
744 def get_remote_unit_name():
745@@ -170,19 +171,19 @@ def get_remote_unit_name():
746 # Note(aluria): lookup all available IPv4/IPv6 addresses (except lo)
747 ip_addresses = set()
748 for iface in netifaces.interfaces():
749- if iface == 'lo':
750+ if iface == "lo":
751 continue
752 ip_addrs = netifaces.ifaddresses(iface)
753 for iface_type in ip_addrs:
754 if iface_type in (netifaces.AF_INET, netifaces.AF_INET6):
755 for addrs in ip_addrs[iface_type]:
756- ip_addresses.add(addrs['addr'])
757+ ip_addresses.add(addrs["addr"])
758
759 # Note(aluria): and try to match them against rel['private-address']
760- for rel_type in hookenv.metadata()['requires'].keys():
761+ for rel_type in hookenv.metadata()["requires"].keys():
762 for rel in hookenv.relations_of_type(rel_type):
763- if rel['private-address'] in ip_addresses:
764- return rel['__unit__']
765+ if rel["private-address"] in ip_addresses:
766+ return rel["__unit__"]
767
768
769 def get_base_inputs():
770@@ -192,28 +193,28 @@ def get_base_inputs():
771 extra_options = get_extra_options()
772 conntrack = os.path.exists("/proc/sys/net/netfilter/nf_conntrack_max")
773 config = hookenv.config()
774- str_disabled_plugins = config['disabled_plugins']
775- disabled_plugins = str_disabled_plugins.split(':') if str_disabled_plugins else []
776+ str_disabled_plugins = config["disabled_plugins"]
777+ disabled_plugins = str_disabled_plugins.split(":") if str_disabled_plugins else []
778 return {
779- 'extra_options': extra_options['inputs'],
780- 'bcache': is_bcache(),
781- 'python': sys.executable,
782- 'files_dir': get_files_dir(),
783- 'disabled_plugins': disabled_plugins,
784- 'openvswitch': host.service_running('openvswitch-switch'),
785- 'conntrack': conntrack,
786+ "extra_options": extra_options["inputs"],
787+ "bcache": is_bcache(),
788+ "python": sys.executable,
789+ "files_dir": get_files_dir(),
790+ "disabled_plugins": disabled_plugins,
791+ "openvswitch": host.service_running("openvswitch-switch"),
792+ "conntrack": conntrack,
793 }
794
795
796 def render_base_inputs():
797 # use base inputs from charm templates
798- with open(os.path.join(get_templates_dir(), 'base_inputs.conf'), 'r') as fd:
799+ with open(os.path.join(get_templates_dir(), "base_inputs.conf"), "r") as fd:
800 return render_template(fd.read(), get_base_inputs())
801
802
803 def get_extra_options():
804- extra_options = {'inputs': {}, 'outputs': {}}
805- extra_options_raw = hookenv.config()['extra_options']
806+ extra_options = {"inputs": {}, "outputs": {}}
807+ extra_options_raw = hookenv.config()["extra_options"]
808 extra_opts = yaml.full_load(extra_options_raw) or {}
809 extra_options.update(extra_opts)
810 # jsonify value, required as the telegraf config values format is similar
811@@ -227,7 +228,7 @@ def get_extra_options():
812 json_vals[k][plugin] = {}
813 # inner plugin (aka key:value)
814 for key, val in values.items():
815- if key in ('tagpass', 'tagdrop'):
816+ if key in ("tagpass", "tagdrop"):
817 # this is a tagpass/drop, we need to go deeper
818 json_vals[k][plugin][key] = {}
819 for tag, tagvalue in val.items():
820@@ -257,9 +258,11 @@ def render_extra_options(kind, name, extra_options=None):
821 """
822 if extra_options is None:
823 extra_options = get_extra_options()
824- context = {"extra_options": extra_options[kind].get(name, {}),
825- "kind": kind,
826- "name": name}
827+ context = {
828+ "extra_options": extra_options[kind].get(name, {}),
829+ "kind": kind,
830+ "name": name,
831+ }
832 return render_template(template, context)
833
834
835@@ -269,7 +272,7 @@ def render_template(template, context):
836
837
838 def check_prometheus_port(key, new_port):
839- unitdata_key = '{}.port'.format(key)
840+ unitdata_key = "{}.port".format(key)
841 kv = unitdata.kv()
842 existing_port = kv.get(unitdata_key)
843 if existing_port != new_port:
844@@ -286,31 +289,35 @@ def check_prometheus_port(key, new_port):
845
846 def get_prometheus_port():
847 config = hookenv.config()
848- if not config.get('prometheus_output_port', False):
849+ if not config.get("prometheus_output_port", False):
850 return False
851- if config.get('prometheus_output_port') == 'default':
852+ if config.get("prometheus_output_port") == "default":
853 return 9103
854 else:
855- return int(config.get('prometheus_output_port'))
856+ return int(config.get("prometheus_output_port"))
857
858
859 def get_socket_listener_port():
860 config = hookenv.config()
861- if not config.get('socket_listener_port', False):
862+ if not config.get("socket_listener_port", False):
863 return 8094
864 else:
865- return int(config.get('socket_listener_port'))
866+ return int(config.get("socket_listener_port"))
867
868
869 def render_socket_listener_config(context):
870 # Remove deprecated config file
871- old_config_path = '{}/tcp_listener.conf'.format(get_configs_dir())
872+ old_config_path = "{}/tcp_listener.conf".format(get_configs_dir())
873 if os.path.exists(old_config_path):
874 os.remove(old_config_path)
875
876- config_path = '{}/socket_listener.conf'.format(get_configs_dir())
877- render(source='socket_listener.tmpl', templates_dir=get_templates_dir(),
878- target=config_path, context=context)
879+ config_path = "{}/socket_listener.conf".format(get_configs_dir())
880+ render(
881+ source="socket_listener.tmpl",
882+ templates_dir=get_templates_dir(),
883+ target=config_path,
884+ context=context,
885+ )
886
887
888 def get_sysstat_config_with_sadc_xall(content):
889@@ -337,23 +344,35 @@ def get_sysstat_config_with_sadc_xall(content):
890 value = match.group(1)
891 if "-S" in value:
892 # if `-S` in value, replace it to XALL, keep other options unchanged.
893- return re.sub(r'^SADC_OPTIONS="(.*-S\s+)(\w+)(.*)"', r'SADC_OPTIONS="\1XALL\3"', content, flags=re.M)
894+ return re.sub(
895+ r'^SADC_OPTIONS="(.*-S\s+)(\w+)(.*)"',
896+ r'SADC_OPTIONS="\1XALL\3"',
897+ content,
898+ flags=re.M,
899+ )
900 else:
901 # if `-S` not in value, append `-S XALL` to value
902- return re.sub(r'^SADC_OPTIONS="(.*)"', r'SADC_OPTIONS="\1 -S XALL"', content, flags=re.M)
903+ return re.sub(
904+ r'^SADC_OPTIONS="(.*)"',
905+ r'SADC_OPTIONS="\1 -S XALL"',
906+ content,
907+ flags=re.M,
908+ )
909
910
911-def update_sysstat_config_with_sdac_xall(path='/etc/sysstat/sysstat'):
912+def update_sysstat_config_with_sdac_xall(path="/etc/sysstat/sysstat"):
913 """Update `/etc/sysstat/sysstat` to ensure `-S XALL` in `SADC_OPTIONS`."""
914 if os.path.isfile(path):
915- with open(path, mode='r', encoding='utf8') as f:
916+ with open(path, mode="r", encoding="utf8") as f:
917 new_text = get_sysstat_config_with_sadc_xall(f.read())
918 if new_text:
919 hookenv.log("updating {} to ensure `-S XALL` in SADC_OPTIONS".format(path))
920- with open(path, mode='w', encoding='utf8') as f:
921+ with open(path, mode="w", encoding="utf8") as f:
922 f.write(new_text)
923 else:
924- hookenv.log("sysstat config file not found: {}".format(path), level=hookenv.WARNING)
925+ hookenv.log(
926+ "sysstat config file not found: {}".format(path), level=hookenv.WARNING
927+ )
928
929
930 def configure_telegraf(): # noqa: C901
931@@ -363,39 +382,46 @@ def configure_telegraf(): # noqa: C901
932 try:
933 config_path = get_main_config_path()
934 except InvalidInstallMethod:
935- hookenv.status_set('blocked', 'Wrong install_method provided: {!r}'.format(config['install_method']))
936+ hookenv.status_set(
937+ "blocked",
938+ "Wrong install_method provided: {!r}".format(config["install_method"]),
939+ )
940 return
941 if get_remote_unit_name() is None:
942- hookenv.status_set('waiting', 'Waiting for juju-info relation')
943+ hookenv.status_set("waiting", "Waiting for juju-info relation")
944 # if UNIT_NAME in hostname config and relation not yet available,
945 # make telegraf unable to start to not get weird metrics names
946 if os.path.exists(config_path):
947 os.unlink(config_path)
948 return
949
950- inputs = config.get('inputs_config', '')
951- outputs = config.get('outputs_config', '')
952+ inputs = config.get("inputs_config", "")
953+ outputs = config.get("outputs_config", "")
954 # just for the migration out of base64
955 if inputs:
956 try:
957- inputs = base64.b64decode(inputs.encode('utf-8'), validate=True).decode('utf-8')
958+ inputs = base64.b64decode(inputs.encode("utf-8"), validate=True).decode(
959+ "utf-8"
960+ )
961 except binascii.Error:
962 # not bas64, probably already up to date configs
963 pass
964 if outputs:
965 try:
966- outputs = base64.b64decode(outputs.encode('utf-8'), validate=True).decode('utf-8')
967+ outputs = base64.b64decode(outputs.encode("utf-8"), validate=True).decode(
968+ "utf-8"
969+ )
970 except binascii.Error:
971 # not bas64, probably already up to date configs
972 pass
973 tags = []
974- if config['tags']:
975- for tag in config['tags'].split(','):
976+ if config["tags"]:
977+ for tag in config["tags"].split(","):
978 key, value = tag.split("=")
979 tags.append('{} = "{}"'.format(key, value))
980 # add extra juju-related tags to be exposed as labels
981- tags.append('juju_application = "{}"'.format(get_remote_unit_name().split('/')[0]))
982- tags.append('juju_unit = "{}"'.format(get_remote_unit_name().replace('/', '-')))
983+ tags.append('juju_application = "{}"'.format(get_remote_unit_name().split("/")[0]))
984+ tags.append('juju_unit = "{}"'.format(get_remote_unit_name().replace("/", "-")))
985 tags.append('juju_model = "{}"'.format(hookenv.model_name()))
986 context["tags"] = tags
987 if inputs:
988@@ -412,42 +438,56 @@ def configure_telegraf(): # noqa: C901
989 context["hostname"] = get_hostname_label()
990
991 logfile_path = os.path.normpath(context["logfile"])
992- if (context["logfile"] and not logfile_path.startswith("/var/log/") and not
993- (config["install_method"] == 'snap' and
994- logfile_path.startswith("/var/snap/telegraf/common/"))):
995+ if (
996+ context["logfile"]
997+ and not logfile_path.startswith("/var/log/")
998+ and not (
999+ config["install_method"] == "snap"
1000+ and logfile_path.startswith("/var/snap/telegraf/common/")
1001+ )
1002+ ):
1003 # only allow logging in /var/log, syslog, or /var/snap/telegraf/common
1004- hookenv.log("logfile value reset to stderr."
1005- " Original value: {}".format(context["logfile"]),
1006- hookenv.DEBUG)
1007+ hookenv.log(
1008+ "logfile value reset to stderr."
1009+ " Original value: {}".format(context["logfile"]),
1010+ hookenv.DEBUG,
1011+ )
1012 context["logfile"] = ""
1013
1014 if get_prometheus_port():
1015 context["prometheus_output_port"] = get_prometheus_port()
1016 check_prometheus_port("prometheus_output", get_prometheus_port())
1017- context['extra_options'] = get_extra_options()
1018+ context["extra_options"] = get_extra_options()
1019
1020 if get_socket_listener_port():
1021 context["socket_listener_port"] = get_socket_listener_port()
1022
1023 render_socket_listener_config(context=context)
1024
1025- telegraf_exec_metrics = os.path.join(get_files_dir(), 'telegraf_exec_metrics.py')
1026+ telegraf_exec_metrics = os.path.join(get_files_dir(), "telegraf_exec_metrics.py")
1027 cmd = [
1028 telegraf_exec_metrics,
1029- '--render-config-files',
1030- '--disabled-metrics', config['disabled_plugins'],
1031- '--configs-dir', get_configs_dir(), # unit test can monkeypatch this path
1032- '--python', sys.executable, # this will be venv python interpreter path
1033+ "--render-config-files",
1034+ "--disabled-metrics",
1035+ config["disabled_plugins"],
1036+ "--configs-dir",
1037+ get_configs_dir(), # unit test can monkeypatch this path
1038+ "--python",
1039+ sys.executable, # this will be venv python interpreter path
1040 ]
1041- hookenv.log("Rendering exec metrics config files: {}".format(' '.join(cmd)))
1042+ hookenv.log("Rendering exec metrics config files: {}".format(" ".join(cmd)))
1043 subprocess.check_call(cmd)
1044
1045 hookenv.log("Updating main config file")
1046- render(source='telegraf.conf.tmpl', templates_dir=get_templates_dir(),
1047- target=config_path, context=context)
1048+ render(
1049+ source="telegraf.conf.tmpl",
1050+ templates_dir=get_templates_dir(),
1051+ target=config_path,
1052+ context=context,
1053+ )
1054
1055 # add sudoers file for telegraf if openvswitch is running
1056- if host.service_running('openvswitch-switch'):
1057+ if host.service_running("openvswitch-switch"):
1058 sudoers_filename = "telegraf_sudoers"
1059 src = os.path.join(get_files_dir(), sudoers_filename)
1060 dst = os.path.join(SUDOERS_DIR, sudoers_filename)
1061@@ -466,360 +506,388 @@ def configure_telegraf(): # noqa: C901
1062 # If we're using the snap, and the deb failed to install, it's fine too
1063 pass
1064
1065- set_flag('telegraf.configured')
1066- set_flag('telegraf.needs_reload')
1067- if config["install_method"] == 'deb':
1068- set_flag('telegraf.apt.configured')
1069+ set_flag("telegraf.configured")
1070+ set_flag("telegraf.needs_reload")
1071+ if config["install_method"] == "deb":
1072+ set_flag("telegraf.apt.configured")
1073 else:
1074- set_flag('telegraf.snap.configured')
1075+ set_flag("telegraf.snap.configured")
1076
1077
1078 # States
1079
1080-@when_not('telegraf.installed')
1081+
1082+@when_not("telegraf.installed")
1083 def install_telegraf():
1084 try:
1085 install_method = get_install_method()
1086 except InvalidInstallMethod:
1087- hookenv.status_set('blocked', "Wrong install_method provided. Expected either 'deb' or 'snap'.")
1088+ hookenv.status_set(
1089+ "blocked", "Wrong install_method provided. Expected either 'deb' or 'snap'."
1090+ )
1091 return
1092- if install_method == 'deb':
1093+ if install_method == "deb":
1094 try:
1095- snap.remove('telegraf')
1096+ snap.remove("telegraf")
1097 except Exception:
1098 # the snap may already be absent, or snaps may not even be supported in this environment
1099 pass
1100- apt.queue_install(['telegraf'])
1101- elif install_method == 'snap':
1102- apt.purge('telegraf')
1103+ apt.queue_install(["telegraf"])
1104+ elif install_method == "snap":
1105+ apt.purge("telegraf")
1106 config = hookenv.config()
1107- snap_channel = config.get('snap_channel')
1108- snap.install('telegraf', channel=snap_channel, classic=True)
1109+ snap_channel = config.get("snap_channel")
1110+ snap.install("telegraf", channel=snap_channel, classic=True)
1111 if install_method:
1112- set_flag('telegraf.installed')
1113+ set_flag("telegraf.installed")
1114
1115
1116-@when('telegraf.installed')
1117-@when('apt.installed.telegraf')
1118-@when_not('telegraf.configured')
1119-@when_not('telegraf.apt.configured')
1120+@when("telegraf.installed")
1121+@when("apt.installed.telegraf")
1122+@when_not("telegraf.configured")
1123+@when_not("telegraf.apt.configured")
1124 def configure_telegraf_deb():
1125 configure_telegraf()
1126
1127
1128-@when('telegraf.installed')
1129-@when('snap.installed.telegraf')
1130-@when_not('telegraf.configured')
1131-@when_not('telegraf.snap.configured')
1132+@when("telegraf.installed")
1133+@when("snap.installed.telegraf")
1134+@when_not("telegraf.configured")
1135+@when_not("telegraf.snap.configured")
1136 def configure_telegraf_snap():
1137 configure_telegraf()
1138
1139
1140-@hook('upgrade-charm')
1141+@hook("upgrade-charm")
1142 def upgrade_charm():
1143 for plugin in list_supported_plugins():
1144- clear_flag('plugins.{}.configured'.format(plugin))
1145- clear_flag('extra_plugins.configured')
1146- clear_flag('telegraf.configured')
1147- clear_flag('telegraf.apt.configured')
1148- clear_flag('telegraf.snap.configured')
1149- clear_flag('grafana.configured')
1150+ clear_flag("plugins.{}.configured".format(plugin))
1151+ clear_flag("extra_plugins.configured")
1152+ clear_flag("telegraf.configured")
1153+ clear_flag("telegraf.apt.configured")
1154+ clear_flag("telegraf.snap.configured")
1155+ clear_flag("grafana.configured")
1156
1157
1158-@when('config.changed')
1159+@when("config.changed")
1160 def handle_config_changes():
1161 config = hookenv.config()
1162- if config.changed('extra_options'):
1163+ if config.changed("extra_options"):
1164 for plugin in list_supported_plugins():
1165- clear_flag('plugins.{}.configured'.format(plugin))
1166+ clear_flag("plugins.{}.configured".format(plugin))
1167 # if something else changed, let's reconfigure telegraf itself just in case
1168- if config.changed('extra_plugins'):
1169- clear_flag('extra_plugins.configured')
1170- if config.changed('install_method') or config.changed('snap_channel') or config.changed('install_sources'):
1171- clear_flag('telegraf.installed')
1172- clear_flag('telegraf.configured')
1173- clear_flag('telegraf.apt.configured')
1174- clear_flag('telegraf.snap.configured')
1175- clear_flag('telegraf.nagios-setup.complete')
1176-
1177-
1178-@when('telegraf.configured')
1179-@when_not('extra_plugins.configured')
1180+ if config.changed("extra_plugins"):
1181+ clear_flag("extra_plugins.configured")
1182+ if (
1183+ config.changed("install_method")
1184+ or config.changed("snap_channel")
1185+ or config.changed("install_sources")
1186+ ):
1187+ clear_flag("telegraf.installed")
1188+ clear_flag("telegraf.configured")
1189+ clear_flag("telegraf.apt.configured")
1190+ clear_flag("telegraf.snap.configured")
1191+ clear_flag("telegraf.nagios-setup.complete")
1192+
1193+
1194+@when("telegraf.configured")
1195+@when_not("extra_plugins.configured")
1196 def configure_extra_plugins():
1197 config = hookenv.config()
1198- plugins = config['extra_plugins']
1199+ plugins = config["extra_plugins"]
1200 if plugins:
1201- config_path = '{}/extra_plugins.conf'.format(get_configs_dir())
1202- host.write_file(config_path, plugins.encode('utf-8'))
1203- set_flag('extra_plugins.configured')
1204- set_flag('telegraf.needs_reload')
1205+ config_path = "{}/extra_plugins.conf".format(get_configs_dir())
1206+ host.write_file(config_path, plugins.encode("utf-8"))
1207+ set_flag("extra_plugins.configured")
1208+ set_flag("telegraf.needs_reload")
1209
1210
1211-@when('elasticsearch.available')
1212+@when("elasticsearch.available")
1213 def elasticsearch_input(es):
1214 template = """
1215 [[inputs.elasticsearch]]
1216 servers = {{ servers }}
1217 """
1218 hosts = []
1219- rels = hookenv.relations_of_type('elasticsearch')
1220+ rels = hookenv.relations_of_type("elasticsearch")
1221 for rel in rels:
1222- es_host = rel.get('host')
1223- port = rel.get('port')
1224+ es_host = rel.get("host")
1225+ port = rel.get("port")
1226 if not es_host or not port:
1227- hookenv.log('No host received for relation: {}.'.format(rel))
1228+ hookenv.log("No host received for relation: {}.".format(rel))
1229 continue
1230 hosts.append("http://{}:{}".format(es_host, port))
1231- config_path = '{}/{}.conf'.format(get_configs_dir(), 'elasticsearch')
1232+ config_path = "{}/{}.conf".format(get_configs_dir(), "elasticsearch")
1233 if hosts:
1234 context = {"servers": json.dumps(hosts)}
1235- input_config = render_template(template, context) + \
1236- render_extra_options("inputs", "elasticsearch")
1237- hookenv.log("Updating {} plugin config file".format('elasticsearch'))
1238- host.write_file(config_path, input_config.encode('utf-8'))
1239- set_flag('plugins.elasticsearch.configured')
1240+ input_config = render_template(template, context) + render_extra_options(
1241+ "inputs", "elasticsearch"
1242+ )
1243+ hookenv.log("Updating {} plugin config file".format("elasticsearch"))
1244+ host.write_file(config_path, input_config.encode("utf-8"))
1245+ set_flag("plugins.elasticsearch.configured")
1246 elif os.path.exists(config_path):
1247 os.unlink(config_path)
1248- clear_flag('plugins.elasticsearch.configured')
1249- set_flag('telegraf.needs_reload')
1250+ clear_flag("plugins.elasticsearch.configured")
1251+ set_flag("telegraf.needs_reload")
1252
1253
1254-@when('memcached.available')
1255+@when("memcached.available")
1256 def memcached_input(memcache):
1257 template = """
1258 [[inputs.memcached]]
1259 servers = {{ servers }}
1260 """
1261- required_keys = ['host', 'port']
1262- rels = hookenv.relations_of_type('memcached')
1263+ required_keys = ["host", "port"]
1264+ rels = hookenv.relations_of_type("memcached")
1265 addresses = []
1266 for rel in rels:
1267 if all([rel.get(key) for key in required_keys]):
1268- addr = rel['host']
1269- port = rel['port']
1270- address = '{}:{}'.format(addr, port)
1271+ addr = rel["host"]
1272+ port = rel["port"]
1273+ address = "{}:{}".format(addr, port)
1274 addresses.append(address)
1275- config_path = '{}/{}.conf'.format(get_configs_dir(), 'memcached')
1276+ config_path = "{}/{}.conf".format(get_configs_dir(), "memcached")
1277 if addresses:
1278 context = {"servers": json.dumps(addresses)}
1279- input_config = render_template(template, context) + \
1280- render_extra_options("inputs", "memcached")
1281- hookenv.log("Updating {} plugin config file".format('memcached'))
1282- host.write_file(config_path, input_config.encode('utf-8'))
1283- set_flag('plugins.memcached.configured')
1284+ input_config = render_template(template, context) + render_extra_options(
1285+ "inputs", "memcached"
1286+ )
1287+ hookenv.log("Updating {} plugin config file".format("memcached"))
1288+ host.write_file(config_path, input_config.encode("utf-8"))
1289+ set_flag("plugins.memcached.configured")
1290 elif os.path.exists(config_path):
1291 os.unlink(config_path)
1292- set_flag('telegraf.needs_reload')
1293+ set_flag("telegraf.needs_reload")
1294
1295
1296-@when('mongodb.database.available')
1297+@when("mongodb.database.available")
1298 def mongodb_input(mongodb):
1299 template = """
1300 [[inputs.mongodb]]
1301 servers = {{ servers }}
1302 """
1303- rels = hookenv.relations_of_type('mongodb')
1304+ rels = hookenv.relations_of_type("mongodb")
1305 mongo_addresses = []
1306 for rel in rels:
1307- addr = rel['private-address']
1308- port = rel.get('port', None)
1309+ addr = rel["private-address"]
1310+ port = rel.get("port", None)
1311 if port:
1312- mongo_address = '{}:{}'.format(addr, port)
1313+ mongo_address = "{}:{}".format(addr, port)
1314 else:
1315 mongo_address = addr
1316 mongo_addresses.append(mongo_address)
1317- config_path = '{}/{}.conf'.format(get_configs_dir(), 'mongodb')
1318+ config_path = "{}/{}.conf".format(get_configs_dir(), "mongodb")
1319 if mongo_addresses:
1320 context = {"servers": json.dumps(mongo_addresses)}
1321- input_config = render_template(template, context) + \
1322- render_extra_options("inputs", "mongodb")
1323- hookenv.log("Updating {} plugin config file".format('mongodb'))
1324- host.write_file(config_path, input_config.encode('utf-8'))
1325- set_flag('plugins.mongodb.configured')
1326+ input_config = render_template(template, context) + render_extra_options(
1327+ "inputs", "mongodb"
1328+ )
1329+ hookenv.log("Updating {} plugin config file".format("mongodb"))
1330+ host.write_file(config_path, input_config.encode("utf-8"))
1331+ set_flag("plugins.mongodb.configured")
1332 elif os.path.exists(config_path):
1333 os.unlink(config_path)
1334- set_flag('telegraf.needs_reload')
1335+ set_flag("telegraf.needs_reload")
1336
1337
1338-@when('mysql.available')
1339+@when("mysql.available")
1340 def mysql_input(mysql):
1341 contexts = []
1342 for relid, relation in context.Relations()[mysql.relation_name].items():
1343 for unit, reldata in relation.items():
1344 hookenv.log("Available relations", level="DEBUG")
1345- if reldata['private-address'] == hookenv.unit_private_ip():
1346+ if reldata["private-address"] == hookenv.unit_private_ip():
1347 if mysql.connection_string():
1348- contexts.append({'host': mysql.host(),
1349- 'port': mysql.port(),
1350- 'user': mysql.user(),
1351- 'pass': mysql.password(),
1352- 'is_secure': 'false', # TODO: provide config intf for this
1353- 'slave': reldata.get('slave', None)})
1354+ contexts.append(
1355+ {
1356+ "host": mysql.host(),
1357+ "port": mysql.port(),
1358+ "user": mysql.user(),
1359+ "pass": mysql.password(),
1360+ "is_secure": "false", # TODO: provide config intf for this
1361+ "slave": reldata.get("slave", None),
1362+ }
1363+ )
1364 break
1365
1366 render_mysql_tmpl(contexts)
1367- toggle_flag('plugins.mysql.configured', bool(contexts))
1368- set_flag('telegraf.needs_reload')
1369+ toggle_flag("plugins.mysql.configured", bool(contexts))
1370+ set_flag("telegraf.needs_reload")
1371
1372
1373-@when('postgresql.database.connected')
1374+@when("postgresql.database.connected")
1375 def choose_postgresql_database():
1376 # We have no need for our own database. If we need to create
1377 # custom views, we can remove this handler. Or maybe it should
1378 # be configurable, so people can use telegraf to export custom
1379 # metrics about their data.
1380- pgsql = endpoint_from_flag('postgresql.database.connected')
1381- pgsql.set_database('postgres')
1382+ pgsql = endpoint_from_flag("postgresql.database.connected")
1383+ pgsql.set_database("postgres")
1384
1385
1386-@when('postgresql.database.connected')
1387-@when_not('postgresql.database.available')
1388+@when("postgresql.database.connected")
1389+@when_not("postgresql.database.available")
1390 def postgresql_waiting():
1391- hookenv.status_set('waiting', 'Waiting for PostgreSQL relation')
1392+ hookenv.status_set("waiting", "Waiting for PostgreSQL relation")
1393
1394
1395-@when('postgresql.database.available',
1396- 'postgresql.database.changed')
1397+@when("postgresql.database.available", "postgresql.database.changed")
1398 def postgresql_input():
1399 # The subordinate may be connected to several services.
1400 contexts = []
1401 extra_options = get_extra_options()
1402- pg_options = extra_options['inputs'].get('postgresql')
1403+ pg_options = extra_options["inputs"].get("postgresql")
1404 principal = hookenv.principal_unit()
1405
1406 if principal not in hookenv.expected_related_units("postgresql"):
1407 return
1408
1409- pgsql = endpoint_from_flag('postgresql.database.available')
1410+ pgsql = endpoint_from_flag("postgresql.database.available")
1411 assert pgsql is not None
1412 for css in pgsql:
1413 cs = css.get(principal)
1414 if cs:
1415- ver = css.version or '9.3'
1416- contexts.append({'conn_str': str(cs),
1417- 'server': cs.host,
1418- 'replica': 'master' if cs == css.master else 'hot standby',
1419- 'extra_options': pg_options,
1420- 'version': ver,
1421- 'pg10': LooseVersion(ver + '.0') >= LooseVersion('10.0')})
1422- hookenv.status_set('maintenance', 'Monitoring PostgreSQL {} on {}'.format(css.version, principal))
1423+ ver = css.version or "9.3"
1424+ contexts.append(
1425+ {
1426+ "conn_str": str(cs),
1427+ "server": cs.host,
1428+ "replica": "master" if cs == css.master else "hot standby",
1429+ "extra_options": pg_options,
1430+ "version": ver,
1431+ "pg10": LooseVersion(ver + ".0") >= LooseVersion("10.0"),
1432+ }
1433+ )
1434+ hookenv.status_set(
1435+ "maintenance",
1436+ "Monitoring PostgreSQL {} on {}".format(css.version, principal),
1437+ )
1438 if not contexts:
1439- hookenv.status_set('waiting', 'Waiting for PostgreSQL database on {}'.format(principal))
1440- clear_flag('plugins.postgresql.configured')
1441+ hookenv.status_set(
1442+ "waiting", "Waiting for PostgreSQL database on {}".format(principal)
1443+ )
1444+ clear_flag("plugins.postgresql.configured")
1445 return
1446
1447 render_postgresql_tmpl(contexts)
1448- set_flag('plugins.postgresql.configured')
1449- set_flag('telegraf.needs_reload')
1450+ set_flag("plugins.postgresql.configured")
1451+ set_flag("telegraf.needs_reload")
1452
1453
1454 def render_mysql_tmpl(contexts):
1455- config_path = '{}/{}.conf'.format(get_configs_dir(), 'mysql')
1456+ config_path = "{}/{}.conf".format(get_configs_dir(), "mysql")
1457
1458 if contexts:
1459 f = io.StringIO()
1460- template = open(os.path.join(get_templates_dir(),
1461- 'mysql.tmpl'), 'r').read()
1462+ template = open(os.path.join(get_templates_dir(), "mysql.tmpl"), "r").read()
1463 for ctx in contexts:
1464 f.write(render_template(template, ctx))
1465 f.write(render_extra_options("inputs", "mysql"))
1466- host.write_file(config_path, f.getvalue().encode('UTF-8'))
1467+ host.write_file(config_path, f.getvalue().encode("UTF-8"))
1468 elif os.path.exists(config_path):
1469 os.unlink(config_path)
1470
1471
1472 def render_postgresql_tmpl(contexts):
1473- config_path = '{}/{}.conf'.format(get_configs_dir(), 'postgresql')
1474+ config_path = "{}/{}.conf".format(get_configs_dir(), "postgresql")
1475
1476 if contexts:
1477 f = io.StringIO()
1478- template = open(os.path.join(get_templates_dir(),
1479- 'postgresql.tmpl'), 'r').read()
1480+ template = open(
1481+ os.path.join(get_templates_dir(), "postgresql.tmpl"), "r"
1482+ ).read()
1483 for ctx in contexts:
1484 f.write(render_template(template, ctx))
1485- host.write_file(config_path, f.getvalue().encode('UTF-8'))
1486+ host.write_file(config_path, f.getvalue().encode("UTF-8"))
1487 elif os.path.exists(config_path):
1488 os.unlink(config_path)
1489
1490
1491-@when('haproxy.available')
1492+@when("haproxy.available")
1493 def haproxy_input(haproxy):
1494 template = """
1495 [[inputs.haproxy]]
1496 servers = {{ servers }}
1497 """
1498- rels = hookenv.relations_of_type('haproxy')
1499+ rels = hookenv.relations_of_type("haproxy")
1500 haproxy_addresses = []
1501 for rel in rels:
1502- enabled = rel.get('enabled', False)
1503+ enabled = rel.get("enabled", False)
1504 # Juju gives us a string instead of a boolean, fix it
1505 if isinstance(enabled, str):
1506- if enabled in ['y', 'yes', 'true', 't', 'on', 'True']:
1507+ if enabled in ["y", "yes", "true", "t", "on", "True"]:
1508 enabled = True
1509 else:
1510 enabled = False
1511 if not enabled:
1512 continue
1513- addr = rel['private-address']
1514+ addr = rel["private-address"]
1515 if addr == hookenv.unit_private_ip():
1516 addr = "localhost"
1517- port = rel['port']
1518- user = rel['user']
1519- password = rel.get('password', None)
1520+ port = rel["port"]
1521+ user = rel["user"]
1522+ password = rel.get("password", None)
1523 userpass = user
1524 if password:
1525 userpass += ":{}".format(password)
1526- haproxy_address = 'http://{}@{}:{}'.format(userpass, addr, port)
1527+ haproxy_address = "http://{}@{}:{}".format(userpass, addr, port)
1528 haproxy_addresses.append(haproxy_address)
1529- config_path = '{}/{}.conf'.format(get_configs_dir(), 'haproxy')
1530+ config_path = "{}/{}.conf".format(get_configs_dir(), "haproxy")
1531 if haproxy_addresses:
1532- input_config = render_template(template, {"servers": json.dumps(haproxy_addresses)}) + \
1533- render_extra_options("inputs", "haproxy")
1534- hookenv.log("Updating {} plugin config file".format('haproxy'))
1535- host.write_file(config_path, input_config.encode('utf-8'))
1536- set_flag('plugins.haproxy.configured')
1537+ input_config = render_template(
1538+ template, {"servers": json.dumps(haproxy_addresses)}
1539+ ) + render_extra_options("inputs", "haproxy")
1540+ hookenv.log("Updating {} plugin config file".format("haproxy"))
1541+ host.write_file(config_path, input_config.encode("utf-8"))
1542+ set_flag("plugins.haproxy.configured")
1543 elif os.path.exists(config_path):
1544 os.unlink(config_path)
1545- set_flag('telegraf.needs_reload')
1546+ set_flag("telegraf.needs_reload")
1547
1548
1549-@when('apache.available')
1550+@when("apache.available")
1551 def apache_input(apache):
1552 template = """
1553 [[inputs.apache]]
1554 urls = {{ urls }}
1555 """
1556- config_path = '{}/{}.conf'.format(get_configs_dir(), 'apache')
1557- port = '8080'
1558- vhost = render(source='apache-server-status.tmpl',
1559- templates_dir=get_templates_dir(),
1560- target=None,
1561- context={'port': port})
1562- relation_info = {"ports": port,
1563- "domain": "apache-status",
1564- "enabled": True,
1565- "site_config": vhost,
1566- "site_modules": "status"}
1567+ config_path = "{}/{}.conf".format(get_configs_dir(), "apache")
1568+ port = "8080"
1569+ vhost = render(
1570+ source="apache-server-status.tmpl",
1571+ templates_dir=get_templates_dir(),
1572+ target=None,
1573+ context={"port": port},
1574+ )
1575+ relation_info = {
1576+ "ports": port,
1577+ "domain": "apache-status",
1578+ "enabled": True,
1579+ "site_config": vhost,
1580+ "site_modules": "status",
1581+ }
1582 urls = []
1583- rels = hookenv.relations_of_type('apache')
1584+ rels = hookenv.relations_of_type("apache")
1585 for rel in rels:
1586- hookenv.relation_set(rel['__relid__'], relation_settings=relation_info)
1587- addr = rel['private-address']
1588- url = 'http://{}:{}/server-status?auto'.format(addr, port)
1589+ hookenv.relation_set(rel["__relid__"], relation_settings=relation_info)
1590+ addr = rel["private-address"]
1591+ url = "http://{}:{}/server-status?auto".format(addr, port)
1592 urls.append(url)
1593 if urls:
1594 context = {"urls": json.dumps(urls)}
1595- input_config = render_template(template, context) + \
1596- render_extra_options("inputs", "apache")
1597- hookenv.log("Updating {} plugin config file".format('apache'))
1598- host.write_file(config_path, input_config.encode('utf-8'))
1599- set_flag('plugins.apache.configured')
1600+ input_config = render_template(template, context) + render_extra_options(
1601+ "inputs", "apache"
1602+ )
1603+ hookenv.log("Updating {} plugin config file".format("apache"))
1604+ host.write_file(config_path, input_config.encode("utf-8"))
1605+ set_flag("plugins.apache.configured")
1606 elif os.path.exists(config_path):
1607 os.unlink(config_path)
1608- set_flag('telegraf.needs_reload')
1609+ set_flag("telegraf.needs_reload")
1610
1611
1612-@when('endpoint.redis.available')
1613+@when("endpoint.redis.available")
1614 def redis_input(redis):
1615 template = """
1616 [[inputs.redis]]
1617@@ -827,30 +895,34 @@ def redis_input(redis):
1618 # Until https://github.com/influxdata/telegraf/issues/5036 is fixed
1619 fielddrop = ["aof_last_bgrewrite_status","aof_last_write_status","maxmemory_policy","rdb_last_bgsave_status","used_memory_dataset_perc","used_memory_peak_perc"]
1620 """
1621- config_path = '{}/{}.conf'.format(get_configs_dir(), 'redis')
1622+ config_path = "{}/{}.conf".format(get_configs_dir(), "redis")
1623
1624- rels = hookenv.relations_of_type('redis')
1625+ rels = hookenv.relations_of_type("redis")
1626 if rels:
1627 if len(rels) != 1:
1628- hookenv.log("Unexpected number of units in the redis relation."
1629- "Expected 1, got {}".format(len(rels)), "WARNING")
1630+ hookenv.log(
1631+ "Unexpected number of units in the redis relation."
1632+ "Expected 1, got {}".format(len(rels)),
1633+ "WARNING",
1634+ )
1635
1636 ctxt = {}
1637- ctxt["host"] = rels[0]['host'].strip('"')
1638- ctxt["port"] = rels[0]['port']
1639- input_config = render_template(template, ctxt) + \
1640- render_extra_options("inputs", "redis")
1641- hookenv.log("Updating {} plugin config file".format('redis'))
1642- host.write_file(config_path, input_config.encode('utf-8'))
1643- set_flag('plugins.redis.configured')
1644+ ctxt["host"] = rels[0]["host"].strip('"')
1645+ ctxt["port"] = rels[0]["port"]
1646+ input_config = render_template(template, ctxt) + render_extra_options(
1647+ "inputs", "redis"
1648+ )
1649+ hookenv.log("Updating {} plugin config file".format("redis"))
1650+ host.write_file(config_path, input_config.encode("utf-8"))
1651+ set_flag("plugins.redis.configured")
1652 elif os.path.exists(config_path):
1653 os.unlink(config_path)
1654- clear_flag('plugins.redis.configured')
1655+ clear_flag("plugins.redis.configured")
1656
1657- set_flag('telegraf.needs_reload')
1658+ set_flag("telegraf.needs_reload")
1659
1660
1661-@when('endpoint.sentry.joined')
1662+@when("endpoint.sentry.joined")
1663 def sentry_input(sentry):
1664 template = """
1665 [[inputs.statsd]]
1666@@ -861,24 +933,25 @@ def sentry_input(sentry):
1667 delete_sets = false
1668 delete_timings = false
1669 """
1670- config_path = '{}/{}.conf'.format(get_configs_dir(), 'sentry')
1671+ config_path = "{}/{}.conf".format(get_configs_dir(), "sentry")
1672
1673- rels = hookenv.relations_of_type('sentry')
1674+ rels = hookenv.relations_of_type("sentry")
1675 if rels:
1676 for rel in rels:
1677- input_config = render_template(template, {}) + \
1678- render_extra_options("inputs", "sentry")
1679- hookenv.log("Updating {} plugin config file".format('sentry'))
1680- host.write_file(config_path, input_config.encode('utf-8'))
1681- set_flag('plugins.sentry.configured')
1682+ input_config = render_template(template, {}) + render_extra_options(
1683+ "inputs", "sentry"
1684+ )
1685+ hookenv.log("Updating {} plugin config file".format("sentry"))
1686+ host.write_file(config_path, input_config.encode("utf-8"))
1687+ set_flag("plugins.sentry.configured")
1688 elif os.path.exists(config_path):
1689 os.unlink(config_path)
1690- clear_flag('plugins.sentry.configured')
1691+ clear_flag("plugins.sentry.configured")
1692
1693- set_flag('telegraf.needs_reload')
1694+ set_flag("telegraf.needs_reload")
1695
1696
1697-@when('exec.available')
1698+@when("exec.available")
1699 def exec_input(exec_rel):
1700 template = """
1701 {% for cmd in commands %}
1702@@ -898,52 +971,52 @@ def exec_input(exec_rel):
1703
1704 {% endfor %}
1705 """
1706- config_path = '{}/{}.conf'.format(get_configs_dir(), 'exec')
1707+ config_path = "{}/{}.conf".format(get_configs_dir(), "exec")
1708 commands = exec_rel.commands()
1709 if not commands:
1710 hookenv.log("No Commands defined in the exec relation, doing nothing.")
1711 return
1712 pre_proc_cmds = []
1713 for command in commands:
1714- run_on_this_unit = command.pop('run_on_this_unit')
1715+ run_on_this_unit = command.pop("run_on_this_unit")
1716 if run_on_this_unit:
1717 pre_proc_cmds.append(command)
1718 if pre_proc_cmds:
1719- input_config = render_template(template, {'commands': pre_proc_cmds})
1720- hookenv.log("Updating {} plugin config file".format('exec'))
1721- host.write_file(config_path, input_config.encode('utf-8'))
1722- set_flag('plugins.exec.configured')
1723+ input_config = render_template(template, {"commands": pre_proc_cmds})
1724+ hookenv.log("Updating {} plugin config file".format("exec"))
1725+ host.write_file(config_path, input_config.encode("utf-8"))
1726+ set_flag("plugins.exec.configured")
1727 else:
1728 # if no commands, remove previous config
1729 if os.path.exists(config_path):
1730 os.unlink(config_path)
1731- set_flag('telegraf.needs_reload')
1732+ set_flag("telegraf.needs_reload")
1733
1734
1735-@when_not('exec.available')
1736-@when('plugins.exec.configured')
1737+@when_not("exec.available")
1738+@when("plugins.exec.configured")
1739 def exec_input_departed():
1740- config_path = '{}/{}.conf'.format(get_configs_dir(), 'exec')
1741- rels = hookenv.relations_of_type('exec')
1742+ config_path = "{}/{}.conf".format(get_configs_dir(), "exec")
1743+ rels = hookenv.relations_of_type("exec")
1744 if not rels:
1745- clear_flag('plugins.exec.configured')
1746+ clear_flag("plugins.exec.configured")
1747 if os.path.exists(config_path):
1748 os.unlink(config_path)
1749- set_flag('telegraf.needs_reload')
1750+ set_flag("telegraf.needs_reload")
1751
1752
1753-@when('amqp.connected')
1754-@when_not('amqp.available')
1755+@when("amqp.connected")
1756+@when_not("amqp.available")
1757 def rabbitmq_input_setup(rabbitmq):
1758 # Requires management_plugin=true on the rabbitmq-server application.
1759 # vhost will not be used, but still needs to be requested.
1760- username = vhost = 'telegraf-' + hookenv.local_unit().replace('/', '-')
1761+ username = vhost = "telegraf-" + hookenv.local_unit().replace("/", "-")
1762 rabbitmq.set_local(admin=True)
1763 rabbitmq.set_remote(admin=True)
1764 rabbitmq.request_access(username=username, vhost=vhost)
1765
1766
1767-@when('amqp.available')
1768+@when("amqp.available")
1769 def rabbitmq_input(rabbitmq):
1770 template = """
1771 [[inputs.rabbitmq]]
1772@@ -953,113 +1026,123 @@ def rabbitmq_input(rabbitmq):
1773 fielddrop = ["idle_since"]
1774 """
1775 addr = rabbitmq.private_address()
1776- port = '15672'
1777+ port = "15672"
1778 username = rabbitmq.username()
1779 password = rabbitmq.password()
1780
1781 if not (addr and username and password):
1782 return
1783
1784- config_path = '{}/{}.conf'.format(get_configs_dir(), 'rabbitmq')
1785- input_config = render_template(template, {'server': addr, 'username': username, 'password': password, 'port': port})
1786+ config_path = "{}/{}.conf".format(get_configs_dir(), "rabbitmq")
1787+ input_config = render_template(
1788+ template,
1789+ {"server": addr, "username": username, "password": password, "port": port},
1790+ )
1791
1792- hookenv.log('Updating {} plugin config file'.format('rabbitmq'))
1793- host.write_file(config_path, input_config.encode('utf-8'))
1794+ hookenv.log("Updating {} plugin config file".format("rabbitmq"))
1795+ host.write_file(config_path, input_config.encode("utf-8"))
1796
1797- set_flag('plugins.rabbitmq.configured')
1798- set_flag('telegraf.needs_reload')
1799+ set_flag("plugins.rabbitmq.configured")
1800+ set_flag("telegraf.needs_reload")
1801
1802
1803-@when_not('amqp.available')
1804-@when('plugins.rabbitmq.configured')
1805+@when_not("amqp.available")
1806+@when("plugins.rabbitmq.configured")
1807 def rabbitmq_input_departed():
1808- config_path = '{}/{}.conf'.format(get_configs_dir(), 'rabbitmq')
1809- clear_flag('plugins.rabbitmq.configured')
1810+ config_path = "{}/{}.conf".format(get_configs_dir(), "rabbitmq")
1811+ clear_flag("plugins.rabbitmq.configured")
1812 if os.path.exists(config_path):
1813 os.unlink(config_path)
1814- set_flag('telegraf.needs_reload')
1815+ set_flag("telegraf.needs_reload")
1816
1817
1818-@when('influxdb-api.available')
1819+@when("influxdb-api.available")
1820 def influxdb_api_output(influxdb):
1821- required_keys = ['hostname', 'port', 'user', 'password']
1822- rels = hookenv.relations_of_type('influxdb-api')
1823+ required_keys = ["hostname", "port", "user", "password"]
1824+ rels = hookenv.relations_of_type("influxdb-api")
1825 endpoints = []
1826 user = None
1827 password = None
1828 for rel in rels:
1829 if all([rel.get(key) for key in required_keys]):
1830- endpoints.append("http://{}:{}".format(rel['hostname'], rel['port']))
1831+ endpoints.append("http://{}:{}".format(rel["hostname"], rel["port"]))
1832 if user is None:
1833- user = rel['user']
1834+ user = rel["user"]
1835 if password is None:
1836- password = rel['password']
1837- config_path = '{}/{}.conf'.format(get_configs_dir(), 'influxdb-api')
1838+ password = rel["password"]
1839+ config_path = "{}/{}.conf".format(get_configs_dir(), "influxdb-api")
1840 if endpoints:
1841- hookenv.log("Updating {} plugin config file".format('influxdb-api'))
1842- content = render(source='influxdb-api.conf.tmpl', target=None,
1843- templates_dir=get_templates_dir(),
1844- context={'urls': json.dumps(endpoints),
1845- 'username': '{}'.format(user),
1846- 'password': '{}'.format(password)})
1847+ hookenv.log("Updating {} plugin config file".format("influxdb-api"))
1848+ content = render(
1849+ source="influxdb-api.conf.tmpl",
1850+ target=None,
1851+ templates_dir=get_templates_dir(),
1852+ context={
1853+ "urls": json.dumps(endpoints),
1854+ "username": "{}".format(user),
1855+ "password": "{}".format(password),
1856+ },
1857+ )
1858 extra_opts = render_extra_options("outputs", "influxdb")
1859- host.write_file(config_path, '\n'.join([content, extra_opts]).encode('utf-8'))
1860- set_flag('plugins.influxdb-api.configured')
1861+ host.write_file(config_path, "\n".join([content, extra_opts]).encode("utf-8"))
1862+ set_flag("plugins.influxdb-api.configured")
1863 elif os.path.exists(config_path):
1864 os.unlink(config_path)
1865- set_flag('telegraf.needs_reload')
1866+ set_flag("telegraf.needs_reload")
1867
1868
1869-@when('prometheus-client.available')
1870+@when("prometheus-client.available")
1871 def prometheus_client(prometheus):
1872 template = """
1873 [[outputs.prometheus_client]]
1874 listen = "{{ listen }}"
1875 """
1876- for relation_id in hookenv.relation_ids('prometheus-client'):
1877+ for relation_id in hookenv.relation_ids("prometheus-client"):
1878 # if juju 2.x+ then we'll attempt to get the network space address
1879 try:
1880- hookenv.log('Network Info')
1881- network_info = hookenv.network_get('prometheus-client', relation_id=relation_id)
1882+ hookenv.log("Network Info")
1883+ network_info = hookenv.network_get(
1884+ "prometheus-client", relation_id=relation_id
1885+ )
1886 hookenv.log(network_info)
1887- if 'ingress-addresses' in network_info:
1888- ip_addr = network_info.get('ingress-addresses')[0]
1889+ if "ingress-addresses" in network_info:
1890+ ip_addr = network_info.get("ingress-addresses")[0]
1891 else:
1892- ip_addr = hookenv.network_get_primary_address('prometheus-client')
1893+ ip_addr = hookenv.network_get_primary_address("prometheus-client")
1894 except NotImplementedError:
1895 # if that fails, just let prometheus.configure(...) do it's default
1896 ip_addr = None
1897 if get_prometheus_port():
1898 hookenv.log("Prometheus configured globally, skipping plugin setup")
1899- prometheus.configure(get_prometheus_port(),
1900- hostname=ip_addr,
1901- private_address=ip_addr)
1902- set_flag('prometheus-client.configured')
1903+ prometheus.configure(
1904+ get_prometheus_port(), hostname=ip_addr, private_address=ip_addr
1905+ )
1906+ set_flag("prometheus-client.configured")
1907 # bail out, nothing more need to be configured here
1908 return
1909 port = 9126
1910 extra_options = get_extra_options()
1911- options = extra_options['outputs'].get('prometheus-client', {})
1912- listen = options.pop('listen', None)
1913+ options = extra_options["outputs"].get("prometheus-client", {})
1914+ listen = options.pop("listen", None)
1915 if listen is not None:
1916- hookenv.log("Configuring prometheus_client plugin to listen on: '{}'".format(listen))
1917+ hookenv.log(
1918+ "Configuring prometheus_client plugin to listen on: '{}'".format(listen)
1919+ )
1920 port = int(listen.split(":", 1)[1])
1921 else:
1922 listen = ":{}".format(port)
1923 check_prometheus_port("prometheus_output", port)
1924- prometheus.configure(port,
1925- hostname=ip_addr,
1926- private_address=ip_addr)
1927- config_path = '{}/{}.conf'.format(get_configs_dir(), 'prometheus-client')
1928- hookenv.log("Updating {} plugin config file".format('prometheus-client'))
1929+ prometheus.configure(port, hostname=ip_addr, private_address=ip_addr)
1930+ config_path = "{}/{}.conf".format(get_configs_dir(), "prometheus-client")
1931+ hookenv.log("Updating {} plugin config file".format("prometheus-client"))
1932 context = {"listen": listen}
1933- content = render_template(template, context) + \
1934- render_extra_options("outputs", "prometheus_client",
1935- extra_options=extra_options)
1936- host.write_file(config_path, content.encode('utf-8'))
1937- set_flag('plugins.prometheus-client.configured')
1938- set_flag('telegraf.needs_reload')
1939- set_flag('prometheus-client.configured')
1940+ content = render_template(template, context) + render_extra_options(
1941+ "outputs", "prometheus_client", extra_options=extra_options
1942+ )
1943+ host.write_file(config_path, content.encode("utf-8"))
1944+ set_flag("plugins.prometheus-client.configured")
1945+ set_flag("telegraf.needs_reload")
1946+ set_flag("prometheus-client.configured")
1947
1948
1949 def convert_days(time_string):
1950@@ -1070,91 +1153,98 @@ def convert_days(time_string):
1951 Not included, months and years, because the number of days in each changes.
1952 Also not included, seconds.
1953 """
1954- days = re.search(r'(\d+)d$', time_string)
1955+ days = re.search(r"(\d+)d$", time_string)
1956 if days:
1957 return days.group(1)
1958- weeks = re.search(r'(\d+)w$', time_string)
1959+ weeks = re.search(r"(\d+)w$", time_string)
1960 if weeks:
1961 days = int(weeks.group(1)) * 7
1962 return str(days)
1963- hours = re.search(r'(\d+)h$', time_string)
1964+ hours = re.search(r"(\d+)h$", time_string)
1965 if hours:
1966 days = int(hours.group(1)) / 24
1967 return str(days)
1968- mins = re.search(r'(\d+)m$', time_string)
1969+ mins = re.search(r"(\d+)m$", time_string)
1970 if mins:
1971 days = int(hours.group(1)) / 24 * 60
1972 return str(days)
1973
1974
1975-@when('prometheus-rules.available')
1976+@when("prometheus-rules.available")
1977 def render_prometheus_rules(prometheus_rules):
1978 # Send a list of rules for alerting to Prometheus
1979 config = hookenv.config()
1980- unit_name = os.environ.get('JUJU_PRINCIPAL_UNIT')
1981- lead_time = config.get('lead_time')
1982- context = {'hostname': socket.gethostname(),
1983- 'cpu_idle': config.get('cpu_idle'),
1984- 'wait_time': config.get('wait_time'),
1985- 'lead_time': lead_time,
1986- 'lead_days': convert_days(lead_time),
1987- 'prometheus_context': config.get('prometheus_context'),
1988- 'unit_name': unit_name,
1989- 'application_name': unit_name.split('/')[0],
1990- }
1991+ unit_name = os.environ.get("JUJU_PRINCIPAL_UNIT")
1992+ lead_time = config.get("lead_time")
1993+ context = {
1994+ "hostname": socket.gethostname(),
1995+ "cpu_idle": config.get("cpu_idle"),
1996+ "wait_time": config.get("wait_time"),
1997+ "lead_time": lead_time,
1998+ "lead_days": convert_days(lead_time),
1999+ "prometheus_context": config.get("prometheus_context"),
2000+ "unit_name": unit_name,
2001+ "application_name": unit_name.split("/")[0],
2002+ }
2003 formatted_rules = []
2004- template_files = ['rule_cpu_usage.tmpl',
2005- 'rule_disk_predictive.tmpl',
2006- 'rule_mem_starvation.tmpl',
2007- ]
2008+ template_files = [
2009+ "rule_cpu_usage.tmpl",
2010+ "rule_disk_predictive.tmpl",
2011+ "rule_mem_starvation.tmpl",
2012+ ]
2013 for template_file in template_files:
2014- with open(os.path.join(get_templates_dir(), template_file), 'r') as fd:
2015+ with open(os.path.join(get_templates_dir(), template_file), "r") as fd:
2016 formatted_rules.append(render_template(fd.read(), context))
2017 prometheus_rules.configure("\n".join(formatted_rules))
2018
2019
2020-@when_not('prometheus-client.available')
2021-@when('plugins.prometheus-client.configured')
2022+@when_not("prometheus-client.available")
2023+@when("plugins.prometheus-client.configured")
2024 def prometheus_client_departed():
2025 hookenv.log("prometheus-client relation not available")
2026- config_path = '{}/{}.conf'.format(get_configs_dir(), 'prometheus-client')
2027- rels = hookenv.relations_of_type('prometheus-client')
2028+ config_path = "{}/{}.conf".format(get_configs_dir(), "prometheus-client")
2029+ rels = hookenv.relations_of_type("prometheus-client")
2030 if not rels and os.path.exists(config_path):
2031- hookenv.log("Deleting {} plugin config file".format('prometheus-client'))
2032+ hookenv.log("Deleting {} plugin config file".format("prometheus-client"))
2033 os.unlink(config_path)
2034- clear_flag('plugins.prometheus-client.configured')
2035- set_flag('telegraf.needs_reload')
2036- clear_flag('prometheus-client.configured')
2037+ clear_flag("plugins.prometheus-client.configured")
2038+ set_flag("telegraf.needs_reload")
2039+ clear_flag("prometheus-client.configured")
2040
2041
2042-@when('prometheus-client.configured',
2043- 'endpoint.dashboards.joined',
2044- 'leadership.is_leader')
2045-@when_not('grafana.configured')
2046+@when(
2047+ "prometheus-client.configured", "endpoint.dashboards.joined", "leadership.is_leader"
2048+)
2049+@when_not("grafana.configured")
2050 def register_grafana_dashboard():
2051- grafana = endpoint_from_flag('endpoint.dashboards.joined')
2052- hookenv.log('Loading grafana dashboard', level=hookenv.DEBUG)
2053+ grafana = endpoint_from_flag("endpoint.dashboards.joined")
2054+ hookenv.log("Loading grafana dashboard", level=hookenv.DEBUG)
2055 dashboard = _load_grafana_dashboard()
2056 dashboard_dict = json.loads(dashboard)
2057- hookenv.log('Rendered dashboard dict:\n{}'.format(dashboard_dict), level=hookenv.DEBUG)
2058+ hookenv.log(
2059+ "Rendered dashboard dict:\n{}".format(dashboard_dict), level=hookenv.DEBUG
2060+ )
2061 grafana.register_dashboard(name=GRAFANA_DASHBOARD_NAME, dashboard=dashboard_dict)
2062 hookenv.log('Grafana dashboard "{}" registered.'.format(GRAFANA_DASHBOARD_NAME))
2063- set_flag('grafana.configured')
2064+ set_flag("grafana.configured")
2065
2066
2067 def _load_grafana_dashboard():
2068 prometheus_datasource = "{} - Juju generated source".format(
2069- hookenv.config().get('prometheus_datasource', 'prometheus'))
2070+ hookenv.config().get("prometheus_datasource", "prometheus")
2071+ )
2072 dashboard_context = dict(datasource=prometheus_datasource)
2073 # TODO: Figure out if metrics exist and then set bools accordingly.
2074 # For now, setting bools to true.
2075- dashboard_context['bonds_enabled'] = True
2076- dashboard_context['bcache_enabled'] = True
2077- dashboard_context['conntrack_enabled'] = True
2078- return render_custom(source=GRAFANA_DASHBOARD_TELEGRAF_FILE_NAME,
2079- render_context=dashboard_context,
2080- variable_start_string="<<",
2081- variable_end_string=">>")
2082+ dashboard_context["bonds_enabled"] = True
2083+ dashboard_context["bcache_enabled"] = True
2084+ dashboard_context["conntrack_enabled"] = True
2085+ return render_custom(
2086+ source=GRAFANA_DASHBOARD_TELEGRAF_FILE_NAME,
2087+ render_context=dashboard_context,
2088+ variable_start_string="<<",
2089+ variable_end_string=">>",
2090+ )
2091
2092
2093 # This isn't exposed in charmhelpers: https://github.com/juju/charm-helpers/issues/367
2094@@ -1167,51 +1257,63 @@ def render_custom(source, render_context, **parameters):
2095
2096 returns the rendered template content
2097 """
2098- template_folder = os.path.join(hookenv.charm_dir(), 'templates/dashboards/grafana')
2099+ template_folder = os.path.join(hookenv.charm_dir(), "templates/dashboards/grafana")
2100 environment = Environment(loader=FileSystemLoader(template_folder), **parameters)
2101 try:
2102 template = environment.get_template(source)
2103 except exceptions.TemplateNotFound as e:
2104- hookenv.log('Could not load template {} from {}'.format(source, template_folder))
2105+ hookenv.log(
2106+ "Could not load template {} from {}".format(source, template_folder)
2107+ )
2108 raise e
2109 return template.render(render_context)
2110
2111
2112-@when('endpoint.dashboards.departed',
2113- 'grafana.configured')
2114+@when("endpoint.dashboards.departed", "grafana.configured")
2115 def unregister_grafana_dashboard():
2116- clear_flag('grafana.configured')
2117+ clear_flag("grafana.configured")
2118
2119
2120-@when('endpoint.dashboards.failed',
2121- 'leadership.is_leader')
2122+@when("endpoint.dashboards.failed", "leadership.is_leader")
2123 def grafana_dashboard_import_failed():
2124- grafana = endpoint_from_flag('endpoint.dashboards.failed')
2125+ grafana = endpoint_from_flag("endpoint.dashboards.failed")
2126 for failed_import in grafana.failed_imports:
2127 hookenv.log(
2128 message='Grafana dashboard "{}" import failed with: {}'.format(
2129- failed_import.name, failed_import.reason),
2130- level=hookenv.ERROR
2131+ failed_import.name, failed_import.reason
2132+ ),
2133+ level=hookenv.ERROR,
2134 )
2135- clear_flag('grafana.configured')
2136+ clear_flag("grafana.configured")
2137
2138
2139-@when('telegraf.needs_reload')
2140+@when("telegraf.needs_reload")
2141 def start_or_restart():
2142- states = sorted([k for k in get_states().keys()
2143- if k.startswith('plugins') or k.startswith('extra_plugins')])
2144+ states = sorted(
2145+ [
2146+ k
2147+ for k in get_states().keys()
2148+ if k.startswith("plugins") or k.startswith("extra_plugins")
2149+ ]
2150+ )
2151
2152 service = get_service()
2153 config_files_changed = helpers.any_file_changed(list_config_files())
2154- active_plugins_changed = helpers.data_changed('active_plugins', states or '')
2155- if not host.service_running(service) \
2156- or config_files_changed or active_plugins_changed:
2157+ active_plugins_changed = helpers.data_changed("active_plugins", states or "")
2158+ if (
2159+ not host.service_running(service)
2160+ or config_files_changed
2161+ or active_plugins_changed
2162+ ):
2163 hookenv.log("Restarting telegraf")
2164 host.service_restart(service)
2165 else:
2166- hookenv.log("Not restarting: active_plugins_changed={} | "
2167- "config_files_changed={}".format(active_plugins_changed,
2168- config_files_changed))
2169+ hookenv.log(
2170+ "Not restarting: active_plugins_changed={} | "
2171+ "config_files_changed={}".format(
2172+ active_plugins_changed, config_files_changed
2173+ )
2174+ )
2175
2176 # Give telegraf time to restart.
2177 timeout = time.time() + 15
2178@@ -1219,12 +1321,10 @@ def start_or_restart():
2179 time.sleep(0.1)
2180
2181 if host.service_running(service):
2182- hookenv.status_set('active',
2183- 'Monitoring {}'.format(get_remote_unit_name()))
2184- clear_flag('telegraf.needs_reload')
2185+ hookenv.status_set("active", "Monitoring {}".format(get_remote_unit_name()))
2186+ clear_flag("telegraf.needs_reload")
2187 else:
2188- hookenv.status_set('blocked',
2189- 'Telegraf failed to start. Check config.')
2190+ hookenv.status_set("blocked", "Telegraf failed to start. Check config.")
2191
2192
2193 def is_bcache():
2194@@ -1232,25 +1332,24 @@ def is_bcache():
2195 return true if bcache is present, and this is not a container
2196 """
2197 container = is_container()
2198- return (os.path.exists("/sys/fs/bcache") and not container)
2199+ return os.path.exists("/sys/fs/bcache") and not container
2200
2201
2202-@hook('update-status')
2203+@hook("update-status")
2204 def update_status():
2205 changed = charms.reactive.helpers.is_data_changed(
2206- 'detect_changes',
2207- get_base_inputs(),
2208- hash_type='sha256')
2209+ "detect_changes", get_base_inputs(), hash_type="sha256"
2210+ )
2211 if changed:
2212- clear_flag('telegraf.configured')
2213- clear_flag('telegraf.apt.configured')
2214- clear_flag('telegraf.snap.configured')
2215+ clear_flag("telegraf.configured")
2216+ clear_flag("telegraf.apt.configured")
2217+ clear_flag("telegraf.snap.configured")
2218
2219
2220-@when('nrpe-external-master.available')
2221-@when('telegraf.installed')
2222-@when('telegraf.configured')
2223-@when_not('telegraf.nagios-setup.complete')
2224+@when("nrpe-external-master.available")
2225+@when("telegraf.installed")
2226+@when("telegraf.configured")
2227+@when_not("telegraf.nagios-setup.complete")
2228 def configure_nagios(nagios):
2229 """Configure nagios process check.
2230 the flag 'telegraf.nagios-setup.complete' is reset at the moment config is
2231@@ -1262,9 +1361,9 @@ def configure_nagios(nagios):
2232
2233 # use charmhelpers to create a process check
2234 nrpe_setup.add_check(
2235- 'telegraf_http',
2236- 'Telegraf HTTP check',
2237- 'check_http -I 127.0.0.1 -p {} -u /metrics'.format(get_prometheus_port())
2238+ "telegraf_http",
2239+ "Telegraf HTTP check",
2240+ "check_http -I 127.0.0.1 -p {} -u /metrics".format(get_prometheus_port()),
2241 )
2242 nrpe_setup.write()
2243- set_flag('telegraf.nagios-setup.complete')
2244+ set_flag("telegraf.nagios-setup.complete")
2245diff --git a/src/tests/functional/tests/test_telegraf.py b/src/tests/functional/tests/test_telegraf.py
2246index e9341e7..1b80661 100644
2247--- a/src/tests/functional/tests/test_telegraf.py
2248+++ b/src/tests/functional/tests/test_telegraf.py
2249@@ -48,26 +48,30 @@ class BaseTelegrafTest(unittest.TestCase):
2250
2251
2252 class TestTelegraf(BaseTelegrafTest):
2253-
2254 def check_re_pattern(self, re_pattern, text):
2255- logging.info('checking metrics %s', re_pattern)
2256+ logging.info("checking metrics %s", re_pattern)
2257 # findall returns a list, [] when no match
2258 self.assertTrue(re.findall(re_pattern, text, flags=re.M))
2259
2260 def test_01_service(self):
2261- principal_units = (model.get_units(app)
2262- for app in juju.get_principle_applications(self.application_name))
2263+ principal_units = (
2264+ model.get_units(app)
2265+ for app in juju.get_principle_applications(self.application_name)
2266+ )
2267 for unit in it.chain.from_iterable(principal_units):
2268 if not unit.public_address:
2269 continue
2270- url = "http://{}:{}/metrics".format(unit.public_address, DEFAULT_TELEGRAF_EXPORTER_PORT)
2271+ url = "http://{}:{}/metrics".format(
2272+ unit.public_address, DEFAULT_TELEGRAF_EXPORTER_PORT
2273+ )
2274 for retry in range(DEFAULT_RETRIES):
2275 resp = requests.get(url, timeout=DEFAULT_HTTPGET_TIMEOUT)
2276 self.assertEqual(resp.status_code, 200)
2277
2278- if ((unit.name.startswith("postgresql/") and
2279- "postgresql_blks_hit" not in resp.text) or
2280- "cpu_usage_idle" not in resp.text):
2281+ if (
2282+ unit.name.startswith("postgresql/")
2283+ and "postgresql_blks_hit" not in resp.text
2284+ ) or "cpu_usage_idle" not in resp.text:
2285 time.sleep(DEFAULT_RETRIES_TIMEOUT)
2286 continue
2287
2288@@ -79,12 +83,12 @@ class TestTelegraf(BaseTelegrafTest):
2289
2290 # check metrics are available
2291 re_patterns = [
2292- r'^sockstat_',
2293- r'^sockstat6_',
2294- r'^softnet_stat',
2295- r'^buddyinfo_',
2296- r'^zoneinfo_',
2297- r'^processes_',
2298+ r"^sockstat_",
2299+ r"^sockstat6_",
2300+ r"^softnet_stat",
2301+ r"^buddyinfo_",
2302+ r"^zoneinfo_",
2303+ r"^processes_",
2304 ]
2305 for re_pattern in re_patterns:
2306 self.check_re_pattern(re_pattern, text)
2307@@ -97,34 +101,52 @@ class TestTelegraf(BaseTelegrafTest):
2308
2309 def test_02_telegraf_logfile(self):
2310 """Check logfile parameter exists in ${BASE_DIR}/telegraf.conf."""
2311- install_method = model.get_application_config('telegraf')['install_method']['value']
2312- if install_method == 'deb':
2313+ install_method = model.get_application_config("telegraf")["install_method"][
2314+ "value"
2315+ ]
2316+ if install_method == "deb":
2317 telegraf_conf = DEB_TELEGRAF_CONF
2318 else:
2319 telegraf_conf = SNAP_TELEGRAF_CONF
2320 cmd = "cat {}".format(telegraf_conf)
2321 response = model.run_on_unit(self.lead_unit_name, cmd)
2322 if response["Code"] != "0":
2323- self.fail("test_02_telegraf_logfile: could not read file {}".format(telegraf_conf))
2324+ self.fail(
2325+ "test_02_telegraf_logfile: could not read file {}".format(telegraf_conf)
2326+ )
2327
2328 for line in response["Stdout"].splitlines():
2329 if line.strip() == 'logfile = "/var/log/telegraf/telegraf.log"':
2330 logging.info("test_02_telegraf_logfile: logfile config parameter found")
2331 return
2332
2333- self.fail("test_02_telegraf_logfile: logfile parameter not found in {}".format(telegraf_conf))
2334+ self.fail(
2335+ "test_02_telegraf_logfile: logfile parameter not found in {}".format(
2336+ telegraf_conf
2337+ )
2338+ )
2339
2340 def test_03_system_service(self):
2341 """Check that the right service is running, e.g. either the deb's or the snap's."""
2342- install_method = model.get_application_config('telegraf')['install_method']['value']
2343- services = {'deb': 'telegraf', 'snap': 'snap.telegraf.telegraf'}
2344+ install_method = model.get_application_config("telegraf")["install_method"][
2345+ "value"
2346+ ]
2347+ services = {"deb": "telegraf", "snap": "snap.telegraf.telegraf"}
2348 for method in services.keys():
2349 service = services[method]
2350 cmd = "service {} status".format(service)
2351 response = model.run_on_unit(self.lead_unit_name, cmd)
2352 if install_method == method and response["Code"] != "0":
2353- self.fail("test_03_system_service: service {} should be running on {} but is not. "
2354- "install_method is {}.".format(service, self.lead_unit_name, install_method))
2355+ self.fail(
2356+ "test_03_system_service: service {} should be running on {} but is not. "
2357+ "install_method is {}.".format(
2358+ service, self.lead_unit_name, install_method
2359+ )
2360+ )
2361 elif install_method != method and response["Code"] == "0":
2362- self.fail("test_03_system_service: service {} is running on {} but shouldn't. "
2363- "install_method is {}.".format(service, self.lead_unit_name, install_method))
2364+ self.fail(
2365+ "test_03_system_service: service {} is running on {} but shouldn't. "
2366+ "install_method is {}.".format(
2367+ service, self.lead_unit_name, install_method
2368+ )
2369+ )
2370diff --git a/src/tests/unit/__init__.py b/src/tests/unit/__init__.py
2371index 03acc40..28e9795 100644
2372--- a/src/tests/unit/__init__.py
2373+++ b/src/tests/unit/__init__.py
2374@@ -1,2 +1,3 @@
2375 import sys
2376-sys.path.append('.')
2377+
2378+sys.path.append(".")
2379diff --git a/src/tests/unit/test_mysql.py b/src/tests/unit/test_mysql.py
2380index 242fc37..27f206d 100644
2381--- a/src/tests/unit/test_mysql.py
2382+++ b/src/tests/unit/test_mysql.py
2383@@ -21,27 +21,26 @@ from unittest.mock import ANY, MagicMock, patch, sentinel
2384
2385 # Mock layer modules
2386 import charms
2387+
2388 promreg = MagicMock()
2389 charms.promreg = promreg
2390-sys.modules['charms.promreg'] = promreg
2391+sys.modules["charms.promreg"] = promreg
2392 import reactive
2393
2394
2395 class TestMySQL(unittest.TestCase):
2396- @patch('reactive.telegraf.render_mysql_tmpl')
2397- @patch('reactive.telegraf.toggle_flag')
2398- @patch('charmhelpers.core.hookenv.unit_private_ip')
2399- @patch('charmhelpers.context.Relations')
2400- def test_mysql_input(self, relations, unit_private_ip, toggle_flag,
2401- render):
2402+ @patch("reactive.telegraf.render_mysql_tmpl")
2403+ @patch("reactive.telegraf.toggle_flag")
2404+ @patch("charmhelpers.core.hookenv.unit_private_ip")
2405+ @patch("charmhelpers.context.Relations")
2406+ def test_mysql_input(self, relations, unit_private_ip, toggle_flag, render):
2407 mysql = MagicMock()
2408- mysql.relation_name = 'dbrel'
2409+ mysql.relation_name = "dbrel"
2410 relation = MagicMock()
2411- relations()[mysql.relation_name].items.return_value = [('dbrel:1',
2412- relation)]
2413- relation.items.return_value = [('mysql/0',
2414- {'private-address': sentinel.priv_ip,
2415- 'slave': 'standalone'})]
2416+ relations()[mysql.relation_name].items.return_value = [("dbrel:1", relation)]
2417+ relation.items.return_value = [
2418+ ("mysql/0", {"private-address": sentinel.priv_ip, "slave": "standalone"})
2419+ ]
2420
2421 unit_private_ip.return_value = sentinel.priv_ip
2422
2423@@ -49,51 +48,57 @@ class TestMySQL(unittest.TestCase):
2424
2425 reactive.telegraf.mysql_input(mysql)
2426
2427- render.assert_called_once_with([{'host': mysql.host(),
2428- 'port': mysql.port(),
2429- 'user': mysql.user(),
2430- 'pass': mysql.password(),
2431- 'is_secure': 'false',
2432- 'slave': 'standalone'
2433- }])
2434- toggle_flag.assert_called_once_with('plugins.mysql.configured', True)
2435+ render.assert_called_once_with(
2436+ [
2437+ {
2438+ "host": mysql.host(),
2439+ "port": mysql.port(),
2440+ "user": mysql.user(),
2441+ "pass": mysql.password(),
2442+ "is_secure": "false",
2443+ "slave": "standalone",
2444+ }
2445+ ]
2446+ )
2447+ toggle_flag.assert_called_once_with("plugins.mysql.configured", True)
2448
2449- @patch('reactive.telegraf.render_extra_options')
2450- @patch('charmhelpers.core.host.write_file')
2451- @patch('reactive.telegraf.get_templates_dir')
2452- @patch('reactive.telegraf.get_base_dir')
2453- def test_render_mysql_tmpl(self, get_base_dir, get_templates_dir, write_file,
2454- extra_options):
2455- get_base_dir.return_value = '/etc/telegraf'
2456+ @patch("reactive.telegraf.render_extra_options")
2457+ @patch("charmhelpers.core.host.write_file")
2458+ @patch("reactive.telegraf.get_templates_dir")
2459+ @patch("reactive.telegraf.get_base_dir")
2460+ def test_render_mysql_tmpl(
2461+ self, get_base_dir, get_templates_dir, write_file, extra_options
2462+ ):
2463+ get_base_dir.return_value = "/etc/telegraf"
2464 get_templates_dir.return_value = os.path.join(
2465- os.path.dirname(__file__), '../..', 'templates')
2466- extra_options.return_value = ''
2467-
2468- reactive.telegraf.render_mysql_tmpl([{'host': 'localhost',
2469- 'port': '3306',
2470- 'user': 'test',
2471- 'pass': 'tester',
2472- 'is_secure': 'false',
2473- 'slave': 'standalone'
2474- }])
2475+ os.path.dirname(__file__), "../..", "templates"
2476+ )
2477+ extra_options.return_value = ""
2478
2479- write_file.assert_called_once_with(
2480- '/etc/telegraf/telegraf.d/mysql.conf', ANY
2481+ reactive.telegraf.render_mysql_tmpl(
2482+ [
2483+ {
2484+ "host": "localhost",
2485+ "port": "3306",
2486+ "user": "test",
2487+ "pass": "tester",
2488+ "is_secure": "false",
2489+ "slave": "standalone",
2490+ }
2491+ ]
2492 )
2493
2494- @patch('os.unlink')
2495- @patch('os.path.exists')
2496- @patch('reactive.telegraf.get_base_dir')
2497+ write_file.assert_called_once_with("/etc/telegraf/telegraf.d/mysql.conf", ANY)
2498+
2499+ @patch("os.unlink")
2500+ @patch("os.path.exists")
2501+ @patch("reactive.telegraf.get_base_dir")
2502 def test_render_mysql_tmpl_no_context(self, get_base_dir, exists, unlink):
2503 exists.return_value = False
2504- get_base_dir.return_value = '/etc/telegraf'
2505+ get_base_dir.return_value = "/etc/telegraf"
2506 reactive.telegraf.render_mysql_tmpl([])
2507- exists.assert_called_once_with(
2508- '/etc/telegraf/telegraf.d/mysql.conf'
2509- )
2510+ exists.assert_called_once_with("/etc/telegraf/telegraf.d/mysql.conf")
2511 self.assertFalse(unlink.called)
2512 exists.return_value = True
2513 reactive.telegraf.render_mysql_tmpl([])
2514- unlink.assert_called_once_with(
2515- '/etc/telegraf/telegraf.d/mysql.conf'
2516- )
2517+ unlink.assert_called_once_with("/etc/telegraf/telegraf.d/mysql.conf")
2518diff --git a/src/tests/unit/test_postgresql.py b/src/tests/unit/test_postgresql.py
2519index d831ef9..9192ea4 100644
2520--- a/src/tests/unit/test_postgresql.py
2521+++ b/src/tests/unit/test_postgresql.py
2522@@ -21,56 +21,69 @@ from unittest.mock import ANY, call, MagicMock, patch, sentinel
2523
2524 # Mock layer modules
2525 import charms
2526+
2527 apt = MagicMock()
2528 layer = MagicMock()
2529 promreg = MagicMock()
2530 charms.apt = apt
2531 charms.layer = layer
2532 charms.promreg = promreg
2533-sys.modules['charms.apt'] = apt
2534-sys.modules['charms.layer'] = layer
2535-sys.modules['charms.promreg'] = promreg
2536+sys.modules["charms.apt"] = apt
2537+sys.modules["charms.layer"] = layer
2538+sys.modules["charms.promreg"] = promreg
2539
2540 import reactive
2541 from reactive import telegraf
2542
2543
2544 class TestPostgreSQL(unittest.TestCase):
2545- @patch('reactive.telegraf.endpoint_from_flag')
2546+ @patch("reactive.telegraf.endpoint_from_flag")
2547 def test_choose_postgresql_database(self, endpoint_from_flag):
2548 telegraf.choose_postgresql_database()
2549- endpoint_from_flag.assert_called_once_with('postgresql.database.connected')
2550- endpoint_from_flag().set_database.assert_called_once_with('postgres')
2551+ endpoint_from_flag.assert_called_once_with("postgresql.database.connected")
2552+ endpoint_from_flag().set_database.assert_called_once_with("postgres")
2553
2554- @patch('reactive.telegraf.hookenv.principal_unit')
2555- @patch('reactive.telegraf.hookenv.expected_related_units')
2556- @patch('reactive.telegraf.endpoint_from_flag')
2557- @patch('reactive.telegraf.get_extra_options')
2558+ @patch("reactive.telegraf.hookenv.principal_unit")
2559+ @patch("reactive.telegraf.hookenv.expected_related_units")
2560+ @patch("reactive.telegraf.endpoint_from_flag")
2561+ @patch("reactive.telegraf.get_extra_options")
2562 def test_postgresql_input_principal_not_postgresql(
2563- self, get_extra_options, endpoint_from_flag, expected_related_units, principal_unit):
2564+ self,
2565+ get_extra_options,
2566+ endpoint_from_flag,
2567+ expected_related_units,
2568+ principal_unit,
2569+ ):
2570 """Skip execution when the principal unit is not of type postgresql-charm."""
2571 principal_unit.return_value = sentinel.principal_unit
2572 expected_related_units.return_value = []
2573 reactive.telegraf.postgresql_input()
2574 endpoint_from_flag.assert_not_called()
2575
2576- @patch('reactive.telegraf.set_flag')
2577- @patch('reactive.telegraf.hookenv.principal_unit')
2578- @patch('reactive.telegraf.hookenv.expected_related_units')
2579- @patch('reactive.telegraf.endpoint_from_flag')
2580- @patch('reactive.telegraf.get_extra_options')
2581- @patch('reactive.telegraf.render_postgresql_tmpl')
2582- def test_postgresql_input(self, render, get_extra_options, endpoint_from_flag, expected_related_units,
2583- principal_unit, set_flag):
2584+ @patch("reactive.telegraf.set_flag")
2585+ @patch("reactive.telegraf.hookenv.principal_unit")
2586+ @patch("reactive.telegraf.hookenv.expected_related_units")
2587+ @patch("reactive.telegraf.endpoint_from_flag")
2588+ @patch("reactive.telegraf.get_extra_options")
2589+ @patch("reactive.telegraf.render_postgresql_tmpl")
2590+ def test_postgresql_input(
2591+ self,
2592+ render,
2593+ get_extra_options,
2594+ endpoint_from_flag,
2595+ expected_related_units,
2596+ principal_unit,
2597+ set_flag,
2598+ ):
2599 principal_unit.return_value = sentinel.principal_unit
2600 expected_related_units.return_value = [principal_unit.return_value]
2601
2602- cs = MagicMock() # ConnectionString from interface:pgsql
2603- cs.__str__.return_value = 'libpq connection string'
2604+ cs = MagicMock() # ConnectionString from interface:pgsql
2605+ cs.__str__.return_value = "libpq connection string"
2606 cs.host = sentinel.host
2607
2608 css = MagicMock() # ConnectionStrings from interface:pgsql
2609- css.version = '10'
2610+ css.version = "10"
2611 css.get.return_value = cs
2612 css.master = cs
2613
2614@@ -78,64 +91,76 @@ class TestPostgreSQL(unittest.TestCase):
2615 pgsql.__iter__.return_value = [css]
2616 endpoint_from_flag.return_value = pgsql
2617
2618- get_extra_options.return_value = {'inputs': {}}
2619+ get_extra_options.return_value = {"inputs": {}}
2620
2621 reactive.telegraf.postgresql_input()
2622
2623- endpoint_from_flag.assert_called_once_with('postgresql.database.available')
2624+ endpoint_from_flag.assert_called_once_with("postgresql.database.available")
2625 css.get.assert_called_once_with(sentinel.principal_unit)
2626- render.assert_called_once_with([{'replica': 'master',
2627- 'conn_str': 'libpq connection string',
2628- 'server': sentinel.host,
2629- 'extra_options': None,
2630- 'version': '10',
2631- 'pg10': True}])
2632- set_flag.assert_has_calls([call('plugins.postgresql.configured'), call('telegraf.needs_reload')])
2633-
2634- @patch('charmhelpers.core.host.write_file')
2635- @patch('reactive.telegraf.get_templates_dir')
2636- @patch('reactive.telegraf.get_base_dir')
2637+ render.assert_called_once_with(
2638+ [
2639+ {
2640+ "replica": "master",
2641+ "conn_str": "libpq connection string",
2642+ "server": sentinel.host,
2643+ "extra_options": None,
2644+ "version": "10",
2645+ "pg10": True,
2646+ }
2647+ ]
2648+ )
2649+ set_flag.assert_has_calls(
2650+ [call("plugins.postgresql.configured"), call("telegraf.needs_reload")]
2651+ )
2652+
2653+ @patch("charmhelpers.core.host.write_file")
2654+ @patch("reactive.telegraf.get_templates_dir")
2655+ @patch("reactive.telegraf.get_base_dir")
2656 def test_render_postgresql_tmpl(self, get_base_dir, get_templates_dir, write_file):
2657 get_templates_dir.return_value = os.path.join(
2658- os.path.dirname(__file__), '../..', 'templates')
2659- get_base_dir.return_value = '/etc/telegraf'
2660+ os.path.dirname(__file__), "../..", "templates"
2661+ )
2662+ get_base_dir.return_value = "/etc/telegraf"
2663
2664- reactive.telegraf.render_postgresql_tmpl([
2665- {'replica': 'master',
2666- 'conn_str': 'my_conn_str',
2667- 'server': 'my_server'},
2668- ])
2669+ reactive.telegraf.render_postgresql_tmpl(
2670+ [{"replica": "master", "conn_str": "my_conn_str", "server": "my_server"},]
2671+ )
2672
2673 write_file.assert_called_once_with(
2674- '/etc/telegraf/telegraf.d/postgresql.conf', ANY
2675+ "/etc/telegraf/telegraf.d/postgresql.conf", ANY
2676 )
2677
2678- @patch('charmhelpers.core.host.write_file')
2679- @patch('reactive.telegraf.get_templates_dir')
2680- @patch('reactive.telegraf.get_base_dir')
2681- def test_render_postgresql_tmpl_extra_options(self, get_base_dir, get_templates_dir,
2682- write_file):
2683+ @patch("charmhelpers.core.host.write_file")
2684+ @patch("reactive.telegraf.get_templates_dir")
2685+ @patch("reactive.telegraf.get_base_dir")
2686+ def test_render_postgresql_tmpl_extra_options(
2687+ self, get_base_dir, get_templates_dir, write_file
2688+ ):
2689 get_templates_dir.return_value = os.path.join(
2690- os.path.dirname(__file__), '../..', 'templates')
2691- get_base_dir.return_value = '/etc/telegraf'
2692+ os.path.dirname(__file__), "../..", "templates"
2693+ )
2694+ get_base_dir.return_value = "/etc/telegraf"
2695
2696 pg_extra_opts = {
2697 "tagexclude": ["server"],
2698 "tagdrop": {"db": ["template*", "postgres", "telegraf"]},
2699 }
2700
2701- context = {'replica': 'master',
2702- 'conn_str': 'my_conn_str',
2703- 'server': 'my_server',
2704- 'extra_options': pg_extra_opts}
2705+ context = {
2706+ "replica": "master",
2707+ "conn_str": "my_conn_str",
2708+ "server": "my_server",
2709+ "extra_options": pg_extra_opts,
2710+ }
2711 reactive.telegraf.render_postgresql_tmpl([context])
2712
2713- with open(os.path.join(telegraf.get_templates_dir(), 'postgresql.tmpl'),
2714- 'r') as fd:
2715+ with open(
2716+ os.path.join(telegraf.get_templates_dir(), "postgresql.tmpl"), "r"
2717+ ) as fd:
2718 rendered = telegraf.render_template(fd.read(), context)
2719
2720 write_file.assert_called_once_with(
2721- '/etc/telegraf/telegraf.d/postgresql.conf', rendered.encode('UTF-8')
2722+ "/etc/telegraf/telegraf.d/postgresql.conf", rendered.encode("UTF-8")
2723 )
2724 # now check if what's there is the thing we actually expect
2725 expected = """[[inputs.postgresql_extensible]]
2726@@ -150,21 +175,17 @@ class TestPostgreSQL(unittest.TestCase):
2727 replica = "master"
2728
2729 [[inputs.postgresql_extensible.query]]"""
2730- self.assertEqual(rendered.split('\n')[3:15], expected.split('\n'))
2731+ self.assertEqual(rendered.split("\n")[3:15], expected.split("\n"))
2732
2733- @patch('os.unlink')
2734- @patch('os.path.exists')
2735- @patch('reactive.telegraf.get_base_dir')
2736+ @patch("os.unlink")
2737+ @patch("os.path.exists")
2738+ @patch("reactive.telegraf.get_base_dir")
2739 def test_render_postgresql_tmpl_no_context(self, get_base_dir, exists, unlink):
2740 exists.return_value = False
2741- get_base_dir.return_value = '/etc/telegraf'
2742+ get_base_dir.return_value = "/etc/telegraf"
2743 reactive.telegraf.render_postgresql_tmpl([])
2744- exists.assert_called_once_with(
2745- '/etc/telegraf/telegraf.d/postgresql.conf'
2746- )
2747+ exists.assert_called_once_with("/etc/telegraf/telegraf.d/postgresql.conf")
2748 self.assertFalse(unlink.called)
2749 exists.return_value = True
2750 reactive.telegraf.render_postgresql_tmpl([])
2751- unlink.assert_called_once_with(
2752- '/etc/telegraf/telegraf.d/postgresql.conf'
2753- )
2754+ unlink.assert_called_once_with("/etc/telegraf/telegraf.d/postgresql.conf")
2755diff --git a/src/tests/unit/test_telegraf.py b/src/tests/unit/test_telegraf.py
2756index c21b4c2..1825fa6 100644
2757--- a/src/tests/unit/test_telegraf.py
2758+++ b/src/tests/unit/test_telegraf.py
2759@@ -37,29 +37,30 @@ from charmhelpers.core.templating import render
2760
2761 # Mock layer modules
2762 import charms
2763+
2764 promreg = MagicMock()
2765 charms.promreg = promreg
2766-sys.modules['charms.promreg'] = promreg
2767+sys.modules["charms.promreg"] = promreg
2768
2769 import reactive
2770 from reactive import telegraf
2771
2772 UNIT_TESTS_DIR = os.path.dirname(os.path.abspath(__file__))
2773-UNIT_TESTS_DATA_DIR = os.path.join(UNIT_TESTS_DIR, 'data')
2774+UNIT_TESTS_DATA_DIR = os.path.join(UNIT_TESTS_DIR, "data")
2775
2776
2777 @pytest.fixture(autouse=True)
2778 def setup(monkeypatch, tmpdir):
2779- monkeypatch.setitem(os.environ, 'JUJU_UNIT_NAME', 'telegraf/0')
2780- monkeypatch.setitem(os.environ, 'JUJU_MODEL_NAME', 'telegraf-test-model')
2781- monkeypatch.setattr(telegraf, 'get_remote_unit_name', lambda: 'remote-unit/0')
2782+ monkeypatch.setitem(os.environ, "JUJU_UNIT_NAME", "telegraf/0")
2783+ monkeypatch.setitem(os.environ, "JUJU_MODEL_NAME", "telegraf-test-model")
2784+ monkeypatch.setattr(telegraf, "get_remote_unit_name", lambda: "remote-unit/0")
2785 # mock this to avoid permission errors
2786- monkeypatch.setattr(telegraf, 'update_sysstat_config_with_sdac_xall', lambda: True)
2787- monkeypatch.setattr(telegraf.hookenv, 'status_set', lambda status, msg: None)
2788- monkeypatch.setattr(telegraf.hookenv, 'log', lambda msg, **kw: None)
2789- monkeypatch.setattr(telegraf.host, 'service_resume', lambda svc: None)
2790- monkeypatch.setattr(telegraf.host, 'service_reload', lambda svc: None)
2791- monkeypatch.setattr(telegraf.host, 'service_pause', lambda svc: None)
2792+ monkeypatch.setattr(telegraf, "update_sysstat_config_with_sdac_xall", lambda: True)
2793+ monkeypatch.setattr(telegraf.hookenv, "status_set", lambda status, msg: None)
2794+ monkeypatch.setattr(telegraf.hookenv, "log", lambda msg, **kw: None)
2795+ monkeypatch.setattr(telegraf.host, "service_resume", lambda svc: None)
2796+ monkeypatch.setattr(telegraf.host, "service_reload", lambda svc: None)
2797+ monkeypatch.setattr(telegraf.host, "service_pause", lambda svc: None)
2798
2799 # patch host.write for non-root
2800 user = getpass.getuser()
2801@@ -71,16 +72,17 @@ def setup(monkeypatch, tmpdir):
2802 # owner/group as positional arguments like
2803 # charmhelpers.core.templating.render
2804 if len(a) > 2:
2805- if a[2] == 'root' and a[3] == 'root':
2806+ if a[2] == "root" and a[3] == "root":
2807 # make all files writable by owner, as we need don't run as root
2808 a = (a[0], a[1], user, group, 0o744)
2809 else:
2810- kw['owner'] = user
2811- kw['group'] = group
2812+ kw["owner"] = user
2813+ kw["group"] = group
2814 # make all files writable by owner, as we need don't run as root
2815- kw['perms'] = 0o744
2816+ kw["perms"] = 0o744
2817 return orig_write_file(*a, **kw)
2818- monkeypatch.setattr(telegraf.host, 'write_file', intercept_write_file)
2819+
2820+ monkeypatch.setattr(telegraf.host, "write_file", intercept_write_file)
2821
2822
2823 @pytest.fixture(autouse=True)
2824@@ -88,46 +90,50 @@ def cleanup(request):
2825 def unit_state_cleanup():
2826 # cleanup unitdata
2827 from charmhelpers.core import unitdata
2828+
2829 unitdata._KV = None
2830 # rm unit-state.db file
2831- unit_state_db = os.path.join(telegraf.hookenv.charm_dir(), '.unit-state.db')
2832+ unit_state_db = os.path.join(telegraf.hookenv.charm_dir(), ".unit-state.db")
2833 if os.path.exists(unit_state_db):
2834 os.unlink(unit_state_db)
2835+
2836 request.addfinalizer(unit_state_cleanup)
2837
2838
2839 @pytest.fixture()
2840 def temp_charm_dir(monkeypatch, tmpdir):
2841 charm_dir = tmpdir.mkdir("charm_dir")
2842- os.environ['CHARM_DIR'] = charm_dir.strpath
2843+ os.environ["CHARM_DIR"] = charm_dir.strpath
2844 # also monkeypatch get_templates_dir to fix the path
2845 real_charm_dir = os.path.join(os.path.dirname(reactive.__file__), "../")
2846- monkeypatch.setattr(telegraf, 'get_templates_dir',
2847- lambda: os.path.join(real_charm_dir, 'templates'))
2848- monkeypatch.setattr(telegraf, 'get_files_dir',
2849- lambda: os.path.join(real_charm_dir, 'files'))
2850+ monkeypatch.setattr(
2851+ telegraf, "get_templates_dir", lambda: os.path.join(real_charm_dir, "templates")
2852+ )
2853+ monkeypatch.setattr(
2854+ telegraf, "get_files_dir", lambda: os.path.join(real_charm_dir, "files")
2855+ )
2856 # fix hookenv.metadata
2857- with open(os.path.join(real_charm_dir, 'metadata.yaml')) as md:
2858+ with open(os.path.join(real_charm_dir, "metadata.yaml")) as md:
2859 metadata = yaml.full_load(md)
2860- monkeypatch.setattr(telegraf.hookenv, 'metadata', lambda: metadata)
2861+ monkeypatch.setattr(telegraf.hookenv, "metadata", lambda: metadata)
2862
2863
2864 @pytest.fixture(autouse=True)
2865 def temp_config_dir(monkeypatch, tmpdir):
2866 base_dir = tmpdir.mkdir("etc_telegraf")
2867 base_dir.mkdir(telegraf.CONFIG_DIR)
2868- monkeypatch.setattr(telegraf, 'DEB_BASE_DIR', base_dir.strpath)
2869+ monkeypatch.setattr(telegraf, "DEB_BASE_DIR", base_dir.strpath)
2870
2871 sudoers_dir = tmpdir.mkdir("etc_sudoers")
2872- monkeypatch.setattr(telegraf, 'SUDOERS_DIR', sudoers_dir.strpath)
2873+ monkeypatch.setattr(telegraf, "SUDOERS_DIR", sudoers_dir.strpath)
2874
2875
2876 @pytest.fixture(autouse=True)
2877 def config(monkeypatch, temp_charm_dir):
2878- raw_config = yaml.full_load(open('config.yaml', 'r'))
2879- data = dict((k, v['default']) for k, v in raw_config['options'].items())
2880+ raw_config = yaml.full_load(open("config.yaml", "r"))
2881+ data = dict((k, v["default"]) for k, v in raw_config["options"].items())
2882 config = Config(data)
2883- monkeypatch.setattr(telegraf.hookenv, 'config', lambda: config)
2884+ monkeypatch.setattr(telegraf.hookenv, "config", lambda: config)
2885 return config
2886
2887
2888@@ -142,15 +148,19 @@ def configs_dir():
2889
2890 def persist_state():
2891 """Fake persistent state by calling helpers that modify unitdata.kv"""
2892- states = [k for k in bus.get_states().keys()
2893- if k.startswith('plugins') or k.startswith('extra_plugins')]
2894+ states = [
2895+ k
2896+ for k in bus.get_states().keys()
2897+ if k.startswith("plugins") or k.startswith("extra_plugins")
2898+ ]
2899 helpers.any_file_changed(telegraf.list_config_files())
2900 if states:
2901- helpers.data_changed('active_plugins', states)
2902+ helpers.data_changed("active_plugins", states)
2903
2904
2905 # Tests
2906
2907+
2908 def check_sysstat_config(original, expected):
2909 original = original.strip()
2910 expected = expected.strip()
2911@@ -160,331 +170,372 @@ def check_sysstat_config(original, expected):
2912
2913 def test_sadc_options_correct(monkeypatch):
2914 """If SADC_OPTIONS is already correct, should return None"""
2915- original = dedent("""
2916+ original = dedent(
2917+ """
2918 # some comment
2919 COMPRESSAFTER=10
2920 SADC_OPTIONS="-S XALL"
2921 # another comment
2922 UMASK=0022
2923- """)
2924+ """
2925+ )
2926 assert telegraf.get_sysstat_config_with_sadc_xall(original) is None
2927
2928
2929 def test_sadc_options_correct_included(monkeypatch):
2930 """If SADC_OPTIONS already includes `-S XALL`, should return None"""
2931- original = dedent("""
2932+ original = dedent(
2933+ """
2934 # some comment
2935 COMPRESSAFTER=10
2936 SADC_OPTIONS="-B before -S XALL -A after"
2937 # another comment
2938 UMASK=0022
2939- """)
2940+ """
2941+ )
2942 assert telegraf.get_sysstat_config_with_sadc_xall(original) is None
2943
2944
2945 def test_sadc_options_non_exist(monkeypatch):
2946 """If SADC_OPTIONS doesn't exist, should just append"""
2947- original = dedent("""
2948+ original = dedent(
2949+ """
2950 # some comment
2951 COMPRESSAFTER=10
2952- """)
2953+ """
2954+ )
2955
2956- expected = dedent("""
2957+ expected = dedent(
2958+ """
2959 # some comment
2960 COMPRESSAFTER=10
2961 SADC_OPTIONS="-S XALL"
2962- """)
2963+ """
2964+ )
2965
2966 check_sysstat_config(original, expected)
2967
2968
2969 def test_sadc_options_commented(monkeypatch):
2970 """If SADC_OPTIONS exists but commented, should ignore and append"""
2971- original = dedent("""
2972+ original = dedent(
2973+ """
2974 # some comment
2975 COMPRESSAFTER=10
2976 #SADC_OPTIONS="-S XALL"
2977 # another comment
2978 UMASK=0022
2979- """)
2980+ """
2981+ )
2982
2983- expected = dedent("""
2984+ expected = dedent(
2985+ """
2986 # some comment
2987 COMPRESSAFTER=10
2988 #SADC_OPTIONS="-S XALL"
2989 # another comment
2990 UMASK=0022
2991 SADC_OPTIONS="-S XALL"
2992- """)
2993+ """
2994+ )
2995
2996 check_sysstat_config(original, expected)
2997
2998
2999 def test_sadc_options_incorrect(monkeypatch):
3000 """If SADC_OPTIONS exists but not XALL, should replace"""
3001- original = dedent("""
3002+ original = dedent(
3003+ """
3004 # some comment
3005 COMPRESSAFTER=10
3006 SADC_OPTIONS="-S DISK"
3007 # another comment
3008 UMASK=0022
3009- """)
3010+ """
3011+ )
3012
3013- expected = dedent("""
3014+ expected = dedent(
3015+ """
3016 # some comment
3017 COMPRESSAFTER=10
3018 SADC_OPTIONS="-S XALL"
3019 # another comment
3020 UMASK=0022
3021- """)
3022+ """
3023+ )
3024 check_sysstat_config(original, expected)
3025
3026
3027 def test_sadc_options_incorrect_included(monkeypatch):
3028 """If SADC_OPTIONS exists but not XALL, should replace"""
3029- original = dedent("""
3030+ original = dedent(
3031+ """
3032 # some comment
3033 COMPRESSAFTER=10
3034 SADC_OPTIONS="-B before -S DISK -A after"
3035 # another comment
3036 UMASK=0022
3037- """)
3038+ """
3039+ )
3040
3041- expected = dedent("""
3042+ expected = dedent(
3043+ """
3044 # some comment
3045 COMPRESSAFTER=10
3046 SADC_OPTIONS="-B before -S XALL -A after"
3047 # another comment
3048 UMASK=0022
3049- """)
3050+ """
3051+ )
3052 check_sysstat_config(original, expected)
3053
3054
3055 def test_sadc_options_commented_line_not_touched(monkeypatch):
3056 """If SADC_OPTIONS exists but has no -S, should append"""
3057- original = dedent("""
3058+ original = dedent(
3059+ """
3060 # some comment
3061 COMPRESSAFTER=10
3062 #SADC_OPTIONS="-C a-comment -D -V --arg1 --arg2"
3063 SADC_OPTIONS="-C a-comment -D -V"
3064 # another comment
3065 UMASK=0022
3066- """)
3067+ """
3068+ )
3069
3070- expected = dedent("""
3071+ expected = dedent(
3072+ """
3073 # some comment
3074 COMPRESSAFTER=10
3075 #SADC_OPTIONS="-C a-comment -D -V --arg1 --arg2"
3076 SADC_OPTIONS="-C a-comment -D -V -S XALL"
3077 # another comment
3078 UMASK=0022
3079- """)
3080+ """
3081+ )
3082
3083 check_sysstat_config(original, expected)
3084
3085
3086 def test_sadc_options_s_missing(monkeypatch):
3087 """If SADC_OPTIONS exists but has no -S, should append"""
3088- original = dedent("""
3089+ original = dedent(
3090+ """
3091 # some comment
3092 COMPRESSAFTER=10
3093 SADC_OPTIONS="-C a-comment -D -V"
3094 # another comment
3095 UMASK=0022
3096- """)
3097+ """
3098+ )
3099
3100- expected = dedent("""
3101+ expected = dedent(
3102+ """
3103 # some comment
3104 COMPRESSAFTER=10
3105 SADC_OPTIONS="-C a-comment -D -V -S XALL"
3106 # another comment
3107 UMASK=0022
3108- """)
3109+ """
3110+ )
3111
3112 check_sysstat_config(original, expected)
3113
3114
3115 def test_telegraf_exec_metrics(monkeypatch, temp_config_dir):
3116-
3117 def run_telegraf_exec_metrics(*args):
3118- script = os.path.join(telegraf.get_files_dir(), 'telegraf_exec_metrics.py')
3119+ script = os.path.join(telegraf.get_files_dir(), "telegraf_exec_metrics.py")
3120 cmd = [script] + list(args)
3121 assert 0 == subprocess.call(cmd)
3122
3123- metrics = set(['sockstat', 'sockstat6', 'softnet_stat', 'buddyinfo', 'zoneinfo', 'netns'])
3124+ metrics = set(
3125+ ["sockstat", "sockstat6", "softnet_stat", "buddyinfo", "zoneinfo", "netns"]
3126+ )
3127 for metric in metrics:
3128- run_telegraf_exec_metrics('--metric', metric)
3129+ run_telegraf_exec_metrics("--metric", metric)
3130
3131 # another test for netns, read cmd output from file
3132- run_telegraf_exec_metrics('--metric', 'netns', '--input-file', os.path.join(UNIT_TESTS_DATA_DIR, 'netns.txt'))
3133+ run_telegraf_exec_metrics(
3134+ "--metric",
3135+ "netns",
3136+ "--input-file",
3137+ os.path.join(UNIT_TESTS_DATA_DIR, "netns.txt"),
3138+ )
3139 # parse output form `sudo ovs-appctl dpctl/show -s`
3140- run_telegraf_exec_metrics('--metric', 'ovs_dpctl', '--input-file', os.path.join(UNIT_TESTS_DATA_DIR, 'ovs_dpctl.txt'))
3141+ run_telegraf_exec_metrics(
3142+ "--metric",
3143+ "ovs_dpctl",
3144+ "--input-file",
3145+ os.path.join(UNIT_TESTS_DATA_DIR, "ovs_dpctl.txt"),
3146+ )
3147
3148 # ensure config files exists after render
3149 run_telegraf_exec_metrics(
3150- '--render-config-files',
3151- '--configs-dir', configs_dir(),
3152+ "--render-config-files", "--configs-dir", configs_dir(),
3153 )
3154 for metric in metrics:
3155- assert os.path.isfile(os.path.join(configs_dir(), '{}.conf'.format(metric)))
3156+ assert os.path.isfile(os.path.join(configs_dir(), "{}.conf".format(metric)))
3157
3158 # ensure --disabled-metrics option is working
3159- disabled_metrics = set(['sockstat', 'zoneinfo'])
3160+ disabled_metrics = set(["sockstat", "zoneinfo"])
3161 run_telegraf_exec_metrics(
3162- '--render-config-files',
3163- '--configs-dir', configs_dir(),
3164- '--disabled-metrics', ':'.join(disabled_metrics),
3165+ "--render-config-files",
3166+ "--configs-dir",
3167+ configs_dir(),
3168+ "--disabled-metrics",
3169+ ":".join(disabled_metrics),
3170 )
3171 # config files for disabled metrics should be removed.
3172 for metric in disabled_metrics:
3173- assert not os.path.isfile(os.path.join(configs_dir(), '{}.conf'.format(metric)))
3174+ assert not os.path.isfile(os.path.join(configs_dir(), "{}.conf".format(metric)))
3175 # config files for other metrics should still be there
3176- for metric in (metrics - disabled_metrics):
3177- assert os.path.isfile(os.path.join(configs_dir(), '{}.conf'.format(metric)))
3178+ for metric in metrics - disabled_metrics:
3179+ assert os.path.isfile(os.path.join(configs_dir(), "{}.conf".format(metric)))
3180
3181
3182 def test_get_remote_unit_name_juju2(monkeypatch):
3183 monkeypatch.undo()
3184- monkeypatch.setitem(os.environ, 'JUJU_PRINCIPAL_UNIT', 'remote/0')
3185- assert telegraf.get_remote_unit_name() == 'remote/0'
3186+ monkeypatch.setitem(os.environ, "JUJU_PRINCIPAL_UNIT", "remote/0")
3187+ assert telegraf.get_remote_unit_name() == "remote/0"
3188
3189
3190 def test_get_remote_unit_name_juju1(monkeypatch):
3191 monkeypatch.undo()
3192- monkeypatch.setattr(telegraf.netifaces,
3193- 'interfaces',
3194- lambda: ['lo', 'eth0'])
3195-
3196- ifaddresses = {17: [{'addr': 'AA:BB:CC:DD:EE:FF',
3197- 'broadcast': 'ff:ff:ff:ff:ff:ff'}],
3198- 2: [{'addr': '1.2.3.4',
3199- 'netmask': '255.255.255.0',
3200- 'broadcast': '1.2.3.1'}],
3201- 10: [{'addr': '2620:0:862:ed1a::1',
3202- 'netmask': 'ffff:ffff:ffff:ffff::'}]}
3203- monkeypatch.setattr(telegraf.netifaces,
3204- 'ifaddresses',
3205- lambda n: ifaddresses if n == 'eth0' else {})
3206-
3207- md = {'name': 'telegraf',
3208- 'requires': {'mysql': {'interface': 'mysql-root'},
3209- 'postgresql': {'interface': 'pgsql'},
3210- 'mongodb': {'interface': 'mongodb',
3211- 'scope': 'container'},
3212- 'memcached': {'interface': 'memcache',
3213- 'scope': 'container'},
3214- 'elasticsearch': {'interface':
3215- 'elasticsearch',
3216- 'scope': 'container'},
3217- 'haproxy': {'interface': 'statistics',
3218- 'scope': 'container'},
3219- 'apache': {'interface': 'apache-website',
3220- 'scope': 'container'},
3221- 'influxdb-api': {'interface':
3222- 'influxdb-api'},
3223- 'juju-info': {'interface': 'juju-info',
3224- 'scope': 'container'},
3225- 'exec': {'interface': 'telegraf-exec',
3226- 'scope': 'container'}},
3227- 'provides': {'prometheus-client': {'interface': 'http'},
3228- 'prometheus-rules': {'interface': 'prometheus-rules'}}}
3229- monkeypatch.setattr(telegraf.hookenv, 'metadata', lambda: md)
3230+ monkeypatch.setattr(telegraf.netifaces, "interfaces", lambda: ["lo", "eth0"])
3231+
3232+ ifaddresses = {
3233+ 17: [{"addr": "AA:BB:CC:DD:EE:FF", "broadcast": "ff:ff:ff:ff:ff:ff"}],
3234+ 2: [{"addr": "1.2.3.4", "netmask": "255.255.255.0", "broadcast": "1.2.3.1"}],
3235+ 10: [{"addr": "2620:0:862:ed1a::1", "netmask": "ffff:ffff:ffff:ffff::"}],
3236+ }
3237+ monkeypatch.setattr(
3238+ telegraf.netifaces, "ifaddresses", lambda n: ifaddresses if n == "eth0" else {}
3239+ )
3240+
3241+ md = {
3242+ "name": "telegraf",
3243+ "requires": {
3244+ "mysql": {"interface": "mysql-root"},
3245+ "postgresql": {"interface": "pgsql"},
3246+ "mongodb": {"interface": "mongodb", "scope": "container"},
3247+ "memcached": {"interface": "memcache", "scope": "container"},
3248+ "elasticsearch": {"interface": "elasticsearch", "scope": "container"},
3249+ "haproxy": {"interface": "statistics", "scope": "container"},
3250+ "apache": {"interface": "apache-website", "scope": "container"},
3251+ "influxdb-api": {"interface": "influxdb-api"},
3252+ "juju-info": {"interface": "juju-info", "scope": "container"},
3253+ "exec": {"interface": "telegraf-exec", "scope": "container"},
3254+ },
3255+ "provides": {
3256+ "prometheus-client": {"interface": "http"},
3257+ "prometheus-rules": {"interface": "prometheus-rules"},
3258+ },
3259+ }
3260+ monkeypatch.setattr(telegraf.hookenv, "metadata", lambda: md)
3261
3262 def relation_ids(reltype):
3263- if reltype == 'juju-info':
3264- return ['juju-info:0']
3265+ if reltype == "juju-info":
3266+ return ["juju-info:0"]
3267 else:
3268 return []
3269- monkeypatch.setattr(telegraf.hookenv,
3270- 'relation_ids',
3271- relation_ids)
3272+
3273+ monkeypatch.setattr(telegraf.hookenv, "relation_ids", relation_ids)
3274
3275 def related_units(relid):
3276- if relid == 'juju-info:0':
3277- return ['remote/0']
3278+ if relid == "juju-info:0":
3279+ return ["remote/0"]
3280 else:
3281 return []
3282- monkeypatch.setattr(telegraf.hookenv,
3283- 'related_units',
3284- related_units)
3285+
3286+ monkeypatch.setattr(telegraf.hookenv, "related_units", related_units)
3287
3288 relations = []
3289- monkeypatch.setattr(telegraf.hookenv,
3290- 'relations_of_type',
3291- lambda n: relations)
3292+ monkeypatch.setattr(telegraf.hookenv, "relations_of_type", lambda n: relations)
3293 assert telegraf.get_remote_unit_name() is None
3294
3295- relations = [{'private-address': '1.2.3.4', '__unit__': 'remote/0'}]
3296- monkeypatch.setattr(telegraf.hookenv,
3297- 'relations_of_type',
3298- lambda n: relations)
3299- assert telegraf.get_remote_unit_name() == 'remote/0'
3300+ relations = [{"private-address": "1.2.3.4", "__unit__": "remote/0"}]
3301+ monkeypatch.setattr(telegraf.hookenv, "relations_of_type", lambda n: relations)
3302+ assert telegraf.get_remote_unit_name() == "remote/0"
3303
3304
3305 def test_inputs_config_set(monkeypatch, config):
3306- config['inputs_config'] = """
3307+ config[
3308+ "inputs_config"
3309+ ] = """
3310 [[inputs.cpu]]
3311 percpu = true
3312 """
3313
3314 def check(*a, **kw):
3315- assert kw['context']['inputs'] == config['inputs_config']
3316- monkeypatch.setattr(telegraf, 'check_prometheus_port', lambda a, b: None)
3317- monkeypatch.setattr(telegraf, 'render', check)
3318+ assert kw["context"]["inputs"] == config["inputs_config"]
3319+
3320+ monkeypatch.setattr(telegraf, "check_prometheus_port", lambda a, b: None)
3321+ monkeypatch.setattr(telegraf, "render", check)
3322 telegraf.configure_telegraf()
3323
3324
3325 def test_old_base64_inputs_and_outputs(monkeypatch, config):
3326- config['inputs_config'] = base64.b64encode(b"""
3327+ config["inputs_config"] = base64.b64encode(
3328+ b"""
3329 [[inputs.cpu]]
3330 percpu = true
3331-""").decode('utf-8')
3332- config['outputs_config'] = base64.b64encode(b"""
3333+"""
3334+ ).decode("utf-8")
3335+ config["outputs_config"] = base64.b64encode(
3336+ b"""
3337 [[outputs.fake]]
3338 foo = true
3339-""").decode('utf-8')
3340- monkeypatch.setattr(telegraf, 'check_prometheus_port', lambda a, b: None)
3341+"""
3342+ ).decode("utf-8")
3343+ monkeypatch.setattr(telegraf, "check_prometheus_port", lambda a, b: None)
3344
3345 def check(*a, **kw):
3346- expected = base64.b64decode(config['inputs_config']).decode('utf-8')
3347- assert kw['context']['inputs'] == expected
3348- expected = base64.b64decode(config['outputs_config']).decode('utf-8')
3349- assert kw['context']['outputs'] == expected
3350- monkeypatch.setattr(telegraf, 'render', check)
3351+ expected = base64.b64decode(config["inputs_config"]).decode("utf-8")
3352+ assert kw["context"]["inputs"] == expected
3353+ expected = base64.b64decode(config["outputs_config"]).decode("utf-8")
3354+ assert kw["context"]["outputs"] == expected
3355+
3356+ monkeypatch.setattr(telegraf, "render", check)
3357 telegraf.configure_telegraf()
3358
3359
3360 def test_inputs_config_not_set(monkeypatch, config):
3361- monkeypatch.setattr(telegraf, 'check_prometheus_port', lambda a, b: None)
3362- config['inputs_config'] = ""
3363+ monkeypatch.setattr(telegraf, "check_prometheus_port", lambda a, b: None)
3364+ config["inputs_config"] = ""
3365
3366 def check(*a, **kw):
3367- assert kw['context']['inputs'] == telegraf.render_base_inputs()
3368- monkeypatch.setattr(telegraf, 'render', check)
3369+ assert kw["context"]["inputs"] == telegraf.render_base_inputs()
3370+
3371+ monkeypatch.setattr(telegraf, "render", check)
3372 telegraf.configure_telegraf()
3373
3374
3375 def test_outputs_config(monkeypatch, config):
3376- monkeypatch.setattr(telegraf, 'check_prometheus_port', lambda a, b: None)
3377- config['outputs_config'] = """
3378+ monkeypatch.setattr(telegraf, "check_prometheus_port", lambda a, b: None)
3379+ config[
3380+ "outputs_config"
3381+ ] = """
3382 [[outputs.foo]]
3383 server = "http://localhost:42"
3384 """
3385
3386 def check(*a, **kw):
3387- assert kw['context']['outputs'] == config['outputs_config']
3388- monkeypatch.setattr(telegraf, 'render', check)
3389+ assert kw["context"]["outputs"] == config["outputs_config"]
3390+
3391+ monkeypatch.setattr(telegraf, "render", check)
3392 telegraf.configure_telegraf()
3393
3394
3395 def test_extra_plugins(config):
3396- config['extra_plugins'] = """[[inputs.foo]]
3397+ config[
3398+ "extra_plugins"
3399+ ] = """[[inputs.foo]]
3400 some_option = "http://foo.bar.com"
3401 [[outputs.baz]]
3402 option = "enabled"
3403 """
3404 telegraf.configure_extra_plugins()
3405- assert configs_dir().join('extra_plugins.conf').read() == config['extra_plugins']
3406+ assert configs_dir().join("extra_plugins.conf").read() == config["extra_plugins"]
3407
3408
3409 def test_render_extra_options(config):
3410@@ -495,8 +546,8 @@ def test_render_extra_options(config):
3411 string: 10s
3412 list: ["a", "b"]
3413 """
3414- config['extra_options'] = extra_options
3415- content = telegraf.render_extra_options('inputs', 'test')
3416+ config["extra_options"] = extra_options
3417+ content = telegraf.render_extra_options("inputs", "test")
3418 expected = """ boolean = true\n list = ["a", "b"]\n string = "10s"\n"""
3419 assert sorted(content.split()) == sorted(expected.split())
3420
3421@@ -511,7 +562,7 @@ def test_get_extra_options(config):
3422 tagdrop:
3423 tag: ["foo", "bar"]
3424 """
3425- config['extra_options'] = extra_options
3426+ config["extra_options"] = extra_options
3427 extra_opts = telegraf.get_extra_options()
3428 expected = {
3429 "inputs": {
3430@@ -519,12 +570,10 @@ def test_get_extra_options(config):
3431 "boolean": "true",
3432 "string": '"somestring"',
3433 "list": '["a", "b"]',
3434- "tagdrop": {
3435- "tag": '["foo", "bar"]'
3436- }
3437+ "tagdrop": {"tag": '["foo", "bar"]'},
3438 }
3439 },
3440- "outputs": {}
3441+ "outputs": {},
3442 }
3443 assert extra_opts == expected
3444
3445@@ -537,10 +586,10 @@ def test_render_extra_options_override(config):
3446 string: 10s
3447 list: ["a", "b"]
3448 """
3449- config['extra_options'] = extra_options
3450+ config["extra_options"] = extra_options
3451 # clone extra_options and use a modified version
3452- options = {'inputs': {'test': {'string': json.dumps("20s")}}}
3453- content = telegraf.render_extra_options('inputs', 'test', extra_options=options)
3454+ options = {"inputs": {"test": {"string": json.dumps("20s")}}}
3455+ content = telegraf.render_extra_options("inputs", "test", extra_options=options)
3456 expected = """ string = "20s"\n"""
3457 assert sorted(content.split()) == sorted(expected.split())
3458
3459@@ -555,7 +604,7 @@ inputs:
3460 tagpass:
3461 cpu: ["cpu0"]
3462 """
3463- config['extra_options'] = base_inputs_opts
3464+ config["extra_options"] = base_inputs_opts
3465 content = telegraf.render_base_inputs()
3466 expected = """
3467 # Read metrics about cpu usage
3468@@ -566,76 +615,71 @@ inputs:
3469 [inputs.cpu.tagpass]
3470 cpu = ["cpu0"]
3471 """
3472- assert content[:len(expected)] == expected
3473+ assert content[: len(expected)] == expected
3474
3475
3476 def test_base_inputs_disabled_plugins(config):
3477 """Check disabled_plugins option is working for builtin inputs"""
3478- config['disabled_plugins'] = 'cpu:disk'
3479+ config["disabled_plugins"] = "cpu:disk"
3480 content = telegraf.render_base_inputs()
3481
3482 # disabled, should not exist
3483- assert '[[inputs.cpu]]' not in content
3484- assert '[[inputs.disk]]' not in content
3485+ assert "[[inputs.cpu]]" not in content
3486+ assert "[[inputs.disk]]" not in content
3487
3488 # not disabled, should exist
3489- assert '[[inputs.mem]]' in content
3490+ assert "[[inputs.mem]]" in content
3491
3492
3493 def test_check_prometheus_port(monkeypatch):
3494 open_ports = set()
3495- monkeypatch.setattr(telegraf.hookenv, 'open_port',
3496- lambda p: open_ports.add(p))
3497- telegraf.check_prometheus_port('test_check_port', 10042)
3498+ monkeypatch.setattr(telegraf.hookenv, "open_port", lambda p: open_ports.add(p))
3499+ telegraf.check_prometheus_port("test_check_port", 10042)
3500 assert 10042 in open_ports
3501
3502
3503 def test_check_prometheus_port_replace_old_port(monkeypatch):
3504 open_ports = set()
3505- monkeypatch.setattr(telegraf.hookenv, 'open_port',
3506- lambda p: open_ports.add(p))
3507- monkeypatch.setattr(telegraf.hookenv, 'close_port',
3508- lambda p: open_ports.remove(p))
3509- telegraf.check_prometheus_port('test_check_port', 10042)
3510+ monkeypatch.setattr(telegraf.hookenv, "open_port", lambda p: open_ports.add(p))
3511+ monkeypatch.setattr(telegraf.hookenv, "close_port", lambda p: open_ports.remove(p))
3512+ telegraf.check_prometheus_port("test_check_port", 10042)
3513 assert 10042 in open_ports
3514- telegraf.check_prometheus_port('test_check_port', 10043)
3515+ telegraf.check_prometheus_port("test_check_port", 10043)
3516 assert 10043 in open_ports
3517 assert 10042 not in open_ports
3518
3519
3520 def test_get_prometheus_port(monkeypatch, config):
3521- config['prometheus_output_port'] = ''
3522+ config["prometheus_output_port"] = ""
3523 assert telegraf.get_prometheus_port() is False
3524- config['prometheus_output_port'] = 'default'
3525+ config["prometheus_output_port"] = "default"
3526 assert telegraf.get_prometheus_port() == 9103
3527- config['prometheus_output_port'] = '9126'
3528+ config["prometheus_output_port"] = "9126"
3529 assert telegraf.get_prometheus_port() == 9126
3530
3531
3532 def test_prometheus_global(monkeypatch, config):
3533 open_ports = set()
3534- monkeypatch.setattr(telegraf.hookenv, 'open_port',
3535- lambda p: open_ports.add(p))
3536- monkeypatch.setattr(telegraf.hookenv, 'close_port',
3537- lambda p: open_ports.remove(p))
3538- config['prometheus_output_port'] = 'default'
3539+ monkeypatch.setattr(telegraf.hookenv, "open_port", lambda p: open_ports.add(p))
3540+ monkeypatch.setattr(telegraf.hookenv, "close_port", lambda p: open_ports.remove(p))
3541+ config["prometheus_output_port"] = "default"
3542 telegraf.configure_telegraf()
3543 expected = """
3544 [[outputs.prometheus_client]]
3545 listen = ":9103"
3546 """
3547- config_file = base_dir().join('telegraf.conf')
3548+ config_file = base_dir().join("telegraf.conf")
3549 assert expected in config_file.read()
3550
3551
3552 def test_prometheus_global_with_extra_options(monkeypatch, config):
3553 open_ports = set()
3554- monkeypatch.setattr(telegraf.hookenv, 'open_port',
3555- lambda p: open_ports.add(p))
3556- monkeypatch.setattr(telegraf.hookenv, 'close_port',
3557- lambda p: open_ports.remove(p))
3558- config['prometheus_output_port'] = 'default'
3559- config['extra_options'] = """
3560+ monkeypatch.setattr(telegraf.hookenv, "open_port", lambda p: open_ports.add(p))
3561+ monkeypatch.setattr(telegraf.hookenv, "close_port", lambda p: open_ports.remove(p))
3562+ config["prometheus_output_port"] = "default"
3563+ config[
3564+ "extra_options"
3565+ ] = """
3566 outputs:
3567 prometheus_client:
3568 namedrop: ["aerospike*"]
3569@@ -651,15 +695,13 @@ outputs:
3570 [outputs.prometheus_client.tagpass]
3571 cpu = ["cpu0"]
3572 """
3573- config_file = base_dir().join('telegraf.conf')
3574+ config_file = base_dir().join("telegraf.conf")
3575 assert expected in config_file.read()
3576
3577
3578 def test_default_tags(monkeypatch, config):
3579- monkeypatch.setattr(telegraf.hookenv, 'principal_unit',
3580- lambda: 'principal-unit')
3581- monkeypatch.setattr(telegraf.hookenv, 'open_port',
3582- lambda p: None)
3583+ monkeypatch.setattr(telegraf.hookenv, "principal_unit", lambda: "principal-unit")
3584+ monkeypatch.setattr(telegraf.hookenv, "open_port", lambda p: None)
3585 telegraf.configure_telegraf()
3586 expected = """
3587 [tags]
3588@@ -673,122 +715,133 @@ def test_default_tags(monkeypatch, config):
3589 juju_model = "telegraf-test-model"
3590
3591 """
3592- config_file = base_dir().join('telegraf.conf')
3593+ config_file = base_dir().join("telegraf.conf")
3594 assert expected in config_file.read()
3595
3596+
3597 # Plugin tests
3598
3599
3600 def test_elasticsearch_input(monkeypatch, config):
3601- relations = [{'host': '1.2.3.4', 'port': 1234}]
3602- monkeypatch.setattr(telegraf.hookenv, 'relations_of_type', lambda n: relations)
3603+ relations = [{"host": "1.2.3.4", "port": 1234}]
3604+ monkeypatch.setattr(telegraf.hookenv, "relations_of_type", lambda n: relations)
3605
3606- telegraf.elasticsearch_input('test')
3607+ telegraf.elasticsearch_input("test")
3608 expected = """
3609 [[inputs.elasticsearch]]
3610 servers = ["http://1.2.3.4:1234"]
3611 """
3612- assert configs_dir().join('elasticsearch.conf').read().strip() == expected.strip()
3613+ assert configs_dir().join("elasticsearch.conf").read().strip() == expected.strip()
3614
3615
3616 def test_elasticsearch_input_no_relations(monkeypatch):
3617- monkeypatch.setattr(telegraf.hookenv, 'relations_of_type', lambda n: [])
3618- telegraf.elasticsearch_input('test')
3619- assert not configs_dir().join('elasticsearch.conf').exists()
3620+ monkeypatch.setattr(telegraf.hookenv, "relations_of_type", lambda n: [])
3621+ telegraf.elasticsearch_input("test")
3622+ assert not configs_dir().join("elasticsearch.conf").exists()
3623
3624
3625 def test_memcached_input(monkeypatch, config):
3626- relations = [{'host': '1.2.3.4', 'port': 1234}]
3627- monkeypatch.setattr(telegraf.hookenv, 'relations_of_type', lambda n: relations)
3628- telegraf.memcached_input('test')
3629+ relations = [{"host": "1.2.3.4", "port": 1234}]
3630+ monkeypatch.setattr(telegraf.hookenv, "relations_of_type", lambda n: relations)
3631+ telegraf.memcached_input("test")
3632 expected = """
3633 [[inputs.memcached]]
3634 servers = ["1.2.3.4:1234"]
3635 """
3636- assert configs_dir().join('memcached.conf').read().strip() == expected.strip()
3637+ assert configs_dir().join("memcached.conf").read().strip() == expected.strip()
3638
3639
3640 def test_memcached_input_no_relations(monkeypatch):
3641- monkeypatch.setattr(telegraf.hookenv, 'relations_of_type', lambda n: [])
3642- telegraf.memcached_input('test')
3643- assert not configs_dir().join('memcached.conf').exists()
3644+ monkeypatch.setattr(telegraf.hookenv, "relations_of_type", lambda n: [])
3645+ telegraf.memcached_input("test")
3646+ assert not configs_dir().join("memcached.conf").exists()
3647
3648
3649 def test_mongodb_input(monkeypatch, config):
3650- relations = [{'private-address': '1.2.3.4', 'port': 1234}]
3651- monkeypatch.setattr(telegraf.hookenv, 'relations_of_type', lambda n: relations)
3652- telegraf.mongodb_input('test')
3653+ relations = [{"private-address": "1.2.3.4", "port": 1234}]
3654+ monkeypatch.setattr(telegraf.hookenv, "relations_of_type", lambda n: relations)
3655+ telegraf.mongodb_input("test")
3656 expected = """
3657 [[inputs.mongodb]]
3658 servers = ["1.2.3.4:1234"]
3659 """
3660- assert configs_dir().join('mongodb.conf').read().strip() == expected.strip()
3661+ assert configs_dir().join("mongodb.conf").read().strip() == expected.strip()
3662
3663
3664 def test_mongodb_input_no_relations(monkeypatch):
3665- monkeypatch.setattr(telegraf.hookenv, 'relations_of_type', lambda n: [])
3666- telegraf.mongodb_input('test')
3667- assert not configs_dir().join('mongodb.conf').exists()
3668+ monkeypatch.setattr(telegraf.hookenv, "relations_of_type", lambda n: [])
3669+ telegraf.mongodb_input("test")
3670+ assert not configs_dir().join("mongodb.conf").exists()
3671
3672
3673 def test_haproxy_input(monkeypatch, config):
3674- relations = [{'private-address': '1.2.3.4',
3675- 'port': 1234,
3676- 'user': 'foo',
3677- 'password': 'bar',
3678- 'enabled': 'True'}]
3679- monkeypatch.setattr(telegraf.hookenv, 'relations_of_type', lambda n: relations)
3680- monkeypatch.setattr(telegraf.hookenv, 'unit_private_ip', lambda: '1.2.3.4')
3681- telegraf.haproxy_input('test')
3682+ relations = [
3683+ {
3684+ "private-address": "1.2.3.4",
3685+ "port": 1234,
3686+ "user": "foo",
3687+ "password": "bar",
3688+ "enabled": "True",
3689+ }
3690+ ]
3691+ monkeypatch.setattr(telegraf.hookenv, "relations_of_type", lambda n: relations)
3692+ monkeypatch.setattr(telegraf.hookenv, "unit_private_ip", lambda: "1.2.3.4")
3693+ telegraf.haproxy_input("test")
3694 expected = """
3695 [[inputs.haproxy]]
3696 servers = ["http://foo:bar@localhost:1234"]
3697 """
3698- assert configs_dir().join('haproxy.conf').read().strip() == expected.strip()
3699+ assert configs_dir().join("haproxy.conf").read().strip() == expected.strip()
3700
3701
3702 def test_haproxy_input_no_relations(monkeypatch):
3703- monkeypatch.setattr(telegraf.hookenv, 'relations_of_type', lambda n: [])
3704- telegraf.haproxy_input('test')
3705- assert not configs_dir().join('haproxy.conf').exists()
3706+ monkeypatch.setattr(telegraf.hookenv, "relations_of_type", lambda n: [])
3707+ telegraf.haproxy_input("test")
3708+ assert not configs_dir().join("haproxy.conf").exists()
3709
3710
3711 def test_haproxy_input_not_enabled(monkeypatch):
3712- relations = [{'private-address': '1.2.3.4',
3713- 'port': 1234,
3714- 'user': 'foo',
3715- 'password': 'bar',
3716- 'enabled': 'False'}]
3717- monkeypatch.setattr(telegraf.hookenv, 'relations_of_type', lambda n: relations)
3718- telegraf.haproxy_input('test')
3719- assert not configs_dir().join('haproxy.conf').exists()
3720+ relations = [
3721+ {
3722+ "private-address": "1.2.3.4",
3723+ "port": 1234,
3724+ "user": "foo",
3725+ "password": "bar",
3726+ "enabled": "False",
3727+ }
3728+ ]
3729+ monkeypatch.setattr(telegraf.hookenv, "relations_of_type", lambda n: relations)
3730+ telegraf.haproxy_input("test")
3731+ assert not configs_dir().join("haproxy.conf").exists()
3732
3733
3734 def test_apache_input(monkeypatch, config):
3735- relations = [{'__relid__': 'apache:0', 'private-address': '1.2.3.4'}]
3736- monkeypatch.setattr(telegraf.hookenv, 'relations_of_type', lambda n: relations)
3737- monkeypatch.setattr(telegraf.hookenv, 'relation_set', lambda *a, **kw: None)
3738- telegraf.apache_input('test')
3739+ relations = [{"__relid__": "apache:0", "private-address": "1.2.3.4"}]
3740+ monkeypatch.setattr(telegraf.hookenv, "relations_of_type", lambda n: relations)
3741+ monkeypatch.setattr(telegraf.hookenv, "relation_set", lambda *a, **kw: None)
3742+ telegraf.apache_input("test")
3743 expected = """
3744 [[inputs.apache]]
3745 urls = ["http://1.2.3.4:8080/server-status?auto"]
3746 """
3747- assert configs_dir().join('apache.conf').read().strip() == expected.strip()
3748+ assert configs_dir().join("apache.conf").read().strip() == expected.strip()
3749
3750
3751 def test_apache_input_no_relations(monkeypatch):
3752- monkeypatch.setattr(telegraf.hookenv, 'relations_of_type', lambda n: [])
3753- telegraf.apache_input('test')
3754- assert not configs_dir().join('apache.conf').exists()
3755+ monkeypatch.setattr(telegraf.hookenv, "relations_of_type", lambda n: [])
3756+ telegraf.apache_input("test")
3757+ assert not configs_dir().join("apache.conf").exists()
3758
3759
3760 def test_exec_input(mocker, monkeypatch):
3761 interface = mocker.Mock(spec=RelationBase)
3762 interface.commands = mocker.Mock()
3763- command = {'commands': ['/srv/bin/test.sh', '/bin/true'],
3764- 'data_format': 'json',
3765- 'timeout': '5s',
3766- 'run_on_this_unit': True}
3767+ command = {
3768+ "commands": ["/srv/bin/test.sh", "/bin/true"],
3769+ "data_format": "json",
3770+ "timeout": "5s",
3771+ "run_on_this_unit": True,
3772+ }
3773 interface.commands.return_value = [command.copy()]
3774 telegraf.exec_input(interface)
3775 expected = """
3776@@ -797,22 +850,26 @@ def test_exec_input(mocker, monkeypatch):
3777 data_format = "json"
3778 timeout = "5s"
3779 """
3780- assert configs_dir().join('exec.conf').read().strip() == expected.strip()
3781+ assert configs_dir().join("exec.conf").read().strip() == expected.strip()
3782 # add a second relation/command set
3783 interface.commands.return_value = [command.copy(), command.copy()]
3784 telegraf.exec_input(interface)
3785 expected = expected + expected
3786- assert configs_dir().join('exec.conf').read().strip() == expected.strip()
3787+ assert configs_dir().join("exec.conf").read().strip() == expected.strip()
3788
3789
3790 def test_exec_input_with_tags(mocker, monkeypatch):
3791 interface = mocker.Mock(spec=RelationBase)
3792 interface.commands = mocker.Mock()
3793- commands = [{'commands': ['/srv/bin/test.sh', '/bin/true'],
3794- 'data_format': 'json',
3795- 'timeout': '5s',
3796- 'run_on_this_unit': True,
3797- 'tags': {'test': 'test'}}]
3798+ commands = [
3799+ {
3800+ "commands": ["/srv/bin/test.sh", "/bin/true"],
3801+ "data_format": "json",
3802+ "timeout": "5s",
3803+ "run_on_this_unit": True,
3804+ "tags": {"test": "test"},
3805+ }
3806+ ]
3807 interface.commands.return_value = commands
3808 telegraf.exec_input(interface)
3809 expected = """
3810@@ -823,28 +880,36 @@ def test_exec_input_with_tags(mocker, monkeypatch):
3811 [inputs.exec.tags]
3812 test = "test"
3813 """
3814- assert configs_dir().join('exec.conf').read().strip() == expected.strip()
3815+ assert configs_dir().join("exec.conf").read().strip() == expected.strip()
3816
3817
3818 def test_exec_input_no_leader(mocker, monkeypatch):
3819 interface = mocker.Mock(spec=RelationBase)
3820 interface.commands = mocker.Mock()
3821- commands = [{'commands': ['/srv/bin/test.sh', '/bin/true'],
3822- 'data_format': 'json',
3823- 'timeout': '5s',
3824- 'run_on_this_unit': False}]
3825+ commands = [
3826+ {
3827+ "commands": ["/srv/bin/test.sh", "/bin/true"],
3828+ "data_format": "json",
3829+ "timeout": "5s",
3830+ "run_on_this_unit": False,
3831+ }
3832+ ]
3833 interface.commands.return_value = commands
3834 telegraf.exec_input(interface)
3835- assert not configs_dir().join('exec.conf').exists()
3836+ assert not configs_dir().join("exec.conf").exists()
3837
3838
3839 def test_exec_input_all_units(mocker, monkeypatch):
3840 interface = mocker.Mock(spec=RelationBase)
3841 interface.commands = mocker.Mock()
3842- commands = [{"commands": ["/srv/bin/test.sh", "/bin/true"],
3843- 'data_format': 'json',
3844- 'timeout': '5s',
3845- 'run_on_this_unit': True}]
3846+ commands = [
3847+ {
3848+ "commands": ["/srv/bin/test.sh", "/bin/true"],
3849+ "data_format": "json",
3850+ "timeout": "5s",
3851+ "run_on_this_unit": True,
3852+ }
3853+ ]
3854 interface.commands.return_value = commands
3855 telegraf.exec_input(interface)
3856 expected = """
3857@@ -853,16 +918,18 @@ def test_exec_input_all_units(mocker, monkeypatch):
3858 data_format = "json"
3859 timeout = "5s"
3860 """
3861- assert configs_dir().join('exec.conf').read().strip() == expected.strip()
3862+ assert configs_dir().join("exec.conf").read().strip() == expected.strip()
3863
3864
3865 def test_exec_input_leader_no_more(mocker, monkeypatch):
3866 interface = mocker.Mock(spec=RelationBase)
3867 interface.commands = mocker.Mock()
3868- command = {'commands': ['/srv/bin/test.sh', '/bin/true'],
3869- 'data_format': 'json',
3870- 'timeout': '5s',
3871- 'run_on_this_unit': True}
3872+ command = {
3873+ "commands": ["/srv/bin/test.sh", "/bin/true"],
3874+ "data_format": "json",
3875+ "timeout": "5s",
3876+ "run_on_this_unit": True,
3877+ }
3878 interface.commands.return_value = [command.copy()]
3879 telegraf.exec_input(interface)
3880 expected = """
3881@@ -871,57 +938,59 @@ def test_exec_input_leader_no_more(mocker, monkeypatch):
3882 data_format = "json"
3883 timeout = "5s"
3884 """
3885- assert configs_dir().join('exec.conf').read().strip() == expected.strip()
3886+ assert configs_dir().join("exec.conf").read().strip() == expected.strip()
3887 # add a second relation/command set
3888 new_command = command.copy()
3889- new_command['run_on_this_unit'] = False
3890+ new_command["run_on_this_unit"] = False
3891 interface.commands.return_value = [new_command.copy()]
3892 telegraf.exec_input(interface)
3893- assert not configs_dir().join('exec.conf').exists()
3894+ assert not configs_dir().join("exec.conf").exists()
3895
3896
3897 def test_exec_input_departed(mocker, monkeypatch):
3898- configs_dir().join('exec.conf').write('empty')
3899+ configs_dir().join("exec.conf").write("empty")
3900 relations = [1]
3901- monkeypatch.setattr(telegraf.hookenv, 'relations_of_type', lambda n: relations)
3902+ monkeypatch.setattr(telegraf.hookenv, "relations_of_type", lambda n: relations)
3903 telegraf.exec_input_departed()
3904- assert configs_dir().join('exec.conf').exists()
3905+ assert configs_dir().join("exec.conf").exists()
3906 relations.pop()
3907 telegraf.exec_input_departed()
3908- assert not configs_dir().join('exec.conf').exists()
3909+ assert not configs_dir().join("exec.conf").exists()
3910
3911
3912 def test_influxdb_api_output(monkeypatch, config):
3913- relations = [{'hostname': '1.2.3.4',
3914- 'port': 1234,
3915- 'user': 'foo',
3916- 'password': 'bar'}]
3917- monkeypatch.setattr(telegraf.hookenv, 'relations_of_type', lambda n: relations)
3918- telegraf.influxdb_api_output('test')
3919- expected = render(source='influxdb-api.conf.tmpl', target=None,
3920- templates_dir=telegraf.get_templates_dir(),
3921- context={'username': 'foo',
3922- 'password': 'bar',
3923- 'urls': '["http://1.2.3.4:1234"]'})
3924- assert configs_dir().join('influxdb-api.conf').read().strip() == expected.strip()
3925+ relations = [
3926+ {"hostname": "1.2.3.4", "port": 1234, "user": "foo", "password": "bar"}
3927+ ]
3928+ monkeypatch.setattr(telegraf.hookenv, "relations_of_type", lambda n: relations)
3929+ telegraf.influxdb_api_output("test")
3930+ expected = render(
3931+ source="influxdb-api.conf.tmpl",
3932+ target=None,
3933+ templates_dir=telegraf.get_templates_dir(),
3934+ context={
3935+ "username": "foo",
3936+ "password": "bar",
3937+ "urls": '["http://1.2.3.4:1234"]',
3938+ },
3939+ )
3940+ assert configs_dir().join("influxdb-api.conf").read().strip() == expected.strip()
3941
3942
3943 def test_prometheus_client_output(mocker, monkeypatch, config):
3944- config['prometheus_output_port'] = '' # Not enabled globally
3945- monkeypatch.setattr(telegraf.hookenv, 'open_port',
3946- lambda p: None)
3947+ config["prometheus_output_port"] = "" # Not enabled globally
3948+ monkeypatch.setattr(telegraf.hookenv, "open_port", lambda p: None)
3949
3950- relation_ids = ['prometheus-client:0']
3951- monkeypatch.setattr(telegraf.hookenv,
3952- 'relation_ids',
3953- lambda r: relation_ids)
3954+ relation_ids = ["prometheus-client:0"]
3955+ monkeypatch.setattr(telegraf.hookenv, "relation_ids", lambda r: relation_ids)
3956
3957 network_get_primary_address = mocker.patch.object(
3958- telegraf.hookenv, 'network_get_primary_address', return_value="foo")
3959+ telegraf.hookenv, "network_get_primary_address", return_value="foo"
3960+ )
3961
3962 mocker.patch.object(
3963- telegraf.hookenv, 'network_get',
3964- return_value={"ingress_addresses": ["1.2.3.4"]})
3965+ telegraf.hookenv, "network_get", return_value={"ingress_addresses": ["1.2.3.4"]}
3966+ )
3967
3968 interface = mocker.Mock(spec=RelationBase)
3969 interface.configure = mocker.Mock()
3970@@ -930,236 +999,233 @@ def test_prometheus_client_output(mocker, monkeypatch, config):
3971 [[outputs.prometheus_client]]
3972 listen = ":9126"
3973 """
3974- assert configs_dir().join('prometheus-client.conf').read().strip() == expected.strip()
3975- network_get_primary_address.assert_called_once_with('prometheus-client')
3976- interface.configure.assert_called_once_with(9126,
3977- hostname='foo',
3978- private_address='foo')
3979+ assert (
3980+ configs_dir().join("prometheus-client.conf").read().strip() == expected.strip()
3981+ )
3982+ network_get_primary_address.assert_called_once_with("prometheus-client")
3983+ interface.configure.assert_called_once_with(
3984+ 9126, hostname="foo", private_address="foo"
3985+ )
3986
3987
3988 def test_prometheus_client_output_departed(mocker, monkeypatch, config):
3989- configs_dir().join('prometheus-client.conf').write('empty')
3990+ configs_dir().join("prometheus-client.conf").write("empty")
3991 relations = [1]
3992- monkeypatch.setattr(telegraf.hookenv, 'relations_of_type', lambda n: relations)
3993+ monkeypatch.setattr(telegraf.hookenv, "relations_of_type", lambda n: relations)
3994 telegraf.prometheus_client_departed()
3995- assert configs_dir().join('prometheus-client.conf').exists()
3996+ assert configs_dir().join("prometheus-client.conf").exists()
3997 relations.pop()
3998 telegraf.prometheus_client_departed()
3999- assert not configs_dir().join('prometheus-client.conf').exists()
4000+ assert not configs_dir().join("prometheus-client.conf").exists()
4001
4002
4003 # Integration tests (kind of)
4004 def test_basic_config(mocker, monkeypatch, config):
4005- service_restart = mocker.patch('reactive.telegraf.host.service_restart')
4006- monkeypatch.setattr(telegraf.host, 'service_running',
4007- lambda n: True)
4008- check_prometheus_port = mocker.patch('reactive.telegraf.check_prometheus_port')
4009- set_flag('apt.installed.telegraf')
4010- assert not base_dir().join('telegraf.conf').exists()
4011+ service_restart = mocker.patch("reactive.telegraf.host.service_restart")
4012+ monkeypatch.setattr(telegraf.host, "service_running", lambda n: True)
4013+ check_prometheus_port = mocker.patch("reactive.telegraf.check_prometheus_port")
4014+ set_flag("apt.installed.telegraf")
4015+ assert not base_dir().join("telegraf.conf").exists()
4016 bus.dispatch()
4017- assert 'telegraf.configured' in bus.get_states().keys()
4018- assert base_dir().join('telegraf.conf').exists()
4019+ assert "telegraf.configured" in bus.get_states().keys()
4020+ assert base_dir().join("telegraf.conf").exists()
4021 service_restart.assert_called_once_with(telegraf.DEB_SERVICE)
4022- check_prometheus_port.assert_called_once_with('prometheus_output', 9103)
4023+ check_prometheus_port.assert_called_once_with("prometheus_output", 9103)
4024
4025
4026 def test_config_no_prometheus(mocker, monkeypatch, config):
4027- service_restart = mocker.patch('reactive.telegraf.host.service_restart')
4028- monkeypatch.setattr(telegraf.host, 'service_running',
4029- lambda n: True)
4030- check_prometheus_port = mocker.patch('reactive.telegraf.check_prometheus_port')
4031- config['prometheus_output_port'] = ''
4032- set_flag('apt.installed.telegraf')
4033- assert not base_dir().join('telegraf.conf').exists()
4034+ service_restart = mocker.patch("reactive.telegraf.host.service_restart")
4035+ monkeypatch.setattr(telegraf.host, "service_running", lambda n: True)
4036+ check_prometheus_port = mocker.patch("reactive.telegraf.check_prometheus_port")
4037+ config["prometheus_output_port"] = ""
4038+ set_flag("apt.installed.telegraf")
4039+ assert not base_dir().join("telegraf.conf").exists()
4040 bus.dispatch()
4041- assert 'telegraf.configured' in bus.get_states().keys()
4042- assert base_dir().join('telegraf.conf').exists()
4043+ assert "telegraf.configured" in bus.get_states().keys()
4044+ assert base_dir().join("telegraf.conf").exists()
4045 service_restart.assert_called_once_with(telegraf.DEB_SERVICE)
4046 assert not check_prometheus_port.called
4047
4048
4049 def test_config_changed_apt(mocker, monkeypatch, config):
4050- service_restart = mocker.patch('reactive.telegraf.host.service_restart')
4051- monkeypatch.setattr(telegraf.host, 'service_running',
4052- lambda n: True)
4053- mocker.patch('reactive.telegraf.check_prometheus_port')
4054- set_flag('apt.installed.telegraf')
4055- set_flag('config.changed')
4056+ service_restart = mocker.patch("reactive.telegraf.host.service_restart")
4057+ monkeypatch.setattr(telegraf.host, "service_running", lambda n: True)
4058+ mocker.patch("reactive.telegraf.check_prometheus_port")
4059+ set_flag("apt.installed.telegraf")
4060+ set_flag("config.changed")
4061 bus.dispatch()
4062 service_restart.assert_called_once_with(telegraf.DEB_SERVICE)
4063
4064
4065 def test_config_changed_extra_options(mocker, monkeypatch, config):
4066- service_restart = mocker.patch('reactive.telegraf.host.service_restart')
4067- monkeypatch.setattr(telegraf.host, 'service_running',
4068- lambda n: True)
4069- mocker.patch('reactive.telegraf.check_prometheus_port')
4070- set_flag('apt.telegraf.installed')
4071- set_flag('plugins.haproxy.configured')
4072+ service_restart = mocker.patch("reactive.telegraf.host.service_restart")
4073+ monkeypatch.setattr(telegraf.host, "service_running", lambda n: True)
4074+ mocker.patch("reactive.telegraf.check_prometheus_port")
4075+ set_flag("apt.telegraf.installed")
4076+ set_flag("plugins.haproxy.configured")
4077 config.save()
4078 config.load_previous()
4079- config['extra_options'] = yaml.dump({'inputs': {'haproxy': {'timeout': 10}}})
4080- set_flag('apt.installed.telegraf')
4081- set_flag('config.changed')
4082+ config["extra_options"] = yaml.dump({"inputs": {"haproxy": {"timeout": 10}}})
4083+ set_flag("apt.installed.telegraf")
4084+ set_flag("config.changed")
4085 bus.dispatch()
4086- assert 'plugins.haproxy.configured' not in bus.get_states().keys()
4087+ assert "plugins.haproxy.configured" not in bus.get_states().keys()
4088 service_restart.assert_called_once_with(telegraf.DEB_SERVICE)
4089
4090
4091 def test_config_changed_extra_plugins(mocker, monkeypatch, config):
4092- service_restart = mocker.patch('reactive.telegraf.host.service_restart')
4093- monkeypatch.setattr(telegraf.host, 'service_running',
4094- lambda n: True)
4095- mocker.patch('reactive.telegraf.check_prometheus_port')
4096- set_flag('apt.telegraf.installed')
4097- assert not configs_dir().join('extra_plugins.conf').exists()
4098+ service_restart = mocker.patch("reactive.telegraf.host.service_restart")
4099+ monkeypatch.setattr(telegraf.host, "service_running", lambda n: True)
4100+ mocker.patch("reactive.telegraf.check_prometheus_port")
4101+ set_flag("apt.telegraf.installed")
4102+ assert not configs_dir().join("extra_plugins.conf").exists()
4103 config.save()
4104 config.load_previous()
4105 # once the config is saved, change it. This will also trigger a service
4106 # restart
4107- config['extra_plugins'] = """[[inputs.foo]]
4108+ config[
4109+ "extra_plugins"
4110+ ] = """[[inputs.foo]]
4111 some_option = "http://foo.bar.com"
4112 [[outputs.baz]]
4113 option = "enabled"
4114 """
4115- set_flag('apt.installed.telegraf')
4116- set_flag('config.changed')
4117+ set_flag("apt.installed.telegraf")
4118+ set_flag("config.changed")
4119 bus.dispatch()
4120- assert configs_dir().join('extra_plugins.conf').exists()
4121- assert configs_dir().join('extra_plugins.conf').read() == config['extra_plugins']
4122+ assert configs_dir().join("extra_plugins.conf").exists()
4123+ assert configs_dir().join("extra_plugins.conf").read() == config["extra_plugins"]
4124 service_restart.assert_called_with(telegraf.DEB_SERVICE)
4125
4126
4127 def test_restart_on_output_plugin_relation_departed(mocker, monkeypatch, config):
4128- service_restart = mocker.patch('reactive.telegraf.host.service_restart')
4129- monkeypatch.setattr(telegraf.host, 'service_running',
4130- lambda n: True)
4131- monkeypatch.setattr(telegraf.hookenv, 'relations_of_type', lambda n: [])
4132- monkeypatch.setattr(telegraf.hookenv, 'open_port',
4133- lambda p: None)
4134- relation_ids = ['prometheus-client:0']
4135- monkeypatch.setattr(telegraf.hookenv,
4136- 'relation_ids',
4137- lambda r: relation_ids)
4138+ service_restart = mocker.patch("reactive.telegraf.host.service_restart")
4139+ monkeypatch.setattr(telegraf.host, "service_running", lambda n: True)
4140+ monkeypatch.setattr(telegraf.hookenv, "relations_of_type", lambda n: [])
4141+ monkeypatch.setattr(telegraf.hookenv, "open_port", lambda p: None)
4142+ relation_ids = ["prometheus-client:0"]
4143+ monkeypatch.setattr(telegraf.hookenv, "relation_ids", lambda r: relation_ids)
4144 mocker.patch.object(
4145- telegraf.hookenv, 'network_get',
4146- return_value={"ingress_addresses": ["1.2.3.4"]})
4147- config['prometheus_output_port'] = ''
4148+ telegraf.hookenv, "network_get", return_value={"ingress_addresses": ["1.2.3.4"]}
4149+ )
4150+ config["prometheus_output_port"] = ""
4151 bus.discover()
4152- set_flag('snap.telegraf.installed')
4153- set_flag('telegraf.configured')
4154+ set_flag("snap.telegraf.installed")
4155+ set_flag("telegraf.configured")
4156 interface = mocker.Mock(spec=RelationBase)
4157 interface.configure = mocker.Mock()
4158 telegraf.prometheus_client(interface)
4159- assert configs_dir().join('prometheus-client.conf').exists()
4160+ assert configs_dir().join("prometheus-client.conf").exists()
4161 # dispatch, file should be gone and telegraf restarted.
4162 bus.dispatch()
4163- assert not configs_dir().join('prometheus-client.conf').exists()
4164+ assert not configs_dir().join("prometheus-client.conf").exists()
4165 service_restart.assert_called_with(telegraf.DEB_SERVICE)
4166
4167
4168 def test_upgrade_charm(mocker):
4169- list_plugins = mocker.patch('reactive.telegraf.list_supported_plugins')
4170- clear_flag = mocker.patch('reactive.telegraf.clear_flag')
4171- list_plugins.return_value = ['foo', 'bar']
4172+ list_plugins = mocker.patch("reactive.telegraf.list_supported_plugins")
4173+ clear_flag = mocker.patch("reactive.telegraf.clear_flag")
4174+ list_plugins.return_value = ["foo", "bar"]
4175 telegraf.upgrade_charm()
4176- clear_flag.assert_any_call('telegraf.configured')
4177- clear_flag.assert_any_call('telegraf.apt.configured')
4178- clear_flag.assert_any_call('telegraf.snap.configured')
4179- clear_flag.assert_any_call('plugins.foo.configured')
4180- clear_flag.assert_any_call('plugins.bar.configured')
4181- clear_flag.assert_any_call('extra_plugins.configured')
4182- clear_flag.assert_any_call('grafana.configured')
4183+ clear_flag.assert_any_call("telegraf.configured")
4184+ clear_flag.assert_any_call("telegraf.apt.configured")
4185+ clear_flag.assert_any_call("telegraf.snap.configured")
4186+ clear_flag.assert_any_call("plugins.foo.configured")
4187+ clear_flag.assert_any_call("plugins.bar.configured")
4188+ clear_flag.assert_any_call("extra_plugins.configured")
4189+ clear_flag.assert_any_call("grafana.configured")
4190 assert clear_flag.call_count == 7
4191
4192
4193 def test_get_socket_listener_port(monkeypatch, config):
4194- config['socket_listener_port'] = ''
4195+ config["socket_listener_port"] = ""
4196 assert telegraf.get_socket_listener_port() == 8094
4197- config['socket_listener_port'] = '9090'
4198+ config["socket_listener_port"] = "9090"
4199 assert telegraf.get_socket_listener_port() == 9090
4200
4201
4202 def test_socket_listener_config(monkeypatch, config):
4203 open_ports = set()
4204- monkeypatch.setattr(telegraf.hookenv, 'open_port',
4205- lambda p: open_ports.add(p))
4206- monkeypatch.setattr(telegraf.hookenv, 'close_port',
4207- lambda p: open_ports.remove(p))
4208- config['prometheus_output_port'] = 'default'
4209+ monkeypatch.setattr(telegraf.hookenv, "open_port", lambda p: open_ports.add(p))
4210+ monkeypatch.setattr(telegraf.hookenv, "close_port", lambda p: open_ports.remove(p))
4211+ config["prometheus_output_port"] = "default"
4212 telegraf.configure_telegraf()
4213 expected = 'service_address = "tcp://127.0.0.1:8094"'
4214- config_file = base_dir().join('telegraf.d', 'socket_listener.conf')
4215+ config_file = base_dir().join("telegraf.d", "socket_listener.conf")
4216 assert expected in config_file.read()
4217
4218
4219 class TestGetHostnameLabel(unittest.TestCase):
4220- @patch('reactive.telegraf.get_remote_unit_name')
4221- @patch('charmhelpers.core.hookenv.config')
4222+ @patch("reactive.telegraf.get_remote_unit_name")
4223+ @patch("charmhelpers.core.hookenv.config")
4224 def test_legacy(self, config, get_remote_unit_name):
4225- config.return_value = dict(hostname='UNIT_NAME')
4226- get_remote_unit_name.return_value = 'remote/10'
4227- self.assertEqual(telegraf.get_hostname_label(),
4228- 'remote-10')
4229+ config.return_value = dict(hostname="UNIT_NAME")
4230+ get_remote_unit_name.return_value = "remote/10"
4231+ self.assertEqual(telegraf.get_hostname_label(), "remote-10")
4232
4233- @patch('reactive.telegraf.get_remote_unit_name')
4234- @patch('charmhelpers.core.hookenv.config')
4235+ @patch("reactive.telegraf.get_remote_unit_name")
4236+ @patch("charmhelpers.core.hookenv.config")
4237 def test_juju1(self, config, get_remote_unit_name):
4238- get_remote_unit_name.return_value = 'remote/10'
4239- env = dict(JUJU_ENV_NAME='env_name',
4240- JUJU_ENV_UUID='env_uuid')
4241- config.return_value = dict(hostname='{uuid}:{model}:{unit}')
4242+ get_remote_unit_name.return_value = "remote/10"
4243+ env = dict(JUJU_ENV_NAME="env_name", JUJU_ENV_UUID="env_uuid")
4244+ config.return_value = dict(hostname="{uuid}:{model}:{unit}")
4245 with patch.dict(os.environ, env):
4246- self.assertEqual(telegraf.get_hostname_label(),
4247- 'env_uuid:env_name:remote-10')
4248+ self.assertEqual(
4249+ telegraf.get_hostname_label(), "env_uuid:env_name:remote-10"
4250+ )
4251
4252- @patch('reactive.telegraf.get_remote_unit_name')
4253- @patch('charmhelpers.core.hookenv.config')
4254+ @patch("reactive.telegraf.get_remote_unit_name")
4255+ @patch("charmhelpers.core.hookenv.config")
4256 def test_juju2(self, config, get_remote_unit_name):
4257- get_remote_unit_name.return_value = 'remote/10'
4258- env = dict(JUJU_MODEL_NAME='model_name',
4259- JUJU_MODEL_UUID='model_uuid')
4260- config.return_value = dict(hostname='{uuid}:{model}:{unit}')
4261+ get_remote_unit_name.return_value = "remote/10"
4262+ env = dict(JUJU_MODEL_NAME="model_name", JUJU_MODEL_UUID="model_uuid")
4263+ config.return_value = dict(hostname="{uuid}:{model}:{unit}")
4264 with patch.dict(os.environ, env):
4265- self.assertEqual(telegraf.get_hostname_label(),
4266- 'model_uuid:model_name:remote-10')
4267+ self.assertEqual(
4268+ telegraf.get_hostname_label(), "model_uuid:model_name:remote-10"
4269+ )
4270
4271
4272 class TestTelegrafNagios(unittest.TestCase):
4273- @mock.patch('charmhelpers.contrib.charmsupport.nrpe.NRPE')
4274- @mock.patch('charmhelpers.contrib.charmsupport.nrpe.get_nagios_hostname')
4275- def test_update_nrpe_config(self,
4276- mock_get_nagios_hostname,
4277- mock_nrpe,
4278- *args):
4279- mock_get_nagios_hostname.return_value = 'testunit'
4280+ @mock.patch("charmhelpers.contrib.charmsupport.nrpe.NRPE")
4281+ @mock.patch("charmhelpers.contrib.charmsupport.nrpe.get_nagios_hostname")
4282+ def test_update_nrpe_config(self, mock_get_nagios_hostname, mock_nrpe, *args):
4283+ mock_get_nagios_hostname.return_value = "testunit"
4284 svc = object()
4285 telegraf.configure_nagios(svc)
4286 calls = [
4287- call(hostname='testunit', primary=False),
4288- call().add_check('telegraf_http',
4289- 'Telegraf HTTP check',
4290- 'check_http -I 127.0.0.1 -p 9103 -u '
4291- '/metrics'),
4292- call().write()]
4293+ call(hostname="testunit", primary=False),
4294+ call().add_check(
4295+ "telegraf_http",
4296+ "Telegraf HTTP check",
4297+ "check_http -I 127.0.0.1 -p 9103 -u " "/metrics",
4298+ ),
4299+ call().write(),
4300+ ]
4301 mock_nrpe.assert_has_calls(calls)
4302
4303
4304 class TestGrafanaDashboard(unittest.TestCase):
4305- @patch('reactive.telegraf.render_custom')
4306- @patch('reactive.telegraf.endpoint_from_flag')
4307- @patch('reactive.telegraf.hookenv')
4308- @patch('reactive.telegraf.set_flag')
4309- @patch('reactive.telegraf.json')
4310- def test_register_grafana_dashboard(self, mock_json, mock_set_flag, mock_hookenv,
4311- mock_endpoint_from_flag, mock_render):
4312- expected_datasource = 'my_prometheus'
4313+ @patch("reactive.telegraf.render_custom")
4314+ @patch("reactive.telegraf.endpoint_from_flag")
4315+ @patch("reactive.telegraf.hookenv")
4316+ @patch("reactive.telegraf.set_flag")
4317+ @patch("reactive.telegraf.json")
4318+ def test_register_grafana_dashboard(
4319+ self,
4320+ mock_json,
4321+ mock_set_flag,
4322+ mock_hookenv,
4323+ mock_endpoint_from_flag,
4324+ mock_render,
4325+ ):
4326+ expected_datasource = "my_prometheus"
4327 fake_config = dict(prometheus_datasource=expected_datasource)
4328 expected_dashboard_context = dict(
4329- datasource='{} - Juju generated source'.format(expected_datasource),
4330+ datasource="{} - Juju generated source".format(expected_datasource),
4331 bonds_enabled=True,
4332 bcache_enabled=True,
4333- conntrack_enabled=True
4334+ conntrack_enabled=True,
4335 )
4336
4337 mock_grafana = MagicMock()
4338@@ -1180,22 +1246,25 @@ class TestGrafanaDashboard(unittest.TestCase):
4339 variable_end_string=">>",
4340 )
4341 mock_grafana.register_dashboard.assert_called_once_with(
4342- name=telegraf.GRAFANA_DASHBOARD_NAME,
4343- dashboard=mock_dashboard_dict,
4344+ name=telegraf.GRAFANA_DASHBOARD_NAME, dashboard=mock_dashboard_dict,
4345 )
4346- mock_set_flag.assert_called_once_with('grafana.configured')
4347+ mock_set_flag.assert_called_once_with("grafana.configured")
4348
4349- @patch('reactive.telegraf.clear_flag')
4350+ @patch("reactive.telegraf.clear_flag")
4351 def test_unregister_grafana_dashboard(self, mock_clear_flag):
4352 telegraf.unregister_grafana_dashboard()
4353- mock_clear_flag.assert_called_with('grafana.configured')
4354-
4355- @patch('reactive.telegraf.endpoint_from_flag')
4356- @patch('reactive.telegraf.clear_flag')
4357- @patch('reactive.telegraf.hookenv')
4358- def test_grafana_dashboard_import_failed(self, mock_hookenv, mock_clear_flag, mock_endpoint_from_flag):
4359- test_failed_imports = [MagicMock(name='import1', reason='some_reason1'),
4360- MagicMock(name='import2', reason='some_reason2')]
4361+ mock_clear_flag.assert_called_with("grafana.configured")
4362+
4363+ @patch("reactive.telegraf.endpoint_from_flag")
4364+ @patch("reactive.telegraf.clear_flag")
4365+ @patch("reactive.telegraf.hookenv")
4366+ def test_grafana_dashboard_import_failed(
4367+ self, mock_hookenv, mock_clear_flag, mock_endpoint_from_flag
4368+ ):
4369+ test_failed_imports = [
4370+ MagicMock(name="import1", reason="some_reason1"),
4371+ MagicMock(name="import2", reason="some_reason2"),
4372+ ]
4373
4374 mock_grafana = MagicMock()
4375 mock_grafana.failed_imports = test_failed_imports
4376@@ -1204,4 +1273,4 @@ class TestGrafanaDashboard(unittest.TestCase):
4377 telegraf.grafana_dashboard_import_failed()
4378
4379 assert mock_hookenv.log.call_count == 2
4380- mock_clear_flag.assert_called_once_with('grafana.configured')
4381+ mock_clear_flag.assert_called_once_with("grafana.configured")
4382diff --git a/src/tox.ini b/src/tox.ini
4383index 163018d..40c62d6 100644
4384--- a/src/tox.ini
4385+++ b/src/tox.ini
4386@@ -25,7 +25,7 @@ passenv =
4387 [testenv:lint]
4388 commands =
4389 flake8
4390-# TODO black --check --exclude "/(\.eggs|\.git|\.tox|\.venv|\.build|dist|charmhelpers|mod)/" .
4391+ black --check --exclude "/(\.eggs|\.git|\.tox|\.venv|\.build|dist|charmhelpers|mod)/" .
4392 deps =
4393 black
4394 flake8
4395@@ -42,7 +42,7 @@ exclude =
4396 charmhelpers,
4397 mod,
4398 .build
4399-ignore = I100, D101, D102, D103, I201, D205, W504, D400, D401, D403, D209, D100, E403, I101, E501, N803, E226, E128, D200, E741, D202, E261, E402, D104 # TODO
4400+ignore = I100, D101, D102, D103, I201, D205, W504, D400, D401, D403, D209, D100, E403, I101, E501, N803, E226, E128, D200, E741, D202, E261, E402, D104, W503, E231 # TODO
4401
4402 max-line-length = 88
4403 max-complexity = 10

Subscribers

People subscribed via source and target branches

to all changes: