Merge ~dmzoneill/charm-prometheus-libvirt-exporter:dev/q2-20 into charm-prometheus-libvirt-exporter:master

Proposed by David O Neill
Status: Merged
Merge reported by: Alvaro Uria
Merged at revision: 78cbf7a6c3109fa232a083f9dbd7d9db317008ea
Proposed branch: ~dmzoneill/charm-prometheus-libvirt-exporter:dev/q2-20
Merge into: charm-prometheus-libvirt-exporter:master
Diff against target: 2440 lines (+2225/-49)
23 files modified
.gitignore (+24/-0)
Makefile (+52/-0)
README.md (+43/-0)
config.yaml (+14/-0)
dev/null (+0/-46)
files/grafana-dashboards/libvirt.json (+1374/-0)
icon.svg (+279/-0)
interfaces/.empty (+0/-0)
layer.yaml (+10/-3)
layers/.empty (+0/-0)
metadata.yaml (+12/-0)
reactive/prometheus-libvirt-exporter.py (+185/-0)
requirements.txt (+1/-0)
tests/__init__.py (+1/-0)
tests/bundles/bionic.yaml (+22/-0)
tests/bundles/focal.yaml (+22/-0)
tests/bundles/overlays/local-charm-overlay.yaml.j2 (+3/-0)
tests/bundles/xenial.yaml (+22/-0)
tests/requirements.txt (+1/-0)
tests/test_prometheus_libvirt_exporter.py (+78/-0)
tests/tests.yaml (+11/-0)
tests/unit_tests/requirements.txt (+6/-0)
tox.ini (+65/-0)
Reviewer Review Type Date Requested Status
Alvaro Uria (community) Approve
Giuseppe Petralia Needs Fixing
Chris MacNaughton Pending
Andrew McLeod Pending
Review via email: mp+380729@code.launchpad.net
To post a comment you must log in.
78cbf7a... by David O Neill

Zaza, nrpe, prometheus updates

- makefile updates for CAHRM_BUILD_DIR
- removed pytest artefacts
- added support for pushing dashboard upstream to grafana when leader
- provided resource for attaching or updateing additional dashboards
- fix layer and metadata

Revision history for this message
Chris MacNaughton (chris.macnaughton) wrote :

General code review
===================

See inline comments for an overall code review.

The code has lint checking which it passes

Unit testing coverage
=====================

This charm change has no unit test coverage. As such, any new functionality introduced, and the potential impact of this change to existing behavior has not been assessed by the reviewer.

Functional testing coverage
===========================

The cham has basic functional coverage of all series that the charm supports

Revision history for this message
James Troup (elmo) wrote :

Some drive by comments

Revision history for this message
Giuseppe Petralia (peppepetra) wrote :

Some more comments in line

Revision history for this message
Giuseppe Petralia (peppepetra) wrote :

Added one more comment

review: Needs Fixing
Revision history for this message
Giuseppe Petralia (peppepetra) wrote :

Comment inline

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

I've added more comments inline. Other comments:
* The COMMIT_MSG has a typo (CHARM_BUILD_DIR)
* After cloning the repo, "make lint" failed because "mkdir report" is needed (I think it should be included by adding ./report/.keep or the extra flags in the flake8 command removed). Unit tests would not fail because of this, because pytest creates the folder if it does not exist.
* Unit tests should be added, and functional tests moved to a new folder ./tests/functional/
* If this MP won't add unit tests, I'd suggest removing all references to unit tests.

In general, the change looks good. I need to review a full deployment because the Zaza test does not include nova-compute to verify that metrics are retrieved from a running libvirt service.

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

BTW, this MP should be rebased. OTOH, I've found another MP [1] that should be merged with this one (I'll add a similar comment on the other MP).

1. https://code.launchpad.net/~woutervb/charm-prometheus-libvirt-exporter/+git/prometheus-libvirt-exporter-charm/+merge/382466

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

There is a dashboard that was initially included in charm-grafana [1]. However, the approach followed in this MP (share dashboards via relations) is the end goal. Please have a look to the mentioned charm-grafana MP because it uses the "_input" attribute to rewrite the datasources. Currently, it is hardcoded to "prometheus - Juju generated datasource". However, the Juju application may be named "prometheus2". In such case, the datasource name should be "prometheus2 - Juju generated datasource".

1. https://code.launchpad.net/~llama-charmers/charm-grafana/+git/charm-grafana/+merge/380965

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

This dashboard uses the "stat" plugin which is only available from v6.6 onwards. The snap is v5.0.

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

