Merge ~xavpaice/charm-prometheus-blackbox-exporter:dev/q2-20 into charm-prometheus-blackbox-exporter:master
- Git
- lp:~xavpaice/charm-prometheus-blackbox-exporter
- dev/q2-20
- Merge into master
Status: | Merged |
---|---|
Approved by: | Paul Goins |
Approved revision: | ff9ed95c3e232fe6aa77fcf4235fcb0d8e0ccdf6 |
Merged at revision: | ff9ed95c3e232fe6aa77fcf4235fcb0d8e0ccdf6 |
Proposed branch: | ~xavpaice/charm-prometheus-blackbox-exporter:dev/q2-20 |
Merge into: | charm-prometheus-blackbox-exporter:master |
Diff against target: |
975 lines (+765/-7) 19 files modified
.gitignore (+24/-0) Makefile (+48/-0) README.md (+33/-0) config.yaml (+14/-0) copyright (+17/-0) icon.svg (+279/-0) layer.yaml (+7/-2) metadata.yaml (+11/-0) reactive/prometheus_blackbox_exporter.py (+124/-5) requirements.txt (+1/-0) tests/functional/requirements.txt (+1/-0) tests/functional/tests/__init__.py (+1/-0) tests/functional/tests/bundles/bionic.yaml (+16/-0) tests/functional/tests/bundles/focal.yaml (+16/-0) tests/functional/tests/bundles/overlays/local-charm-overlay.yaml.j2 (+3/-0) tests/functional/tests/bundles/xenial.yaml (+16/-0) tests/functional/tests/test_prometheus_blackbox_exporter.py (+78/-0) tests/functional/tests/tests.yaml (+11/-0) tox.ini (+65/-0) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Paul Goins | Approve | ||
Xav Paice | Pending | ||
Review via email: mp+384318@code.launchpad.net |
This proposal supersedes a proposal from 2020-04-02.
Commit message
Description of the change
Xav Paice (xavpaice) wrote : Posted in a previous version of this proposal | # |
Xav Paice (xavpaice) wrote : | # |
I've updated the change with a commit that works for functional testing and lint, and also renames the charm code itself to a name that doesn't have - (because Python).
My review now is of course a +1, but need someone else to look at it now.
Xav Paice (xavpaice) wrote : | # |
Note: there's no unit tests as yet.
Paul Goins (vultaire) wrote : | # |
Overall, this looks good.
I have a few comments, the most important likely being about the license, which I think requires attention. The others are things I think should be fixed but aren't really that important.
Xav Paice (xavpaice) wrote : | # |
I've updated the commit with updates for the catches - entirely removed unit tests (since they're not actually present), updated license to GPLv3, and removed the totally unused flag.
Preview Diff
1 | diff --git a/.gitignore b/.gitignore |
2 | new file mode 100644 |
3 | index 0000000..2dc89c9 |
4 | --- /dev/null |
5 | +++ b/.gitignore |
6 | @@ -0,0 +1,24 @@ |
7 | +# Byte-compiled / optimized / DLL files |
8 | +__pycache__/ |
9 | +*.py[cod] |
10 | +*$py.class |
11 | + |
12 | +# Log files |
13 | +*.log |
14 | +.tox/ |
15 | +.coverage |
16 | + |
17 | +# vi |
18 | +.*.swp |
19 | + |
20 | +# pycharm |
21 | +.idea/ |
22 | + |
23 | +# version data |
24 | +repo-info |
25 | + |
26 | +# reports |
27 | +report/* |
28 | + |
29 | +# layers |
30 | +layers/* |
31 | \ No newline at end of file |
32 | diff --git a/Makefile b/Makefile |
33 | new file mode 100644 |
34 | index 0000000..949713b |
35 | --- /dev/null |
36 | +++ b/Makefile |
37 | @@ -0,0 +1,48 @@ |
38 | +ifndef CHARM_BUILD_DIR |
39 | + CHARM_BUILD_DIR=/tmp/builds |
40 | +endif |
41 | + |
42 | +help: |
43 | + @echo "This project supports the following targets" |
44 | + @echo "" |
45 | + @echo " make help - show this text" |
46 | + @echo " make submodules - make sure that the submodules are up-to-date" |
47 | + @echo " make lint - run flake8" |
48 | + @echo " make test - run the functional tests and lint" |
49 | + @echo " make functional - run the tests defined in the functional subdirectory" |
50 | + @echo " make release - build the charm" |
51 | + @echo " make clean - remove unneeded files" |
52 | + @echo "" |
53 | + |
54 | +submodules: |
55 | + @echo "Cloning submodules" |
56 | + @git submodule update --init --recursive |
57 | + |
58 | +lint: |
59 | + @mkdir -p report/lint/ |
60 | + @echo "Running flake8" |
61 | + @tox -e lint |
62 | + |
63 | +test: lint functional |
64 | + |
65 | +functional: build |
66 | + @echo Executing with: CHARM_BUILD_DIR=$(CHARM_BUILD_DIR) tox -e func |
67 | + @CHARM_BUILD_DIR=$(CHARM_BUILD_DIR) tox -e func |
68 | + |
69 | +build: |
70 | + @echo "Building charm to base directory $(CHARM_BUILD_DIR)" |
71 | + @-git describe --tags > ./repo-info |
72 | + @CHARM_LAYERS_DIR=./layers CHARM_INTERFACES_DIR=./interfaces TERM=linux \ |
73 | + CHARM_BUILD_DIR=$(CHARM_BUILD_DIR) charm build . --force |
74 | + |
75 | +release: clean build |
76 | + @echo "Charm is built at $(CHARM_BUILD_DIR)/prometheus-blackbox-exporter" |
77 | + |
78 | +clean: |
79 | + @echo "Cleaning files" |
80 | + @if [ -d .tox ] ; then rm -r .tox ; fi |
81 | + @if [ -d .pytest_cache ] ; then rm -r .pytest_cache ; fi |
82 | + @find . -iname __pycache__ -exec rm -r {} + |
83 | + |
84 | +# The targets below don't depend on a file |
85 | +.PHONY: lint test functional build release clean help submodules |
86 | diff --git a/README.md b/README.md |
87 | index 58725ef..ffde3eb 100644 |
88 | --- a/README.md |
89 | +++ b/README.md |
90 | @@ -16,3 +16,36 @@ you can update the charm's configuration using: |
91 | To confirm configuration was set: |
92 | |
93 | juju config prometheus-blackbox-exporter |
94 | + |
95 | +## Testing |
96 | + |
97 | +# This directory needs to be create in the charm path prior to testing |
98 | +``` |
99 | +mkdir -p report/lint |
100 | +``` |
101 | + |
102 | +## Deployment |
103 | + |
104 | +# To avail of the metrics in grafana the following steps can be used |
105 | +``` |
106 | +juju deploy grafana |
107 | +juju deploy prometheus2 |
108 | +juju add-relation prometheus-blackbox-exporter:scrape prometheus2:target |
109 | +juju add-relation prometheus-blackbox-exporter:dashboards grafana:dashboards |
110 | +``` |
111 | + |
112 | +# To setup reporting with nagios |
113 | +``` |
114 | +juju deploy nrpe |
115 | +juju add-relation prometheus-blackbox-exporter:nrpe-external-master nrpe:nrpe-external-master |
116 | +``` |
117 | + |
118 | +# Change or update dashboards |
119 | +``` |
120 | +# To provide your own dashboards, create a zip file and attach it as a resource |
121 | +zip grafana-dashboards.zip blackbox-simple.json blackbox-advanced.json |
122 | +juju attach-resource prometheus-blackbox-exporter dashboards=./grafana-dashboards.zip |
123 | +``` |
124 | + |
125 | +# Contact Information |
126 | +- Charm bugs: https://bugs.launchpad.net/charm-prometheus-blackbox-exporter |
127 | diff --git a/config.yaml b/config.yaml |
128 | index d1dc24d..2f5db13 100644 |
129 | --- a/config.yaml |
130 | +++ b/config.yaml |
131 | @@ -5,6 +5,20 @@ options: |
132 | description: | |
133 | If install_method is set to "snap" this option controlls channel name. |
134 | Supported values are: "stable", "candidate", "beta" and "edge" |
135 | + nagios_context: |
136 | + default: "juju" |
137 | + type: string |
138 | + description: | |
139 | + A string that will be prepended to instance name to set the host name |
140 | + in nagios. So for instance the hostname would be something like: |
141 | + juju-myservice-0 |
142 | + If you're running multiple environments with the same services in them |
143 | + this allows you to differentiate between them. |
144 | + nagios_servicegroups: |
145 | + default: "juju" |
146 | + type: string |
147 | + description: | |
148 | + Comma separated list of nagios servicegroups |
149 | modules: |
150 | default: | |
151 | http_2xx: |
152 | diff --git a/copyright b/copyright |
153 | new file mode 100644 |
154 | index 0000000..8dddbf0 |
155 | --- /dev/null |
156 | +++ b/copyright |
157 | @@ -0,0 +1,17 @@ |
158 | +Format: http://dep.debian.net/deps/dep5/ |
159 | + |
160 | +Files: * |
161 | +Copyright: Copyright 2012-2018, Canonical Ltd., All Rights Reserved. |
162 | +License: GPL-3 |
163 | + This program is free software: you can redistribute it and/or modify |
164 | + it under the terms of the GNU General Public License as published by |
165 | + the Free Software Foundation, either version 3 of the License, or |
166 | + (at your option) any later version. |
167 | + . |
168 | + This program is distributed in the hope that it will be useful, |
169 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
170 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
171 | + GNU General Public License for more details. |
172 | + . |
173 | + You should have received a copy of the GNU General Public License |
174 | + along with this program. If not, see <http://www.gnu.org/licenses/>. |
175 | diff --git a/icon.svg b/icon.svg |
176 | new file mode 100644 |
177 | index 0000000..96a5d0c |
178 | --- /dev/null |
179 | +++ b/icon.svg |
180 | @@ -0,0 +1,279 @@ |
181 | +<?xml version="1.0" encoding="UTF-8" standalone="no"?> |
182 | +<!-- Created with Inkscape (http://www.inkscape.org/) --> |
183 | + |
184 | +<svg |
185 | + xmlns:dc="http://purl.org/dc/elements/1.1/" |
186 | + xmlns:cc="http://creativecommons.org/ns#" |
187 | + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" |
188 | + xmlns:svg="http://www.w3.org/2000/svg" |
189 | + xmlns="http://www.w3.org/2000/svg" |
190 | + xmlns:xlink="http://www.w3.org/1999/xlink" |
191 | + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" |
192 | + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" |
193 | + width="96" |
194 | + height="96" |
195 | + id="svg6517" |
196 | + version="1.1" |
197 | + inkscape:version="0.48+devel r12274" |
198 | + sodipodi:docname="Juju_charm_icon_template.svg"> |
199 | + <defs |
200 | + id="defs6519"> |
201 | + <linearGradient |
202 | + inkscape:collect="always" |
203 | + xlink:href="#Background" |
204 | + id="linearGradient6461" |
205 | + gradientUnits="userSpaceOnUse" |
206 | + x1="0" |
207 | + y1="970.29498" |
208 | + x2="144" |
209 | + y2="970.29498" |
210 | + gradientTransform="matrix(0,-0.66666669,0.6660448,0,-866.25992,731.29077)" /> |
211 | + <linearGradient |
212 | + id="Background"> |
213 | + <stop |
214 | + id="stop4178" |
215 | + offset="0" |
216 | + style="stop-color:#b8b8b8;stop-opacity:1" /> |
217 | + <stop |
218 | + id="stop4180" |
219 | + offset="1" |
220 | + style="stop-color:#c9c9c9;stop-opacity:1" /> |
221 | + </linearGradient> |
222 | + <filter |
223 | + style="color-interpolation-filters:sRGB;" |
224 | + inkscape:label="Inner Shadow" |
225 | + id="filter1121"> |
226 | + <feFlood |
227 | + flood-opacity="0.59999999999999998" |
228 | + flood-color="rgb(0,0,0)" |
229 | + result="flood" |
230 | + id="feFlood1123" /> |
231 | + <feComposite |
232 | + in="flood" |
233 | + in2="SourceGraphic" |
234 | + operator="out" |
235 | + result="composite1" |
236 | + id="feComposite1125" /> |
237 | + <feGaussianBlur |
238 | + in="composite1" |
239 | + stdDeviation="1" |
240 | + result="blur" |
241 | + id="feGaussianBlur1127" /> |
242 | + <feOffset |
243 | + dx="0" |
244 | + dy="2" |
245 | + result="offset" |
246 | + id="feOffset1129" /> |
247 | + <feComposite |
248 | + in="offset" |
249 | + in2="SourceGraphic" |
250 | + operator="atop" |
251 | + result="composite2" |
252 | + id="feComposite1131" /> |
253 | + </filter> |
254 | + <filter |
255 | + style="color-interpolation-filters:sRGB;" |
256 | + inkscape:label="Drop Shadow" |
257 | + id="filter950"> |
258 | + <feFlood |
259 | + flood-opacity="0.25" |
260 | + flood-color="rgb(0,0,0)" |
261 | + result="flood" |
262 | + id="feFlood952" /> |
263 | + <feComposite |
264 | + in="flood" |
265 | + in2="SourceGraphic" |
266 | + operator="in" |
267 | + result="composite1" |
268 | + id="feComposite954" /> |
269 | + <feGaussianBlur |
270 | + in="composite1" |
271 | + stdDeviation="1" |
272 | + result="blur" |
273 | + id="feGaussianBlur956" /> |
274 | + <feOffset |
275 | + dx="0" |
276 | + dy="1" |
277 | + result="offset" |
278 | + id="feOffset958" /> |
279 | + <feComposite |
280 | + in="SourceGraphic" |
281 | + in2="offset" |
282 | + operator="over" |
283 | + result="composite2" |
284 | + id="feComposite960" /> |
285 | + </filter> |
286 | + <clipPath |
287 | + clipPathUnits="userSpaceOnUse" |
288 | + id="clipPath873"> |
289 | + <g |
290 | + transform="matrix(0,-0.66666667,0.66604479,0,-258.25992,677.00001)" |
291 | + id="g875" |
292 | + inkscape:label="Layer 1" |
293 | + style="fill:#ff00ff;fill-opacity:1;stroke:none;display:inline"> |
294 | + <path |
295 | + style="fill:#ff00ff;fill-opacity:1;stroke:none;display:inline" |
296 | + d="m 46.702703,898.22775 50.594594,0 C 138.16216,898.22775 144,904.06497 144,944.92583 l 0,50.73846 c 0,40.86071 -5.83784,46.69791 -46.702703,46.69791 l -50.594594,0 C 5.8378378,1042.3622 0,1036.525 0,995.66429 L 0,944.92583 C 0,904.06497 5.8378378,898.22775 46.702703,898.22775 Z" |
297 | + id="path877" |
298 | + inkscape:connector-curvature="0" |
299 | + sodipodi:nodetypes="sssssssss" /> |
300 | + </g> |
301 | + </clipPath> |
302 | + <filter |
303 | + inkscape:collect="always" |
304 | + id="filter891" |
305 | + inkscape:label="Badge Shadow"> |
306 | + <feGaussianBlur |
307 | + inkscape:collect="always" |
308 | + stdDeviation="0.71999962" |
309 | + id="feGaussianBlur893" /> |
310 | + </filter> |
311 | + </defs> |
312 | + <sodipodi:namedview |
313 | + id="base" |
314 | + pagecolor="#ffffff" |
315 | + bordercolor="#666666" |
316 | + borderopacity="1.0" |
317 | + inkscape:pageopacity="0.0" |
318 | + inkscape:pageshadow="2" |
319 | + inkscape:zoom="4.0745362" |
320 | + inkscape:cx="18.514671" |
321 | + inkscape:cy="49.018169" |
322 | + inkscape:document-units="px" |
323 | + inkscape:current-layer="layer1" |
324 | + showgrid="true" |
325 | + fit-margin-top="0" |
326 | + fit-margin-left="0" |
327 | + fit-margin-right="0" |
328 | + fit-margin-bottom="0" |
329 | + inkscape:window-width="1920" |
330 | + inkscape:window-height="1029" |
331 | + inkscape:window-x="0" |
332 | + inkscape:window-y="24" |
333 | + inkscape:window-maximized="1" |
334 | + showborder="true" |
335 | + showguides="true" |
336 | + inkscape:guide-bbox="true" |
337 | + inkscape:showpageshadow="false"> |
338 | + <inkscape:grid |
339 | + type="xygrid" |
340 | + id="grid821" /> |
341 | + <sodipodi:guide |
342 | + orientation="1,0" |
343 | + position="16,48" |
344 | + id="guide823" /> |
345 | + <sodipodi:guide |
346 | + orientation="0,1" |
347 | + position="64,80" |
348 | + id="guide825" /> |
349 | + <sodipodi:guide |
350 | + orientation="1,0" |
351 | + position="80,40" |
352 | + id="guide827" /> |
353 | + <sodipodi:guide |
354 | + orientation="0,1" |
355 | + position="64,16" |
356 | + id="guide829" /> |
357 | + </sodipodi:namedview> |
358 | + <metadata |
359 | + id="metadata6522"> |
360 | + <rdf:RDF> |
361 | + <cc:Work |
362 | + rdf:about=""> |
363 | + <dc:format>image/svg+xml</dc:format> |
364 | + <dc:type |
365 | + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> |
366 | + <dc:title></dc:title> |
367 | + </cc:Work> |
368 | + </rdf:RDF> |
369 | + </metadata> |
370 | + <g |
371 | + inkscape:label="BACKGROUND" |
372 | + inkscape:groupmode="layer" |
373 | + id="layer1" |
374 | + transform="translate(268,-635.29076)" |
375 | + style="display:inline"> |
376 | + <path |
377 | + style="fill:url(#linearGradient6461);fill-opacity:1;stroke:none;display:inline;filter:url(#filter1121)" |
378 | + d="m -268,700.15563 0,-33.72973 c 0,-27.24324 3.88785,-31.13513 31.10302,-31.13513 l 33.79408,0 c 27.21507,0 31.1029,3.89189 31.1029,31.13513 l 0,33.72973 c 0,27.24325 -3.88783,31.13514 -31.1029,31.13514 l -33.79408,0 C -264.11215,731.29077 -268,727.39888 -268,700.15563 Z" |
379 | + id="path6455" |
380 | + inkscape:connector-curvature="0" |
381 | + sodipodi:nodetypes="sssssssss" /> |
382 | + </g> |
383 | + <g |
384 | + inkscape:groupmode="layer" |
385 | + id="layer3" |
386 | + inkscape:label="PLACE YOUR PICTOGRAM HERE" |
387 | + style="display:inline" /> |
388 | + <g |
389 | + inkscape:groupmode="layer" |
390 | + id="layer2" |
391 | + inkscape:label="BADGE" |
392 | + style="display:none" |
393 | + sodipodi:insensitive="true"> |
394 | + <g |
395 | + style="display:inline" |
396 | + transform="translate(-340.00001,-581)" |
397 | + id="g4394" |
398 | + clip-path="none"> |
399 | + <g |
400 | + id="g855"> |
401 | + <g |
402 | + inkscape:groupmode="maskhelper" |
403 | + id="g870" |
404 | + clip-path="url(#clipPath873)" |
405 | + style="opacity:0.6;filter:url(#filter891)"> |
406 | + <path |
407 | + transform="matrix(1.4999992,0,0,1.4999992,-29.999795,-237.54282)" |
408 | + d="m 264,552.36218 a 12,12 0 1 1 -24,0 A 12,12 0 1 1 264,552.36218 Z" |
409 | + sodipodi:ry="12" |
410 | + sodipodi:rx="12" |
411 | + sodipodi:cy="552.36218" |
412 | + sodipodi:cx="252" |
413 | + id="path844" |
414 | + style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" |
415 | + sodipodi:type="arc" /> |
416 | + </g> |
417 | + <g |
418 | + id="g862"> |
419 | + <path |
420 | + sodipodi:type="arc" |
421 | + style="color:#000000;fill:#f5f5f5;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" |
422 | + id="path4398" |
423 | + sodipodi:cx="252" |
424 | + sodipodi:cy="552.36218" |
425 | + sodipodi:rx="12" |
426 | + sodipodi:ry="12" |
427 | + d="m 264,552.36218 a 12,12 0 1 1 -24,0 A 12,12 0 1 1 264,552.36218 Z" |
428 | + transform="matrix(1.4999992,0,0,1.4999992,-29.999795,-238.54282)" /> |
429 | + <path |
430 | + transform="matrix(1.25,0,0,1.25,33,-100.45273)" |
431 | + d="m 264,552.36218 a 12,12 0 1 1 -24,0 A 12,12 0 1 1 264,552.36218 Z" |
432 | + sodipodi:ry="12" |
433 | + sodipodi:rx="12" |
434 | + sodipodi:cy="552.36218" |
435 | + sodipodi:cx="252" |
436 | + id="path4400" |
437 | + style="color:#000000;fill:#dd4814;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" |
438 | + sodipodi:type="arc" /> |
439 | + <path |
440 | + sodipodi:type="star" |
441 | + style="color:#000000;fill:#f5f5f5;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" |
442 | + id="path4459" |
443 | + sodipodi:sides="5" |
444 | + sodipodi:cx="666.19574" |
445 | + sodipodi:cy="589.50385" |
446 | + sodipodi:r1="7.2431178" |
447 | + sodipodi:r2="4.3458705" |
448 | + sodipodi:arg1="1.0471976" |
449 | + sodipodi:arg2="1.6755161" |
450 | + inkscape:flatsided="false" |
451 | + inkscape:rounded="0.1" |
452 | + inkscape:randomized="0" |
453 | + d="m 669.8173,595.77657 c -0.39132,0.22593 -3.62645,-1.90343 -4.07583,-1.95066 -0.44938,-0.0472 -4.05653,1.36297 -4.39232,1.06062 -0.3358,-0.30235 0.68963,-4.03715 0.59569,-4.47913 -0.0939,-0.44198 -2.5498,-3.43681 -2.36602,-3.8496 0.18379,-0.41279 4.05267,-0.59166 4.44398,-0.81759 0.39132,-0.22593 2.48067,-3.48704 2.93005,-3.4398 0.44938,0.0472 1.81505,3.67147 2.15084,3.97382 0.3358,0.30236 4.08294,1.2817 4.17689,1.72369 0.0939,0.44198 -2.9309,2.86076 -3.11469,3.27355 C 669.9821,591.68426 670.20862,595.55064 669.8173,595.77657 Z" |
454 | + transform="matrix(1.511423,-0.16366377,0.16366377,1.511423,-755.37346,-191.93651)" /> |
455 | + </g> |
456 | + </g> |
457 | + </g> |
458 | + </g> |
459 | +</svg> |
460 | diff --git a/layer.yaml b/layer.yaml |
461 | index ddd95fc..52f61b2 100644 |
462 | --- a/layer.yaml |
463 | +++ b/layer.yaml |
464 | @@ -1,5 +1,10 @@ |
465 | -includes: ['layer:basic', 'interface:http', 'layer:snap'] |
466 | -repo: 'https://git.launchpad.net/prometheus-blackbox-exporter-charm' |
467 | +includes: |
468 | + - layer:basic |
469 | + - interface:http |
470 | + - layer:snap |
471 | + - interface:nrpe-external-master |
472 | + - interface:grafana-dashboard |
473 | +repo: https://git.launchpad.net/prometheus-blackbox-exporter-charm |
474 | ignore: ['.*.swp' ] |
475 | options: |
476 | basic: |
477 | diff --git a/metadata.yaml b/metadata.yaml |
478 | index 831b6aa..6a9436b 100644 |
479 | --- a/metadata.yaml |
480 | +++ b/metadata.yaml |
481 | @@ -14,3 +14,14 @@ subordinate: false |
482 | provides: |
483 | blackbox-exporter: |
484 | interface: http |
485 | + nrpe-external-master: |
486 | + interface: nrpe-external-master |
487 | + scope: container |
488 | + dashboards: |
489 | + interface: grafana-dashboard |
490 | +resources: |
491 | + dashboards: |
492 | + type: file |
493 | + filename: grafana-dashboards.zip |
494 | + description: |
495 | + Zip file to provide grafana dashboards |
496 | diff --git a/reactive/prometheus-blackbox-exporter.py b/reactive/prometheus_blackbox_exporter.py |
497 | similarity index 60% |
498 | rename from reactive/prometheus-blackbox-exporter.py |
499 | rename to reactive/prometheus_blackbox_exporter.py |
500 | index 2da0bed..eb4677d 100644 |
501 | --- a/reactive/prometheus-blackbox-exporter.py |
502 | +++ b/reactive/prometheus_blackbox_exporter.py |
503 | @@ -1,18 +1,30 @@ |
504 | -import yaml |
505 | +#!/usr/bin/python3 |
506 | +"""Installs and configures prometheus-blackbox-exporter.""" |
507 | + |
508 | +import os |
509 | +from pathlib import Path |
510 | +import shutil |
511 | +from zipfile import BadZipFile, ZipFile |
512 | |
513 | -from charmhelpers.core import host, hookenv |
514 | +from charmhelpers.contrib.charmsupport import nrpe |
515 | +from charmhelpers.core import hookenv, host |
516 | from charmhelpers.core.templating import render |
517 | +from charms.layer import snap |
518 | from charms.reactive import ( |
519 | + endpoint_from_flag, |
520 | endpoint_from_name, |
521 | + hook, |
522 | remove_state, |
523 | set_state, |
524 | when, |
525 | + when_all, |
526 | when_not, |
527 | ) |
528 | from charms.reactive.helpers import any_file_changed, data_changed |
529 | -from charms.layer import snap |
530 | +import yaml |
531 | |
532 | |
533 | +DASHBOARD_PATH = os.getcwd() + '/templates/' |
534 | SNAP_NAME = 'prometheus-blackbox-exporter' |
535 | SVC_NAME = 'snap.prometheus-blackbox-exporter.daemon' |
536 | PORT_DEF = 9115 |
537 | @@ -21,11 +33,13 @@ CONF_FILE_PATH = '/var/snap/prometheus-blackbox-exporter/current/blackbox.yml' |
538 | |
539 | |
540 | def templates_changed(tmpl_list): |
541 | + """Return list of changed files.""" |
542 | return any_file_changed(['templates/{}'.format(x) for x in tmpl_list]) |
543 | |
544 | |
545 | @when_not('blackbox-exporter.installed') |
546 | def install_packages(): |
547 | + """Installs the snap exporter.""" |
548 | hookenv.status_set('maintenance', 'Installing software') |
549 | config = hookenv.config() |
550 | channel = config.get('snap_channel', 'stable') |
551 | @@ -34,11 +48,21 @@ def install_packages(): |
552 | set_state('blackbox-exporter.do-check-reconfig') |
553 | |
554 | |
555 | +@hook('upgrade-charm') |
556 | +def upgrade(): |
557 | + """Reset the install state on upgrade, to ensure resource extraction.""" |
558 | + hookenv.status_set('maintenance', 'Charm upgrade in progress') |
559 | + update_dashboards_from_resource() |
560 | + set_state('blackbox-exporter.do-restart') |
561 | + |
562 | + |
563 | def get_modules(): |
564 | + """Load the modules.""" |
565 | config = hookenv.config() |
566 | try: |
567 | modules = yaml.safe_load(config.get('modules')) |
568 | - except: |
569 | + except yaml.YAMLError as error: |
570 | + hookenv.log('Failed to load modules, error {}'.format(error)) |
571 | return None |
572 | |
573 | if 'modules' in modules: |
574 | @@ -50,6 +74,7 @@ def get_modules(): |
575 | @when('blackbox-exporter.installed') |
576 | @when('blackbox-exporter.do-reconfig-yaml') |
577 | def write_blackbox_exporter_config_yaml(): |
578 | + """Render the template.""" |
579 | modules = get_modules() |
580 | render(source=BLACKBOX_EXPORTER_YML_TMPL, |
581 | target=CONF_FILE_PATH, |
582 | @@ -62,11 +87,13 @@ def write_blackbox_exporter_config_yaml(): |
583 | |
584 | @when('blackbox-exporter.started') |
585 | def check_config(): |
586 | + """Check the config once started.""" |
587 | set_state('blackbox-exporter.do-check-reconfig') |
588 | |
589 | |
590 | @when('blackbox-exporter.do-check-reconfig') |
591 | def check_reconfig_blackbox_exporter(): |
592 | + """Configure the exporter.""" |
593 | config = hookenv.config() |
594 | |
595 | if data_changed('blackbox-exporter.config', config): |
596 | @@ -80,6 +107,7 @@ def check_reconfig_blackbox_exporter(): |
597 | |
598 | @when('blackbox-exporter.do-restart') |
599 | def restart_blackbox_exporter(): |
600 | + """Restart the exporter.""" |
601 | if not host.service_running(SVC_NAME): |
602 | hookenv.log('Starting {}...'.format(SVC_NAME)) |
603 | host.service_start(SVC_NAME) |
604 | @@ -93,7 +121,98 @@ def restart_blackbox_exporter(): |
605 | |
606 | # Relations |
607 | @when('blackbox-exporter.started') |
608 | -@when('blackbox-exporter.available') # Relation name is "blackbox-exporter" |
609 | +@when('blackbox-exporter.available') |
610 | def configure_blackbox_exporter_relation(): |
611 | + """Configure the http relation.""" |
612 | target = endpoint_from_name('blackbox-exporter') |
613 | target.configure(PORT_DEF) |
614 | + remove_state('blackbox-exporter.configured') |
615 | + |
616 | + |
617 | +@when('nrpe-external-master.changed') |
618 | +def nrpe_changed(): |
619 | + """Trigger nrpe update.""" |
620 | + remove_state('blackbox-exporter.configured') |
621 | + |
622 | + |
623 | +@when('blackbox-exporter.changed') |
624 | +def prometheus_changed(): |
625 | + """Trigger prometheus update.""" |
626 | + remove_state('blackbox-exporter.configured') |
627 | + |
628 | + |
629 | +@when('nrpe-external-master.available') |
630 | +@when_not('blackbox-exporter.configured') |
631 | +def update_nrpe_config(svc): |
632 | + """Configure the nrpe check for the service.""" |
633 | + if not os.path.exists('/var/lib/nagios'): |
634 | + hookenv.status_set('blocked', 'Waiting for nrpe package installation') |
635 | + return |
636 | + |
637 | + hookenv.status_set('maintenance', 'Configuring nrpe checks') |
638 | + |
639 | + hostname = nrpe.get_nagios_hostname() |
640 | + nrpe_setup = nrpe.NRPE(hostname=hostname) |
641 | + nrpe_setup.add_check(shortname='prometheus_blackbox_exporter_http', |
642 | + check_cmd='check_http -I 127.0.0.1 -p {} -u /metrics'.format(PORT_DEF), |
643 | + description='Prometheus blackbox Exporter HTTP check') |
644 | + nrpe_setup.write() |
645 | + hookenv.status_set('active', 'Ready') |
646 | + set_state('blackbox-exporter.configured') |
647 | + |
648 | + |
649 | +@when('blackbox-exporter.configured') |
650 | +@when_not('nrpe-external-master.available') |
651 | +def remove_nrpe_check(): |
652 | + """Remove the nrpe check.""" |
653 | + hostname = nrpe.get_nagios_hostname() |
654 | + nrpe_setup = nrpe.NRPE(hostname=hostname) |
655 | + nrpe_setup.remove_check(shortname="prometheus_blackbox_exporter_http") |
656 | + remove_state('blackbox-exporter.configured') |
657 | + |
658 | + |
659 | +@when_all('endpoint.dashboards.joined') |
660 | +def register_grafana_dashboards(): |
661 | + """After joining to grafana, push the dashboard.""" |
662 | + grafana_endpoint = endpoint_from_flag('endpoint.dashboards.joined') |
663 | + |
664 | + if grafana_endpoint is None: |
665 | + return |
666 | + |
667 | + hookenv.log('Grafana relation joined, push dashboard') |
668 | + |
669 | + # load pre-distributed dashboards, that may havew been overwritten by resource |
670 | + dash_dir = Path(DASHBOARD_PATH) |
671 | + for dash_file in dash_dir.glob('*.json'): |
672 | + dashboard = dash_file.read_text() |
673 | + grafana_endpoint.register_dashboard(dash_file.stem, dashboard) |
674 | + hookenv.log('Pushed {}'.format(dash_file)) |
675 | + |
676 | + |
677 | +def update_dashboards_from_resource(): |
678 | + """Extract resource zip file into templates directory.""" |
679 | + dashboards_zip_resource = hookenv.resource_get('dashboards') |
680 | + if not dashboards_zip_resource: |
681 | + hookenv.log('No dashboards resource found', hookenv.DEBUG) |
682 | + # no dashboards zip found, go with the default distributed dashboard |
683 | + return |
684 | + |
685 | + hookenv.log('Installing dashboards from resource', hookenv.DEBUG) |
686 | + try: |
687 | + shutil.copy(dashboards_zip_resource, DASHBOARD_PATH) |
688 | + except IOError as error: |
689 | + hookenv.log('Problem copying resource: {}'.format(error), hookenv.ERROR) |
690 | + return |
691 | + |
692 | + try: |
693 | + with ZipFile(dashboards_zip_resource, 'r') as zipfile: |
694 | + zipfile.extractall(path=DASHBOARD_PATH) |
695 | + hookenv.log('Extracted dashboards from resource', hookenv.DEBUG) |
696 | + except BadZipFile as error: |
697 | + hookenv.log('BadZipFile: {}'.format(error), hookenv.ERROR) |
698 | + return |
699 | + except PermissionError as error: |
700 | + hookenv.log('Unable to unzip the provided resource: {}'.format(error), hookenv.ERROR) |
701 | + return |
702 | + |
703 | + register_grafana_dashboards() |
704 | diff --git a/requirements.txt b/requirements.txt |
705 | new file mode 100644 |
706 | index 0000000..1713f68 |
707 | --- /dev/null |
708 | +++ b/requirements.txt |
709 | @@ -0,0 +1 @@ |
710 | +# Include python requirements here |
711 | \ No newline at end of file |
712 | diff --git a/tests/functional/requirements.txt b/tests/functional/requirements.txt |
713 | new file mode 100644 |
714 | index 0000000..b7c9112 |
715 | --- /dev/null |
716 | +++ b/tests/functional/requirements.txt |
717 | @@ -0,0 +1 @@ |
718 | +git+https://github.com/openstack-charmers/zaza.git#egg=zaza |
719 | diff --git a/tests/functional/tests/__init__.py b/tests/functional/tests/__init__.py |
720 | new file mode 100644 |
721 | index 0000000..d236d73 |
722 | --- /dev/null |
723 | +++ b/tests/functional/tests/__init__.py |
724 | @@ -0,0 +1 @@ |
725 | +"""Zaza tests.""" |
726 | diff --git a/tests/functional/tests/bundles/bionic.yaml b/tests/functional/tests/bundles/bionic.yaml |
727 | new file mode 100644 |
728 | index 0000000..4b510f1 |
729 | --- /dev/null |
730 | +++ b/tests/functional/tests/bundles/bionic.yaml |
731 | @@ -0,0 +1,16 @@ |
732 | +series: bionic |
733 | +applications: |
734 | + prometheus-blackbox-exporter: |
735 | + options: |
736 | + snap_channel: stable |
737 | + num_units: 1 |
738 | + nrpe: |
739 | + charm: cs:nrpe |
740 | + prometheus: |
741 | + charm: cs:prometheus2 |
742 | + num_units: 1 |
743 | +relations: |
744 | + - - prometheus-blackbox-exporter:nrpe-external-master |
745 | + - nrpe:nrpe-external-master |
746 | + - - prometheus-blackbox-exporter:blackbox-exporter |
747 | + - prometheus:target |
748 | \ No newline at end of file |
749 | diff --git a/tests/functional/tests/bundles/focal.yaml b/tests/functional/tests/bundles/focal.yaml |
750 | new file mode 100644 |
751 | index 0000000..2f3dc6c |
752 | --- /dev/null |
753 | +++ b/tests/functional/tests/bundles/focal.yaml |
754 | @@ -0,0 +1,16 @@ |
755 | +series: focal |
756 | +applications: |
757 | + prometheus-blackbox-exporter: |
758 | + options: |
759 | + snap_channel: stable |
760 | + num_units: 1 |
761 | + nrpe: |
762 | + charm: cs:nrpe |
763 | + prometheus: |
764 | + charm: cs:prometheus2 |
765 | + num_units: 1 |
766 | +relations: |
767 | + - - prometheus-blackbox-exporter:nrpe-external-master |
768 | + - nrpe:nrpe-external-master |
769 | + - - prometheus-blackbox-exporter:blackbox-exporter |
770 | + - prometheus:target |
771 | \ No newline at end of file |
772 | diff --git a/tests/functional/tests/bundles/overlays/local-charm-overlay.yaml.j2 b/tests/functional/tests/bundles/overlays/local-charm-overlay.yaml.j2 |
773 | new file mode 100644 |
774 | index 0000000..df81abd |
775 | --- /dev/null |
776 | +++ b/tests/functional/tests/bundles/overlays/local-charm-overlay.yaml.j2 |
777 | @@ -0,0 +1,3 @@ |
778 | +applications: |
779 | + prometheus-blackbox-exporter: |
780 | + charm: "{{ CHARM_BUILD_DIR }}/{{ charm_name }}" |
781 | diff --git a/tests/functional/tests/bundles/xenial.yaml b/tests/functional/tests/bundles/xenial.yaml |
782 | new file mode 100644 |
783 | index 0000000..be4f6dc |
784 | --- /dev/null |
785 | +++ b/tests/functional/tests/bundles/xenial.yaml |
786 | @@ -0,0 +1,16 @@ |
787 | +series: xenial |
788 | +applications: |
789 | + prometheus-blackbox-exporter: |
790 | + options: |
791 | + snap_channel: stable |
792 | + num_units: 1 |
793 | + nrpe: |
794 | + charm: cs:nrpe |
795 | + prometheus: |
796 | + charm: cs:prometheus2 |
797 | + num_units: 1 |
798 | +relations: |
799 | + - - prometheus-blackbox-exporter:nrpe-external-master |
800 | + - nrpe:nrpe-external-master |
801 | + - - prometheus-blackbox-exporter:blackbox-exporter |
802 | + - prometheus:target |
803 | \ No newline at end of file |
804 | diff --git a/tests/functional/tests/test_prometheus_blackbox_exporter.py b/tests/functional/tests/test_prometheus_blackbox_exporter.py |
805 | new file mode 100644 |
806 | index 0000000..b02154b |
807 | --- /dev/null |
808 | +++ b/tests/functional/tests/test_prometheus_blackbox_exporter.py |
809 | @@ -0,0 +1,78 @@ |
810 | +"""Encapsulate prometheus-blackbox-exporter testing.""" |
811 | +import logging |
812 | +import time |
813 | +import unittest |
814 | + |
815 | +import zaza.model as model |
816 | + |
817 | + |
818 | +CURL_TIMEOUT = 180 |
819 | +REQ_TIMEOUT = 12 |
820 | +DEFAULT_API_PORT = "9115" |
821 | +DEFAULT_API_URL = "/metrics" |
822 | + |
823 | + |
824 | +class BasePrometheusBlackboxExporterTest(unittest.TestCase): |
825 | + """Base for Prometheus-blackbox-exporter charm tests.""" |
826 | + |
827 | + @classmethod |
828 | + def setUpClass(cls): |
829 | + """Set up tests.""" |
830 | + super(BasePrometheusBlackboxExporterTest, cls).setUpClass() |
831 | + cls.model_name = model.get_juju_model() |
832 | + cls.application_name = "prometheus-blackbox-exporter" |
833 | + cls.lead_unit_name = model.get_lead_unit_name( |
834 | + cls.application_name, model_name=cls.model_name |
835 | + ) |
836 | + cls.units = model.get_units( |
837 | + cls.application_name, model_name=cls.model_name |
838 | + ) |
839 | + cls.prometheus_blackbox_exporter_ip = model.get_app_ips(cls.application_name)[0] |
840 | + |
841 | + |
842 | +class CharmOperationTest(BasePrometheusBlackboxExporterTest): |
843 | + """Verify operations.""" |
844 | + |
845 | + def test_01_api_ready(self): |
846 | + """Verify if the API is ready. |
847 | + |
848 | + Curl the api endpoint. |
849 | + We'll retry until the CURL_TIMEOUT. |
850 | + """ |
851 | + curl_command = "curl http://localhost:{}/metrics".format(DEFAULT_API_PORT) |
852 | + timeout = time.time() + CURL_TIMEOUT |
853 | + while time.time() < timeout: |
854 | + response = model.run_on_unit(self.lead_unit_name, curl_command) |
855 | + if response["Code"] == "0": |
856 | + return |
857 | + logging.warning( |
858 | + "Unexpected curl response: {}. Retrying in 30s.".format( |
859 | + response |
860 | + ) |
861 | + ) |
862 | + time.sleep(30) |
863 | + |
864 | + # we didn't get rc=0 in the allowed time, fail the test |
865 | + self.fail( |
866 | + "Prometheus-blackbox-exporter didn't respond to the command \n" |
867 | + "'{curl_command}' as expected.\n" |
868 | + "Result: {result}".format( |
869 | + curl_command=curl_command, result=response |
870 | + ) |
871 | + ) |
872 | + |
873 | + def test_02_nrpe_http_check(self): |
874 | + """Verify nrpe check exists.""" |
875 | + expected_nrpe_check = "command[check_prometheus_blackbox_exporter_http]={} -I 127.0.0.1 -p {} -u {}".format( |
876 | + "/usr/lib/nagios/plugins/check_http", |
877 | + DEFAULT_API_PORT, |
878 | + DEFAULT_API_URL |
879 | + ) |
880 | + logging.debug('Verify the nrpe check is created and has the required content...') |
881 | + cmd = "cat /etc/nagios/nrpe.d/check_prometheus_blackbox_exporter_http.cfg" |
882 | + result = model.run_on_unit(self.lead_unit_name, cmd) |
883 | + code = result.get('Code') |
884 | + if code != '0': |
885 | + raise model.CommandRunFailed(cmd, result) |
886 | + content = result.get('Stdout') |
887 | + self.assertTrue(expected_nrpe_check in content) |
888 | diff --git a/tests/functional/tests/tests.yaml b/tests/functional/tests/tests.yaml |
889 | new file mode 100644 |
890 | index 0000000..dd32bc7 |
891 | --- /dev/null |
892 | +++ b/tests/functional/tests/tests.yaml |
893 | @@ -0,0 +1,11 @@ |
894 | +charm_name: prometheus-blackbox-exporter |
895 | +gate_bundles: |
896 | + - focal |
897 | + - bionic |
898 | + - xenial |
899 | +smoke_bundles: |
900 | + - bionic |
901 | +dev_bundles: |
902 | + - bionic |
903 | +tests: |
904 | + - tests.test_prometheus_blackbox_exporter.CharmOperationTest |
905 | diff --git a/tox.ini b/tox.ini |
906 | new file mode 100644 |
907 | index 0000000..1859695 |
908 | --- /dev/null |
909 | +++ b/tox.ini |
910 | @@ -0,0 +1,65 @@ |
911 | +[tox] |
912 | +skipsdist=True |
913 | +envlist = unit, functional |
914 | +skip_missing_interpreters = True |
915 | + |
916 | +[testenv] |
917 | +basepython = python3 |
918 | +setenv = |
919 | + PYTHONPATH = . |
920 | +passenv = |
921 | + HOME |
922 | + CHARM_BUILD_DIR |
923 | + MODEL_SETTINGS |
924 | + |
925 | +[testenv:unit] |
926 | +commands = pytest -v \ |
927 | + --ignore {toxinidir}/tests/ \ |
928 | + --ignore {toxinidir}/interfaces \ |
929 | + --ignore {toxinidir}/layers \ |
930 | + --cov=lib \ |
931 | + --cov=actions \ |
932 | + --cov-report=term \ |
933 | + --cov-report=annotate:report/unit/coverage-annotated \ |
934 | + --cov-report=html:report/unit/coverage-html \ |
935 | + --html=report/unit/tests/index.html \ |
936 | + --junitxml=report/unit/junit.xml |
937 | +deps = -r{toxinidir}/tests/unit_tests/requirements.txt |
938 | + -r{toxinidir}/tests/requirements.txt |
939 | +setenv = PYTHONPATH={toxinidir}/lib |
940 | + |
941 | +[testenv:func] |
942 | +changedir = {toxinidir}/tests/functional |
943 | +commands = functest-run-suite --keep-model |
944 | +deps = -r{toxinidir}/tests/functional/requirements.txt |
945 | + |
946 | +[testenv:lint] |
947 | +commands = flake8 --tee |
948 | +deps = |
949 | + flake8 |
950 | + flake8-colors |
951 | + flake8-docstrings |
952 | + flake8-import-order |
953 | + pep8-naming |
954 | + |
955 | +[flake8] |
956 | +exclude = |
957 | + .git, |
958 | + __pycache__, |
959 | + .tox, |
960 | + layers, |
961 | + interfaces, |
962 | +max-line-length = 120 |
963 | +max-complexity = 10 |
964 | +import-order-style = google |
965 | + |
966 | +[isort] |
967 | +order_by_type = true |
968 | +from_first = true |
969 | +line_length = 120 |
970 | + |
971 | +[pytest] |
972 | +markers = |
973 | + deploy: mark deployment tests to allow running w/o redeploy |
974 | +filterwarnings = |
975 | + ignore::DeprecationWarning |
Passed lint test, but unit tests are failing with https:/ /pastebin. canonical. com/p/9tnFBtWrd 8/, even after I'd added the report dir mentioned in the README. This is a sizable change, and while I appreciate that this is introducing tests where there were none, it would be good to be able to pass the tests introduced and know the change is good. It's likely that there's something on my test env that's different to the author's, which we should be able to document or, better, add to the Makefile etc.
From what I can see so far, the rest of the change looks good.