Merge ~xavpaice/charm-telegraf:lint-20.08 into charm-telegraf:master
- Git
- lp:~xavpaice/charm-telegraf
- lint-20.08
- Merge into master
Proposed by
Xav Paice
Status: | Merged |
---|---|
Approved by: | Alvaro Uria |
Approved revision: | b9e75f78db2428389d614f412f6dc0baca255fce |
Merged at revision: | 5b7391d840a618ab91dc1597864bb29138a04d19 |
Proposed branch: | ~xavpaice/charm-telegraf:lint-20.08 |
Merge into: | charm-telegraf:master |
Prerequisite: | ~xavpaice/charm-telegraf:blacken-20.08 |
Diff against target: |
1281 lines (+226/-112) 12 files modified
src/files/telegraf_exec_metrics.py (+69/-34) src/hooks/relations/apache-website/requires.py (+1/-3) src/hooks/relations/statistics/requires.py (+2/-3) src/hooks/relations/telegraf-exec/requires.py (+7/-3) src/reactive/__init__.py (+1/-0) src/reactive/telegraf.py (+82/-31) src/tests/functional/tests/test_telegraf.py (+19/-6) src/tests/unit/__init__.py (+2/-0) src/tests/unit/test_mysql.py (+2/-1) src/tests/unit/test_postgresql.py (+4/-4) src/tests/unit/test_telegraf.py (+35/-26) src/tox.ini (+2/-1) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Alvaro Uria (community) | Approve | ||
James Troup (community) | Approve | ||
Canonical IS Reviewers | Pending | ||
Review via email: mp+388546@code.launchpad.net |
Commit message
Extra Linting completed for 20.08 charm release
Description of the change
To post a comment you must log in.
Revision history for this message
🤖 Canonical IS Merge Bot (canonical-is-mergebot) wrote : | # |
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
Alvaro Uria (aluria) wrote : | # |
+1 to this and the other 2 related MPs (makefile and blacken)
review:
Approve
Revision history for this message
🤖 Canonical IS Merge Bot (canonical-is-mergebot) wrote : | # |
Change successfully merged at revision 5b7391d840a618a
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | diff --git a/src/files/telegraf_exec_metrics.py b/src/files/telegraf_exec_metrics.py | |||
2 | index f03e23a..d9b3402 100755 | |||
3 | --- a/src/files/telegraf_exec_metrics.py | |||
4 | +++ b/src/files/telegraf_exec_metrics.py | |||
5 | @@ -1,29 +1,32 @@ | |||
6 | 1 | #!/usr/bin/env python3 | 1 | #!/usr/bin/env python3 |
10 | 2 | import os | 2 | import argparse |
8 | 3 | import re | ||
9 | 4 | import sys | ||
11 | 5 | import json | 3 | import json |
12 | 6 | import logging | 4 | import logging |
15 | 7 | import argparse | 5 | import os |
16 | 8 | import subprocess | 6 | import re |
17 | 9 | import shutil | 7 | import shutil |
18 | 8 | import subprocess | ||
19 | 9 | import sys | ||
20 | 10 | from collections import OrderedDict | 10 | from collections import OrderedDict |
21 | 11 | from textwrap import dedent | 11 | from textwrap import dedent |
22 | 12 | 12 | ||
23 | 13 | from insights.tests import context_wrap | ||
24 | 14 | from insights.parsers.softnet_stat import SoftNetStats | 13 | from insights.parsers.softnet_stat import SoftNetStats |
26 | 15 | 14 | from insights.tests import context_wrap | |
27 | 16 | 15 | ||
28 | 17 | LOG = logging.getLogger() | 16 | LOG = logging.getLogger() |
29 | 18 | 17 | ||
30 | 19 | METRICS = OrderedDict() | 18 | METRICS = OrderedDict() |
31 | 20 | 19 | ||
32 | 21 | 20 | ||
36 | 22 | def register_metric(MetricClass): | 21 | def register_metric(metricclass): |
37 | 23 | """A decorator to create a metric class instance and register it""" | 22 | """Create metric class instance. |
38 | 24 | metric = MetricClass() | 23 | |
39 | 24 | Decorator that creates a metric class and registers it. | ||
40 | 25 | """ | ||
41 | 26 | metric = metricclass() | ||
42 | 25 | METRICS[metric.name] = metric | 27 | METRICS[metric.name] = metric |
44 | 26 | return MetricClass | 28 | |
45 | 29 | return metricclass | ||
46 | 27 | 30 | ||
47 | 28 | 31 | ||
48 | 29 | class FileMetric: | 32 | class FileMetric: |
49 | @@ -46,18 +49,22 @@ class FileMetric: | |||
50 | 46 | LOG.info("rendering config to %s", config_path) | 49 | LOG.info("rendering config to %s", config_path) |
51 | 47 | script = os.path.abspath(__file__) | 50 | script = os.path.abspath(__file__) |
52 | 48 | output = self.config_template.format( | 51 | output = self.config_template.format( |
54 | 49 | python=python or sys.executable, script=script, name=self.name, | 52 | python=python or sys.executable, script=script, name=self.name |
55 | 50 | ) | 53 | ) |
56 | 51 | LOG.debug(output) | 54 | LOG.debug(output) |
57 | 55 | |||
58 | 52 | if not dry_run: | 56 | if not dry_run: |
59 | 53 | with open(config_path, mode="w", encoding="utf8") as f: | 57 | with open(config_path, mode="w", encoding="utf8") as f: |
60 | 54 | f.write(output) | 58 | f.write(output) |
61 | 59 | |||
62 | 55 | return output | 60 | return output |
63 | 56 | 61 | ||
64 | 57 | def remove_config(self, configs_dir, dry_run=False): | 62 | def remove_config(self, configs_dir, dry_run=False): |
65 | 58 | config_path = self.config_path(configs_dir) | 63 | config_path = self.config_path(configs_dir) |
66 | 64 | |||
67 | 59 | if os.path.isfile(config_path): | 65 | if os.path.isfile(config_path): |
68 | 60 | LOG.info("removing %s", config_path) | 66 | LOG.info("removing %s", config_path) |
69 | 67 | |||
70 | 61 | if not dry_run: | 68 | if not dry_run: |
71 | 62 | os.remove(config_path) | 69 | os.remove(config_path) |
72 | 63 | else: | 70 | else: |
73 | @@ -78,6 +85,7 @@ class SockStatFileMetric(FileMetric): | |||
74 | 78 | 85 | ||
75 | 79 | def parse(self, content): | 86 | def parse(self, content): |
76 | 80 | results = {} | 87 | results = {} |
77 | 88 | |||
78 | 81 | for line in content.splitlines(): | 89 | for line in content.splitlines(): |
79 | 82 | LOG.debug("parsing line: %s", line) | 90 | LOG.debug("parsing line: %s", line) |
80 | 83 | # line example: TCP: inuse 62 orphan 0 tw 5 alloc 222 mem 20 | 91 | # line example: TCP: inuse 62 orphan 0 tw 5 alloc 222 mem 20 |
81 | @@ -86,9 +94,11 @@ class SockStatFileMetric(FileMetric): | |||
82 | 86 | count = len(items) | 94 | count = len(items) |
83 | 87 | assert count % 2 == 0 | 95 | assert count % 2 == 0 |
84 | 88 | group = {} | 96 | group = {} |
85 | 97 | |||
86 | 89 | for i in range(0, count, 2): | 98 | for i in range(0, count, 2): |
87 | 90 | group[items[i]] = int(items[i + 1]) | 99 | group[items[i]] = int(items[i + 1]) |
88 | 91 | results[key.strip()] = group | 100 | results[key.strip()] = group |
89 | 101 | |||
90 | 92 | return results | 102 | return results |
91 | 93 | 103 | ||
92 | 94 | 104 | ||
93 | @@ -175,18 +185,22 @@ class BuddyinfoFileMetric(FileMetric): | |||
94 | 175 | re_line = re.compile( | 185 | re_line = re.compile( |
95 | 176 | r"Node\s+(?P<node>\d+).*zone\s+(?P<zone>\w+)\s+(?P<pages>.*)" | 186 | r"Node\s+(?P<node>\d+).*zone\s+(?P<zone>\w+)\s+(?P<pages>.*)" |
96 | 177 | ) | 187 | ) |
97 | 188 | |||
98 | 178 | for line in content.splitlines(): | 189 | for line in content.splitlines(): |
99 | 179 | LOG.debug(line) | 190 | LOG.debug(line) |
100 | 180 | match = re_line.match(line) | 191 | match = re_line.match(line) |
101 | 192 | |||
102 | 181 | if match: | 193 | if match: |
103 | 182 | data = match.groupdict() | 194 | data = match.groupdict() |
104 | 183 | LOG.debug(data) | 195 | LOG.debug(data) |
105 | 184 | pages = data["pages"].split() | 196 | pages = data["pages"].split() |
106 | 197 | |||
107 | 185 | if not human_sizes: | 198 | if not human_sizes: |
108 | 186 | human_sizes = [ | 199 | human_sizes = [ |
109 | 187 | self._get_human_size(page_size * 2 ** i) | 200 | self._get_human_size(page_size * 2 ** i) |
110 | 188 | for i, _ in enumerate(pages) | 201 | for i, _ in enumerate(pages) |
111 | 189 | ] | 202 | ] |
112 | 203 | |||
113 | 190 | for k, v in zip(human_sizes, pages): | 204 | for k, v in zip(human_sizes, pages): |
114 | 191 | items.append( | 205 | items.append( |
115 | 192 | { | 206 | { |
116 | @@ -196,6 +210,7 @@ class BuddyinfoFileMetric(FileMetric): | |||
117 | 196 | "count": int(v), | 210 | "count": int(v), |
118 | 197 | } | 211 | } |
119 | 198 | ) | 212 | ) |
120 | 213 | |||
121 | 199 | return items | 214 | return items |
122 | 200 | 215 | ||
123 | 201 | 216 | ||
124 | @@ -228,14 +243,17 @@ class ZoneinfoFileMetric(FileMetric): | |||
125 | 228 | re.MULTILINE + re.DOTALL, | 243 | re.MULTILINE + re.DOTALL, |
126 | 229 | ) | 244 | ) |
127 | 230 | items = [] | 245 | items = [] |
128 | 246 | |||
129 | 231 | for match in pattern.finditer(content): | 247 | for match in pattern.finditer(content): |
130 | 232 | data = match.groupdict() | 248 | data = match.groupdict() |
131 | 233 | LOG.debug(data) | 249 | LOG.debug(data) |
132 | 234 | # convert str to int | 250 | # convert str to int |
133 | 251 | |||
134 | 235 | for k, v in data.items(): | 252 | for k, v in data.items(): |
135 | 236 | if v.isdigit(): | 253 | if v.isdigit(): |
136 | 237 | data[k] = int(v) | 254 | data[k] = int(v) |
137 | 238 | items.append(data) | 255 | items.append(data) |
138 | 256 | |||
139 | 239 | return items | 257 | return items |
140 | 240 | 258 | ||
141 | 241 | 259 | ||
142 | @@ -246,11 +264,14 @@ class CmdMetric(FileMetric): | |||
143 | 246 | def get_cmd_output(self, cmd, is_json=False): | 264 | def get_cmd_output(self, cmd, is_json=False): |
144 | 247 | LOG.debug("running cmd: %s", " ".join(cmd)) | 265 | LOG.debug("running cmd: %s", " ".join(cmd)) |
145 | 248 | output = subprocess.check_output(cmd).decode("utf8").strip() | 266 | output = subprocess.check_output(cmd).decode("utf8").strip() |
146 | 267 | |||
147 | 249 | return json.loads(output) if is_json else output | 268 | return json.loads(output) if is_json else output |
148 | 250 | 269 | ||
149 | 251 | def get_input_content(self): | 270 | def get_input_content(self): |
150 | 252 | if self.input_file: | 271 | if self.input_file: |
152 | 253 | # if provided, still read cmd output from a file, helpful for debuging/testing. | 272 | # if provided, still read cmd output from a file, helpful |
153 | 273 | # for debuging/testing. | ||
154 | 274 | |||
155 | 254 | return super().get_input_content() | 275 | return super().get_input_content() |
156 | 255 | else: | 276 | else: |
157 | 256 | return self.get_cmd_output(self.cmd) | 277 | return self.get_cmd_output(self.cmd) |
158 | @@ -277,17 +298,18 @@ class NetNSCmdMetric(CmdMetric): | |||
159 | 277 | items = [] | 298 | items = [] |
160 | 278 | # find openstack/neutron netns list pattern | 299 | # find openstack/neutron netns list pattern |
161 | 279 | pattern = re.compile(r"^([\w-]+)\s+\(id:\s+(\d+)\)", flags=re.M) | 300 | pattern = re.compile(r"^([\w-]+)\s+\(id:\s+(\d+)\)", flags=re.M) |
162 | 301 | |||
163 | 280 | for match in pattern.finditer(content): | 302 | for match in pattern.finditer(content): |
164 | 281 | items.append( | 303 | items.append( |
166 | 282 | {"namespace": match.group(1), "id": match.group(2), "state": 1,} | 304 | {"namespace": match.group(1), "id": match.group(2), "state": 1} |
167 | 283 | ) | 305 | ) |
168 | 284 | 306 | ||
169 | 285 | # no re matches, should be in simple list format | 307 | # no re matches, should be in simple list format |
170 | 308 | |||
171 | 286 | if not items: | 309 | if not items: |
172 | 287 | for line in content.splitlines(): | 310 | for line in content.splitlines(): |
176 | 288 | items.append( | 311 | items.append({"namespace": line.strip(), "state": 1}) |
177 | 289 | {"namespace": line.strip(), "state": 1,} | 312 | |
175 | 290 | ) | ||
178 | 291 | return items | 313 | return items |
179 | 292 | 314 | ||
180 | 293 | 315 | ||
181 | @@ -321,8 +343,10 @@ class OvsDumpFlowsCmdMetric(CmdMetric): | |||
182 | 321 | flows = {} | 343 | flows = {} |
183 | 322 | 344 | ||
184 | 323 | ovs_cmd = "ovs-ofctl" | 345 | ovs_cmd = "ovs-ofctl" |
185 | 346 | |||
186 | 324 | if not shutil.which(ovs_cmd): | 347 | if not shutil.which(ovs_cmd): |
187 | 325 | LOG.error('openvswitch command "%s" is not available, exit', ovs_cmd) | 348 | LOG.error('openvswitch command "%s" is not available, exit', ovs_cmd) |
188 | 349 | |||
189 | 326 | return flows | 350 | return flows |
190 | 327 | 351 | ||
191 | 328 | for bridge in ["br-int", "br-tun", "br-data"]: | 352 | for bridge in ["br-int", "br-tun", "br-data"]: |
192 | @@ -335,7 +359,6 @@ class OvsDumpFlowsCmdMetric(CmdMetric): | |||
193 | 335 | def parse(self, input_content): | 359 | def parse(self, input_content): |
194 | 336 | """Parse input content for each bridge and convert to a json list. | 360 | """Parse input content for each bridge and convert to a json list. |
195 | 337 | 361 | ||
196 | 338 | |||
197 | 339 | Example final json result: | 362 | Example final json result: |
198 | 340 | 363 | ||
199 | 341 | [ | 364 | [ |
200 | @@ -356,12 +379,14 @@ class OvsDumpFlowsCmdMetric(CmdMetric): | |||
201 | 356 | # input_content here is a dict with cmd output for each bridge for this metric | 379 | # input_content here is a dict with cmd output for each bridge for this metric |
202 | 357 | flows = input_content | 380 | flows = input_content |
203 | 358 | items = [] | 381 | items = [] |
204 | 382 | |||
205 | 359 | for bridge, output in flows.items(): | 383 | for bridge, output in flows.items(): |
206 | 360 | # when invoked via python (or redirected) it includes an extra line | 384 | # when invoked via python (or redirected) it includes an extra line |
207 | 361 | # like 'NXST_FLOW reply (xid=0x4):' | 385 | # like 'NXST_FLOW reply (xid=0x4):' |
208 | 362 | # so need to substract one | 386 | # so need to substract one |
209 | 363 | lines = output.splitlines() | 387 | lines = output.splitlines() |
210 | 364 | items.append({"bridge": bridge, "count": len(lines) - 1}) | 388 | items.append({"bridge": bridge, "count": len(lines) - 1}) |
211 | 389 | |||
212 | 365 | return items | 390 | return items |
213 | 366 | 391 | ||
214 | 367 | 392 | ||
215 | @@ -381,8 +406,9 @@ class OvsDpCtlCmdMetric(CmdMetric): | |||
216 | 381 | ) | 406 | ) |
217 | 382 | 407 | ||
218 | 383 | def parse_fields(self, text): | 408 | def parse_fields(self, text): |
221 | 384 | """ | 409 | """Parse lines following pattern to a dictionary. |
222 | 385 | parse lines following pattern to a dictionary, | 410 | |
223 | 411 | Parse lines following pattern to a dictionary, | ||
224 | 386 | converting int/floats as relevant | 412 | converting int/floats as relevant |
225 | 387 | 'hit:706 missed:456 lost:0' | 413 | 'hit:706 missed:456 lost:0' |
226 | 388 | """ | 414 | """ |
227 | @@ -396,23 +422,26 @@ class OvsDpCtlCmdMetric(CmdMetric): | |||
228 | 396 | # parse lines of key/values into a dict | 422 | # parse lines of key/values into a dict |
229 | 397 | # hit:706 missed:489 lost:1 | 423 | # hit:706 missed:489 lost:1 |
230 | 398 | data = {} | 424 | data = {} |
231 | 425 | |||
232 | 399 | for datapair in text.split(): | 426 | for datapair in text.split(): |
233 | 400 | k, v = datapair.split(":") | 427 | k, v = datapair.split(":") |
234 | 401 | # do nothing if the line has question marks (no data), e.g.: | 428 | # do nothing if the line has question marks (no data), e.g.: |
235 | 402 | # RX packets:0 errors:? dropped:? overruns:? frame:? | 429 | # RX packets:0 errors:? dropped:? overruns:? frame:? |
236 | 430 | |||
237 | 403 | if "?" in v: | 431 | if "?" in v: |
238 | 404 | continue | 432 | continue |
239 | 405 | # reuse field parsing logic by recursion, no nested dicts | 433 | # reuse field parsing logic by recursion, no nested dicts |
240 | 406 | data[k] = self.parse_fields(v) | 434 | data[k] = self.parse_fields(v) |
241 | 435 | |||
242 | 407 | return data | 436 | return data |
243 | 437 | |||
244 | 408 | return text | 438 | return text |
245 | 409 | 439 | ||
246 | 410 | def parse(self, input_content): | 440 | def parse(self, input_content): |
250 | 411 | """ | 441 | """Parse the output of `ovs-appctl dpctl/show -s`.""" |
248 | 412 | parse the output of `ovs-appctl dpctl/show -s` | ||
249 | 413 | """ | ||
251 | 414 | result = [] | 442 | result = [] |
252 | 415 | datapath_entry = None | 443 | datapath_entry = None |
253 | 444 | |||
254 | 416 | for line in input_content.splitlines(): | 445 | for line in input_content.splitlines(): |
255 | 417 | if line[0].isalnum(): # datapath header, other lines start w/space or tab | 446 | if line[0].isalnum(): # datapath header, other lines start w/space or tab |
256 | 418 | if datapath_entry: # store the current one before creating a new one | 447 | if datapath_entry: # store the current one before creating a new one |
257 | @@ -422,9 +451,10 @@ class OvsDpCtlCmdMetric(CmdMetric): | |||
258 | 422 | "port": "", | 451 | "port": "", |
259 | 423 | "portname": "", | 452 | "portname": "", |
260 | 424 | } | 453 | } |
261 | 454 | |||
262 | 425 | continue | 455 | continue |
263 | 426 | 456 | ||
265 | 427 | label, rest = (l.strip() for l in line.split(":", maxsplit=1)) | 457 | label, rest = (item.strip() for item in line.split(":", maxsplit=1)) |
266 | 428 | 458 | ||
267 | 429 | if label.startswith("port"): | 459 | if label.startswith("port"): |
268 | 430 | # complete previous entry, and initialise a new one for the new port | 460 | # complete previous entry, and initialise a new one for the new port |
269 | @@ -434,12 +464,14 @@ class OvsDpCtlCmdMetric(CmdMetric): | |||
270 | 434 | } | 464 | } |
271 | 435 | datapath_entry["port"] = label.split()[-1] | 465 | datapath_entry["port"] = label.split()[-1] |
272 | 436 | datapath_entry["portname"] = rest | 466 | datapath_entry["portname"] = rest |
273 | 467 | |||
274 | 437 | continue | 468 | continue |
275 | 438 | 469 | ||
276 | 439 | if datapath_entry["port"]: # parsing lines corresponding to a port block | 470 | if datapath_entry["port"]: # parsing lines corresponding to a port block |
277 | 440 | if "X packets" in label: | 471 | if "X packets" in label: |
278 | 441 | # parse the RX|TX packets line using a prefix | 472 | # parse the RX|TX packets line using a prefix |
279 | 442 | prefix, data = line.strip().split(maxsplit=1) | 473 | prefix, data = line.strip().split(maxsplit=1) |
280 | 474 | |||
281 | 443 | for k, v in self.parse_fields(data).items(): | 475 | for k, v in self.parse_fields(data).items(): |
282 | 444 | datapath_entry["{}_{}".format(prefix, k)] = v | 476 | datapath_entry["{}_{}".format(prefix, k)] = v |
283 | 445 | else: # parse the non-packet lines (collisions/bytes) | 477 | else: # parse the non-packet lines (collisions/bytes) |
284 | @@ -449,12 +481,14 @@ class OvsDpCtlCmdMetric(CmdMetric): | |||
285 | 449 | # use RX/TX as a prefix by removing the space | 481 | # use RX/TX as a prefix by removing the space |
286 | 450 | data = line.replace(" bytes", "_bytes") | 482 | data = line.replace(" bytes", "_bytes") |
287 | 451 | datapath_entry.update(self.parse_fields(data)) | 483 | datapath_entry.update(self.parse_fields(data)) |
288 | 484 | |||
289 | 452 | continue | 485 | continue |
290 | 453 | 486 | ||
291 | 454 | # all other cases, are datapairs or metrics | 487 | # all other cases, are datapairs or metrics |
292 | 455 | datapath_entry[label] = self.parse_fields(rest.rstrip()) | 488 | datapath_entry[label] = self.parse_fields(rest.rstrip()) |
293 | 456 | 489 | ||
294 | 457 | # handle the end of the output | 490 | # handle the end of the output |
295 | 491 | |||
296 | 458 | if datapath_entry: | 492 | if datapath_entry: |
297 | 459 | result.append(datapath_entry) | 493 | result.append(datapath_entry) |
298 | 460 | 494 | ||
299 | @@ -462,17 +496,18 @@ class OvsDpCtlCmdMetric(CmdMetric): | |||
300 | 462 | 496 | ||
301 | 463 | 497 | ||
302 | 464 | def render_config_files(configs_dir, python, disabled_metrics="", dry_run=False): | 498 | def render_config_files(configs_dir, python, disabled_metrics="", dry_run=False): |
305 | 465 | """Render config files for any metrics not disabled, and remove any disabled""" | 499 | """Render config files for any metrics not disabled, and remove any disabled.""" |
304 | 466 | |||
306 | 467 | disabled_metrics_set = ( | 500 | disabled_metrics_set = ( |
307 | 468 | set(disabled_metrics.split(":")) if disabled_metrics else set([]) | 501 | set(disabled_metrics.split(":")) if disabled_metrics else set([]) |
308 | 469 | ) | 502 | ) |
309 | 503 | |||
310 | 470 | for metric in disabled_metrics_set: | 504 | for metric in disabled_metrics_set: |
311 | 471 | try: | 505 | try: |
312 | 472 | METRICS[metric].remove_config(configs_dir, dry_run=dry_run) | 506 | METRICS[metric].remove_config(configs_dir, dry_run=dry_run) |
313 | 473 | except KeyError: | 507 | except KeyError: |
314 | 474 | LOG.warning("metric name %s not in %s", metric, ",".join(METRICS)) | 508 | LOG.warning("metric name %s not in %s", metric, ",".join(METRICS)) |
315 | 475 | enabled_metrics_set = set(METRICS.keys()) - disabled_metrics_set | 509 | enabled_metrics_set = set(METRICS.keys()) - disabled_metrics_set |
316 | 510 | |||
317 | 476 | for metric in enabled_metrics_set: | 511 | for metric in enabled_metrics_set: |
318 | 477 | METRICS[metric].render_config(configs_dir, python, dry_run=dry_run) | 512 | METRICS[metric].render_config(configs_dir, python, dry_run=dry_run) |
319 | 478 | 513 | ||
320 | @@ -484,10 +519,7 @@ def main(): | |||
321 | 484 | ) | 519 | ) |
322 | 485 | choices = list(METRICS) # sorted dict | 520 | choices = list(METRICS) # sorted dict |
323 | 486 | argparser.add_argument( | 521 | argparser.add_argument( |
328 | 487 | "--metric", | 522 | "--metric", choices=choices, default=choices[0], help="which metric to execuate" |
325 | 488 | choices=choices, | ||
326 | 489 | default=choices[0], | ||
327 | 490 | help="which metric to execuate", | ||
329 | 491 | ) | 523 | ) |
330 | 492 | argparser.add_argument( | 524 | argparser.add_argument( |
331 | 493 | "-f", | 525 | "-f", |
332 | @@ -499,7 +531,8 @@ def main(): | |||
333 | 499 | "--render-config-files", | 531 | "--render-config-files", |
334 | 500 | dest="render_config_files", | 532 | dest="render_config_files", |
335 | 501 | action="store_true", | 533 | action="store_true", |
337 | 502 | help="render config files for all metrics, use --disabled-metrics to exclude specific ones", | 534 | help="render config files for all metrics, use --disabled-metrics to " |
338 | 535 | "exclude specific ones", | ||
339 | 503 | ) | 536 | ) |
340 | 504 | argparser.add_argument( | 537 | argparser.add_argument( |
341 | 505 | "--disabled-metrics", | 538 | "--disabled-metrics", |
342 | @@ -511,7 +544,8 @@ def main(): | |||
343 | 511 | "--python", | 544 | "--python", |
344 | 512 | dest="python", | 545 | dest="python", |
345 | 513 | default=sys.executable, | 546 | default=sys.executable, |
347 | 514 | help="python interperter path in config file to execute this script, required for venv", | 547 | help="python interperter path in config file to execute this script, " |
348 | 548 | "required for venv", | ||
349 | 515 | ) | 549 | ) |
350 | 516 | # useful for testing | 550 | # useful for testing |
351 | 517 | argparser.add_argument( | 551 | argparser.add_argument( |
352 | @@ -521,10 +555,10 @@ def main(): | |||
353 | 521 | help="telegraf configs dir for exec metrics", | 555 | help="telegraf configs dir for exec metrics", |
354 | 522 | ) | 556 | ) |
355 | 523 | argparser.add_argument( | 557 | argparser.add_argument( |
357 | 524 | "--dry-run", action="store_true", help="dry run without real actions", | 558 | "--dry-run", action="store_true", help="dry run without real actions" |
358 | 525 | ) | 559 | ) |
359 | 526 | argparser.add_argument( | 560 | argparser.add_argument( |
361 | 527 | "-v", "--verbose", action="store_true", help="be verbose in log", | 561 | "-v", "--verbose", action="store_true", help="be verbose in log" |
362 | 528 | ) | 562 | ) |
363 | 529 | 563 | ||
364 | 530 | cli = argparser.parse_args() | 564 | cli = argparser.parse_args() |
365 | @@ -542,6 +576,7 @@ def main(): | |||
366 | 542 | ) | 576 | ) |
367 | 543 | else: | 577 | else: |
368 | 544 | metric = METRICS[cli.metric] | 578 | metric = METRICS[cli.metric] |
369 | 579 | |||
370 | 545 | if cli.input_file: | 580 | if cli.input_file: |
371 | 546 | metric.input_file = cli.input_file | 581 | metric.input_file = cli.input_file |
372 | 547 | output = metric.parse(metric.get_input_content()) | 582 | output = metric.parse(metric.get_input_content()) |
373 | diff --git a/src/hooks/relations/apache-website/requires.py b/src/hooks/relations/apache-website/requires.py | |||
374 | index ecb663a..861fb8f 100644 | |||
375 | --- a/src/hooks/relations/apache-website/requires.py | |||
376 | +++ b/src/hooks/relations/apache-website/requires.py | |||
377 | @@ -14,9 +14,7 @@ | |||
378 | 14 | # You should have received a copy of the GNU General Public License | 14 | # You should have received a copy of the GNU General Public License |
379 | 15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | 15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
380 | 16 | 16 | ||
384 | 17 | from charms.reactive import hook | 17 | from charms.reactive import RelationBase, hook, scopes |
382 | 18 | from charms.reactive import RelationBase | ||
383 | 19 | from charms.reactive import scopes | ||
385 | 20 | 18 | ||
386 | 21 | 19 | ||
387 | 22 | class WSGIRequires(RelationBase): | 20 | class WSGIRequires(RelationBase): |
388 | diff --git a/src/hooks/relations/statistics/requires.py b/src/hooks/relations/statistics/requires.py | |||
389 | index 4aafb2a..702db6f 100644 | |||
390 | --- a/src/hooks/relations/statistics/requires.py | |||
391 | +++ b/src/hooks/relations/statistics/requires.py | |||
392 | @@ -14,9 +14,7 @@ | |||
393 | 14 | # You should have received a copy of the GNU General Public License | 14 | # You should have received a copy of the GNU General Public License |
394 | 15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | 15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
395 | 16 | 16 | ||
399 | 17 | from charms.reactive import hook | 17 | from charms.reactive import RelationBase, hook, scopes |
397 | 18 | from charms.reactive import RelationBase | ||
398 | 19 | from charms.reactive import scopes | ||
400 | 20 | 18 | ||
401 | 21 | 19 | ||
402 | 22 | class WSGIRequires(RelationBase): | 20 | class WSGIRequires(RelationBase): |
403 | @@ -26,6 +24,7 @@ class WSGIRequires(RelationBase): | |||
404 | 26 | def changed(self): | 24 | def changed(self): |
405 | 27 | conv = self.conversation() | 25 | conv = self.conversation() |
406 | 28 | conv.set_state("{relation_name}.connected") | 26 | conv.set_state("{relation_name}.connected") |
407 | 27 | |||
408 | 29 | if conv.get_remote("enabled"): | 28 | if conv.get_remote("enabled"): |
409 | 30 | # this unit's conversation has a port, so | 29 | # this unit's conversation has a port, so |
410 | 31 | # it is part of the set of available units | 30 | # it is part of the set of available units |
411 | diff --git a/src/hooks/relations/telegraf-exec/requires.py b/src/hooks/relations/telegraf-exec/requires.py | |||
412 | index 42bb783..453203b 100644 | |||
413 | --- a/src/hooks/relations/telegraf-exec/requires.py | |||
414 | +++ b/src/hooks/relations/telegraf-exec/requires.py | |||
415 | @@ -16,9 +16,7 @@ | |||
416 | 16 | 16 | ||
417 | 17 | import json | 17 | import json |
418 | 18 | 18 | ||
422 | 19 | from charms.reactive import hook | 19 | from charms.reactive import RelationBase, hook, scopes |
420 | 20 | from charms.reactive import RelationBase | ||
421 | 21 | from charms.reactive import scopes | ||
423 | 22 | 20 | ||
424 | 23 | 21 | ||
425 | 24 | class ExecRequires(RelationBase): | 22 | class ExecRequires(RelationBase): |
426 | @@ -29,6 +27,7 @@ class ExecRequires(RelationBase): | |||
427 | 29 | conv = self.conversation() | 27 | conv = self.conversation() |
428 | 30 | conv.set_state("{relation_name}.connected") | 28 | conv.set_state("{relation_name}.connected") |
429 | 31 | commands_json_dict = conv.get_remote("commands") # list of commands to run | 29 | commands_json_dict = conv.get_remote("commands") # list of commands to run |
430 | 30 | |||
431 | 32 | if commands_json_dict is not None and json.loads(commands_json_dict): | 31 | if commands_json_dict is not None and json.loads(commands_json_dict): |
432 | 33 | conv.set_state("{relation_name}.available") | 32 | conv.set_state("{relation_name}.available") |
433 | 34 | 33 | ||
434 | @@ -40,12 +39,16 @@ class ExecRequires(RelationBase): | |||
435 | 40 | 39 | ||
436 | 41 | def commands(self): | 40 | def commands(self): |
437 | 42 | cmds = [] | 41 | cmds = [] |
438 | 42 | |||
439 | 43 | for conv in self.conversations(): | 43 | for conv in self.conversations(): |
440 | 44 | commands_json_dict = conv.get_remote("commands") # list of commands dicts | 44 | commands_json_dict = conv.get_remote("commands") # list of commands dicts |
441 | 45 | |||
442 | 45 | for cmd_info in json.loads(commands_json_dict): | 46 | for cmd_info in json.loads(commands_json_dict): |
443 | 46 | commands = cmd_info.pop("commands", []) # list of commands | 47 | commands = cmd_info.pop("commands", []) # list of commands |
444 | 48 | |||
445 | 47 | if commands is None and "command" in cmd_info: | 49 | if commands is None and "command" in cmd_info: |
446 | 48 | commands = [cmd_info.pop("command")] | 50 | commands = [cmd_info.pop("command")] |
447 | 51 | |||
448 | 49 | if not commands: | 52 | if not commands: |
449 | 50 | continue | 53 | continue |
450 | 51 | data_format = cmd_info.pop("data_format") # json, graphite, influx | 54 | data_format = cmd_info.pop("data_format") # json, graphite, influx |
451 | @@ -57,4 +60,5 @@ class ExecRequires(RelationBase): | |||
452 | 57 | cmd["run_on_this_unit"] = cmd_info.pop("run_on_this_unit", True) | 60 | cmd["run_on_this_unit"] = cmd_info.pop("run_on_this_unit", True) |
453 | 58 | cmd.update(cmd_info) | 61 | cmd.update(cmd_info) |
454 | 59 | cmds.append(cmd) | 62 | cmds.append(cmd) |
455 | 63 | |||
456 | 60 | return cmds | 64 | return cmds |
457 | diff --git a/src/reactive/__init__.py b/src/reactive/__init__.py | |||
458 | index e69de29..82e3dfc 100644 | |||
459 | --- a/src/reactive/__init__.py | |||
460 | +++ b/src/reactive/__init__.py | |||
461 | @@ -0,0 +1 @@ | |||
462 | 1 | """Reactive package.""" | ||
463 | diff --git a/src/reactive/telegraf.py b/src/reactive/telegraf.py | |||
464 | index ba47505..4b72eab 100644 | |||
465 | --- a/src/reactive/telegraf.py | |||
466 | +++ b/src/reactive/telegraf.py | |||
467 | @@ -16,40 +16,43 @@ | |||
468 | 16 | 16 | ||
469 | 17 | import base64 | 17 | import base64 |
470 | 18 | import binascii | 18 | import binascii |
471 | 19 | from distutils.version import LooseVersion | ||
472 | 20 | import io | 19 | import io |
473 | 21 | import json | 20 | import json |
474 | 22 | import os | 21 | import os |
475 | 22 | import re | ||
476 | 23 | import shutil | 23 | import shutil |
477 | 24 | import socket | 24 | import socket |
478 | 25 | import subprocess | ||
479 | 25 | import sys | 26 | import sys |
480 | 26 | import time | 27 | import time |
485 | 27 | import yaml | 28 | from distutils.version import LooseVersion |
486 | 28 | import re | 29 | |
487 | 29 | import netifaces | 30 | from charmhelpers import context |
488 | 30 | import subprocess | 31 | from charmhelpers.contrib.charmsupport import nrpe |
489 | 32 | from charmhelpers.core import hookenv, host, unitdata | ||
490 | 33 | from charmhelpers.core.host import is_container | ||
491 | 34 | from charmhelpers.core.templating import render | ||
492 | 31 | 35 | ||
493 | 36 | import charms.promreg | ||
494 | 32 | from charms import apt | 37 | from charms import apt |
495 | 33 | from charms.layer import snap | 38 | from charms.layer import snap |
496 | 34 | from charms.reactive import ( | 39 | from charms.reactive import ( |
497 | 40 | clear_flag, | ||
498 | 35 | endpoint_from_flag, | 41 | endpoint_from_flag, |
499 | 36 | helpers, | 42 | helpers, |
500 | 37 | hook, | 43 | hook, |
501 | 38 | when, | ||
502 | 39 | when_not, | ||
503 | 40 | set_flag, | 44 | set_flag, |
504 | 41 | clear_flag, | ||
505 | 42 | toggle_flag, | 45 | toggle_flag, |
506 | 46 | when, | ||
507 | 47 | when_not, | ||
508 | 43 | ) | 48 | ) |
509 | 44 | from charms.reactive.bus import get_states | 49 | from charms.reactive.bus import get_states |
510 | 45 | 50 | ||
518 | 46 | from charmhelpers import context | 51 | from jinja2 import Environment, FileSystemLoader, Template, exceptions |
519 | 47 | from charmhelpers.core import hookenv, host, unitdata | 52 | |
520 | 48 | from charmhelpers.core.templating import render | 53 | import netifaces |
521 | 49 | from charmhelpers.core.host import is_container | 54 | |
522 | 50 | from charmhelpers.contrib.charmsupport import nrpe | 55 | import yaml |
516 | 51 | import charms.promreg | ||
517 | 52 | from jinja2 import Template, Environment, FileSystemLoader, exceptions | ||
523 | 53 | 56 | ||
524 | 54 | DEB_BASE_DIR = "/etc/telegraf" | 57 | DEB_BASE_DIR = "/etc/telegraf" |
525 | 55 | SNAP_BASE_DIR = "/var/snap/telegraf/current" | 58 | SNAP_BASE_DIR = "/var/snap/telegraf/current" |
526 | @@ -75,6 +78,7 @@ class InvalidInstallMethod(Exception): | |||
527 | 75 | 78 | ||
528 | 76 | def get_install_method(): | 79 | def get_install_method(): |
529 | 77 | config = hookenv.config() | 80 | config = hookenv.config() |
530 | 81 | |||
531 | 78 | if config["install_method"] in ["deb", "snap"]: | 82 | if config["install_method"] in ["deb", "snap"]: |
532 | 79 | return config["install_method"] | 83 | return config["install_method"] |
533 | 80 | else: | 84 | else: |
534 | @@ -87,6 +91,7 @@ def get_install_method(): | |||
535 | 87 | 91 | ||
536 | 88 | def get_base_dir(): | 92 | def get_base_dir(): |
537 | 89 | config = hookenv.config() | 93 | config = hookenv.config() |
538 | 94 | |||
539 | 90 | if config["install_method"] == "deb": | 95 | if config["install_method"] == "deb": |
540 | 91 | return DEB_BASE_DIR | 96 | return DEB_BASE_DIR |
541 | 92 | elif config["install_method"] == "snap": | 97 | elif config["install_method"] == "snap": |
542 | @@ -101,6 +106,7 @@ def get_base_dir(): | |||
543 | 101 | 106 | ||
544 | 102 | def get_service(): | 107 | def get_service(): |
545 | 103 | config = hookenv.config() | 108 | config = hookenv.config() |
546 | 109 | |||
547 | 104 | if config["install_method"] == "deb": | 110 | if config["install_method"] == "deb": |
548 | 105 | return DEB_SERVICE | 111 | return DEB_SERVICE |
549 | 106 | elif config["install_method"] == "snap": | 112 | elif config["install_method"] == "snap": |
550 | @@ -139,13 +145,16 @@ def list_config_files(): | |||
551 | 139 | config_files = [get_main_config_path()] | 145 | config_files = [get_main_config_path()] |
552 | 140 | # only include config files for configured plugins | 146 | # only include config files for configured plugins |
553 | 141 | current_states = get_states() | 147 | current_states = get_states() |
554 | 148 | |||
555 | 142 | for plugin in list_supported_plugins(): | 149 | for plugin in list_supported_plugins(): |
556 | 143 | if "plugins.{}.configured".format(plugin) in current_states.keys(): | 150 | if "plugins.{}.configured".format(plugin) in current_states.keys(): |
557 | 144 | config_path = "{}/{}.conf".format(get_configs_dir(), plugin) | 151 | config_path = "{}/{}.conf".format(get_configs_dir(), plugin) |
558 | 145 | config_files.append(config_path) | 152 | config_files.append(config_path) |
559 | 153 | |||
560 | 146 | if "extra_plugins.configured" in current_states.keys(): | 154 | if "extra_plugins.configured" in current_states.keys(): |
561 | 147 | config_files.append("{}/extra_plugins.conf".format(get_configs_dir())) | 155 | config_files.append("{}/extra_plugins.conf".format(get_configs_dir())) |
562 | 148 | config_files.append("{}/socket_listener.conf".format(get_configs_dir())) | 156 | config_files.append("{}/socket_listener.conf".format(get_configs_dir())) |
563 | 157 | |||
564 | 149 | return config_files | 158 | return config_files |
565 | 150 | 159 | ||
566 | 151 | 160 | ||
567 | @@ -153,33 +162,40 @@ def get_hostname_label(): | |||
568 | 153 | config = hookenv.config() | 162 | config = hookenv.config() |
569 | 154 | hostname_fmt = config["hostname"] | 163 | hostname_fmt = config["hostname"] |
570 | 155 | unit = get_remote_unit_name().replace("/", "-") # / is invalid in labels. | 164 | unit = get_remote_unit_name().replace("/", "-") # / is invalid in labels. |
571 | 165 | |||
572 | 156 | if hostname_fmt == "UNIT_NAME": # Deprecated | 166 | if hostname_fmt == "UNIT_NAME": # Deprecated |
573 | 157 | return unit | 167 | return unit |
574 | 158 | env = os.environ | 168 | env = os.environ |
575 | 159 | model = env.get("JUJU_ENV_NAME") or env.get("JUJU_MODEL_NAME", "") | 169 | model = env.get("JUJU_ENV_NAME") or env.get("JUJU_MODEL_NAME", "") |
576 | 160 | uuid = env.get("JUJU_ENV_UUID") or env.get("JUJU_MODEL_UUID", "") | 170 | uuid = env.get("JUJU_ENV_UUID") or env.get("JUJU_MODEL_UUID", "") |
577 | 161 | syshost = socket.gethostname() | 171 | syshost = socket.gethostname() |
578 | 172 | |||
579 | 162 | return hostname_fmt.format(unit=unit, model=model, uuid=uuid, host=syshost) | 173 | return hostname_fmt.format(unit=unit, model=model, uuid=uuid, host=syshost) |
580 | 163 | 174 | ||
581 | 164 | 175 | ||
582 | 165 | def get_remote_unit_name(): | 176 | def get_remote_unit_name(): |
583 | 166 | unit = hookenv.principal_unit() | 177 | unit = hookenv.principal_unit() |
584 | 178 | |||
585 | 167 | if unit: | 179 | if unit: |
586 | 168 | # Note(aluria): use Juju env var available since 2017 | 180 | # Note(aluria): use Juju env var available since 2017 |
587 | 181 | |||
588 | 169 | return unit | 182 | return unit |
589 | 170 | else: | 183 | else: |
590 | 171 | # Note(aluria): lookup all available IPv4/IPv6 addresses (except lo) | 184 | # Note(aluria): lookup all available IPv4/IPv6 addresses (except lo) |
591 | 172 | ip_addresses = set() | 185 | ip_addresses = set() |
592 | 186 | |||
593 | 173 | for iface in netifaces.interfaces(): | 187 | for iface in netifaces.interfaces(): |
594 | 174 | if iface == "lo": | 188 | if iface == "lo": |
595 | 175 | continue | 189 | continue |
596 | 176 | ip_addrs = netifaces.ifaddresses(iface) | 190 | ip_addrs = netifaces.ifaddresses(iface) |
597 | 191 | |||
598 | 177 | for iface_type in ip_addrs: | 192 | for iface_type in ip_addrs: |
599 | 178 | if iface_type in (netifaces.AF_INET, netifaces.AF_INET6): | 193 | if iface_type in (netifaces.AF_INET, netifaces.AF_INET6): |
600 | 179 | for addrs in ip_addrs[iface_type]: | 194 | for addrs in ip_addrs[iface_type]: |
601 | 180 | ip_addresses.add(addrs["addr"]) | 195 | ip_addresses.add(addrs["addr"]) |
602 | 181 | 196 | ||
603 | 182 | # Note(aluria): and try to match them against rel['private-address'] | 197 | # Note(aluria): and try to match them against rel['private-address'] |
604 | 198 | |||
605 | 183 | for rel_type in hookenv.metadata()["requires"].keys(): | 199 | for rel_type in hookenv.metadata()["requires"].keys(): |
606 | 184 | for rel in hookenv.relations_of_type(rel_type): | 200 | for rel in hookenv.relations_of_type(rel_type): |
607 | 185 | if rel["private-address"] in ip_addresses: | 201 | if rel["private-address"] in ip_addresses: |
608 | @@ -188,6 +204,7 @@ def get_remote_unit_name(): | |||
609 | 188 | 204 | ||
610 | 189 | def get_base_inputs(): | 205 | def get_base_inputs(): |
611 | 190 | """Make a structure for rendering the base_inputs template. | 206 | """Make a structure for rendering the base_inputs template. |
612 | 207 | |||
613 | 191 | Returns a dict of items for the template. | 208 | Returns a dict of items for the template. |
614 | 192 | """ | 209 | """ |
615 | 193 | extra_options = get_extra_options() | 210 | extra_options = get_extra_options() |
616 | @@ -195,6 +212,7 @@ def get_base_inputs(): | |||
617 | 195 | config = hookenv.config() | 212 | config = hookenv.config() |
618 | 196 | str_disabled_plugins = config["disabled_plugins"] | 213 | str_disabled_plugins = config["disabled_plugins"] |
619 | 197 | disabled_plugins = str_disabled_plugins.split(":") if str_disabled_plugins else [] | 214 | disabled_plugins = str_disabled_plugins.split(":") if str_disabled_plugins else [] |
620 | 215 | |||
621 | 198 | return { | 216 | return { |
622 | 199 | "extra_options": extra_options["inputs"], | 217 | "extra_options": extra_options["inputs"], |
623 | 200 | "bcache": is_bcache(), | 218 | "bcache": is_bcache(), |
624 | @@ -221,20 +239,25 @@ def get_extra_options(): | |||
625 | 221 | # to raw json | 239 | # to raw json |
626 | 222 | json_vals = {} | 240 | json_vals = {} |
627 | 223 | # kind level | 241 | # kind level |
628 | 242 | |||
629 | 224 | for k, v in extra_options.items(): | 243 | for k, v in extra_options.items(): |
630 | 225 | json_vals[k] = {} | 244 | json_vals[k] = {} |
631 | 226 | # plugins level | 245 | # plugins level |
632 | 246 | |||
633 | 227 | for plugin, values in v.items(): | 247 | for plugin, values in v.items(): |
634 | 228 | json_vals[k][plugin] = {} | 248 | json_vals[k][plugin] = {} |
635 | 229 | # inner plugin (aka key:value) | 249 | # inner plugin (aka key:value) |
636 | 250 | |||
637 | 230 | for key, val in values.items(): | 251 | for key, val in values.items(): |
638 | 231 | if key in ("tagpass", "tagdrop"): | 252 | if key in ("tagpass", "tagdrop"): |
639 | 232 | # this is a tagpass/drop, we need to go deeper | 253 | # this is a tagpass/drop, we need to go deeper |
640 | 233 | json_vals[k][plugin][key] = {} | 254 | json_vals[k][plugin][key] = {} |
641 | 255 | |||
642 | 234 | for tag, tagvalue in val.items(): | 256 | for tag, tagvalue in val.items(): |
643 | 235 | json_vals[k][plugin][key][tag] = json.dumps(tagvalue) | 257 | json_vals[k][plugin][key][tag] = json.dumps(tagvalue) |
644 | 236 | else: | 258 | else: |
645 | 237 | json_vals[k][plugin][key] = json.dumps(val) | 259 | json_vals[k][plugin][key] = json.dumps(val) |
646 | 260 | |||
647 | 238 | return json_vals | 261 | return json_vals |
648 | 239 | 262 | ||
649 | 240 | 263 | ||
650 | @@ -323,13 +346,17 @@ def render_socket_listener_config(context): | |||
651 | 323 | def get_sysstat_config_with_sadc_xall(content): | 346 | def get_sysstat_config_with_sadc_xall(content): |
652 | 324 | """Get updated sysstat config content with `-S XALL` in `SADC_OPTIONS`. | 347 | """Get updated sysstat config content with `-S XALL` in `SADC_OPTIONS`. |
653 | 325 | 348 | ||
655 | 326 | `/etc/sysstat/systat` consists of a sequence of shell variable assignments used to configure sysstat logging. | 349 | `/etc/sysstat/systat` consists of a sequence of shell variable assignments |
656 | 350 | used to configure sysstat logging. | ||
657 | 327 | 351 | ||
658 | 328 | Check the original config content. | 352 | Check the original config content. |
659 | 353 | |||
660 | 329 | If change needed, make the change and return new config content. | 354 | If change needed, make the change and return new config content. |
661 | 355 | |||
662 | 330 | If no change, return None. | 356 | If no change, return None. |
663 | 331 | """ | 357 | """ |
665 | 332 | # if SADC_OPTIONS already exists with `-S XALL` in value, no need to change, return None | 358 | # if SADC_OPTIONS already exists with `-S XALL` in value, no need to change, |
666 | 359 | # return None | ||
667 | 333 | if re.search(r'^SADC_OPTIONS=".*-S\s+XALL.*"', content, flags=re.M): | 360 | if re.search(r'^SADC_OPTIONS=".*-S\s+XALL.*"', content, flags=re.M): |
668 | 334 | return None | 361 | return None |
669 | 335 | 362 | ||
670 | @@ -365,6 +392,7 @@ def update_sysstat_config_with_sdac_xall(path="/etc/sysstat/sysstat"): | |||
671 | 365 | if os.path.isfile(path): | 392 | if os.path.isfile(path): |
672 | 366 | with open(path, mode="r", encoding="utf8") as f: | 393 | with open(path, mode="r", encoding="utf8") as f: |
673 | 367 | new_text = get_sysstat_config_with_sadc_xall(f.read()) | 394 | new_text = get_sysstat_config_with_sadc_xall(f.read()) |
674 | 395 | |||
675 | 368 | if new_text: | 396 | if new_text: |
676 | 369 | hookenv.log("updating {} to ensure `-S XALL` in SADC_OPTIONS".format(path)) | 397 | hookenv.log("updating {} to ensure `-S XALL` in SADC_OPTIONS".format(path)) |
677 | 370 | with open(path, mode="w", encoding="utf8") as f: | 398 | with open(path, mode="w", encoding="utf8") as f: |
678 | @@ -386,18 +414,23 @@ def configure_telegraf(): # noqa: C901 | |||
679 | 386 | "blocked", | 414 | "blocked", |
680 | 387 | "Wrong install_method provided: {!r}".format(config["install_method"]), | 415 | "Wrong install_method provided: {!r}".format(config["install_method"]), |
681 | 388 | ) | 416 | ) |
682 | 417 | |||
683 | 389 | return | 418 | return |
684 | 419 | |||
685 | 390 | if get_remote_unit_name() is None: | 420 | if get_remote_unit_name() is None: |
686 | 391 | hookenv.status_set("waiting", "Waiting for juju-info relation") | 421 | hookenv.status_set("waiting", "Waiting for juju-info relation") |
687 | 392 | # if UNIT_NAME in hostname config and relation not yet available, | 422 | # if UNIT_NAME in hostname config and relation not yet available, |
688 | 393 | # make telegraf unable to start to not get weird metrics names | 423 | # make telegraf unable to start to not get weird metrics names |
689 | 424 | |||
690 | 394 | if os.path.exists(config_path): | 425 | if os.path.exists(config_path): |
691 | 395 | os.unlink(config_path) | 426 | os.unlink(config_path) |
692 | 427 | |||
693 | 396 | return | 428 | return |
694 | 397 | 429 | ||
695 | 398 | inputs = config.get("inputs_config", "") | 430 | inputs = config.get("inputs_config", "") |
696 | 399 | outputs = config.get("outputs_config", "") | 431 | outputs = config.get("outputs_config", "") |
697 | 400 | # just for the migration out of base64 | 432 | # just for the migration out of base64 |
698 | 433 | |||
699 | 401 | if inputs: | 434 | if inputs: |
700 | 402 | try: | 435 | try: |
701 | 403 | inputs = base64.b64decode(inputs.encode("utf-8"), validate=True).decode( | 436 | inputs = base64.b64decode(inputs.encode("utf-8"), validate=True).decode( |
702 | @@ -406,6 +439,7 @@ def configure_telegraf(): # noqa: C901 | |||
703 | 406 | except binascii.Error: | 439 | except binascii.Error: |
704 | 407 | # not bas64, probably already up to date configs | 440 | # not bas64, probably already up to date configs |
705 | 408 | pass | 441 | pass |
706 | 442 | |||
707 | 409 | if outputs: | 443 | if outputs: |
708 | 410 | try: | 444 | try: |
709 | 411 | outputs = base64.b64decode(outputs.encode("utf-8"), validate=True).decode( | 445 | outputs = base64.b64decode(outputs.encode("utf-8"), validate=True).decode( |
710 | @@ -415,6 +449,7 @@ def configure_telegraf(): # noqa: C901 | |||
711 | 415 | # not bas64, probably already up to date configs | 449 | # not bas64, probably already up to date configs |
712 | 416 | pass | 450 | pass |
713 | 417 | tags = [] | 451 | tags = [] |
714 | 452 | |||
715 | 418 | if config["tags"]: | 453 | if config["tags"]: |
716 | 419 | for tag in config["tags"].split(","): | 454 | for tag in config["tags"].split(","): |
717 | 420 | key, value = tag.split("=") | 455 | key, value = tag.split("=") |
718 | @@ -424,11 +459,13 @@ def configure_telegraf(): # noqa: C901 | |||
719 | 424 | tags.append('juju_unit = "{}"'.format(get_remote_unit_name().replace("/", "-"))) | 459 | tags.append('juju_unit = "{}"'.format(get_remote_unit_name().replace("/", "-"))) |
720 | 425 | tags.append('juju_model = "{}"'.format(hookenv.model_name())) | 460 | tags.append('juju_model = "{}"'.format(hookenv.model_name())) |
721 | 426 | context["tags"] = tags | 461 | context["tags"] = tags |
722 | 462 | |||
723 | 427 | if inputs: | 463 | if inputs: |
724 | 428 | context["inputs"] = inputs | 464 | context["inputs"] = inputs |
725 | 429 | else: | 465 | else: |
726 | 430 | # use base inputs from charm templates | 466 | # use base inputs from charm templates |
727 | 431 | context["inputs"] = render_base_inputs() | 467 | context["inputs"] = render_base_inputs() |
728 | 468 | |||
729 | 432 | if outputs: | 469 | if outputs: |
730 | 433 | context["outputs"] = outputs | 470 | context["outputs"] = outputs |
731 | 434 | else: | 471 | else: |
732 | @@ -438,12 +475,13 @@ def configure_telegraf(): # noqa: C901 | |||
733 | 438 | context["hostname"] = get_hostname_label() | 475 | context["hostname"] = get_hostname_label() |
734 | 439 | 476 | ||
735 | 440 | logfile_path = os.path.normpath(context["logfile"]) | 477 | logfile_path = os.path.normpath(context["logfile"]) |
736 | 478 | |||
737 | 441 | if ( | 479 | if ( |
738 | 442 | context["logfile"] | 480 | context["logfile"] |
741 | 443 | and not logfile_path.startswith("/var/log/") | 481 | and not logfile_path.startswith("/var/log/") # noqa W503 |
742 | 444 | and not ( | 482 | and not ( # noqa W503 |
743 | 445 | config["install_method"] == "snap" | 483 | config["install_method"] == "snap" |
745 | 446 | and logfile_path.startswith("/var/snap/telegraf/common/") | 484 | and logfile_path.startswith("/var/snap/telegraf/common/") # noqa W503 |
746 | 447 | ) | 485 | ) |
747 | 448 | ): | 486 | ): |
748 | 449 | # only allow logging in /var/log, syslog, or /var/snap/telegraf/common | 487 | # only allow logging in /var/log, syslog, or /var/snap/telegraf/common |
749 | @@ -487,6 +525,7 @@ def configure_telegraf(): # noqa: C901 | |||
750 | 487 | ) | 525 | ) |
751 | 488 | 526 | ||
752 | 489 | # add sudoers file for telegraf if openvswitch is running | 527 | # add sudoers file for telegraf if openvswitch is running |
753 | 528 | |||
754 | 490 | if host.service_running("openvswitch-switch"): | 529 | if host.service_running("openvswitch-switch"): |
755 | 491 | sudoers_filename = "telegraf_sudoers" | 530 | sudoers_filename = "telegraf_sudoers" |
756 | 492 | src = os.path.join(get_files_dir(), sudoers_filename) | 531 | src = os.path.join(get_files_dir(), sudoers_filename) |
757 | @@ -508,6 +547,7 @@ def configure_telegraf(): # noqa: C901 | |||
758 | 508 | 547 | ||
759 | 509 | set_flag("telegraf.configured") | 548 | set_flag("telegraf.configured") |
760 | 510 | set_flag("telegraf.needs_reload") | 549 | set_flag("telegraf.needs_reload") |
761 | 550 | |||
762 | 511 | if config["install_method"] == "deb": | 551 | if config["install_method"] == "deb": |
763 | 512 | set_flag("telegraf.apt.configured") | 552 | set_flag("telegraf.apt.configured") |
764 | 513 | else: | 553 | else: |
765 | @@ -525,12 +565,15 @@ def install_telegraf(): | |||
766 | 525 | hookenv.status_set( | 565 | hookenv.status_set( |
767 | 526 | "blocked", "Wrong install_method provided. Expected either 'deb' or 'snap'." | 566 | "blocked", "Wrong install_method provided. Expected either 'deb' or 'snap'." |
768 | 527 | ) | 567 | ) |
769 | 568 | |||
770 | 528 | return | 569 | return |
771 | 570 | |||
772 | 529 | if install_method == "deb": | 571 | if install_method == "deb": |
773 | 530 | try: | 572 | try: |
774 | 531 | snap.remove("telegraf") | 573 | snap.remove("telegraf") |
775 | 532 | except Exception: | 574 | except Exception: |
777 | 533 | # the snap may already be absent, or snaps may not even be supported in this environment | 575 | # the snap may already be absent, or snaps may not even be supported |
778 | 576 | # in this environment | ||
779 | 534 | pass | 577 | pass |
780 | 535 | apt.queue_install(["telegraf"]) | 578 | apt.queue_install(["telegraf"]) |
781 | 536 | elif install_method == "snap": | 579 | elif install_method == "snap": |
782 | @@ -538,6 +581,7 @@ def install_telegraf(): | |||
783 | 538 | config = hookenv.config() | 581 | config = hookenv.config() |
784 | 539 | snap_channel = config.get("snap_channel") | 582 | snap_channel = config.get("snap_channel") |
785 | 540 | snap.install("telegraf", channel=snap_channel, classic=True) | 583 | snap.install("telegraf", channel=snap_channel, classic=True) |
786 | 584 | |||
787 | 541 | if install_method: | 585 | if install_method: |
788 | 542 | set_flag("telegraf.installed") | 586 | set_flag("telegraf.installed") |
789 | 543 | 587 | ||
790 | @@ -572,16 +616,19 @@ def upgrade_charm(): | |||
791 | 572 | @when("config.changed") | 616 | @when("config.changed") |
792 | 573 | def handle_config_changes(): | 617 | def handle_config_changes(): |
793 | 574 | config = hookenv.config() | 618 | config = hookenv.config() |
794 | 619 | |||
795 | 575 | if config.changed("extra_options"): | 620 | if config.changed("extra_options"): |
796 | 576 | for plugin in list_supported_plugins(): | 621 | for plugin in list_supported_plugins(): |
797 | 577 | clear_flag("plugins.{}.configured".format(plugin)) | 622 | clear_flag("plugins.{}.configured".format(plugin)) |
798 | 578 | # if something else changed, let's reconfigure telegraf itself just in case | 623 | # if something else changed, let's reconfigure telegraf itself just in case |
799 | 624 | |||
800 | 579 | if config.changed("extra_plugins"): | 625 | if config.changed("extra_plugins"): |
801 | 580 | clear_flag("extra_plugins.configured") | 626 | clear_flag("extra_plugins.configured") |
802 | 627 | |||
803 | 581 | if ( | 628 | if ( |
804 | 582 | config.changed("install_method") | 629 | config.changed("install_method") |
807 | 583 | or config.changed("snap_channel") | 630 | or config.changed("snap_channel") # noqa W503 |
808 | 584 | or config.changed("install_sources") | 631 | or config.changed("install_sources") # noqa W503 |
809 | 585 | ): | 632 | ): |
810 | 586 | clear_flag("telegraf.installed") | 633 | clear_flag("telegraf.installed") |
811 | 587 | clear_flag("telegraf.configured") | 634 | clear_flag("telegraf.configured") |
812 | @@ -595,6 +642,7 @@ def handle_config_changes(): | |||
813 | 595 | def configure_extra_plugins(): | 642 | def configure_extra_plugins(): |
814 | 596 | config = hookenv.config() | 643 | config = hookenv.config() |
815 | 597 | plugins = config["extra_plugins"] | 644 | plugins = config["extra_plugins"] |
816 | 645 | |||
817 | 598 | if plugins: | 646 | if plugins: |
818 | 599 | config_path = "{}/extra_plugins.conf".format(get_configs_dir()) | 647 | config_path = "{}/extra_plugins.conf".format(get_configs_dir()) |
819 | 600 | host.write_file(config_path, plugins.encode("utf-8")) | 648 | host.write_file(config_path, plugins.encode("utf-8")) |
820 | @@ -894,7 +942,7 @@ def redis_input(redis): | |||
821 | 894 | servers = ["tcp://{{ host }}:{{ port }}"] | 942 | servers = ["tcp://{{ host }}:{{ port }}"] |
822 | 895 | # Until https://github.com/influxdata/telegraf/issues/5036 is fixed | 943 | # Until https://github.com/influxdata/telegraf/issues/5036 is fixed |
823 | 896 | fielddrop = ["aof_last_bgrewrite_status","aof_last_write_status","maxmemory_policy","rdb_last_bgsave_status","used_memory_dataset_perc","used_memory_peak_perc"] | 944 | fielddrop = ["aof_last_bgrewrite_status","aof_last_write_status","maxmemory_policy","rdb_last_bgsave_status","used_memory_dataset_perc","used_memory_peak_perc"] |
825 | 897 | """ | 945 | """ # noqa E501 (inline template) |
826 | 898 | config_path = "{}/{}.conf".format(get_configs_dir(), "redis") | 946 | config_path = "{}/{}.conf".format(get_configs_dir(), "redis") |
827 | 899 | 947 | ||
828 | 900 | rels = hookenv.relations_of_type("redis") | 948 | rels = hookenv.relations_of_type("redis") |
829 | @@ -1146,7 +1194,8 @@ def prometheus_client(prometheus): | |||
830 | 1146 | 1194 | ||
831 | 1147 | 1195 | ||
832 | 1148 | def convert_days(time_string): | 1196 | def convert_days(time_string): |
834 | 1149 | """ | 1197 | """Convert string time descript to days. |
835 | 1198 | |||
836 | 1150 | Function to convert strings like 2w or 14d to a sting containing the number | 1199 | Function to convert strings like 2w or 14d to a sting containing the number |
837 | 1151 | of days. | 1200 | of days. |
838 | 1152 | 1201 | ||
839 | @@ -1302,8 +1351,8 @@ def start_or_restart(): | |||
840 | 1302 | active_plugins_changed = helpers.data_changed("active_plugins", states or "") | 1351 | active_plugins_changed = helpers.data_changed("active_plugins", states or "") |
841 | 1303 | if ( | 1352 | if ( |
842 | 1304 | not host.service_running(service) | 1353 | not host.service_running(service) |
845 | 1305 | or config_files_changed | 1354 | or config_files_changed # noqa W503 |
846 | 1306 | or active_plugins_changed | 1355 | or active_plugins_changed # noqa W503 |
847 | 1307 | ): | 1356 | ): |
848 | 1308 | hookenv.log("Restarting telegraf") | 1357 | hookenv.log("Restarting telegraf") |
849 | 1309 | host.service_restart(service) | 1358 | host.service_restart(service) |
850 | @@ -1328,8 +1377,9 @@ def start_or_restart(): | |||
851 | 1328 | 1377 | ||
852 | 1329 | 1378 | ||
853 | 1330 | def is_bcache(): | 1379 | def is_bcache(): |
856 | 1331 | """ | 1380 | """Determine if this is a container. |
857 | 1332 | return true if bcache is present, and this is not a container | 1381 | |
858 | 1382 | return true if bcache is present, and this is not a container. | ||
859 | 1333 | """ | 1383 | """ |
860 | 1334 | container = is_container() | 1384 | container = is_container() |
861 | 1335 | return os.path.exists("/sys/fs/bcache") and not container | 1385 | return os.path.exists("/sys/fs/bcache") and not container |
862 | @@ -1352,9 +1402,10 @@ def update_status(): | |||
863 | 1352 | @when_not("telegraf.nagios-setup.complete") | 1402 | @when_not("telegraf.nagios-setup.complete") |
864 | 1353 | def configure_nagios(nagios): | 1403 | def configure_nagios(nagios): |
865 | 1354 | """Configure nagios process check. | 1404 | """Configure nagios process check. |
866 | 1355 | the flag 'telegraf.nagios-setup.complete' is reset at the moment config is | ||
867 | 1356 | changed, so this should make sure that updates are handled.""" | ||
868 | 1357 | 1405 | ||
869 | 1406 | The flag 'telegraf.nagios-setup.complete' is reset at the moment config is | ||
870 | 1407 | changed, so this should make sure that updates are handled. | ||
871 | 1408 | """ | ||
872 | 1358 | # Use charmhelpers to handle the configuration of nrpe | 1409 | # Use charmhelpers to handle the configuration of nrpe |
873 | 1359 | hostname = nrpe.get_nagios_hostname() | 1410 | hostname = nrpe.get_nagios_hostname() |
874 | 1360 | nrpe_setup = nrpe.NRPE(hostname=hostname, primary=False) | 1411 | nrpe_setup = nrpe.NRPE(hostname=hostname, primary=False) |
875 | diff --git a/src/tests/functional/tests/test_telegraf.py b/src/tests/functional/tests/test_telegraf.py | |||
876 | index 1b80661..3c4354d 100644 | |||
877 | --- a/src/tests/functional/tests/test_telegraf.py | |||
878 | +++ b/src/tests/functional/tests/test_telegraf.py | |||
879 | @@ -21,9 +21,8 @@ import unittest | |||
880 | 21 | 21 | ||
881 | 22 | import requests | 22 | import requests |
882 | 23 | 23 | ||
883 | 24 | from zaza.utilities import juju | ||
884 | 25 | from zaza import model | 24 | from zaza import model |
886 | 26 | 25 | from zaza.utilities import juju | |
887 | 27 | 26 | ||
888 | 28 | DEFAULT_HTTPGET_TIMEOUT = 10 | 27 | DEFAULT_HTTPGET_TIMEOUT = 10 |
889 | 29 | DEFAULT_RETRIES = 12 | 28 | DEFAULT_RETRIES = 12 |
890 | @@ -58,21 +57,24 @@ class TestTelegraf(BaseTelegrafTest): | |||
891 | 58 | model.get_units(app) | 57 | model.get_units(app) |
892 | 59 | for app in juju.get_principle_applications(self.application_name) | 58 | for app in juju.get_principle_applications(self.application_name) |
893 | 60 | ) | 59 | ) |
894 | 60 | |||
895 | 61 | for unit in it.chain.from_iterable(principal_units): | 61 | for unit in it.chain.from_iterable(principal_units): |
896 | 62 | if not unit.public_address: | 62 | if not unit.public_address: |
897 | 63 | continue | 63 | continue |
898 | 64 | url = "http://{}:{}/metrics".format( | 64 | url = "http://{}:{}/metrics".format( |
899 | 65 | unit.public_address, DEFAULT_TELEGRAF_EXPORTER_PORT | 65 | unit.public_address, DEFAULT_TELEGRAF_EXPORTER_PORT |
900 | 66 | ) | 66 | ) |
901 | 67 | |||
902 | 67 | for retry in range(DEFAULT_RETRIES): | 68 | for retry in range(DEFAULT_RETRIES): |
903 | 68 | resp = requests.get(url, timeout=DEFAULT_HTTPGET_TIMEOUT) | 69 | resp = requests.get(url, timeout=DEFAULT_HTTPGET_TIMEOUT) |
904 | 69 | self.assertEqual(resp.status_code, 200) | 70 | self.assertEqual(resp.status_code, 200) |
905 | 70 | 71 | ||
906 | 71 | if ( | 72 | if ( |
907 | 72 | unit.name.startswith("postgresql/") | 73 | unit.name.startswith("postgresql/") |
909 | 73 | and "postgresql_blks_hit" not in resp.text | 74 | and "postgresql_blks_hit" not in resp.text # noqa W503 |
910 | 74 | ) or "cpu_usage_idle" not in resp.text: | 75 | ) or "cpu_usage_idle" not in resp.text: |
911 | 75 | time.sleep(DEFAULT_RETRIES_TIMEOUT) | 76 | time.sleep(DEFAULT_RETRIES_TIMEOUT) |
912 | 77 | |||
913 | 76 | continue | 78 | continue |
914 | 77 | 79 | ||
915 | 78 | logging.info("test_service: Unit {} is reachable".format(unit.name)) | 80 | logging.info("test_service: Unit {} is reachable".format(unit.name)) |
916 | @@ -90,6 +92,7 @@ class TestTelegraf(BaseTelegrafTest): | |||
917 | 90 | r"^zoneinfo_", | 92 | r"^zoneinfo_", |
918 | 91 | r"^processes_", | 93 | r"^processes_", |
919 | 92 | ] | 94 | ] |
920 | 95 | |||
921 | 93 | for re_pattern in re_patterns: | 96 | for re_pattern in re_patterns: |
922 | 94 | self.check_re_pattern(re_pattern, text) | 97 | self.check_re_pattern(re_pattern, text) |
923 | 95 | 98 | ||
924 | @@ -104,12 +107,14 @@ class TestTelegraf(BaseTelegrafTest): | |||
925 | 104 | install_method = model.get_application_config("telegraf")["install_method"][ | 107 | install_method = model.get_application_config("telegraf")["install_method"][ |
926 | 105 | "value" | 108 | "value" |
927 | 106 | ] | 109 | ] |
928 | 110 | |||
929 | 107 | if install_method == "deb": | 111 | if install_method == "deb": |
930 | 108 | telegraf_conf = DEB_TELEGRAF_CONF | 112 | telegraf_conf = DEB_TELEGRAF_CONF |
931 | 109 | else: | 113 | else: |
932 | 110 | telegraf_conf = SNAP_TELEGRAF_CONF | 114 | telegraf_conf = SNAP_TELEGRAF_CONF |
933 | 111 | cmd = "cat {}".format(telegraf_conf) | 115 | cmd = "cat {}".format(telegraf_conf) |
934 | 112 | response = model.run_on_unit(self.lead_unit_name, cmd) | 116 | response = model.run_on_unit(self.lead_unit_name, cmd) |
935 | 117 | |||
936 | 113 | if response["Code"] != "0": | 118 | if response["Code"] != "0": |
937 | 114 | self.fail( | 119 | self.fail( |
938 | 115 | "test_02_telegraf_logfile: could not read file {}".format(telegraf_conf) | 120 | "test_02_telegraf_logfile: could not read file {}".format(telegraf_conf) |
939 | @@ -118,6 +123,7 @@ class TestTelegraf(BaseTelegrafTest): | |||
940 | 118 | for line in response["Stdout"].splitlines(): | 123 | for line in response["Stdout"].splitlines(): |
941 | 119 | if line.strip() == 'logfile = "/var/log/telegraf/telegraf.log"': | 124 | if line.strip() == 'logfile = "/var/log/telegraf/telegraf.log"': |
942 | 120 | logging.info("test_02_telegraf_logfile: logfile config parameter found") | 125 | logging.info("test_02_telegraf_logfile: logfile config parameter found") |
943 | 126 | |||
944 | 121 | return | 127 | return |
945 | 122 | 128 | ||
946 | 123 | self.fail( | 129 | self.fail( |
947 | @@ -127,25 +133,32 @@ class TestTelegraf(BaseTelegrafTest): | |||
948 | 127 | ) | 133 | ) |
949 | 128 | 134 | ||
950 | 129 | def test_03_system_service(self): | 135 | def test_03_system_service(self): |
952 | 130 | """Check that the right service is running, e.g. either the deb's or the snap's.""" | 136 | """Check that the right service is running. |
953 | 137 | |||
954 | 138 | e.g. either the deb's or the snap's. | ||
955 | 139 | """ | ||
956 | 131 | install_method = model.get_application_config("telegraf")["install_method"][ | 140 | install_method = model.get_application_config("telegraf")["install_method"][ |
957 | 132 | "value" | 141 | "value" |
958 | 133 | ] | 142 | ] |
959 | 134 | services = {"deb": "telegraf", "snap": "snap.telegraf.telegraf"} | 143 | services = {"deb": "telegraf", "snap": "snap.telegraf.telegraf"} |
960 | 144 | |||
961 | 135 | for method in services.keys(): | 145 | for method in services.keys(): |
962 | 136 | service = services[method] | 146 | service = services[method] |
963 | 137 | cmd = "service {} status".format(service) | 147 | cmd = "service {} status".format(service) |
964 | 138 | response = model.run_on_unit(self.lead_unit_name, cmd) | 148 | response = model.run_on_unit(self.lead_unit_name, cmd) |
965 | 149 | |||
966 | 139 | if install_method == method and response["Code"] != "0": | 150 | if install_method == method and response["Code"] != "0": |
967 | 140 | self.fail( | 151 | self.fail( |
969 | 141 | "test_03_system_service: service {} should be running on {} but is not. " | 152 | "test_03_system_service: service {} should be running " |
970 | 153 | "on {} but is not. " | ||
971 | 142 | "install_method is {}.".format( | 154 | "install_method is {}.".format( |
972 | 143 | service, self.lead_unit_name, install_method | 155 | service, self.lead_unit_name, install_method |
973 | 144 | ) | 156 | ) |
974 | 145 | ) | 157 | ) |
975 | 146 | elif install_method != method and response["Code"] == "0": | 158 | elif install_method != method and response["Code"] == "0": |
976 | 147 | self.fail( | 159 | self.fail( |
978 | 148 | "test_03_system_service: service {} is running on {} but shouldn't. " | 160 | "test_03_system_service: service {} is running " |
979 | 161 | "on {} but shouldn't. " | ||
980 | 149 | "install_method is {}.".format( | 162 | "install_method is {}.".format( |
981 | 150 | service, self.lead_unit_name, install_method | 163 | service, self.lead_unit_name, install_method |
982 | 151 | ) | 164 | ) |
983 | diff --git a/src/tests/unit/__init__.py b/src/tests/unit/__init__.py | |||
984 | index 28e9795..5f22a2b 100644 | |||
985 | --- a/src/tests/unit/__init__.py | |||
986 | +++ b/src/tests/unit/__init__.py | |||
987 | @@ -1,3 +1,5 @@ | |||
988 | 1 | """Unit test module.""" | ||
989 | 2 | |||
990 | 1 | import sys | 3 | import sys |
991 | 2 | 4 | ||
992 | 3 | sys.path.append(".") | 5 | sys.path.append(".") |
993 | diff --git a/src/tests/unit/test_mysql.py b/src/tests/unit/test_mysql.py | |||
994 | index 27f206d..9015600 100644 | |||
995 | --- a/src/tests/unit/test_mysql.py | |||
996 | +++ b/src/tests/unit/test_mysql.py | |||
997 | @@ -22,10 +22,11 @@ from unittest.mock import ANY, MagicMock, patch, sentinel | |||
998 | 22 | # Mock layer modules | 22 | # Mock layer modules |
999 | 23 | import charms | 23 | import charms |
1000 | 24 | 24 | ||
1001 | 25 | import reactive | ||
1002 | 26 | |||
1003 | 25 | promreg = MagicMock() | 27 | promreg = MagicMock() |
1004 | 26 | charms.promreg = promreg | 28 | charms.promreg = promreg |
1005 | 27 | sys.modules["charms.promreg"] = promreg | 29 | sys.modules["charms.promreg"] = promreg |
1006 | 28 | import reactive | ||
1007 | 29 | 30 | ||
1008 | 30 | 31 | ||
1009 | 31 | class TestMySQL(unittest.TestCase): | 32 | class TestMySQL(unittest.TestCase): |
1010 | diff --git a/src/tests/unit/test_postgresql.py b/src/tests/unit/test_postgresql.py | |||
1011 | index 9192ea4..c011b32 100644 | |||
1012 | --- a/src/tests/unit/test_postgresql.py | |||
1013 | +++ b/src/tests/unit/test_postgresql.py | |||
1014 | @@ -17,7 +17,7 @@ | |||
1015 | 17 | import os | 17 | import os |
1016 | 18 | import sys | 18 | import sys |
1017 | 19 | import unittest | 19 | import unittest |
1019 | 20 | from unittest.mock import ANY, call, MagicMock, patch, sentinel | 20 | from unittest.mock import ANY, MagicMock, call, patch, sentinel |
1020 | 21 | 21 | ||
1021 | 22 | # Mock layer modules | 22 | # Mock layer modules |
1022 | 23 | import charms | 23 | import charms |
1023 | @@ -32,8 +32,8 @@ sys.modules["charms.apt"] = apt | |||
1024 | 32 | sys.modules["charms.layer"] = layer | 32 | sys.modules["charms.layer"] = layer |
1025 | 33 | sys.modules["charms.promreg"] = promreg | 33 | sys.modules["charms.promreg"] = promreg |
1026 | 34 | 34 | ||
1029 | 35 | import reactive | 35 | import reactive # noqa E402 |
1030 | 36 | from reactive import telegraf | 36 | from reactive import telegraf # noqa E402 |
1031 | 37 | 37 | ||
1032 | 38 | 38 | ||
1033 | 39 | class TestPostgreSQL(unittest.TestCase): | 39 | class TestPostgreSQL(unittest.TestCase): |
1034 | @@ -123,7 +123,7 @@ class TestPostgreSQL(unittest.TestCase): | |||
1035 | 123 | get_base_dir.return_value = "/etc/telegraf" | 123 | get_base_dir.return_value = "/etc/telegraf" |
1036 | 124 | 124 | ||
1037 | 125 | reactive.telegraf.render_postgresql_tmpl( | 125 | reactive.telegraf.render_postgresql_tmpl( |
1039 | 126 | [{"replica": "master", "conn_str": "my_conn_str", "server": "my_server"},] | 126 | [{"replica": "master", "conn_str": "my_conn_str", "server": "my_server"}] |
1040 | 127 | ) | 127 | ) |
1041 | 128 | 128 | ||
1042 | 129 | write_file.assert_called_once_with( | 129 | write_file.assert_called_once_with( |
1043 | diff --git a/src/tests/unit/test_telegraf.py b/src/tests/unit/test_telegraf.py | |||
1044 | index 1825fa6..57e7e3c 100644 | |||
1045 | --- a/src/tests/unit/test_telegraf.py | |||
1046 | +++ b/src/tests/unit/test_telegraf.py | |||
1047 | @@ -14,36 +14,38 @@ | |||
1048 | 14 | # You should have received a copy of the GNU General Public License | 14 | # You should have received a copy of the GNU General Public License |
1049 | 15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | 15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
1050 | 16 | 16 | ||
1052 | 17 | """actions.py tests""" | 17 | """Tests for actions.py.""" |
1053 | 18 | import base64 | 18 | import base64 |
1054 | 19 | import os | ||
1055 | 20 | import getpass | 19 | import getpass |
1056 | 21 | import grp | 20 | import grp |
1057 | 22 | import json | 21 | import json |
1059 | 23 | import sys | 22 | import os |
1060 | 24 | import subprocess | 23 | import subprocess |
1061 | 24 | import sys | ||
1062 | 25 | import unittest | 25 | import unittest |
1063 | 26 | from textwrap import dedent | 26 | from textwrap import dedent |
1064 | 27 | from unittest.mock import patch, MagicMock, call | ||
1065 | 28 | from unittest import mock | 27 | from unittest import mock |
1066 | 28 | from unittest.mock import MagicMock, call, patch | ||
1067 | 29 | 29 | ||
1068 | 30 | import yaml | ||
1069 | 31 | import pytest | ||
1070 | 32 | import py | ||
1071 | 33 | |||
1072 | 34 | from charms.reactive import bus, helpers, RelationBase, set_flag | ||
1073 | 35 | from charmhelpers.core.hookenv import Config | 30 | from charmhelpers.core.hookenv import Config |
1074 | 36 | from charmhelpers.core.templating import render | 31 | from charmhelpers.core.templating import render |
1075 | 37 | 32 | ||
1076 | 38 | # Mock layer modules | ||
1077 | 39 | import charms | 33 | import charms |
1078 | 34 | from charms.reactive import RelationBase, bus, helpers, set_flag | ||
1079 | 35 | |||
1080 | 36 | import py | ||
1081 | 40 | 37 | ||
1082 | 38 | import pytest | ||
1083 | 39 | |||
1084 | 40 | import yaml | ||
1085 | 41 | |||
1086 | 42 | # Mock layer modules | ||
1087 | 41 | promreg = MagicMock() | 43 | promreg = MagicMock() |
1088 | 42 | charms.promreg = promreg | 44 | charms.promreg = promreg |
1089 | 43 | sys.modules["charms.promreg"] = promreg | 45 | sys.modules["charms.promreg"] = promreg |
1090 | 44 | 46 | ||
1093 | 45 | import reactive | 47 | import reactive # noqa E402 |
1094 | 46 | from reactive import telegraf | 48 | from reactive import telegraf # noqa E402 |
1095 | 47 | 49 | ||
1096 | 48 | UNIT_TESTS_DIR = os.path.dirname(os.path.abspath(__file__)) | 50 | UNIT_TESTS_DIR = os.path.dirname(os.path.abspath(__file__)) |
1097 | 49 | UNIT_TESTS_DATA_DIR = os.path.join(UNIT_TESTS_DIR, "data") | 51 | UNIT_TESTS_DATA_DIR = os.path.join(UNIT_TESTS_DIR, "data") |
1098 | @@ -71,6 +73,7 @@ def setup(monkeypatch, tmpdir): | |||
1099 | 71 | # fix the args to use non-root, this is for callers that pass | 73 | # fix the args to use non-root, this is for callers that pass |
1100 | 72 | # owner/group as positional arguments like | 74 | # owner/group as positional arguments like |
1101 | 73 | # charmhelpers.core.templating.render | 75 | # charmhelpers.core.templating.render |
1102 | 76 | |||
1103 | 74 | if len(a) > 2: | 77 | if len(a) > 2: |
1104 | 75 | if a[2] == "root" and a[3] == "root": | 78 | if a[2] == "root" and a[3] == "root": |
1105 | 76 | # make all files writable by owner, as we need don't run as root | 79 | # make all files writable by owner, as we need don't run as root |
1106 | @@ -80,6 +83,7 @@ def setup(monkeypatch, tmpdir): | |||
1107 | 80 | kw["group"] = group | 83 | kw["group"] = group |
1108 | 81 | # make all files writable by owner, as we need don't run as root | 84 | # make all files writable by owner, as we need don't run as root |
1109 | 82 | kw["perms"] = 0o744 | 85 | kw["perms"] = 0o744 |
1110 | 86 | |||
1111 | 83 | return orig_write_file(*a, **kw) | 87 | return orig_write_file(*a, **kw) |
1112 | 84 | 88 | ||
1113 | 85 | monkeypatch.setattr(telegraf.host, "write_file", intercept_write_file) | 89 | monkeypatch.setattr(telegraf.host, "write_file", intercept_write_file) |
1114 | @@ -94,6 +98,7 @@ def cleanup(request): | |||
1115 | 94 | unitdata._KV = None | 98 | unitdata._KV = None |
1116 | 95 | # rm unit-state.db file | 99 | # rm unit-state.db file |
1117 | 96 | unit_state_db = os.path.join(telegraf.hookenv.charm_dir(), ".unit-state.db") | 100 | unit_state_db = os.path.join(telegraf.hookenv.charm_dir(), ".unit-state.db") |
1118 | 101 | |||
1119 | 97 | if os.path.exists(unit_state_db): | 102 | if os.path.exists(unit_state_db): |
1120 | 98 | os.unlink(unit_state_db) | 103 | os.unlink(unit_state_db) |
1121 | 99 | 104 | ||
1122 | @@ -134,6 +139,7 @@ def config(monkeypatch, temp_charm_dir): | |||
1123 | 134 | data = dict((k, v["default"]) for k, v in raw_config["options"].items()) | 139 | data = dict((k, v["default"]) for k, v in raw_config["options"].items()) |
1124 | 135 | config = Config(data) | 140 | config = Config(data) |
1125 | 136 | monkeypatch.setattr(telegraf.hookenv, "config", lambda: config) | 141 | monkeypatch.setattr(telegraf.hookenv, "config", lambda: config) |
1126 | 142 | |||
1127 | 137 | return config | 143 | return config |
1128 | 138 | 144 | ||
1129 | 139 | 145 | ||
1130 | @@ -147,13 +153,14 @@ def configs_dir(): | |||
1131 | 147 | 153 | ||
1132 | 148 | 154 | ||
1133 | 149 | def persist_state(): | 155 | def persist_state(): |
1135 | 150 | """Fake persistent state by calling helpers that modify unitdata.kv""" | 156 | """Fake persistent state by calling helpers that modify unitdata.kv.""" |
1136 | 151 | states = [ | 157 | states = [ |
1137 | 152 | k | 158 | k |
1138 | 153 | for k in bus.get_states().keys() | 159 | for k in bus.get_states().keys() |
1139 | 154 | if k.startswith("plugins") or k.startswith("extra_plugins") | 160 | if k.startswith("plugins") or k.startswith("extra_plugins") |
1140 | 155 | ] | 161 | ] |
1141 | 156 | helpers.any_file_changed(telegraf.list_config_files()) | 162 | helpers.any_file_changed(telegraf.list_config_files()) |
1142 | 163 | |||
1143 | 157 | if states: | 164 | if states: |
1144 | 158 | helpers.data_changed("active_plugins", states) | 165 | helpers.data_changed("active_plugins", states) |
1145 | 159 | 166 | ||
1146 | @@ -169,7 +176,7 @@ def check_sysstat_config(original, expected): | |||
1147 | 169 | 176 | ||
1148 | 170 | 177 | ||
1149 | 171 | def test_sadc_options_correct(monkeypatch): | 178 | def test_sadc_options_correct(monkeypatch): |
1151 | 172 | """If SADC_OPTIONS is already correct, should return None""" | 179 | """If SADC_OPTIONS is already correct, should return None.""" |
1152 | 173 | original = dedent( | 180 | original = dedent( |
1153 | 174 | """ | 181 | """ |
1154 | 175 | # some comment | 182 | # some comment |
1155 | @@ -183,7 +190,7 @@ def test_sadc_options_correct(monkeypatch): | |||
1156 | 183 | 190 | ||
1157 | 184 | 191 | ||
1158 | 185 | def test_sadc_options_correct_included(monkeypatch): | 192 | def test_sadc_options_correct_included(monkeypatch): |
1160 | 186 | """If SADC_OPTIONS already includes `-S XALL`, should return None""" | 193 | """If SADC_OPTIONS already includes `-S XALL`, should return None.""" |
1161 | 187 | original = dedent( | 194 | original = dedent( |
1162 | 188 | """ | 195 | """ |
1163 | 189 | # some comment | 196 | # some comment |
1164 | @@ -197,7 +204,7 @@ def test_sadc_options_correct_included(monkeypatch): | |||
1165 | 197 | 204 | ||
1166 | 198 | 205 | ||
1167 | 199 | def test_sadc_options_non_exist(monkeypatch): | 206 | def test_sadc_options_non_exist(monkeypatch): |
1169 | 200 | """If SADC_OPTIONS doesn't exist, should just append""" | 207 | """If SADC_OPTIONS doesn't exist, should just append.""" |
1170 | 201 | original = dedent( | 208 | original = dedent( |
1171 | 202 | """ | 209 | """ |
1172 | 203 | # some comment | 210 | # some comment |
1173 | @@ -217,7 +224,7 @@ def test_sadc_options_non_exist(monkeypatch): | |||
1174 | 217 | 224 | ||
1175 | 218 | 225 | ||
1176 | 219 | def test_sadc_options_commented(monkeypatch): | 226 | def test_sadc_options_commented(monkeypatch): |
1178 | 220 | """If SADC_OPTIONS exists but commented, should ignore and append""" | 227 | """If SADC_OPTIONS exists but commented, should ignore and append.""" |
1179 | 221 | original = dedent( | 228 | original = dedent( |
1180 | 222 | """ | 229 | """ |
1181 | 223 | # some comment | 230 | # some comment |
1182 | @@ -243,7 +250,7 @@ def test_sadc_options_commented(monkeypatch): | |||
1183 | 243 | 250 | ||
1184 | 244 | 251 | ||
1185 | 245 | def test_sadc_options_incorrect(monkeypatch): | 252 | def test_sadc_options_incorrect(monkeypatch): |
1187 | 246 | """If SADC_OPTIONS exists but not XALL, should replace""" | 253 | """If SADC_OPTIONS exists but not XALL, should replace.""" |
1188 | 247 | original = dedent( | 254 | original = dedent( |
1189 | 248 | """ | 255 | """ |
1190 | 249 | # some comment | 256 | # some comment |
1191 | @@ -267,7 +274,7 @@ def test_sadc_options_incorrect(monkeypatch): | |||
1192 | 267 | 274 | ||
1193 | 268 | 275 | ||
1194 | 269 | def test_sadc_options_incorrect_included(monkeypatch): | 276 | def test_sadc_options_incorrect_included(monkeypatch): |
1196 | 270 | """If SADC_OPTIONS exists but not XALL, should replace""" | 277 | """If SADC_OPTIONS exists but not XALL, should replace.""" |
1197 | 271 | original = dedent( | 278 | original = dedent( |
1198 | 272 | """ | 279 | """ |
1199 | 273 | # some comment | 280 | # some comment |
1200 | @@ -291,7 +298,7 @@ def test_sadc_options_incorrect_included(monkeypatch): | |||
1201 | 291 | 298 | ||
1202 | 292 | 299 | ||
1203 | 293 | def test_sadc_options_commented_line_not_touched(monkeypatch): | 300 | def test_sadc_options_commented_line_not_touched(monkeypatch): |
1205 | 294 | """If SADC_OPTIONS exists but has no -S, should append""" | 301 | """If SADC_OPTIONS exists but has no -S, should append.""" |
1206 | 295 | original = dedent( | 302 | original = dedent( |
1207 | 296 | """ | 303 | """ |
1208 | 297 | # some comment | 304 | # some comment |
1209 | @@ -318,7 +325,7 @@ def test_sadc_options_commented_line_not_touched(monkeypatch): | |||
1210 | 318 | 325 | ||
1211 | 319 | 326 | ||
1212 | 320 | def test_sadc_options_s_missing(monkeypatch): | 327 | def test_sadc_options_s_missing(monkeypatch): |
1214 | 321 | """If SADC_OPTIONS exists but has no -S, should append""" | 328 | """If SADC_OPTIONS exists but has no -S, should append.""" |
1215 | 322 | original = dedent( | 329 | original = dedent( |
1216 | 323 | """ | 330 | """ |
1217 | 324 | # some comment | 331 | # some comment |
1218 | @@ -351,6 +358,7 @@ def test_telegraf_exec_metrics(monkeypatch, temp_config_dir): | |||
1219 | 351 | metrics = set( | 358 | metrics = set( |
1220 | 352 | ["sockstat", "sockstat6", "softnet_stat", "buddyinfo", "zoneinfo", "netns"] | 359 | ["sockstat", "sockstat6", "softnet_stat", "buddyinfo", "zoneinfo", "netns"] |
1221 | 353 | ) | 360 | ) |
1222 | 361 | |||
1223 | 354 | for metric in metrics: | 362 | for metric in metrics: |
1224 | 355 | run_telegraf_exec_metrics("--metric", metric) | 363 | run_telegraf_exec_metrics("--metric", metric) |
1225 | 356 | 364 | ||
1226 | @@ -370,9 +378,8 @@ def test_telegraf_exec_metrics(monkeypatch, temp_config_dir): | |||
1227 | 370 | ) | 378 | ) |
1228 | 371 | 379 | ||
1229 | 372 | # ensure config files exists after render | 380 | # ensure config files exists after render |
1233 | 373 | run_telegraf_exec_metrics( | 381 | run_telegraf_exec_metrics("--render-config-files", "--configs-dir", configs_dir()) |
1234 | 374 | "--render-config-files", "--configs-dir", configs_dir(), | 382 | |
1232 | 375 | ) | ||
1235 | 376 | for metric in metrics: | 383 | for metric in metrics: |
1236 | 377 | assert os.path.isfile(os.path.join(configs_dir(), "{}.conf".format(metric))) | 384 | assert os.path.isfile(os.path.join(configs_dir(), "{}.conf".format(metric))) |
1237 | 378 | 385 | ||
1238 | @@ -386,9 +393,11 @@ def test_telegraf_exec_metrics(monkeypatch, temp_config_dir): | |||
1239 | 386 | ":".join(disabled_metrics), | 393 | ":".join(disabled_metrics), |
1240 | 387 | ) | 394 | ) |
1241 | 388 | # config files for disabled metrics should be removed. | 395 | # config files for disabled metrics should be removed. |
1242 | 396 | |||
1243 | 389 | for metric in disabled_metrics: | 397 | for metric in disabled_metrics: |
1244 | 390 | assert not os.path.isfile(os.path.join(configs_dir(), "{}.conf".format(metric))) | 398 | assert not os.path.isfile(os.path.join(configs_dir(), "{}.conf".format(metric))) |
1245 | 391 | # config files for other metrics should still be there | 399 | # config files for other metrics should still be there |
1246 | 400 | |||
1247 | 392 | for metric in metrics - disabled_metrics: | 401 | for metric in metrics - disabled_metrics: |
1248 | 393 | assert os.path.isfile(os.path.join(configs_dir(), "{}.conf".format(metric))) | 402 | assert os.path.isfile(os.path.join(configs_dir(), "{}.conf".format(metric))) |
1249 | 394 | 403 | ||
1250 | @@ -619,7 +628,7 @@ inputs: | |||
1251 | 619 | 628 | ||
1252 | 620 | 629 | ||
1253 | 621 | def test_base_inputs_disabled_plugins(config): | 630 | def test_base_inputs_disabled_plugins(config): |
1255 | 622 | """Check disabled_plugins option is working for builtin inputs""" | 631 | """Check disabled_plugins option is working for builtin inputs.""" |
1256 | 623 | config["disabled_plugins"] = "cpu:disk" | 632 | config["disabled_plugins"] = "cpu:disk" |
1257 | 624 | content = telegraf.render_base_inputs() | 633 | content = telegraf.render_base_inputs() |
1258 | 625 | 634 | ||
1259 | @@ -1246,7 +1255,7 @@ class TestGrafanaDashboard(unittest.TestCase): | |||
1260 | 1246 | variable_end_string=">>", | 1255 | variable_end_string=">>", |
1261 | 1247 | ) | 1256 | ) |
1262 | 1248 | mock_grafana.register_dashboard.assert_called_once_with( | 1257 | mock_grafana.register_dashboard.assert_called_once_with( |
1264 | 1249 | name=telegraf.GRAFANA_DASHBOARD_NAME, dashboard=mock_dashboard_dict, | 1258 | name=telegraf.GRAFANA_DASHBOARD_NAME, dashboard=mock_dashboard_dict |
1265 | 1250 | ) | 1259 | ) |
1266 | 1251 | mock_set_flag.assert_called_once_with("grafana.configured") | 1260 | mock_set_flag.assert_called_once_with("grafana.configured") |
1267 | 1252 | 1261 | ||
1268 | diff --git a/src/tox.ini b/src/tox.ini | |||
1269 | index 40c62d6..4977737 100644 | |||
1270 | --- a/src/tox.ini | |||
1271 | +++ b/src/tox.ini | |||
1272 | @@ -42,7 +42,8 @@ exclude = | |||
1273 | 42 | charmhelpers, | 42 | charmhelpers, |
1274 | 43 | mod, | 43 | mod, |
1275 | 44 | .build | 44 | .build |
1277 | 45 | 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 | 45 | #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 |
1278 | 46 | ignore = D100, D101, D102, D103 | ||
1279 | 46 | 47 | ||
1280 | 47 | max-line-length = 88 | 48 | max-line-length = 88 |
1281 | 48 | max-complexity = 10 | 49 | max-complexity = 10 |
This merge proposal is being monitored by mergebot. Change the status to Approved to merge.