The snap v6.7.3 is going to be released as stable. Besides this fix, there is another one of top of this one that removes unit tests template (there are no unit tests in this charm) as well as it fixes the dashboard's title ("[juju] Libvirt metrics"). Next fix also removes the uid from the dashboard template.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/.coverage b/.coverage
index 834f8fb..e5c6f66 100644
0Binary files a/.coverage and b/.coverage differ0Binary files a/.coverage and b/.coverage differ
diff --git a/.gitignore b/.gitignore
1new file mode 1006441new file mode 100644
index 0000000..2dc89c9
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,24 @@
1# Byte-compiled / optimized / DLL files
2__pycache__/
3*.py[cod]
4*$py.class
5
6# Log files
7*.log
8.tox/
9.coverage
10
11# vi
12.*.swp
13
14# pycharm
15.idea/
16
17# version data
18repo-info
19
20# reports
21report/*
22
23# layers
24layers/*
0\ No newline at end of file25\ No newline at end of file
diff --git a/Makefile b/Makefile
1new file mode 10064426new file mode 100644
index 0000000..a4e48ca
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,52 @@
1ifndef CHARM_BUILD_DIR
2 CHARM_BUILD_DIR=/tmp/builds
3endif
4
5help:
6 @echo "This project supports the following targets"
7 @echo ""
8 @echo " make help - show this text"
9 @echo " make submodules - make sure that the submodules are up-to-date"
10 @echo " make lint - run flake8"
11 @echo " make test - run the unittests and lint"
12 @echo " make unittest - run the tests defined in the unittest subdirectory"
13 @echo " make functional - run the tests defined in the functional subdirectory"
14 @echo " make release - build the charm"
15 @echo " make clean - remove unneeded files"
16 @echo ""
17
18submodules:
19 @echo "Cloning submodules"
20 @git submodule update --init --recursive
21
22lint:
23 @echo "Running flake8"
24 @tox -e lint
25
26#test: lint unittest functional
27test: lint functional
28
29unittest:
30 @tox -e unit
31
32functional: build
33 @echo Executing with: CHARM_BUILD_DIR=$(CHARM_BUILD_DIR) tox -e func
34 @CHARM_BUILD_DIR=$(CHARM_BUILD_DIR) tox -e func
35
36build:
37 @echo "Building charm to base directory $(CHARM_BUILD_DIR)"
38 @-git describe --tags > ./repo-info
39 @CHARM_LAYERS_DIR=./layers CHARM_INTERFACES_DIR=./interfaces TERM=linux \
40 CHARM_BUILD_DIR=$(CHARM_BUILD_DIR) charm build . --force
41
42release: clean build
43 @echo "Charm is built at $(CHARM_BUILD_DIR)/prometheus-libvirt-exporter"
44
45clean:
46 @echo "Cleaning files"
47 @if [ -d .tox ] ; then rm -r .tox ; fi
48 @if [ -d .pytest_cache ] ; then rm -r .pytest_cache ; fi
49 @find . -iname __pycache__ -exec rm -r {} +
50
51# The targets below don't depend on a file
52.PHONY: lint test unittest functional build release clean help submodules
diff --git a/README.md b/README.md
index 1bb3648..fda45af 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,46 @@
1# Juju prometheus libvirt exporter charm1# Juju prometheus libvirt exporter charm
22
3This charm provides the [Prometheus libvirt exporter](https://github.com/kumina/libvirt_exporter)3This charm provides the [Prometheus libvirt exporter](https://github.com/kumina/libvirt_exporter)
4
5## Testing
6
7# This directory needs to be create in the charm path prior to testing
8```
9mkdir -p report/lint
10```
11
12## Deployment
13
14# A typical deployment with nova and libvirt is as follows:
15# The metrics will be at http://nova-compute:9177
16```
17juju deploy nova-compute
18juju deploy prometheus-libvirt-exporter
19juju add-relation nova-compute prometheus-libvirt-exporter
20```
21
22# To avail of the metrics in grafana the following steps can be used
23```
24juju deploy grafana
25juju deploy prometheus2
26juju add-relation prometheus-libvirt-exporter:scrape prometheus2:target
27juju add-relation prometheus-libvirt-exporter:dashboards grafana:dashboards
28```
29
30# To setup reporting with nagios
31```
32juju deploy nrpe
33juju add-relation nova-compute nrpe
34juju add-relation prometheus-libvirt-exporter:nrpe-external-master nrpe:nrpe-external-master
35```
36
37# Change or update dashboards
38```
39# The exporter is distributed with a standard dashboard
40# To provide your own dashboards, create a zip file and attach it as a resource
41zip grafana-dashboards.zip libvirt-simple.json libvirtadvanced.json
42juju attach-resource prometheus-libvirt-exporter dashboards=./grafana-dashboards.zip
43```
44
45# Contact Information
46- Charm bugs: https://bugs.launchpad.net/charm-prometheus-libvirt-exporter
diff --git a/config.yaml b/config.yaml
index 678e69b..b253652 100644
--- a/config.yaml
+++ b/config.yaml
@@ -5,3 +5,17 @@ options:
5 description: |5 description: |
6 If install_method is set to "snap" this option controlls channel name.6 If install_method is set to "snap" this option controlls channel name.
7 Supported values are: "stable", "candidate", "beta" and "edge"7 Supported values are: "stable", "candidate", "beta" and "edge"
8 nagios_context:
9 default: "juju"
10 type: string
11 description: |
12 A string that will be prepended to instance name to set the host name
13 in nagios. So for instance the hostname would be something like:
14 juju-myservice-0
15 If you're running multiple environments with the same services in them
16 this allows you to differentiate between them.
17 nagios_servicegroups:
18 default: "juju"
19 type: string
20 description: |
21 Comma separated list of nagios servicegroups
8\ No newline at end of file22\ No newline at end of file
diff --git a/files/grafana-dashboards/libvirt.json b/files/grafana-dashboards/libvirt.json
9new file mode 10064423new file mode 100644
index 0000000..6954193
--- /dev/null
+++ b/files/grafana-dashboards/libvirt.json
@@ -0,0 +1,1374 @@
1{
2 "dashboard": {
3 "annotations": {
4 "list": [
5 {
6 "builtIn": 1,
7 "datasource": "-- Grafana --",
8 "enable": true,
9 "hide": true,
10 "iconColor": "rgba(0, 211, 255, 1)",
11 "name": "Annotations & Alerts",
12 "type": "dashboard"
13 }
14 ]
15 },
16 "description": "Libvirt Cluster overview.",
17 "editable": true,
18 "gnetId": null,
19 "graphTooltip": 0,
20 "id": null,
21 "iteration": 1584700907234,
22 "links": [],
23 "panels": [
24 {
25 "collapsed": false,
26 "datasource": null,
27 "gridPos": {
28 "h": 1,
29 "w": 24,
30 "x": 0,
31 "y": 0
32 },
33 "id": 24,
34 "panels": [],
35 "title": "Info",
36 "type": "row"
37 },
38 {
39 "content": "\n# Important info\nIf you match very high number of hosts you may kill your browser and/or prometheus. See \"Matching targets\"\n\n\n",
40 "datasource": null,
41 "gridPos": {
42 "h": 4,
43 "w": 12,
44 "x": 0,
45 "y": 1
46 },
47 "id": 20,
48 "mode": "markdown",
49 "timeFrom": null,
50 "timeShift": null,
51 "title": "Panel Title",
52 "type": "text"
53 },
54 {
55 "cacheTimeout": null,
56 "colorBackground": true,
57 "colorValue": false,
58 "colors": [
59 "#73BF69",
60 "rgba(237, 129, 40, 0.89)",
61 "#d44a3a"
62 ],
63 "datasource": "prometheus - Juju generated source",
64 "format": "none",
65 "gauge": {
66 "maxValue": 100,
67 "minValue": 0,
68 "show": false,
69 "thresholdLabels": false,
70 "thresholdMarkers": true
71 },
72 "gridPos": {
73 "h": 4,
74 "w": 12,
75 "x": 12,
76 "y": 1
77 },
78 "id": 22,
79 "interval": null,
80 "links": [],
81 "mappingType": 1,
82 "mappingTypes": [
83 {
84 "name": "value to text",
85 "value": 1
86 },
87 {
88 "name": "range to text",
89 "value": 2
90 }
91 ],
92 "maxDataPoints": 100,
93 "nullPointMode": "connected",
94 "nullText": null,
95 "postfix": "",
96 "postfixFontSize": "50%",
97 "prefix": "",
98 "prefixFontSize": "50%",
99 "rangeMaps": [
100 {
101 "from": "null",
102 "text": "N/A",
103 "to": "null"
104 }
105 ],
106 "sparkline": {
107 "fillColor": "rgba(31, 118, 189, 0.18)",
108 "full": false,
109 "lineColor": "rgb(31, 120, 193)",
110 "show": false,
111 "ymax": null,
112 "ymin": null
113 },
114 "tableColumn": "",
115 "targets": [
116 {
117 "expr": "count(libvirt_up{instance=~\"$host\"})+count(libvirt_domain_info_virtual_cpus{domain=~\"$domain\"})",
118 "interval": "",
119 "legendFormat": "",
120 "refId": "A"
121 }
122 ],
123 "thresholds": "5,10",
124 "timeFrom": null,
125 "timeShift": null,
126 "title": "Matching targets",
127 "type": "singlestat",
128 "valueFontSize": "200%",
129 "valueMaps": [
130 {
131 "op": "=",
132 "text": "N/A",
133 "value": "null"
134 }
135 ],
136 "valueName": "current"
137 },
138 {
139 "collapsed": true,
140 "datasource": null,
141 "gridPos": {
142 "h": 1,
143 "w": 24,
144 "x": 0,
145 "y": 5
146 },
147 "id": 28,
148 "panels": [
149 {
150 "cacheTimeout": null,
151 "datasource": "prometheus - Juju generated source",
152 "gridPos": {
153 "h": 5,
154 "w": 12,
155 "x": 0,
156 "y": 6
157 },
158 "id": 10,
159 "links": [],
160 "options": {
161 "colorMode": "value",
162 "fieldOptions": {
163 "calcs": [
164 "last"
165 ],
166 "defaults": {
167 "mappings": [],
168 "thresholds": {
169 "mode": "absolute",
170 "steps": [
171 {
172 "color": "green",
173 "value": null
174 },
175 {
176 "color": "red",
177 "value": 80
178 }
179 ]
180 }
181 },
182 "overrides": [],
183 "values": false
184 },
185 "graphMode": "area",
186 "justifyMode": "auto",
187 "orientation": "auto"
188 },
189 "pluginVersion": "6.7.0",
190 "targets": [
191 {
192 "expr": "sum(libvirt_up{instance=~\"$host\"})",
193 "interval": "",
194 "legendFormat": "",
195 "refId": "A"
196 }
197 ],
198 "timeFrom": null,
199 "timeShift": null,
200 "title": "Virt Hosts",
201 "type": "stat"
202 },
203 {
204 "cacheTimeout": null,
205 "datasource": "prometheus - Juju generated source",
206 "gridPos": {
207 "h": 5,
208 "w": 12,
209 "x": 12,
210 "y": 6
211 },
212 "id": 8,
213 "links": [],
214 "options": {
215 "colorMode": "value",
216 "fieldOptions": {
217 "calcs": [
218 "mean"
219 ],
220 "defaults": {
221 "mappings": [],
222 "thresholds": {
223 "mode": "absolute",
224 "steps": [
225 {
226 "color": "green",
227 "value": null
228 },
229 {
230 "color": "red",
231 "value": 80
232 }
233 ]
234 }
235 },
236 "overrides": [],
237 "values": false
238 },
239 "graphMode": "area",
240 "justifyMode": "auto",
241 "orientation": "auto"
242 },
243 "pluginVersion": "6.7.0",
244 "targets": [
245 {
246 "expr": "sum(libvirt_domain_info_virtual_cpus{domain=~\"$domain\"})",
247 "interval": "",
248 "legendFormat": "",
249 "refId": "A"
250 }
251 ],
252 "timeFrom": null,
253 "timeShift": null,
254 "title": "Vcpus",
255 "type": "stat"
256 }
257 ],
258 "title": "Host & CPU",
259 "type": "row"
260 },
261 {
262 "collapsed": true,
263 "datasource": null,
264 "gridPos": {
265 "h": 1,
266 "w": 24,
267 "x": 0,
268 "y": 6
269 },
270 "id": 26,
271 "panels": [
272 {
273 "aliasColors": {},
274 "bars": true,
275 "cacheTimeout": null,
276 "dashLength": 10,
277 "dashes": false,
278 "datasource": "prometheus - Juju generated source",
279 "fill": 1,
280 "fillGradient": 0,
281 "gridPos": {
282 "h": 7,
283 "w": 12,
284 "x": 0,
285 "y": 7
286 },
287 "hiddenSeries": false,
288 "id": 6,
289 "legend": {
290 "avg": false,
291 "current": false,
292 "max": false,
293 "min": false,
294 "show": true,
295 "total": false,
296 "values": false
297 },
298 "lines": false,
299 "linewidth": 1,
300 "links": [],
301 "nullPointMode": "null",
302 "options": {
303 "dataLinks": []
304 },
305 "percentage": false,
306 "pluginVersion": "6.6.2",
307 "pointradius": 2,
308 "points": false,
309 "renderer": "flot",
310 "seriesOverrides": [],
311 "spaceLength": 10,
312 "stack": false,
313 "steppedLine": false,
314 "targets": [
315 {
316 "expr": "libvirt_domain_info_maximum_memory_bytes{domain=~\"$domain\"}/1024/1024",
317 "interval": "",
318 "legendFormat": "{{host}} - {{domain}}",
319 "refId": "A"
320 }
321 ],
322 "thresholds": [],
323 "timeFrom": null,
324 "timeRegions": [],
325 "timeShift": null,
326 "title": "Memory Usage",
327 "tooltip": {
328 "shared": true,
329 "sort": 0,
330 "value_type": "individual"
331 },
332 "type": "graph",
333 "xaxis": {
334 "buckets": null,
335 "mode": "time",
336 "name": null,
337 "show": true,
338 "values": []
339 },
340 "yaxes": [
341 {
342 "format": "short",
343 "label": null,
344 "logBase": 1,
345 "max": null,
346 "min": null,
347 "show": true
348 },
349 {
350 "format": "short",
351 "label": null,
352 "logBase": 1,
353 "max": null,
354 "min": null,
355 "show": true
356 }
357 ],
358 "yaxis": {
359 "align": false,
360 "alignLevel": null
361 }
362 },
363 {
364 "cacheTimeout": null,
365 "colorBackground": false,
366 "colorValue": false,
367 "colors": [
368 "#299c46",
369 "rgba(237, 129, 40, 0.89)",
370 "#d44a3a"
371 ],
372 "datasource": "prometheus - Juju generated source",
373 "description": "",
374 "format": "none",
375 "gauge": {
376 "maxValue": 100,
377 "minValue": 0,
378 "show": false,
379 "thresholdLabels": false,
380 "thresholdMarkers": true
381 },
382 "gridPos": {
383 "h": 7,
384 "w": 12,
385 "x": 12,
386 "y": 7
387 },
388 "id": 38,
389 "interval": null,
390 "links": [],
391 "mappingType": 1,
392 "mappingTypes": [
393 {
394 "name": "value to text",
395 "value": 1
396 },
397 {
398 "name": "range to text",
399 "value": 2
400 }
401 ],
402 "maxDataPoints": 100,
403 "nullPointMode": "connected",
404 "nullText": null,
405 "postfix": "",
406 "postfixFontSize": "50%",
407 "prefix": "",
408 "prefixFontSize": "50%",
409 "rangeMaps": [
410 {
411 "from": "null",
412 "text": "N/A",
413 "to": "null"
414 }
415 ],
416 "sparkline": {
417 "fillColor": "rgba(31, 118, 189, 0.18)",
418 "full": false,
419 "lineColor": "rgb(31, 120, 193)",
420 "show": false,
421 "ymax": null,
422 "ymin": null
423 },
424 "tableColumn": "",
425 "targets": [
426 {
427 "expr": "sum(libvirt_domain_info_memory_usage_bytes)/1024/1024/1024",
428 "interval": "",
429 "legendFormat": "Total Memory Usage",
430 "refId": "A"
431 }
432 ],
433 "thresholds": "",
434 "timeFrom": null,
435 "timeShift": null,
436 "title": "Total Memory Usage GB",
437 "type": "singlestat",
438 "valueFontSize": "200%",
439 "valueMaps": [
440 {
441 "op": "=",
442 "text": "N/A",
443 "value": "null"
444 }
445 ],
446 "valueName": "avg"
447 }
448 ],
449 "title": "Memory",
450 "type": "row"
451 },
452 {
453 "collapsed": true,
454 "datasource": null,
455 "gridPos": {
456 "h": 1,
457 "w": 24,
458 "x": 0,
459 "y": 7
460 },
461 "id": 30,
462 "panels": [
463 {
464 "aliasColors": {},
465 "bars": false,
466 "cacheTimeout": null,
467 "dashLength": 10,
468 "dashes": false,
469 "datasource": "prometheus - Juju generated source",
470 "fill": 2,
471 "fillGradient": 0,
472 "gridPos": {
473 "h": 7,
474 "w": 12,
475 "x": 0,
476 "y": 8
477 },
478 "hiddenSeries": false,
479 "id": 12,
480 "legend": {
481 "alignAsTable": false,
482 "avg": false,
483 "current": false,
484 "max": false,
485 "min": false,
486 "show": true,
487 "total": false,
488 "values": false
489 },
490 "lines": true,
491 "linewidth": 1,
492 "links": [],
493 "nullPointMode": "null",
494 "options": {
495 "dataLinks": []
496 },
497 "percentage": false,
498 "pluginVersion": "6.6.2",
499 "pointradius": 2,
500 "points": false,
501 "renderer": "flot",
502 "seriesOverrides": [],
503 "spaceLength": 10,
504 "stack": true,
505 "steppedLine": false,
506 "targets": [
507 {
508 "expr": "sum(libvirt_domain_interface_stats_transmit_bytes_total{domain=~\"$domain\"})",
509 "format": "time_series",
510 "interval": "",
511 "intervalFactor": 2,
512 "legendFormat": "TX",
513 "refId": "A"
514 },
515 {
516 "expr": "sum(libvirt_domain_interface_stats_receive_bytes_total{domain=~\"$domain\"})",
517 "interval": "",
518 "intervalFactor": 2,
519 "legendFormat": "RX",
520 "refId": "B"
521 }
522 ],
523 "thresholds": [],
524 "timeFrom": null,
525 "timeRegions": [],
526 "timeShift": null,
527 "title": "Network RX/TX Throughput",
528 "tooltip": {
529 "shared": true,
530 "sort": 0,
531 "value_type": "individual"
532 },
533 "type": "graph",
534 "xaxis": {
535 "buckets": null,
536 "mode": "time",
537 "name": null,
538 "show": true,
539 "values": []
540 },
541 "yaxes": [
542 {
543 "format": "short",
544 "label": "KiloByes",
545 "logBase": 1,
546 "max": null,
547 "min": null,
548 "show": true
549 },
550 {
551 "format": "short",
552 "label": "",
553 "logBase": 1,
554 "max": null,
555 "min": null,
556 "show": true
557 }
558 ],
559 "yaxis": {
560 "align": false,
561 "alignLevel": null
562 }
563 },
564 {
565 "aliasColors": {},
566 "bars": false,
567 "dashLength": 10,
568 "dashes": false,
569 "datasource": "prometheus - Juju generated source",
570 "fill": 1,
571 "fillGradient": 0,
572 "gridPos": {
573 "h": 7,
574 "w": 12,
575 "x": 12,
576 "y": 8
577 },
578 "hiddenSeries": false,
579 "id": 16,
580 "legend": {
581 "avg": false,
582 "current": false,
583 "max": false,
584 "min": false,
585 "show": true,
586 "total": false,
587 "values": false
588 },
589 "lines": true,
590 "linewidth": 1,
591 "nullPointMode": "null",
592 "options": {
593 "dataLinks": []
594 },
595 "percentage": false,
596 "pointradius": 2,
597 "points": false,
598 "renderer": "flot",
599 "seriesOverrides": [],
600 "spaceLength": 10,
601 "stack": false,
602 "steppedLine": false,
603 "targets": [
604 {
605 "expr": "sum(libvirt_domain_interface_stats_receive_drops_total{domain=~\"$domain\"})",
606 "interval": "",
607 "legendFormat": "RX drops",
608 "refId": "A"
609 },
610 {
611 "expr": "sum(libvirt_domain_interface_stats_receive_errors_total{domain=~\"$domain\"})",
612 "interval": "",
613 "legendFormat": "RX errors",
614 "refId": "B"
615 }
616 ],
617 "thresholds": [],
618 "timeFrom": null,
619 "timeRegions": [],
620 "timeShift": null,
621 "title": "Network Receive Errors/Drops",
622 "tooltip": {
623 "shared": true,
624 "sort": 0,
625 "value_type": "individual"
626 },
627 "type": "graph",
628 "xaxis": {
629 "buckets": null,
630 "mode": "time",
631 "name": null,
632 "show": true,
633 "values": []
634 },
635 "yaxes": [
636 {
637 "format": "short",
638 "label": "Total",
639 "logBase": 1,
640 "max": null,
641 "min": null,
642 "show": true
643 },
644 {
645 "format": "short",
646 "label": null,
647 "logBase": 1,
648 "max": null,
649 "min": null,
650 "show": true
651 }
652 ],
653 "yaxis": {
654 "align": false,
655 "alignLevel": null
656 }
657 },
658 {
659 "columns": [],
660 "datasource": "prometheus - Juju generated source",
661 "fontSize": "100%",
662 "gridPos": {
663 "h": 7,
664 "w": 12,
665 "x": 0,
666 "y": 15
667 },
668 "id": 34,
669 "pageSize": null,
670 "showHeader": true,
671 "sort": {
672 "col": 0,
673 "desc": true
674 },
675 "styles": [
676 {
677 "alias": "",
678 "align": "auto",
679 "colorMode": null,
680 "colors": [
681 "rgba(245, 54, 54, 0.9)",
682 "rgba(237, 129, 40, 0.89)",
683 "rgba(50, 172, 45, 0.97)"
684 ],
685 "dateFormat": "YYYY-MM-DD HH:mm:ss",
686 "decimals": 2,
687 "mappingType": 1,
688 "pattern": "Time",
689 "thresholds": [],
690 "type": "hidden",
691 "unit": "short"
692 },
693 {
694 "alias": "Source",
695 "align": "auto",
696 "colorMode": null,
697 "colors": [
698 "rgba(245, 54, 54, 0.9)",
699 "rgba(237, 129, 40, 0.89)",
700 "rgba(50, 172, 45, 0.97)"
701 ],
702 "dateFormat": "YYYY-MM-DD HH:mm:ss",
703 "decimals": 2,
704 "mappingType": 1,
705 "pattern": "Metric",
706 "thresholds": [],
707 "type": "number",
708 "unit": "short"
709 },
710 {
711 "alias": "Read bytes total",
712 "align": "auto",
713 "colorMode": null,
714 "colors": [
715 "rgba(245, 54, 54, 0.9)",
716 "rgba(237, 129, 40, 0.89)",
717 "rgba(50, 172, 45, 0.97)"
718 ],
719 "dateFormat": "YYYY-MM-DD HH:mm:ss",
720 "decimals": 2,
721 "mappingType": 1,
722 "pattern": "Value",
723 "thresholds": [],
724 "type": "number",
725 "unit": "short"
726 },
727 {
728 "alias": "",
729 "align": "right",
730 "colorMode": null,
731 "colors": [
732 "rgba(245, 54, 54, 0.9)",
733 "rgba(237, 129, 40, 0.89)",
734 "rgba(50, 172, 45, 0.97)"
735 ],
736 "decimals": 2,
737 "pattern": "/.*/",
738 "thresholds": [],
739 "type": "number",
740 "unit": "short"
741 }
742 ],
743 "targets": [
744 {
745 "expr": "libvirt_domain_block_stats_read_bytes_total{instance=~\"$host\"}",
746 "interval": "",
747 "legendFormat": "{{instance}} - {{domain}}",
748 "refId": "A"
749 }
750 ],
751 "timeFrom": null,
752 "timeShift": null,
753 "title": "Instance Read Bytes Total",
754 "transform": "timeseries_to_rows",
755 "type": "table"
756 },
757 {
758 "aliasColors": {},
759 "bars": false,
760 "dashLength": 10,
761 "dashes": false,
762 "datasource": "prometheus - Juju generated source",
763 "fill": 1,
764 "fillGradient": 0,
765 "gridPos": {
766 "h": 7,
767 "w": 12,
768 "x": 12,
769 "y": 15
770 },
771 "hiddenSeries": false,
772 "id": 14,
773 "legend": {
774 "avg": false,
775 "current": false,
776 "max": false,
777 "min": false,
778 "show": true,
779 "total": false,
780 "values": false
781 },
782 "lines": true,
783 "linewidth": 1,
784 "nullPointMode": "null",
785 "options": {
786 "dataLinks": []
787 },
788 "percentage": false,
789 "pointradius": 2,
790 "points": false,
791 "renderer": "flot",
792 "seriesOverrides": [],
793 "spaceLength": 10,
794 "stack": false,
795 "steppedLine": false,
796 "targets": [
797 {
798 "expr": "sum(libvirt_domain_interface_stats_transmit_drops_total{domain=~\"$domain\"})",
799 "interval": "",
800 "legendFormat": "TX drops",
801 "refId": "A"
802 },
803 {
804 "expr": "sum(libvirt_domain_interface_stats_transmit_errors_total{domain=~\"$domain\"})",
805 "interval": "",
806 "legendFormat": "RX drops",
807 "refId": "B"
808 }
809 ],
810 "thresholds": [],
811 "timeFrom": null,
812 "timeRegions": [],
813 "timeShift": null,
814 "title": "Network Transmit Errors/Drops",
815 "tooltip": {
816 "shared": true,
817 "sort": 0,
818 "value_type": "individual"
819 },
820 "type": "graph",
821 "xaxis": {
822 "buckets": null,
823 "mode": "time",
824 "name": null,
825 "show": true,
826 "values": []
827 },
828 "yaxes": [
829 {
830 "format": "short",
831 "label": "Total",
832 "logBase": 1,
833 "max": null,
834 "min": null,
835 "show": true
836 },
837 {
838 "format": "short",
839 "label": null,
840 "logBase": 1,
841 "max": null,
842 "min": null,
843 "show": true
844 }
845 ],
846 "yaxis": {
847 "align": false,
848 "alignLevel": null
849 }
850 },
851 {
852 "columns": [],
853 "datasource": "prometheus - Juju generated source",
854 "fontSize": "100%",
855 "gridPos": {
856 "h": 7,
857 "w": 12,
858 "x": 0,
859 "y": 22
860 },
861 "id": 36,
862 "pageSize": null,
863 "showHeader": true,
864 "sort": {
865 "col": 0,
866 "desc": true
867 },
868 "styles": [
869 {
870 "alias": "",
871 "align": "auto",
872 "colorMode": null,
873 "colors": [
874 "rgba(245, 54, 54, 0.9)",
875 "rgba(237, 129, 40, 0.89)",
876 "rgba(50, 172, 45, 0.97)"
877 ],
878 "dateFormat": "YYYY-MM-DD HH:mm:ss",
879 "decimals": 2,
880 "mappingType": 1,
881 "pattern": "Time",
882 "thresholds": [],
883 "type": "hidden",
884 "unit": "short"
885 },
886 {
887 "alias": "Source",
888 "align": "auto",
889 "colorMode": null,
890 "colors": [
891 "rgba(245, 54, 54, 0.9)",
892 "rgba(237, 129, 40, 0.89)",
893 "rgba(50, 172, 45, 0.97)"
894 ],
895 "dateFormat": "YYYY-MM-DD HH:mm:ss",
896 "decimals": 2,
897 "mappingType": 1,
898 "pattern": "Metric",
899 "thresholds": [],
900 "type": "number",
901 "unit": "short"
902 },
903 {
904 "alias": "Write bytes total",
905 "align": "auto",
906 "colorMode": null,
907 "colors": [
908 "rgba(245, 54, 54, 0.9)",
909 "rgba(237, 129, 40, 0.89)",
910 "rgba(50, 172, 45, 0.97)"
911 ],
912 "dateFormat": "YYYY-MM-DD HH:mm:ss",
913 "decimals": 2,
914 "mappingType": 1,
915 "pattern": "Value",
916 "thresholds": [],
917 "type": "number",
918 "unit": "short"
919 },
920 {
921 "alias": "",
922 "align": "right",
923 "colorMode": null,
924 "colors": [
925 "rgba(245, 54, 54, 0.9)",
926 "rgba(237, 129, 40, 0.89)",
927 "rgba(50, 172, 45, 0.97)"
928 ],
929 "decimals": 2,
930 "pattern": "/.*/",
931 "thresholds": [],
932 "type": "number",
933 "unit": "short"
934 }
935 ],
936 "targets": [
937 {
938 "expr": "libvirt_domain_block_stats_write_bytes_total{instance=~\"$host\"}",
939 "interval": "",
940 "legendFormat": "{{instance}} - {{domain}}",
941 "refId": "A"
942 }
943 ],
944 "timeFrom": null,
945 "timeShift": null,
946 "title": "Instance Write Bytes Total",
947 "transform": "timeseries_to_rows",
948 "type": "table"
949 }
950 ],
951 "title": "Network",
952 "type": "row"
953 },
954 {
955 "collapsed": true,
956 "datasource": null,
957 "gridPos": {
958 "h": 1,
959 "w": 24,
960 "x": 0,
961 "y": 8
962 },
963 "id": 32,
964 "panels": [
965 {
966 "aliasColors": {},
967 "bars": false,
968 "dashLength": 10,
969 "dashes": false,
970 "datasource": "prometheus - Juju generated source",
971 "fill": 5,
972 "fillGradient": 5,
973 "gridPos": {
974 "h": 7,
975 "w": 12,
976 "x": 0,
977 "y": 9
978 },
979 "hiddenSeries": false,
980 "id": 4,
981 "legend": {
982 "avg": false,
983 "current": false,
984 "max": false,
985 "min": false,
986 "show": true,
987 "total": false,
988 "values": false
989 },
990 "lines": true,
991 "linewidth": 2,
992 "nullPointMode": "null",
993 "options": {
994 "dataLinks": []
995 },
996 "percentage": false,
997 "pluginVersion": "6.7.0",
998 "pointradius": 2,
999 "points": false,
1000 "renderer": "flot",
1001 "seriesOverrides": [],
1002 "spaceLength": 10,
1003 "stack": false,
1004 "steppedLine": false,
1005 "targets": [
1006 {
1007 "expr": "libvirt_domain_block_stats_write_bytes_total{domain=~\"$domain\"}/1024/1024",
1008 "interval": "",
1009 "legendFormat": "{{instance}} - {{domain}}",
1010 "refId": "A"
1011 }
1012 ],
1013 "thresholds": [],
1014 "timeFrom": null,
1015 "timeRegions": [],
1016 "timeShift": null,
1017 "title": "Disk Write",
1018 "tooltip": {
1019 "shared": true,
1020 "sort": 0,
1021 "value_type": "individual"
1022 },
1023 "type": "graph",
1024 "xaxis": {
1025 "buckets": null,
1026 "mode": "time",
1027 "name": null,
1028 "show": true,
1029 "values": []
1030 },
1031 "yaxes": [
1032 {
1033 "format": "short",
1034 "label": null,
1035 "logBase": 1,
1036 "max": null,
1037 "min": null,
1038 "show": true
1039 },
1040 {
1041 "format": "short",
1042 "label": null,
1043 "logBase": 1,
1044 "max": null,
1045 "min": null,
1046 "show": true
1047 }
1048 ],
1049 "yaxis": {
1050 "align": false,
1051 "alignLevel": null
1052 }
1053 },
1054 {
1055 "aliasColors": {},
1056 "bars": false,
1057 "dashLength": 10,
1058 "dashes": false,
1059 "datasource": "prometheus - Juju generated source",
1060 "fill": 5,
1061 "fillGradient": 5,
1062 "gridPos": {
1063 "h": 7,
1064 "w": 12,
1065 "x": 12,
1066 "y": 9
1067 },
1068 "hiddenSeries": false,
1069 "id": 40,
1070 "legend": {
1071 "avg": false,
1072 "current": false,
1073 "max": false,
1074 "min": false,
1075 "show": true,
1076 "total": false,
1077 "values": false
1078 },
1079 "lines": true,
1080 "linewidth": 2,
1081 "nullPointMode": "null",
1082 "options": {
1083 "dataLinks": []
1084 },
1085 "percentage": false,
1086 "pluginVersion": "6.7.0",
1087 "pointradius": 2,
1088 "points": false,
1089 "renderer": "flot",
1090 "seriesOverrides": [],
1091 "spaceLength": 10,
1092 "stack": false,
1093 "steppedLine": false,
1094 "targets": [
1095 {
1096 "expr": "libvirt_domain_block_stats_read_bytes_total{domain=~\"$domain\"}/1024/1024",
1097 "interval": "",
1098 "legendFormat": "{{instance}} - {{domain}}",
1099 "refId": "A"
1100 }
1101 ],
1102 "thresholds": [],
1103 "timeFrom": null,
1104 "timeRegions": [],
1105 "timeShift": null,
1106 "title": "Disk Read",
1107 "tooltip": {
1108 "shared": true,
1109 "sort": 0,
1110 "value_type": "individual"
1111 },
1112 "type": "graph",
1113 "xaxis": {
1114 "buckets": null,
1115 "mode": "time",
1116 "name": null,
1117 "show": true,
1118 "values": []
1119 },
1120 "yaxes": [
1121 {
1122 "format": "short",
1123 "label": null,
1124 "logBase": 1,
1125 "max": null,
1126 "min": null,
1127 "show": true
1128 },
1129 {
1130 "format": "short",
1131 "label": null,
1132 "logBase": 1,
1133 "max": null,
1134 "min": null,
1135 "show": true
1136 }
1137 ],
1138 "yaxis": {
1139 "align": false,
1140 "alignLevel": null
1141 }
1142 },
1143 {
1144 "cacheTimeout": null,
1145 "datasource": "prometheus - Juju generated source",
1146 "gridPos": {
1147 "h": 7,
1148 "w": 12,
1149 "x": 0,
1150 "y": 16
1151 },
1152 "id": 44,
1153 "links": [],
1154 "options": {
1155 "fieldOptions": {
1156 "calcs": [
1157 "last"
1158 ],
1159 "defaults": {
1160 "mappings": [
1161 {
1162 "id": 0,
1163 "op": "=",
1164 "text": "N/A",
1165 "type": 1,
1166 "value": "null"
1167 }
1168 ],
1169 "nullValueMode": "connected",
1170 "thresholds": {
1171 "mode": "absolute",
1172 "steps": [
1173 {
1174 "color": "green",
1175 "value": null
1176 },
1177 {
1178 "color": "red",
1179 "value": 80
1180 }
1181 ]
1182 },
1183 "title": "MB / sec",
1184 "unit": "none"
1185 },
1186 "overrides": [],
1187 "values": false
1188 },
1189 "orientation": "horizontal",
1190 "showThresholdLabels": false,
1191 "showThresholdMarkers": true
1192 },
1193 "pluginVersion": "6.7.0",
1194 "targets": [
1195 {
1196 "expr": "sum(libvirt_domain_block_stats_write_bytes_total)/1024/1024",
1197 "format": "heatmap",
1198 "hide": false,
1199 "instant": false,
1200 "interval": "",
1201 "intervalFactor": 1,
1202 "legendFormat": "",
1203 "refId": "A"
1204 }
1205 ],
1206 "timeFrom": null,
1207 "timeShift": null,
1208 "title": "Disk Cumulative Write",
1209 "type": "gauge"
1210 },
1211 {
1212 "cacheTimeout": null,
1213 "datasource": "prometheus - Juju generated source",
1214 "gridPos": {
1215 "h": 7,
1216 "w": 12,
1217 "x": 12,
1218 "y": 16
1219 },
1220 "id": 2,
1221 "links": [],
1222 "options": {
1223 "fieldOptions": {
1224 "calcs": [
1225 "mean"
1226 ],
1227 "defaults": {
1228 "mappings": [
1229 {
1230 "id": 0,
1231 "op": "=",
1232 "text": "N/A",
1233 "type": 1,
1234 "value": "null"
1235 }
1236 ],
1237 "nullValueMode": "connected",
1238 "thresholds": {
1239 "mode": "absolute",
1240 "steps": [
1241 {
1242 "color": "green",
1243 "value": null
1244 },
1245 {
1246 "color": "red",
1247 "value": 80
1248 }
1249 ]
1250 },
1251 "title": "MB",
1252 "unit": "none"
1253 },
1254 "overrides": [],
1255 "values": false
1256 },
1257 "orientation": "horizontal",
1258 "showThresholdLabels": false,
1259 "showThresholdMarkers": true
1260 },
1261 "pluginVersion": "6.7.0",
1262 "targets": [
1263 {
1264 "expr": "sum(libvirt_domain_block_stats_read_bytes_total)/1024/1024",
1265 "format": "heatmap",
1266 "hide": false,
1267 "instant": false,
1268 "intervalFactor": 1,
1269 "legendFormat": "Read {{instance}}",
1270 "refId": "A"
1271 }
1272 ],
1273 "timeFrom": null,
1274 "timeShift": null,
1275 "title": "Disk Cumulative Read",
1276 "type": "gauge"
1277 }
1278 ],
1279 "title": "Disk",
1280 "type": "row"
1281 }
1282 ],
1283 "refresh": "5s",
1284 "schemaVersion": 22,
1285 "style": "dark",
1286 "tags": [],
1287 "templating": {
1288 "list": [
1289 {
1290 "allValue": null,
1291 "current": {
1292 "text": "All",
1293 "value": [
1294 "$__all"
1295 ]
1296 },
1297 "datasource": "prometheus - Juju generated source",
1298 "definition": "libvirt_up",
1299 "hide": 0,
1300 "includeAll": true,
1301 "index": -1,
1302 "label": "libvirt daemon",
1303 "multi": true,
1304 "name": "host",
1305 "options": [],
1306 "query": "libvirt_up",
1307 "refresh": 1,
1308 "regex": ".*instance=\"([^\"]+).*?\".*$",
1309 "skipUrlSync": false,
1310 "sort": 0,
1311 "tagValuesQuery": "",
1312 "tags": [],
1313 "tagsQuery": "",
1314 "type": "query",
1315 "useTags": false
1316 },
1317 {
1318 "allValue": null,
1319 "current": {
1320 "tags": [],
1321 "text": "All",
1322 "value": [
1323 "$__all"
1324 ]
1325 },
1326 "datasource": "prometheus - Juju generated source",
1327 "definition": "libvirt_domain_info_virtual_cpus",
1328 "hide": 0,
1329 "includeAll": true,
1330 "index": -1,
1331 "label": null,
1332 "multi": true,
1333 "name": "domain",
1334 "options": [],
1335 "query": "libvirt_domain_info_virtual_cpus",
1336 "refresh": 1,
1337 "regex": ".*domain=\"([^\"]+)\".*$",
1338 "skipUrlSync": false,
1339 "sort": 1,
1340 "tagValuesQuery": "",
1341 "tags": [],
1342 "tagsQuery": "",
1343 "type": "query",
1344 "useTags": false
1345 }
1346 ]
1347 },
1348 "time": {
1349 "from": "now-1h",
1350 "to": "now"
1351 },
1352 "timepicker": {
1353 "refresh_intervals": [
1354 "5s",
1355 "10s",
1356 "30s",
1357 "1m",
1358 "5m",
1359 "15m",
1360 "30m",
1361 "1h",
1362 "2h",
1363 "1d"
1364 ]
1365 },
1366 "timezone": "",
1367 "title": "libvirt",
1368 "uid": "u_Zk_wuZk",
1369 "variables": {
1370 "list": []
1371 },
1372 "version": 288
1373 }
1374}
diff --git a/icon.svg b/icon.svg
0new file mode 1006441375new file mode 100644
index 0000000..96a5d0c
--- /dev/null
+++ b/icon.svg
@@ -0,0 +1,279 @@
1<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2<!-- Created with Inkscape (http://www.inkscape.org/) -->
3
4<svg
5 xmlns:dc="http://purl.org/dc/elements/1.1/"
6 xmlns:cc="http://creativecommons.org/ns#"
7 xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
8 xmlns:svg="http://www.w3.org/2000/svg"
9 xmlns="http://www.w3.org/2000/svg"
10 xmlns:xlink="http://www.w3.org/1999/xlink"
11 xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
12 xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
13 width="96"
14 height="96"
15 id="svg6517"
16 version="1.1"
17 inkscape:version="0.48+devel r12274"
18 sodipodi:docname="Juju_charm_icon_template.svg">
19 <defs
20 id="defs6519">
21 <linearGradient
22 inkscape:collect="always"
23 xlink:href="#Background"
24 id="linearGradient6461"
25 gradientUnits="userSpaceOnUse"
26 x1="0"
27 y1="970.29498"
28 x2="144"
29 y2="970.29498"
30 gradientTransform="matrix(0,-0.66666669,0.6660448,0,-866.25992,731.29077)" />
31 <linearGradient
32 id="Background">
33 <stop
34 id="stop4178"
35 offset="0"
36 style="stop-color:#b8b8b8;stop-opacity:1" />
37 <stop
38 id="stop4180"
39 offset="1"
40 style="stop-color:#c9c9c9;stop-opacity:1" />
41 </linearGradient>
42 <filter
43 style="color-interpolation-filters:sRGB;"
44 inkscape:label="Inner Shadow"
45 id="filter1121">
46 <feFlood
47 flood-opacity="0.59999999999999998"
48 flood-color="rgb(0,0,0)"
49 result="flood"
50 id="feFlood1123" />
51 <feComposite
52 in="flood"
53 in2="SourceGraphic"
54 operator="out"
55 result="composite1"
56 id="feComposite1125" />
57 <feGaussianBlur
58 in="composite1"
59 stdDeviation="1"
60 result="blur"
61 id="feGaussianBlur1127" />
62 <feOffset
63 dx="0"
64 dy="2"
65 result="offset"
66 id="feOffset1129" />
67 <feComposite
68 in="offset"
69 in2="SourceGraphic"
70 operator="atop"
71 result="composite2"
72 id="feComposite1131" />
73 </filter>
74 <filter
75 style="color-interpolation-filters:sRGB;"
76 inkscape:label="Drop Shadow"
77 id="filter950">
78 <feFlood
79 flood-opacity="0.25"
80 flood-color="rgb(0,0,0)"
81 result="flood"
82 id="feFlood952" />
83 <feComposite
84 in="flood"
85 in2="SourceGraphic"
86 operator="in"
87 result="composite1"
88 id="feComposite954" />
89 <feGaussianBlur
90 in="composite1"
91 stdDeviation="1"
92 result="blur"
93 id="feGaussianBlur956" />
94 <feOffset
95 dx="0"
96 dy="1"
97 result="offset"
98 id="feOffset958" />
99 <feComposite
100 in="SourceGraphic"
101 in2="offset"
102 operator="over"
103 result="composite2"
104 id="feComposite960" />
105 </filter>
106 <clipPath
107 clipPathUnits="userSpaceOnUse"
108 id="clipPath873">
109 <g
110 transform="matrix(0,-0.66666667,0.66604479,0,-258.25992,677.00001)"
111 id="g875"
112 inkscape:label="Layer 1"
113 style="fill:#ff00ff;fill-opacity:1;stroke:none;display:inline">
114 <path
115 style="fill:#ff00ff;fill-opacity:1;stroke:none;display:inline"
116 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"
117 id="path877"
118 inkscape:connector-curvature="0"
119 sodipodi:nodetypes="sssssssss" />
120 </g>
121 </clipPath>
122 <filter
123 inkscape:collect="always"
124 id="filter891"
125 inkscape:label="Badge Shadow">
126 <feGaussianBlur
127 inkscape:collect="always"
128 stdDeviation="0.71999962"
129 id="feGaussianBlur893" />
130 </filter>
131 </defs>
132 <sodipodi:namedview
133 id="base"
134 pagecolor="#ffffff"
135 bordercolor="#666666"
136 borderopacity="1.0"
137 inkscape:pageopacity="0.0"
138 inkscape:pageshadow="2"
139 inkscape:zoom="4.0745362"
140 inkscape:cx="18.514671"
141 inkscape:cy="49.018169"
142 inkscape:document-units="px"
143 inkscape:current-layer="layer1"
144 showgrid="true"
145 fit-margin-top="0"
146 fit-margin-left="0"
147 fit-margin-right="0"
148 fit-margin-bottom="0"
149 inkscape:window-width="1920"
150 inkscape:window-height="1029"
151 inkscape:window-x="0"
152 inkscape:window-y="24"
153 inkscape:window-maximized="1"
154 showborder="true"
155 showguides="true"
156 inkscape:guide-bbox="true"
157 inkscape:showpageshadow="false">
158 <inkscape:grid
159 type="xygrid"
160 id="grid821" />
161 <sodipodi:guide
162 orientation="1,0"
163 position="16,48"
164 id="guide823" />
165 <sodipodi:guide
166 orientation="0,1"
167 position="64,80"
168 id="guide825" />
169 <sodipodi:guide
170 orientation="1,0"
171 position="80,40"
172 id="guide827" />
173 <sodipodi:guide
174 orientation="0,1"
175 position="64,16"
176 id="guide829" />
177 </sodipodi:namedview>
178 <metadata
179 id="metadata6522">
180 <rdf:RDF>
181 <cc:Work
182 rdf:about="">
183 <dc:format>image/svg+xml</dc:format>
184 <dc:type
185 rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
186 <dc:title></dc:title>
187 </cc:Work>
188 </rdf:RDF>
189 </metadata>
190 <g
191 inkscape:label="BACKGROUND"
192 inkscape:groupmode="layer"
193 id="layer1"
194 transform="translate(268,-635.29076)"
195 style="display:inline">
196 <path
197 style="fill:url(#linearGradient6461);fill-opacity:1;stroke:none;display:inline;filter:url(#filter1121)"
198 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"
199 id="path6455"
200 inkscape:connector-curvature="0"
201 sodipodi:nodetypes="sssssssss" />
202 </g>
203 <g
204 inkscape:groupmode="layer"
205 id="layer3"
206 inkscape:label="PLACE YOUR PICTOGRAM HERE"
207 style="display:inline" />
208 <g
209 inkscape:groupmode="layer"
210 id="layer2"
211 inkscape:label="BADGE"
212 style="display:none"
213 sodipodi:insensitive="true">
214 <g
215 style="display:inline"
216 transform="translate(-340.00001,-581)"
217 id="g4394"
218 clip-path="none">
219 <g
220 id="g855">
221 <g
222 inkscape:groupmode="maskhelper"
223 id="g870"
224 clip-path="url(#clipPath873)"
225 style="opacity:0.6;filter:url(#filter891)">
226 <path
227 transform="matrix(1.4999992,0,0,1.4999992,-29.999795,-237.54282)"
228 d="m 264,552.36218 a 12,12 0 1 1 -24,0 A 12,12 0 1 1 264,552.36218 Z"
229 sodipodi:ry="12"
230 sodipodi:rx="12"
231 sodipodi:cy="552.36218"
232 sodipodi:cx="252"
233 id="path844"
234 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"
235 sodipodi:type="arc" />
236 </g>
237 <g
238 id="g862">
239 <path
240 sodipodi:type="arc"
241 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"
242 id="path4398"
243 sodipodi:cx="252"
244 sodipodi:cy="552.36218"
245 sodipodi:rx="12"
246 sodipodi:ry="12"
247 d="m 264,552.36218 a 12,12 0 1 1 -24,0 A 12,12 0 1 1 264,552.36218 Z"
248 transform="matrix(1.4999992,0,0,1.4999992,-29.999795,-238.54282)" />
249 <path
250 transform="matrix(1.25,0,0,1.25,33,-100.45273)"
251 d="m 264,552.36218 a 12,12 0 1 1 -24,0 A 12,12 0 1 1 264,552.36218 Z"
252 sodipodi:ry="12"
253 sodipodi:rx="12"
254 sodipodi:cy="552.36218"
255 sodipodi:cx="252"
256 id="path4400"
257 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"
258 sodipodi:type="arc" />
259 <path
260 sodipodi:type="star"
261 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"
262 id="path4459"
263 sodipodi:sides="5"
264 sodipodi:cx="666.19574"
265 sodipodi:cy="589.50385"
266 sodipodi:r1="7.2431178"
267 sodipodi:r2="4.3458705"
268 sodipodi:arg1="1.0471976"
269 sodipodi:arg2="1.6755161"
270 inkscape:flatsided="false"
271 inkscape:rounded="0.1"
272 inkscape:randomized="0"
273 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"
274 transform="matrix(1.511423,-0.16366377,0.16366377,1.511423,-755.37346,-191.93651)" />
275 </g>
276 </g>
277 </g>
278 </g>
279</svg>
diff --git a/interfaces/.empty b/interfaces/.empty
0new file mode 100644280new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/interfaces/.empty
diff --git a/layer.yaml b/layer.yaml
index b289219..8617d82 100644
--- a/layer.yaml
+++ b/layer.yaml
@@ -1,6 +1,13 @@
1includes: ['layer:basic', 'interface:http', 'layer:snap']1includes:
2 - layer:basic
3 - interface:http
4 - layer:snap
5 - interface:juju-info
6 - interface:nrpe-external-master
7 - interface:grafana-dashboard
8 - layer:leadership
2ignore: ['.*.swp' ]9ignore: ['.*.swp' ]
3options:10options:
4 basic:11 basic:
5 use_venv: true12 use_venv: true
6repo: https://git.launchpad.net/prometheus-libvirt-exporter-charm13repo: https://git.launchpad.net/prometheus-libvirt-exporter-charm
diff --git a/layers/.empty b/layers/.empty
7new file mode 10064414new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/layers/.empty
diff --git a/metadata.yaml b/metadata.yaml
index 1d2bfb4..3c8e44b 100644
--- a/metadata.yaml
+++ b/metadata.yaml
@@ -8,6 +8,7 @@ description: |
8series:8series:
9 - xenial9 - xenial
10 - bionic10 - bionic
11 - focal
11tags:12tags:
12 - monitoring13 - monitoring
13subordinate: true14subordinate: true
@@ -18,8 +19,19 @@ requires:
18provides:19provides:
19 scrape:20 scrape:
20 interface: http21 interface: http
22 nrpe-external-master:
23 interface: nrpe-external-master
24 scope: container
25 dashboards:
26 interface: grafana-dashboard
21resources:27resources:
22 prometheus-libvirt-exporter:28 prometheus-libvirt-exporter:
23 type: file29 type: file
24 filename: prometheus-libvirt-exporter.snap30 filename: prometheus-libvirt-exporter.snap
25 description: Prometheus-libvirt-exporter snap31 description: Prometheus-libvirt-exporter snap
32 dashboards:
33 type: file
34 filename: grafana-dashboards.zip
35 description:
36 By default the charm is distributed with a dashboard that gets pushed to grafana.
37 You can override this dashboard with your own
diff --git a/reactive/libvirt-exporter.py b/reactive/libvirt-exporter.py
26deleted file mode 10064438deleted file mode 100644
index 8727119..0000000
--- a/reactive/libvirt-exporter.py
+++ /dev/null
@@ -1,46 +0,0 @@
1from charmhelpers.core import hookenv, host
2from charms.reactive import (
3 when, when_not, set_state, remove_state
4)
5from charms.layer import snap
6import subprocess
7
8
9SNAP_NAME = 'prometheus-libvirt-exporter'
10SVC_NAME = 'snap.prometheus-libvirt-exporter.daemon'
11PORT_NUMBER = '9177'
12
13
14@when_not('libvirt-exporter.installed')
15def install_packages():
16 hookenv.status_set('maintenance', 'Installing software')
17 config = hookenv.config()
18 channel = config.get('snap_channel', 'stable')
19 snap.install(SNAP_NAME, channel=channel, force_dangerous=False)
20 subprocess.check_call(['snap', 'connect', 'prometheus-libvirt-exporter:libvirt'])
21 hookenv.status_set('active', 'Exporter installed and connected to libvirt slot')
22 hookenv.open_port(PORT_NUMBER)
23 set_state('libvirt-exporter.installed')
24
25
26@when('libvirt-exporter.installed')
27def check_status():
28 config = hookenv.config()
29 if config.changed('snap_channel'):
30 remove_state('libvirt-exporter.installed')
31 return
32 if not host.service_running(SVC_NAME):
33 hookenv.status_set('maintenance', 'Service is down, starting')
34 hookenv.log('Service {} is down, starting...'.format(SVC_NAME))
35 host.service_start(SVC_NAME)
36 hookenv.status_set('active', 'Service started')
37 else:
38 hookenv.status_set('active', 'Service is up')
39 set_state('libvirt-exporter.started')
40
41
42# Relations
43@when('libvirt-exporter.started')
44@when('scrape.available')
45def configure_scrape_relation(scrape_service):
46 scrape_service.configure(PORT_NUMBER)
diff --git a/reactive/prometheus-libvirt-exporter.py b/reactive/prometheus-libvirt-exporter.py
47new file mode 1006440new file mode 100644
index 0000000..1660481
--- /dev/null
+++ b/reactive/prometheus-libvirt-exporter.py
@@ -0,0 +1,185 @@
1#!/usr/bin/python3
2"""Installs and configures prometheus-libvirt-exporter."""
3
4import os
5from pathlib import Path
6import shutil
7import subprocess
8from zipfile import BadZipFile, ZipFile
9
10from charmhelpers.contrib.charmsupport import nrpe
11from charmhelpers.core import hookenv, host
12from charms.layer import snap
13from charms.reactive import (
14 endpoint_from_flag,
15 hook,
16 remove_state,
17 set_state,
18 when,
19 when_all,
20 when_any,
21 when_not,
22 when_not_all
23)
24
25
26DASHBOARD_PATH = os.getcwd() + '/files/grafana-dashboards'
27SNAP_NAME = 'prometheus-libvirt-exporter'
28SVC_NAME = 'snap.prometheus-libvirt-exporter.daemon'
29PORT_NUMBER = '9177'
30
31
32@when('juju-info.connected')
33@when_not_all('libvirt-exporter.installed', 'libvirt-exporter.started')
34def install_packages():
35 """Installs the prometheus-libvirt-exporter snap."""
36 hookenv.status_set('maintenance', 'Installing software')
37 config = hookenv.config()
38 channel = config.get('snap_channel')
39 snap.install(SNAP_NAME, channel=channel, force_dangerous=False)
40 subprocess.check_call(['snap', 'connect', 'prometheus-libvirt-exporter:libvirt'])
41 hookenv.status_set('active', 'Exporter installed and connected to libvirt slot')
42 hookenv.open_port(PORT_NUMBER)
43 set_state('libvirt-exporter.installed')
44
45
46@hook('upgrade-charm')
47def upgrade():
48 """Reset the install state on upgrade, to ensure resource extraction."""
49 hookenv.status_set('maintenance', 'Charm upgrade in progress')
50 remove_state('libvirt-exporter.installed')
51 remove_state('libvirt-exporter.started')
52 update_dashboards_from_resource()
53
54
55@when_not('libvirt-exporter.started')
56@when_any('libvirt-exporter.installed', 'config.changed')
57def start_snap():
58 """Configure snap.prometheus-libvirt-exporter.daemon service."""
59 if not host.service_running(SVC_NAME):
60 hookenv.status_set('maintenance', 'Service is down, starting')
61 hookenv.log('Service {} is down, starting...'.format(SVC_NAME))
62 host.service_start(SVC_NAME)
63 hookenv.status_set('active', 'Service started')
64 hookenv.log('start_snap() Service started')
65 else:
66 hookenv.status_set('active', 'Ready')
67 set_state('libvirt-exporter.started')
68 hookenv.log('start_snap() libvirt-exporter.started')
69
70 update_dashboards_from_resource()
71
72 hookenv.log('Installed and set flag libvirt-exporter.started')
73
74
75@when('config.changed.snap_channel')
76def snap_channel_changed():
77 """Remove the state libvirt.exporter.installed if the snap channel changes."""
78 remove_state('libvirt-exporter.installed')
79 remove_state('libvirt-exporter.started')
80
81
82@when_all('libvirt-exporter.started', 'scrape.available')
83def configure_scrape_relation(scrape_service):
84 """Connect prometheus to the the exporter for consumption."""
85 scrape_service.configure(PORT_NUMBER)
86 remove_state('libvirt-exporter.configured')
87
88
89@when('nrpe-external-master.changed')
90def nrpe_changed():
91 """Trigger nrpe update."""
92 remove_state('libvirt-exporter.configured')
93
94
95@when('libvirt-exporter.changed')
96def prometheus_changed():
97 """Trigger prometheus update."""
98 remove_state('libvirt-exporter.prometheus_relation_configured')
99 remove_state('libvirt-exporter.configured')
100
101
102@when('nrpe-external-master.available')
103@when_not('libvirt-exporter.configured')
104def update_nrpe_config(svc):
105 """Configure the nrpe check for the service."""
106 if not os.path.exists('/var/lib/nagios'):
107 hookenv.status_set('blocked', 'Waiting for nrpe package installation')
108 return
109
110 hookenv.status_set('maintenance', 'Configuring nrpe checks')
111
112 hostname = nrpe.get_nagios_hostname()
113 nrpe_setup = nrpe.NRPE(hostname=hostname)
114 nrpe_setup.add_check(shortname='prometheus_libvirt_exporter_http',
115 check_cmd='check_http -I 127.0.0.1 -p {} -u /metrics'.format(PORT_NUMBER),
116 description='Prometheus Libvirt Exporter HTTP check')
117 nrpe_setup.write()
118 hookenv.status_set('active', 'ready')
119 set_state('libvirt-exporter.configured')
120
121
122@when('libvirt-exporter.installed')
123@when_not('juju-info.available')
124def remove_libvirt_exporter():
125 """Uninstall the snap."""
126 remove_state('libvirt-exporter.installed')
127 remove_state('libvirt-exporter.started')
128 snap.remove(SNAP_NAME)
129
130
131@when('libvirt-exporter.configured')
132@when_not('nrpe-external-master.available')
133def remove_nrpe_check():
134 """Remove the nrpe check."""
135 hostname = nrpe.get_nagios_hostname()
136 nrpe_setup = nrpe.NRPE(hostname=hostname)
137 nrpe_setup.remove_check(shortname="prometheus_libvirt_exporter_http")
138 remove_state('libvirt-exporter.configured')
139
140
141@when_all('leadership.is_leader', 'endpoint.dashboards.joined')
142def register_grafana_dashboards():
143 """After joining to grafana, push the dashboard."""
144 grafana_endpoint = endpoint_from_flag('endpoint.dashboards.joined')
145
146 if grafana_endpoint is None:
147 return
148
149 hookenv.log('Grafana relation joined, push dashboard')
150
151 # load pre-distributed dashboards, that may have been overwritten by resource
152 dash_dir = Path(DASHBOARD_PATH)
153 for dash_file in dash_dir.glob('*.json'):
154 dashboard = dash_file.read_text()
155 grafana_endpoint.register_dashboard(dash_file.stem, dashboard)
156 hookenv.log('Pushed {}'.format(dash_file))
157
158
159def update_dashboards_from_resource():
160 """Extract resource zip file into templates directory."""
161 dashboards_zip_resource = hookenv.resource_get('dashboards')
162 if not dashboards_zip_resource:
163 hookenv.log('No dashboards resource found', hookenv.DEBUG)
164 # no dashboards zip found, go with the default distributed dashboard
165 return
166
167 hookenv.log('Installing dashboards from resource', hookenv.DEBUG)
168 try:
169 shutil.copy(dashboards_zip_resource, DASHBOARD_PATH)
170 except IOError as error:
171 hookenv.log('Problem copying resource: {}'.format(error), hookenv.ERROR)
172 return
173
174 try:
175 with ZipFile(dashboards_zip_resource, 'r') as zipfile:
176 zipfile.extractall(path=DASHBOARD_PATH)
177 hookenv.log('Extracted dashboards from resource', hookenv.DEBUG)
178 except BadZipFile as error:
179 hookenv.log('BadZipFile: {}'.format(error), hookenv.ERROR)
180 return
181 except PermissionError as error:
182 hookenv.log('Unable to unzip the provided resource: {}'.format(error), hookenv.ERROR)
183 return
184
185 register_grafana_dashboards()
diff --git a/requirements.txt b/requirements.txt
0new file mode 100644186new file mode 100644
index 0000000..1713f68
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1 @@
1# Include python requirements here
0\ No newline at end of file2\ No newline at end of file
diff --git a/tests/__init__.py b/tests/__init__.py
1new file mode 1006443new file mode 100644
index 0000000..d236d73
--- /dev/null
+++ b/tests/__init__.py
@@ -0,0 +1 @@
1"""Zaza tests."""
diff --git a/tests/bundles/bionic.yaml b/tests/bundles/bionic.yaml
0new file mode 1006442new file mode 100644
index 0000000..dcff425
--- /dev/null
+++ b/tests/bundles/bionic.yaml
@@ -0,0 +1,22 @@
1series: bionic
2applications:
3 ubuntu:
4 charm: cs:ubuntu
5 num_units: 1
6 prometheus-libvirt-exporter:
7 options:
8 snap_channel: stable
9 nrpe:
10 charm: cs:nrpe
11 prometheus:
12 charm: cs:prometheus2
13 num_units: 1
14relations:
15 - - ubuntu
16 - prometheus-libvirt-exporter
17 - - ubuntu:juju-info
18 - nrpe:general-info
19 - - prometheus-libvirt-exporter:nrpe-external-master
20 - nrpe:nrpe-external-master
21 - - prometheus-libvirt-exporter:scrape
22 - prometheus:target
0\ No newline at end of file23\ No newline at end of file
diff --git a/tests/bundles/focal.yaml b/tests/bundles/focal.yaml
1new file mode 10064424new file mode 100644
index 0000000..13bb440
--- /dev/null
+++ b/tests/bundles/focal.yaml
@@ -0,0 +1,22 @@
1series: focal
2applications:
3 ubuntu:
4 charm: cs:ubuntu
5 num_units: 1
6 prometheus-libvirt-exporter:
7 options:
8 snap_channel: stable
9 nrpe:
10 charm: cs:nrpe
11 prometheus:
12 charm: cs:prometheus2
13 num_units: 1
14relations:
15 - - ubuntu
16 - prometheus-libvirt-exporter
17 - - ubuntu:juju-info
18 - nrpe:general-info
19 - - prometheus-libvirt-exporter:nrpe-external-master
20 - nrpe:nrpe-external-master
21 - - prometheus-libvirt-exporter:scrape
22 - prometheus:target
0\ No newline at end of file23\ No newline at end of file
diff --git a/tests/bundles/overlays/local-charm-overlay.yaml.j2 b/tests/bundles/overlays/local-charm-overlay.yaml.j2
1new file mode 10064424new file mode 100644
index 0000000..bfaaa2d
--- /dev/null
+++ b/tests/bundles/overlays/local-charm-overlay.yaml.j2
@@ -0,0 +1,3 @@
1applications:
2 prometheus-libvirt-exporter:
3 charm: "{{ CHARM_BUILD_DIR }}/{{ charm_name }}"
diff --git a/tests/bundles/xenial.yaml b/tests/bundles/xenial.yaml
0new file mode 1006444new file mode 100644
index 0000000..aff59d8
--- /dev/null
+++ b/tests/bundles/xenial.yaml
@@ -0,0 +1,22 @@
1series: xenial
2applications:
3 ubuntu:
4 charm: cs:ubuntu
5 num_units: 1
6 prometheus-libvirt-exporter:
7 options:
8 snap_channel: stable
9 nrpe:
10 charm: cs:nrpe
11 prometheus:
12 charm: cs:prometheus2
13 num_units: 1
14relations:
15 - - ubuntu
16 - prometheus-libvirt-exporter
17 - - ubuntu:juju-info
18 - nrpe:general-info
19 - - prometheus-libvirt-exporter:nrpe-external-master
20 - nrpe:nrpe-external-master
21 - - prometheus-libvirt-exporter:scrape
22 - prometheus:target
0\ No newline at end of file23\ No newline at end of file
diff --git a/tests/requirements.txt b/tests/requirements.txt
1new file mode 10064424new file mode 100644
index 0000000..b7c9112
--- /dev/null
+++ b/tests/requirements.txt
@@ -0,0 +1 @@
1git+https://github.com/openstack-charmers/zaza.git#egg=zaza
diff --git a/tests/test_prometheus_libvirt_exporter.py b/tests/test_prometheus_libvirt_exporter.py
0new file mode 1006442new file mode 100644
index 0000000..1cb865f
--- /dev/null
+++ b/tests/test_prometheus_libvirt_exporter.py
@@ -0,0 +1,78 @@
1"""Encapsulate prometheus-libvirt-exporter testing."""
2import logging
3import time
4import unittest
5
6import zaza.model as model
7
8
9CURL_TIMEOUT = 180
10REQ_TIMEOUT = 12
11DEFAULT_API_PORT = "9177"
12DEFAULT_API_URL = "/metrics"
13
14
15class BasePrometheusLibvirtExporterTest(unittest.TestCase):
16 """Base for Prometheus-libvirt-exporter charm tests."""
17
18 @classmethod
19 def setUpClass(cls):
20 """Set up tests."""
21 super(BasePrometheusLibvirtExporterTest, cls).setUpClass()
22 cls.model_name = model.get_juju_model()
23 cls.application_name = "prometheus-libvirt-exporter"
24 cls.lead_unit_name = model.get_lead_unit_name(
25 cls.application_name, model_name=cls.model_name
26 )
27 cls.units = model.get_units(
28 cls.application_name, model_name=cls.model_name
29 )
30 cls.prometheus_libvirt_exporter_ip = model.get_app_ips(cls.application_name)[0]
31
32
33class CharmOperationTest(BasePrometheusLibvirtExporterTest):
34 """Verify operations."""
35
36 def test_01_api_ready(self):
37 """Verify if the API is ready.
38
39 Curl the api endpoint.
40 We'll retry until the CURL_TIMEOUT.
41 """
42 curl_command = "curl http://localhost:{}/metrics".format(DEFAULT_API_PORT)
43 timeout = time.time() + CURL_TIMEOUT
44 while time.time() < timeout:
45 response = model.run_on_unit(self.lead_unit_name, curl_command)
46 if response["Code"] == "0":
47 return
48 logging.warning(
49 "Unexpected curl response: {}. Retrying in 30s.".format(
50 response
51 )
52 )
53 time.sleep(30)
54
55 # we didn't get rc=0 in the allowed time, fail the test
56 self.fail(
57 "Prometheus-libvirt-exporter didn't respond to the command \n"
58 "'{curl_command}' as expected.\n"
59 "Result: {result}".format(
60 curl_command=curl_command, result=response
61 )
62 )
63
64 def test_02_nrpe_http_check(self):
65 """Verify nrpe check exists."""
66 expected_nrpe_check = "command[check_prometheus_libvirt_exporter_http]={} -I 127.0.0.1 -p {} -u {}".format(
67 "/usr/lib/nagios/plugins/check_http",
68 DEFAULT_API_PORT,
69 DEFAULT_API_URL
70 )
71 logging.debug('Verify the nrpe check is created and has the required content...')
72 cmd = "cat /etc/nagios/nrpe.d/check_prometheus_libvirt_exporter_http.cfg"
73 result = model.run_on_unit(self.lead_unit_name, cmd)
74 code = result.get('Code')
75 if code != '0':
76 raise model.CommandRunFailed(cmd, result)
77 content = result.get('Stdout')
78 self.assertTrue(expected_nrpe_check in content)
diff --git a/tests/tests.yaml b/tests/tests.yaml
0new file mode 10064479new file mode 100644
index 0000000..24ca291
--- /dev/null
+++ b/tests/tests.yaml
@@ -0,0 +1,11 @@
1charm_name: prometheus-libvirt-exporter
2gate_bundles:
3 - xenial
4 - bionic
5 #- focal # Uncomment when nrpe and prometheus2 become available for focal
6smoke_bundles:
7 - bionic
8dev_bundles:
9 - bionic
10tests:
11 - tests.test_prometheus_libvirt_exporter.CharmOperationTest
diff --git a/tests/unit_tests/requirements.txt b/tests/unit_tests/requirements.txt
0new file mode 10064412new file mode 100644
index 0000000..8e404fb
--- /dev/null
+++ b/tests/unit_tests/requirements.txt
@@ -0,0 +1,6 @@
1charmhelpers
2charms.reactive
3mock
4pytest
5pytest-cov
6pytest-html
0\ No newline at end of file7\ No newline at end of file
diff --git a/tox.ini b/tox.ini
1new file mode 1006448new file mode 100644
index 0000000..b50e481
--- /dev/null
+++ b/tox.ini
@@ -0,0 +1,65 @@
1[tox]
2skipsdist=True
3envlist = unit, functional
4skip_missing_interpreters = True
5
6[testenv]
7basepython = python3
8setenv =
9 PYTHONPATH = .
10
11[testenv:unit]
12commands = pytest -v \
13 --ignore {toxinidir}/tests/ \
14 --ignore {toxinidir}/interfaces \
15 --ignore {toxinidir}/layers \
16 --cov=lib \
17 --cov=actions \
18 --cov-report=term \
19 --cov-report=annotate:report/unit/coverage-annotated \
20 --cov-report=html:report/unit/coverage-html \
21 --html=report/unit/tests/index.html \
22 --junitxml=report/unit/junit.xml
23deps = -r{toxinidir}/tests/unit_tests/requirements.txt
24 -r{toxinidir}/tests/requirements.txt
25setenv = PYTHONPATH={toxinidir}/lib
26
27[testenv:func]
28commands = functest-run-suite --keep-model
29deps = -r{toxinidir}/tests/requirements.txt
30passenv =
31 HOME
32 CHARM_BUILD_DIR
33 MODEL_SETTINGS
34
35[testenv:lint]
36commands = flake8 --format=html --htmldir=report/lint/ --tee
37deps =
38 flake8
39 flake8-colors
40 flake8-docstrings
41 flake8-html
42 flake8-import-order
43 pep8-naming
44
45[flake8]
46exclude =
47 .git,
48 __pycache__,
49 .tox,
50 layers,
51 interfaces,
52max-line-length = 120
53max-complexity = 10
54import-order-style = google
55
56[isort]
57order_by_type = true
58from_first = true
59line_length = 120
60
61[pytest]
62markers =
63 deploy: mark deployment tests to allow running w/o redeploy
64filterwarnings =
65 ignore::DeprecationWarning

Subscribers

People subscribed via source and target branches

to all changes: