Merge ~dmzoneill/charm-prometheus-libvirt-exporter:dev/q2-20 into charm-prometheus-libvirt-exporter:master
- Git
- lp:~dmzoneill/charm-prometheus-libvirt-exporter
- dev/q2-20
- Merge into master
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) |
Related bugs: |
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 |
Commit message
Description of the change
- 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
Chris MacNaughton (chris.macnaughton) wrote : | # |
James Troup (elmo) wrote : | # |
Some drive by comments
Giuseppe Petralia (peppepetra) wrote : | # |
Some more comments in line
Giuseppe Petralia (peppepetra) wrote : | # |
Added one more comment
Giuseppe Petralia (peppepetra) wrote : | # |
Comment inline
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.
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).
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:/
Alvaro Uria (aluria) wrote : | # |
This dashboard uses the "stat" plugin which is only available from v6.6 onwards. The snap is v5.0.
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.
Preview Diff
1 | diff --git a/.coverage b/.coverage |
2 | index 834f8fb..e5c6f66 100644 |
3 | Binary files a/.coverage and b/.coverage differ |
4 | diff --git a/.gitignore b/.gitignore |
5 | new file mode 100644 |
6 | index 0000000..2dc89c9 |
7 | --- /dev/null |
8 | +++ b/.gitignore |
9 | @@ -0,0 +1,24 @@ |
10 | +# Byte-compiled / optimized / DLL files |
11 | +__pycache__/ |
12 | +*.py[cod] |
13 | +*$py.class |
14 | + |
15 | +# Log files |
16 | +*.log |
17 | +.tox/ |
18 | +.coverage |
19 | + |
20 | +# vi |
21 | +.*.swp |
22 | + |
23 | +# pycharm |
24 | +.idea/ |
25 | + |
26 | +# version data |
27 | +repo-info |
28 | + |
29 | +# reports |
30 | +report/* |
31 | + |
32 | +# layers |
33 | +layers/* |
34 | \ No newline at end of file |
35 | diff --git a/Makefile b/Makefile |
36 | new file mode 100644 |
37 | index 0000000..a4e48ca |
38 | --- /dev/null |
39 | +++ b/Makefile |
40 | @@ -0,0 +1,52 @@ |
41 | +ifndef CHARM_BUILD_DIR |
42 | + CHARM_BUILD_DIR=/tmp/builds |
43 | +endif |
44 | + |
45 | +help: |
46 | + @echo "This project supports the following targets" |
47 | + @echo "" |
48 | + @echo " make help - show this text" |
49 | + @echo " make submodules - make sure that the submodules are up-to-date" |
50 | + @echo " make lint - run flake8" |
51 | + @echo " make test - run the unittests and lint" |
52 | + @echo " make unittest - run the tests defined in the unittest subdirectory" |
53 | + @echo " make functional - run the tests defined in the functional subdirectory" |
54 | + @echo " make release - build the charm" |
55 | + @echo " make clean - remove unneeded files" |
56 | + @echo "" |
57 | + |
58 | +submodules: |
59 | + @echo "Cloning submodules" |
60 | + @git submodule update --init --recursive |
61 | + |
62 | +lint: |
63 | + @echo "Running flake8" |
64 | + @tox -e lint |
65 | + |
66 | +#test: lint unittest functional |
67 | +test: lint functional |
68 | + |
69 | +unittest: |
70 | + @tox -e unit |
71 | + |
72 | +functional: build |
73 | + @echo Executing with: CHARM_BUILD_DIR=$(CHARM_BUILD_DIR) tox -e func |
74 | + @CHARM_BUILD_DIR=$(CHARM_BUILD_DIR) tox -e func |
75 | + |
76 | +build: |
77 | + @echo "Building charm to base directory $(CHARM_BUILD_DIR)" |
78 | + @-git describe --tags > ./repo-info |
79 | + @CHARM_LAYERS_DIR=./layers CHARM_INTERFACES_DIR=./interfaces TERM=linux \ |
80 | + CHARM_BUILD_DIR=$(CHARM_BUILD_DIR) charm build . --force |
81 | + |
82 | +release: clean build |
83 | + @echo "Charm is built at $(CHARM_BUILD_DIR)/prometheus-libvirt-exporter" |
84 | + |
85 | +clean: |
86 | + @echo "Cleaning files" |
87 | + @if [ -d .tox ] ; then rm -r .tox ; fi |
88 | + @if [ -d .pytest_cache ] ; then rm -r .pytest_cache ; fi |
89 | + @find . -iname __pycache__ -exec rm -r {} + |
90 | + |
91 | +# The targets below don't depend on a file |
92 | +.PHONY: lint test unittest functional build release clean help submodules |
93 | diff --git a/README.md b/README.md |
94 | index 1bb3648..fda45af 100644 |
95 | --- a/README.md |
96 | +++ b/README.md |
97 | @@ -1,3 +1,46 @@ |
98 | # Juju prometheus libvirt exporter charm |
99 | |
100 | This charm provides the [Prometheus libvirt exporter](https://github.com/kumina/libvirt_exporter) |
101 | + |
102 | +## Testing |
103 | + |
104 | +# This directory needs to be create in the charm path prior to testing |
105 | +``` |
106 | +mkdir -p report/lint |
107 | +``` |
108 | + |
109 | +## Deployment |
110 | + |
111 | +# A typical deployment with nova and libvirt is as follows: |
112 | +# The metrics will be at http://nova-compute:9177 |
113 | +``` |
114 | +juju deploy nova-compute |
115 | +juju deploy prometheus-libvirt-exporter |
116 | +juju add-relation nova-compute prometheus-libvirt-exporter |
117 | +``` |
118 | + |
119 | +# To avail of the metrics in grafana the following steps can be used |
120 | +``` |
121 | +juju deploy grafana |
122 | +juju deploy prometheus2 |
123 | +juju add-relation prometheus-libvirt-exporter:scrape prometheus2:target |
124 | +juju add-relation prometheus-libvirt-exporter:dashboards grafana:dashboards |
125 | +``` |
126 | + |
127 | +# To setup reporting with nagios |
128 | +``` |
129 | +juju deploy nrpe |
130 | +juju add-relation nova-compute nrpe |
131 | +juju add-relation prometheus-libvirt-exporter:nrpe-external-master nrpe:nrpe-external-master |
132 | +``` |
133 | + |
134 | +# Change or update dashboards |
135 | +``` |
136 | +# The exporter is distributed with a standard dashboard |
137 | +# To provide your own dashboards, create a zip file and attach it as a resource |
138 | +zip grafana-dashboards.zip libvirt-simple.json libvirtadvanced.json |
139 | +juju attach-resource prometheus-libvirt-exporter dashboards=./grafana-dashboards.zip |
140 | +``` |
141 | + |
142 | +# Contact Information |
143 | +- Charm bugs: https://bugs.launchpad.net/charm-prometheus-libvirt-exporter |
144 | diff --git a/config.yaml b/config.yaml |
145 | index 678e69b..b253652 100644 |
146 | --- a/config.yaml |
147 | +++ b/config.yaml |
148 | @@ -5,3 +5,17 @@ options: |
149 | description: | |
150 | If install_method is set to "snap" this option controlls channel name. |
151 | Supported values are: "stable", "candidate", "beta" and "edge" |
152 | + nagios_context: |
153 | + default: "juju" |
154 | + type: string |
155 | + description: | |
156 | + A string that will be prepended to instance name to set the host name |
157 | + in nagios. So for instance the hostname would be something like: |
158 | + juju-myservice-0 |
159 | + If you're running multiple environments with the same services in them |
160 | + this allows you to differentiate between them. |
161 | + nagios_servicegroups: |
162 | + default: "juju" |
163 | + type: string |
164 | + description: | |
165 | + Comma separated list of nagios servicegroups |
166 | \ No newline at end of file |
167 | diff --git a/files/grafana-dashboards/libvirt.json b/files/grafana-dashboards/libvirt.json |
168 | new file mode 100644 |
169 | index 0000000..6954193 |
170 | --- /dev/null |
171 | +++ b/files/grafana-dashboards/libvirt.json |
172 | @@ -0,0 +1,1374 @@ |
173 | +{ |
174 | + "dashboard": { |
175 | + "annotations": { |
176 | + "list": [ |
177 | + { |
178 | + "builtIn": 1, |
179 | + "datasource": "-- Grafana --", |
180 | + "enable": true, |
181 | + "hide": true, |
182 | + "iconColor": "rgba(0, 211, 255, 1)", |
183 | + "name": "Annotations & Alerts", |
184 | + "type": "dashboard" |
185 | + } |
186 | + ] |
187 | + }, |
188 | + "description": "Libvirt Cluster overview.", |
189 | + "editable": true, |
190 | + "gnetId": null, |
191 | + "graphTooltip": 0, |
192 | + "id": null, |
193 | + "iteration": 1584700907234, |
194 | + "links": [], |
195 | + "panels": [ |
196 | + { |
197 | + "collapsed": false, |
198 | + "datasource": null, |
199 | + "gridPos": { |
200 | + "h": 1, |
201 | + "w": 24, |
202 | + "x": 0, |
203 | + "y": 0 |
204 | + }, |
205 | + "id": 24, |
206 | + "panels": [], |
207 | + "title": "Info", |
208 | + "type": "row" |
209 | + }, |
210 | + { |
211 | + "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", |
212 | + "datasource": null, |
213 | + "gridPos": { |
214 | + "h": 4, |
215 | + "w": 12, |
216 | + "x": 0, |
217 | + "y": 1 |
218 | + }, |
219 | + "id": 20, |
220 | + "mode": "markdown", |
221 | + "timeFrom": null, |
222 | + "timeShift": null, |
223 | + "title": "Panel Title", |
224 | + "type": "text" |
225 | + }, |
226 | + { |
227 | + "cacheTimeout": null, |
228 | + "colorBackground": true, |
229 | + "colorValue": false, |
230 | + "colors": [ |
231 | + "#73BF69", |
232 | + "rgba(237, 129, 40, 0.89)", |
233 | + "#d44a3a" |
234 | + ], |
235 | + "datasource": "prometheus - Juju generated source", |
236 | + "format": "none", |
237 | + "gauge": { |
238 | + "maxValue": 100, |
239 | + "minValue": 0, |
240 | + "show": false, |
241 | + "thresholdLabels": false, |
242 | + "thresholdMarkers": true |
243 | + }, |
244 | + "gridPos": { |
245 | + "h": 4, |
246 | + "w": 12, |
247 | + "x": 12, |
248 | + "y": 1 |
249 | + }, |
250 | + "id": 22, |
251 | + "interval": null, |
252 | + "links": [], |
253 | + "mappingType": 1, |
254 | + "mappingTypes": [ |
255 | + { |
256 | + "name": "value to text", |
257 | + "value": 1 |
258 | + }, |
259 | + { |
260 | + "name": "range to text", |
261 | + "value": 2 |
262 | + } |
263 | + ], |
264 | + "maxDataPoints": 100, |
265 | + "nullPointMode": "connected", |
266 | + "nullText": null, |
267 | + "postfix": "", |
268 | + "postfixFontSize": "50%", |
269 | + "prefix": "", |
270 | + "prefixFontSize": "50%", |
271 | + "rangeMaps": [ |
272 | + { |
273 | + "from": "null", |
274 | + "text": "N/A", |
275 | + "to": "null" |
276 | + } |
277 | + ], |
278 | + "sparkline": { |
279 | + "fillColor": "rgba(31, 118, 189, 0.18)", |
280 | + "full": false, |
281 | + "lineColor": "rgb(31, 120, 193)", |
282 | + "show": false, |
283 | + "ymax": null, |
284 | + "ymin": null |
285 | + }, |
286 | + "tableColumn": "", |
287 | + "targets": [ |
288 | + { |
289 | + "expr": "count(libvirt_up{instance=~\"$host\"})+count(libvirt_domain_info_virtual_cpus{domain=~\"$domain\"})", |
290 | + "interval": "", |
291 | + "legendFormat": "", |
292 | + "refId": "A" |
293 | + } |
294 | + ], |
295 | + "thresholds": "5,10", |
296 | + "timeFrom": null, |
297 | + "timeShift": null, |
298 | + "title": "Matching targets", |
299 | + "type": "singlestat", |
300 | + "valueFontSize": "200%", |
301 | + "valueMaps": [ |
302 | + { |
303 | + "op": "=", |
304 | + "text": "N/A", |
305 | + "value": "null" |
306 | + } |
307 | + ], |
308 | + "valueName": "current" |
309 | + }, |
310 | + { |
311 | + "collapsed": true, |
312 | + "datasource": null, |
313 | + "gridPos": { |
314 | + "h": 1, |
315 | + "w": 24, |
316 | + "x": 0, |
317 | + "y": 5 |
318 | + }, |
319 | + "id": 28, |
320 | + "panels": [ |
321 | + { |
322 | + "cacheTimeout": null, |
323 | + "datasource": "prometheus - Juju generated source", |
324 | + "gridPos": { |
325 | + "h": 5, |
326 | + "w": 12, |
327 | + "x": 0, |
328 | + "y": 6 |
329 | + }, |
330 | + "id": 10, |
331 | + "links": [], |
332 | + "options": { |
333 | + "colorMode": "value", |
334 | + "fieldOptions": { |
335 | + "calcs": [ |
336 | + "last" |
337 | + ], |
338 | + "defaults": { |
339 | + "mappings": [], |
340 | + "thresholds": { |
341 | + "mode": "absolute", |
342 | + "steps": [ |
343 | + { |
344 | + "color": "green", |
345 | + "value": null |
346 | + }, |
347 | + { |
348 | + "color": "red", |
349 | + "value": 80 |
350 | + } |
351 | + ] |
352 | + } |
353 | + }, |
354 | + "overrides": [], |
355 | + "values": false |
356 | + }, |
357 | + "graphMode": "area", |
358 | + "justifyMode": "auto", |
359 | + "orientation": "auto" |
360 | + }, |
361 | + "pluginVersion": "6.7.0", |
362 | + "targets": [ |
363 | + { |
364 | + "expr": "sum(libvirt_up{instance=~\"$host\"})", |
365 | + "interval": "", |
366 | + "legendFormat": "", |
367 | + "refId": "A" |
368 | + } |
369 | + ], |
370 | + "timeFrom": null, |
371 | + "timeShift": null, |
372 | + "title": "Virt Hosts", |
373 | + "type": "stat" |
374 | + }, |
375 | + { |
376 | + "cacheTimeout": null, |
377 | + "datasource": "prometheus - Juju generated source", |
378 | + "gridPos": { |
379 | + "h": 5, |
380 | + "w": 12, |
381 | + "x": 12, |
382 | + "y": 6 |
383 | + }, |
384 | + "id": 8, |
385 | + "links": [], |
386 | + "options": { |
387 | + "colorMode": "value", |
388 | + "fieldOptions": { |
389 | + "calcs": [ |
390 | + "mean" |
391 | + ], |
392 | + "defaults": { |
393 | + "mappings": [], |
394 | + "thresholds": { |
395 | + "mode": "absolute", |
396 | + "steps": [ |
397 | + { |
398 | + "color": "green", |
399 | + "value": null |
400 | + }, |
401 | + { |
402 | + "color": "red", |
403 | + "value": 80 |
404 | + } |
405 | + ] |
406 | + } |
407 | + }, |
408 | + "overrides": [], |
409 | + "values": false |
410 | + }, |
411 | + "graphMode": "area", |
412 | + "justifyMode": "auto", |
413 | + "orientation": "auto" |
414 | + }, |
415 | + "pluginVersion": "6.7.0", |
416 | + "targets": [ |
417 | + { |
418 | + "expr": "sum(libvirt_domain_info_virtual_cpus{domain=~\"$domain\"})", |
419 | + "interval": "", |
420 | + "legendFormat": "", |
421 | + "refId": "A" |
422 | + } |
423 | + ], |
424 | + "timeFrom": null, |
425 | + "timeShift": null, |
426 | + "title": "Vcpus", |
427 | + "type": "stat" |
428 | + } |
429 | + ], |
430 | + "title": "Host & CPU", |
431 | + "type": "row" |
432 | + }, |
433 | + { |
434 | + "collapsed": true, |
435 | + "datasource": null, |
436 | + "gridPos": { |
437 | + "h": 1, |
438 | + "w": 24, |
439 | + "x": 0, |
440 | + "y": 6 |
441 | + }, |
442 | + "id": 26, |
443 | + "panels": [ |
444 | + { |
445 | + "aliasColors": {}, |
446 | + "bars": true, |
447 | + "cacheTimeout": null, |
448 | + "dashLength": 10, |
449 | + "dashes": false, |
450 | + "datasource": "prometheus - Juju generated source", |
451 | + "fill": 1, |
452 | + "fillGradient": 0, |
453 | + "gridPos": { |
454 | + "h": 7, |
455 | + "w": 12, |
456 | + "x": 0, |
457 | + "y": 7 |
458 | + }, |
459 | + "hiddenSeries": false, |
460 | + "id": 6, |
461 | + "legend": { |
462 | + "avg": false, |
463 | + "current": false, |
464 | + "max": false, |
465 | + "min": false, |
466 | + "show": true, |
467 | + "total": false, |
468 | + "values": false |
469 | + }, |
470 | + "lines": false, |
471 | + "linewidth": 1, |
472 | + "links": [], |
473 | + "nullPointMode": "null", |
474 | + "options": { |
475 | + "dataLinks": [] |
476 | + }, |
477 | + "percentage": false, |
478 | + "pluginVersion": "6.6.2", |
479 | + "pointradius": 2, |
480 | + "points": false, |
481 | + "renderer": "flot", |
482 | + "seriesOverrides": [], |
483 | + "spaceLength": 10, |
484 | + "stack": false, |
485 | + "steppedLine": false, |
486 | + "targets": [ |
487 | + { |
488 | + "expr": "libvirt_domain_info_maximum_memory_bytes{domain=~\"$domain\"}/1024/1024", |
489 | + "interval": "", |
490 | + "legendFormat": "{{host}} - {{domain}}", |
491 | + "refId": "A" |
492 | + } |
493 | + ], |
494 | + "thresholds": [], |
495 | + "timeFrom": null, |
496 | + "timeRegions": [], |
497 | + "timeShift": null, |
498 | + "title": "Memory Usage", |
499 | + "tooltip": { |
500 | + "shared": true, |
501 | + "sort": 0, |
502 | + "value_type": "individual" |
503 | + }, |
504 | + "type": "graph", |
505 | + "xaxis": { |
506 | + "buckets": null, |
507 | + "mode": "time", |
508 | + "name": null, |
509 | + "show": true, |
510 | + "values": [] |
511 | + }, |
512 | + "yaxes": [ |
513 | + { |
514 | + "format": "short", |
515 | + "label": null, |
516 | + "logBase": 1, |
517 | + "max": null, |
518 | + "min": null, |
519 | + "show": true |
520 | + }, |
521 | + { |
522 | + "format": "short", |
523 | + "label": null, |
524 | + "logBase": 1, |
525 | + "max": null, |
526 | + "min": null, |
527 | + "show": true |
528 | + } |
529 | + ], |
530 | + "yaxis": { |
531 | + "align": false, |
532 | + "alignLevel": null |
533 | + } |
534 | + }, |
535 | + { |
536 | + "cacheTimeout": null, |
537 | + "colorBackground": false, |
538 | + "colorValue": false, |
539 | + "colors": [ |
540 | + "#299c46", |
541 | + "rgba(237, 129, 40, 0.89)", |
542 | + "#d44a3a" |
543 | + ], |
544 | + "datasource": "prometheus - Juju generated source", |
545 | + "description": "", |
546 | + "format": "none", |
547 | + "gauge": { |
548 | + "maxValue": 100, |
549 | + "minValue": 0, |
550 | + "show": false, |
551 | + "thresholdLabels": false, |
552 | + "thresholdMarkers": true |
553 | + }, |
554 | + "gridPos": { |
555 | + "h": 7, |
556 | + "w": 12, |
557 | + "x": 12, |
558 | + "y": 7 |
559 | + }, |
560 | + "id": 38, |
561 | + "interval": null, |
562 | + "links": [], |
563 | + "mappingType": 1, |
564 | + "mappingTypes": [ |
565 | + { |
566 | + "name": "value to text", |
567 | + "value": 1 |
568 | + }, |
569 | + { |
570 | + "name": "range to text", |
571 | + "value": 2 |
572 | + } |
573 | + ], |
574 | + "maxDataPoints": 100, |
575 | + "nullPointMode": "connected", |
576 | + "nullText": null, |
577 | + "postfix": "", |
578 | + "postfixFontSize": "50%", |
579 | + "prefix": "", |
580 | + "prefixFontSize": "50%", |
581 | + "rangeMaps": [ |
582 | + { |
583 | + "from": "null", |
584 | + "text": "N/A", |
585 | + "to": "null" |
586 | + } |
587 | + ], |
588 | + "sparkline": { |
589 | + "fillColor": "rgba(31, 118, 189, 0.18)", |
590 | + "full": false, |
591 | + "lineColor": "rgb(31, 120, 193)", |
592 | + "show": false, |
593 | + "ymax": null, |
594 | + "ymin": null |
595 | + }, |
596 | + "tableColumn": "", |
597 | + "targets": [ |
598 | + { |
599 | + "expr": "sum(libvirt_domain_info_memory_usage_bytes)/1024/1024/1024", |
600 | + "interval": "", |
601 | + "legendFormat": "Total Memory Usage", |
602 | + "refId": "A" |
603 | + } |
604 | + ], |
605 | + "thresholds": "", |
606 | + "timeFrom": null, |
607 | + "timeShift": null, |
608 | + "title": "Total Memory Usage GB", |
609 | + "type": "singlestat", |
610 | + "valueFontSize": "200%", |
611 | + "valueMaps": [ |
612 | + { |
613 | + "op": "=", |
614 | + "text": "N/A", |
615 | + "value": "null" |
616 | + } |
617 | + ], |
618 | + "valueName": "avg" |
619 | + } |
620 | + ], |
621 | + "title": "Memory", |
622 | + "type": "row" |
623 | + }, |
624 | + { |
625 | + "collapsed": true, |
626 | + "datasource": null, |
627 | + "gridPos": { |
628 | + "h": 1, |
629 | + "w": 24, |
630 | + "x": 0, |
631 | + "y": 7 |
632 | + }, |
633 | + "id": 30, |
634 | + "panels": [ |
635 | + { |
636 | + "aliasColors": {}, |
637 | + "bars": false, |
638 | + "cacheTimeout": null, |
639 | + "dashLength": 10, |
640 | + "dashes": false, |
641 | + "datasource": "prometheus - Juju generated source", |
642 | + "fill": 2, |
643 | + "fillGradient": 0, |
644 | + "gridPos": { |
645 | + "h": 7, |
646 | + "w": 12, |
647 | + "x": 0, |
648 | + "y": 8 |
649 | + }, |
650 | + "hiddenSeries": false, |
651 | + "id": 12, |
652 | + "legend": { |
653 | + "alignAsTable": false, |
654 | + "avg": false, |
655 | + "current": false, |
656 | + "max": false, |
657 | + "min": false, |
658 | + "show": true, |
659 | + "total": false, |
660 | + "values": false |
661 | + }, |
662 | + "lines": true, |
663 | + "linewidth": 1, |
664 | + "links": [], |
665 | + "nullPointMode": "null", |
666 | + "options": { |
667 | + "dataLinks": [] |
668 | + }, |
669 | + "percentage": false, |
670 | + "pluginVersion": "6.6.2", |
671 | + "pointradius": 2, |
672 | + "points": false, |
673 | + "renderer": "flot", |
674 | + "seriesOverrides": [], |
675 | + "spaceLength": 10, |
676 | + "stack": true, |
677 | + "steppedLine": false, |
678 | + "targets": [ |
679 | + { |
680 | + "expr": "sum(libvirt_domain_interface_stats_transmit_bytes_total{domain=~\"$domain\"})", |
681 | + "format": "time_series", |
682 | + "interval": "", |
683 | + "intervalFactor": 2, |
684 | + "legendFormat": "TX", |
685 | + "refId": "A" |
686 | + }, |
687 | + { |
688 | + "expr": "sum(libvirt_domain_interface_stats_receive_bytes_total{domain=~\"$domain\"})", |
689 | + "interval": "", |
690 | + "intervalFactor": 2, |
691 | + "legendFormat": "RX", |
692 | + "refId": "B" |
693 | + } |
694 | + ], |
695 | + "thresholds": [], |
696 | + "timeFrom": null, |
697 | + "timeRegions": [], |
698 | + "timeShift": null, |
699 | + "title": "Network RX/TX Throughput", |
700 | + "tooltip": { |
701 | + "shared": true, |
702 | + "sort": 0, |
703 | + "value_type": "individual" |
704 | + }, |
705 | + "type": "graph", |
706 | + "xaxis": { |
707 | + "buckets": null, |
708 | + "mode": "time", |
709 | + "name": null, |
710 | + "show": true, |
711 | + "values": [] |
712 | + }, |
713 | + "yaxes": [ |
714 | + { |
715 | + "format": "short", |
716 | + "label": "KiloByes", |
717 | + "logBase": 1, |
718 | + "max": null, |
719 | + "min": null, |
720 | + "show": true |
721 | + }, |
722 | + { |
723 | + "format": "short", |
724 | + "label": "", |
725 | + "logBase": 1, |
726 | + "max": null, |
727 | + "min": null, |
728 | + "show": true |
729 | + } |
730 | + ], |
731 | + "yaxis": { |
732 | + "align": false, |
733 | + "alignLevel": null |
734 | + } |
735 | + }, |
736 | + { |
737 | + "aliasColors": {}, |
738 | + "bars": false, |
739 | + "dashLength": 10, |
740 | + "dashes": false, |
741 | + "datasource": "prometheus - Juju generated source", |
742 | + "fill": 1, |
743 | + "fillGradient": 0, |
744 | + "gridPos": { |
745 | + "h": 7, |
746 | + "w": 12, |
747 | + "x": 12, |
748 | + "y": 8 |
749 | + }, |
750 | + "hiddenSeries": false, |
751 | + "id": 16, |
752 | + "legend": { |
753 | + "avg": false, |
754 | + "current": false, |
755 | + "max": false, |
756 | + "min": false, |
757 | + "show": true, |
758 | + "total": false, |
759 | + "values": false |
760 | + }, |
761 | + "lines": true, |
762 | + "linewidth": 1, |
763 | + "nullPointMode": "null", |
764 | + "options": { |
765 | + "dataLinks": [] |
766 | + }, |
767 | + "percentage": false, |
768 | + "pointradius": 2, |
769 | + "points": false, |
770 | + "renderer": "flot", |
771 | + "seriesOverrides": [], |
772 | + "spaceLength": 10, |
773 | + "stack": false, |
774 | + "steppedLine": false, |
775 | + "targets": [ |
776 | + { |
777 | + "expr": "sum(libvirt_domain_interface_stats_receive_drops_total{domain=~\"$domain\"})", |
778 | + "interval": "", |
779 | + "legendFormat": "RX drops", |
780 | + "refId": "A" |
781 | + }, |
782 | + { |
783 | + "expr": "sum(libvirt_domain_interface_stats_receive_errors_total{domain=~\"$domain\"})", |
784 | + "interval": "", |
785 | + "legendFormat": "RX errors", |
786 | + "refId": "B" |
787 | + } |
788 | + ], |
789 | + "thresholds": [], |
790 | + "timeFrom": null, |
791 | + "timeRegions": [], |
792 | + "timeShift": null, |
793 | + "title": "Network Receive Errors/Drops", |
794 | + "tooltip": { |
795 | + "shared": true, |
796 | + "sort": 0, |
797 | + "value_type": "individual" |
798 | + }, |
799 | + "type": "graph", |
800 | + "xaxis": { |
801 | + "buckets": null, |
802 | + "mode": "time", |
803 | + "name": null, |
804 | + "show": true, |
805 | + "values": [] |
806 | + }, |
807 | + "yaxes": [ |
808 | + { |
809 | + "format": "short", |
810 | + "label": "Total", |
811 | + "logBase": 1, |
812 | + "max": null, |
813 | + "min": null, |
814 | + "show": true |
815 | + }, |
816 | + { |
817 | + "format": "short", |
818 | + "label": null, |
819 | + "logBase": 1, |
820 | + "max": null, |
821 | + "min": null, |
822 | + "show": true |
823 | + } |
824 | + ], |
825 | + "yaxis": { |
826 | + "align": false, |
827 | + "alignLevel": null |
828 | + } |
829 | + }, |
830 | + { |
831 | + "columns": [], |
832 | + "datasource": "prometheus - Juju generated source", |
833 | + "fontSize": "100%", |
834 | + "gridPos": { |
835 | + "h": 7, |
836 | + "w": 12, |
837 | + "x": 0, |
838 | + "y": 15 |
839 | + }, |
840 | + "id": 34, |
841 | + "pageSize": null, |
842 | + "showHeader": true, |
843 | + "sort": { |
844 | + "col": 0, |
845 | + "desc": true |
846 | + }, |
847 | + "styles": [ |
848 | + { |
849 | + "alias": "", |
850 | + "align": "auto", |
851 | + "colorMode": null, |
852 | + "colors": [ |
853 | + "rgba(245, 54, 54, 0.9)", |
854 | + "rgba(237, 129, 40, 0.89)", |
855 | + "rgba(50, 172, 45, 0.97)" |
856 | + ], |
857 | + "dateFormat": "YYYY-MM-DD HH:mm:ss", |
858 | + "decimals": 2, |
859 | + "mappingType": 1, |
860 | + "pattern": "Time", |
861 | + "thresholds": [], |
862 | + "type": "hidden", |
863 | + "unit": "short" |
864 | + }, |
865 | + { |
866 | + "alias": "Source", |
867 | + "align": "auto", |
868 | + "colorMode": null, |
869 | + "colors": [ |
870 | + "rgba(245, 54, 54, 0.9)", |
871 | + "rgba(237, 129, 40, 0.89)", |
872 | + "rgba(50, 172, 45, 0.97)" |
873 | + ], |
874 | + "dateFormat": "YYYY-MM-DD HH:mm:ss", |
875 | + "decimals": 2, |
876 | + "mappingType": 1, |
877 | + "pattern": "Metric", |
878 | + "thresholds": [], |
879 | + "type": "number", |
880 | + "unit": "short" |
881 | + }, |
882 | + { |
883 | + "alias": "Read bytes total", |
884 | + "align": "auto", |
885 | + "colorMode": null, |
886 | + "colors": [ |
887 | + "rgba(245, 54, 54, 0.9)", |
888 | + "rgba(237, 129, 40, 0.89)", |
889 | + "rgba(50, 172, 45, 0.97)" |
890 | + ], |
891 | + "dateFormat": "YYYY-MM-DD HH:mm:ss", |
892 | + "decimals": 2, |
893 | + "mappingType": 1, |
894 | + "pattern": "Value", |
895 | + "thresholds": [], |
896 | + "type": "number", |
897 | + "unit": "short" |
898 | + }, |
899 | + { |
900 | + "alias": "", |
901 | + "align": "right", |
902 | + "colorMode": null, |
903 | + "colors": [ |
904 | + "rgba(245, 54, 54, 0.9)", |
905 | + "rgba(237, 129, 40, 0.89)", |
906 | + "rgba(50, 172, 45, 0.97)" |
907 | + ], |
908 | + "decimals": 2, |
909 | + "pattern": "/.*/", |
910 | + "thresholds": [], |
911 | + "type": "number", |
912 | + "unit": "short" |
913 | + } |
914 | + ], |
915 | + "targets": [ |
916 | + { |
917 | + "expr": "libvirt_domain_block_stats_read_bytes_total{instance=~\"$host\"}", |
918 | + "interval": "", |
919 | + "legendFormat": "{{instance}} - {{domain}}", |
920 | + "refId": "A" |
921 | + } |
922 | + ], |
923 | + "timeFrom": null, |
924 | + "timeShift": null, |
925 | + "title": "Instance Read Bytes Total", |
926 | + "transform": "timeseries_to_rows", |
927 | + "type": "table" |
928 | + }, |
929 | + { |
930 | + "aliasColors": {}, |
931 | + "bars": false, |
932 | + "dashLength": 10, |
933 | + "dashes": false, |
934 | + "datasource": "prometheus - Juju generated source", |
935 | + "fill": 1, |
936 | + "fillGradient": 0, |
937 | + "gridPos": { |
938 | + "h": 7, |
939 | + "w": 12, |
940 | + "x": 12, |
941 | + "y": 15 |
942 | + }, |
943 | + "hiddenSeries": false, |
944 | + "id": 14, |
945 | + "legend": { |
946 | + "avg": false, |
947 | + "current": false, |
948 | + "max": false, |
949 | + "min": false, |
950 | + "show": true, |
951 | + "total": false, |
952 | + "values": false |
953 | + }, |
954 | + "lines": true, |
955 | + "linewidth": 1, |
956 | + "nullPointMode": "null", |
957 | + "options": { |
958 | + "dataLinks": [] |
959 | + }, |
960 | + "percentage": false, |
961 | + "pointradius": 2, |
962 | + "points": false, |
963 | + "renderer": "flot", |
964 | + "seriesOverrides": [], |
965 | + "spaceLength": 10, |
966 | + "stack": false, |
967 | + "steppedLine": false, |
968 | + "targets": [ |
969 | + { |
970 | + "expr": "sum(libvirt_domain_interface_stats_transmit_drops_total{domain=~\"$domain\"})", |
971 | + "interval": "", |
972 | + "legendFormat": "TX drops", |
973 | + "refId": "A" |
974 | + }, |
975 | + { |
976 | + "expr": "sum(libvirt_domain_interface_stats_transmit_errors_total{domain=~\"$domain\"})", |
977 | + "interval": "", |
978 | + "legendFormat": "RX drops", |
979 | + "refId": "B" |
980 | + } |
981 | + ], |
982 | + "thresholds": [], |
983 | + "timeFrom": null, |
984 | + "timeRegions": [], |
985 | + "timeShift": null, |
986 | + "title": "Network Transmit Errors/Drops", |
987 | + "tooltip": { |
988 | + "shared": true, |
989 | + "sort": 0, |
990 | + "value_type": "individual" |
991 | + }, |
992 | + "type": "graph", |
993 | + "xaxis": { |
994 | + "buckets": null, |
995 | + "mode": "time", |
996 | + "name": null, |
997 | + "show": true, |
998 | + "values": [] |
999 | + }, |
1000 | + "yaxes": [ |
1001 | + { |
1002 | + "format": "short", |
1003 | + "label": "Total", |
1004 | + "logBase": 1, |
1005 | + "max": null, |
1006 | + "min": null, |
1007 | + "show": true |
1008 | + }, |
1009 | + { |
1010 | + "format": "short", |
1011 | + "label": null, |
1012 | + "logBase": 1, |
1013 | + "max": null, |
1014 | + "min": null, |
1015 | + "show": true |
1016 | + } |
1017 | + ], |
1018 | + "yaxis": { |
1019 | + "align": false, |
1020 | + "alignLevel": null |
1021 | + } |
1022 | + }, |
1023 | + { |
1024 | + "columns": [], |
1025 | + "datasource": "prometheus - Juju generated source", |
1026 | + "fontSize": "100%", |
1027 | + "gridPos": { |
1028 | + "h": 7, |
1029 | + "w": 12, |
1030 | + "x": 0, |
1031 | + "y": 22 |
1032 | + }, |
1033 | + "id": 36, |
1034 | + "pageSize": null, |
1035 | + "showHeader": true, |
1036 | + "sort": { |
1037 | + "col": 0, |
1038 | + "desc": true |
1039 | + }, |
1040 | + "styles": [ |
1041 | + { |
1042 | + "alias": "", |
1043 | + "align": "auto", |
1044 | + "colorMode": null, |
1045 | + "colors": [ |
1046 | + "rgba(245, 54, 54, 0.9)", |
1047 | + "rgba(237, 129, 40, 0.89)", |
1048 | + "rgba(50, 172, 45, 0.97)" |
1049 | + ], |
1050 | + "dateFormat": "YYYY-MM-DD HH:mm:ss", |
1051 | + "decimals": 2, |
1052 | + "mappingType": 1, |
1053 | + "pattern": "Time", |
1054 | + "thresholds": [], |
1055 | + "type": "hidden", |
1056 | + "unit": "short" |
1057 | + }, |
1058 | + { |
1059 | + "alias": "Source", |
1060 | + "align": "auto", |
1061 | + "colorMode": null, |
1062 | + "colors": [ |
1063 | + "rgba(245, 54, 54, 0.9)", |
1064 | + "rgba(237, 129, 40, 0.89)", |
1065 | + "rgba(50, 172, 45, 0.97)" |
1066 | + ], |
1067 | + "dateFormat": "YYYY-MM-DD HH:mm:ss", |
1068 | + "decimals": 2, |
1069 | + "mappingType": 1, |
1070 | + "pattern": "Metric", |
1071 | + "thresholds": [], |
1072 | + "type": "number", |
1073 | + "unit": "short" |
1074 | + }, |
1075 | + { |
1076 | + "alias": "Write bytes total", |
1077 | + "align": "auto", |
1078 | + "colorMode": null, |
1079 | + "colors": [ |
1080 | + "rgba(245, 54, 54, 0.9)", |
1081 | + "rgba(237, 129, 40, 0.89)", |
1082 | + "rgba(50, 172, 45, 0.97)" |
1083 | + ], |
1084 | + "dateFormat": "YYYY-MM-DD HH:mm:ss", |
1085 | + "decimals": 2, |
1086 | + "mappingType": 1, |
1087 | + "pattern": "Value", |
1088 | + "thresholds": [], |
1089 | + "type": "number", |
1090 | + "unit": "short" |
1091 | + }, |
1092 | + { |
1093 | + "alias": "", |
1094 | + "align": "right", |
1095 | + "colorMode": null, |
1096 | + "colors": [ |
1097 | + "rgba(245, 54, 54, 0.9)", |
1098 | + "rgba(237, 129, 40, 0.89)", |
1099 | + "rgba(50, 172, 45, 0.97)" |
1100 | + ], |
1101 | + "decimals": 2, |
1102 | + "pattern": "/.*/", |
1103 | + "thresholds": [], |
1104 | + "type": "number", |
1105 | + "unit": "short" |
1106 | + } |
1107 | + ], |
1108 | + "targets": [ |
1109 | + { |
1110 | + "expr": "libvirt_domain_block_stats_write_bytes_total{instance=~\"$host\"}", |
1111 | + "interval": "", |
1112 | + "legendFormat": "{{instance}} - {{domain}}", |
1113 | + "refId": "A" |
1114 | + } |
1115 | + ], |
1116 | + "timeFrom": null, |
1117 | + "timeShift": null, |
1118 | + "title": "Instance Write Bytes Total", |
1119 | + "transform": "timeseries_to_rows", |
1120 | + "type": "table" |
1121 | + } |
1122 | + ], |
1123 | + "title": "Network", |
1124 | + "type": "row" |
1125 | + }, |
1126 | + { |
1127 | + "collapsed": true, |
1128 | + "datasource": null, |
1129 | + "gridPos": { |
1130 | + "h": 1, |
1131 | + "w": 24, |
1132 | + "x": 0, |
1133 | + "y": 8 |
1134 | + }, |
1135 | + "id": 32, |
1136 | + "panels": [ |
1137 | + { |
1138 | + "aliasColors": {}, |
1139 | + "bars": false, |
1140 | + "dashLength": 10, |
1141 | + "dashes": false, |
1142 | + "datasource": "prometheus - Juju generated source", |
1143 | + "fill": 5, |
1144 | + "fillGradient": 5, |
1145 | + "gridPos": { |
1146 | + "h": 7, |
1147 | + "w": 12, |
1148 | + "x": 0, |
1149 | + "y": 9 |
1150 | + }, |
1151 | + "hiddenSeries": false, |
1152 | + "id": 4, |
1153 | + "legend": { |
1154 | + "avg": false, |
1155 | + "current": false, |
1156 | + "max": false, |
1157 | + "min": false, |
1158 | + "show": true, |
1159 | + "total": false, |
1160 | + "values": false |
1161 | + }, |
1162 | + "lines": true, |
1163 | + "linewidth": 2, |
1164 | + "nullPointMode": "null", |
1165 | + "options": { |
1166 | + "dataLinks": [] |
1167 | + }, |
1168 | + "percentage": false, |
1169 | + "pluginVersion": "6.7.0", |
1170 | + "pointradius": 2, |
1171 | + "points": false, |
1172 | + "renderer": "flot", |
1173 | + "seriesOverrides": [], |
1174 | + "spaceLength": 10, |
1175 | + "stack": false, |
1176 | + "steppedLine": false, |
1177 | + "targets": [ |
1178 | + { |
1179 | + "expr": "libvirt_domain_block_stats_write_bytes_total{domain=~\"$domain\"}/1024/1024", |
1180 | + "interval": "", |
1181 | + "legendFormat": "{{instance}} - {{domain}}", |
1182 | + "refId": "A" |
1183 | + } |
1184 | + ], |
1185 | + "thresholds": [], |
1186 | + "timeFrom": null, |
1187 | + "timeRegions": [], |
1188 | + "timeShift": null, |
1189 | + "title": "Disk Write", |
1190 | + "tooltip": { |
1191 | + "shared": true, |
1192 | + "sort": 0, |
1193 | + "value_type": "individual" |
1194 | + }, |
1195 | + "type": "graph", |
1196 | + "xaxis": { |
1197 | + "buckets": null, |
1198 | + "mode": "time", |
1199 | + "name": null, |
1200 | + "show": true, |
1201 | + "values": [] |
1202 | + }, |
1203 | + "yaxes": [ |
1204 | + { |
1205 | + "format": "short", |
1206 | + "label": null, |
1207 | + "logBase": 1, |
1208 | + "max": null, |
1209 | + "min": null, |
1210 | + "show": true |
1211 | + }, |
1212 | + { |
1213 | + "format": "short", |
1214 | + "label": null, |
1215 | + "logBase": 1, |
1216 | + "max": null, |
1217 | + "min": null, |
1218 | + "show": true |
1219 | + } |
1220 | + ], |
1221 | + "yaxis": { |
1222 | + "align": false, |
1223 | + "alignLevel": null |
1224 | + } |
1225 | + }, |
1226 | + { |
1227 | + "aliasColors": {}, |
1228 | + "bars": false, |
1229 | + "dashLength": 10, |
1230 | + "dashes": false, |
1231 | + "datasource": "prometheus - Juju generated source", |
1232 | + "fill": 5, |
1233 | + "fillGradient": 5, |
1234 | + "gridPos": { |
1235 | + "h": 7, |
1236 | + "w": 12, |
1237 | + "x": 12, |
1238 | + "y": 9 |
1239 | + }, |
1240 | + "hiddenSeries": false, |
1241 | + "id": 40, |
1242 | + "legend": { |
1243 | + "avg": false, |
1244 | + "current": false, |
1245 | + "max": false, |
1246 | + "min": false, |
1247 | + "show": true, |
1248 | + "total": false, |
1249 | + "values": false |
1250 | + }, |
1251 | + "lines": true, |
1252 | + "linewidth": 2, |
1253 | + "nullPointMode": "null", |
1254 | + "options": { |
1255 | + "dataLinks": [] |
1256 | + }, |
1257 | + "percentage": false, |
1258 | + "pluginVersion": "6.7.0", |
1259 | + "pointradius": 2, |
1260 | + "points": false, |
1261 | + "renderer": "flot", |
1262 | + "seriesOverrides": [], |
1263 | + "spaceLength": 10, |
1264 | + "stack": false, |
1265 | + "steppedLine": false, |
1266 | + "targets": [ |
1267 | + { |
1268 | + "expr": "libvirt_domain_block_stats_read_bytes_total{domain=~\"$domain\"}/1024/1024", |
1269 | + "interval": "", |
1270 | + "legendFormat": "{{instance}} - {{domain}}", |
1271 | + "refId": "A" |
1272 | + } |
1273 | + ], |
1274 | + "thresholds": [], |
1275 | + "timeFrom": null, |
1276 | + "timeRegions": [], |
1277 | + "timeShift": null, |
1278 | + "title": "Disk Read", |
1279 | + "tooltip": { |
1280 | + "shared": true, |
1281 | + "sort": 0, |
1282 | + "value_type": "individual" |
1283 | + }, |
1284 | + "type": "graph", |
1285 | + "xaxis": { |
1286 | + "buckets": null, |
1287 | + "mode": "time", |
1288 | + "name": null, |
1289 | + "show": true, |
1290 | + "values": [] |
1291 | + }, |
1292 | + "yaxes": [ |
1293 | + { |
1294 | + "format": "short", |
1295 | + "label": null, |
1296 | + "logBase": 1, |
1297 | + "max": null, |
1298 | + "min": null, |
1299 | + "show": true |
1300 | + }, |
1301 | + { |
1302 | + "format": "short", |
1303 | + "label": null, |
1304 | + "logBase": 1, |
1305 | + "max": null, |
1306 | + "min": null, |
1307 | + "show": true |
1308 | + } |
1309 | + ], |
1310 | + "yaxis": { |
1311 | + "align": false, |
1312 | + "alignLevel": null |
1313 | + } |
1314 | + }, |
1315 | + { |
1316 | + "cacheTimeout": null, |
1317 | + "datasource": "prometheus - Juju generated source", |
1318 | + "gridPos": { |
1319 | + "h": 7, |
1320 | + "w": 12, |
1321 | + "x": 0, |
1322 | + "y": 16 |
1323 | + }, |
1324 | + "id": 44, |
1325 | + "links": [], |
1326 | + "options": { |
1327 | + "fieldOptions": { |
1328 | + "calcs": [ |
1329 | + "last" |
1330 | + ], |
1331 | + "defaults": { |
1332 | + "mappings": [ |
1333 | + { |
1334 | + "id": 0, |
1335 | + "op": "=", |
1336 | + "text": "N/A", |
1337 | + "type": 1, |
1338 | + "value": "null" |
1339 | + } |
1340 | + ], |
1341 | + "nullValueMode": "connected", |
1342 | + "thresholds": { |
1343 | + "mode": "absolute", |
1344 | + "steps": [ |
1345 | + { |
1346 | + "color": "green", |
1347 | + "value": null |
1348 | + }, |
1349 | + { |
1350 | + "color": "red", |
1351 | + "value": 80 |
1352 | + } |
1353 | + ] |
1354 | + }, |
1355 | + "title": "MB / sec", |
1356 | + "unit": "none" |
1357 | + }, |
1358 | + "overrides": [], |
1359 | + "values": false |
1360 | + }, |
1361 | + "orientation": "horizontal", |
1362 | + "showThresholdLabels": false, |
1363 | + "showThresholdMarkers": true |
1364 | + }, |
1365 | + "pluginVersion": "6.7.0", |
1366 | + "targets": [ |
1367 | + { |
1368 | + "expr": "sum(libvirt_domain_block_stats_write_bytes_total)/1024/1024", |
1369 | + "format": "heatmap", |
1370 | + "hide": false, |
1371 | + "instant": false, |
1372 | + "interval": "", |
1373 | + "intervalFactor": 1, |
1374 | + "legendFormat": "", |
1375 | + "refId": "A" |
1376 | + } |
1377 | + ], |
1378 | + "timeFrom": null, |
1379 | + "timeShift": null, |
1380 | + "title": "Disk Cumulative Write", |
1381 | + "type": "gauge" |
1382 | + }, |
1383 | + { |
1384 | + "cacheTimeout": null, |
1385 | + "datasource": "prometheus - Juju generated source", |
1386 | + "gridPos": { |
1387 | + "h": 7, |
1388 | + "w": 12, |
1389 | + "x": 12, |
1390 | + "y": 16 |
1391 | + }, |
1392 | + "id": 2, |
1393 | + "links": [], |
1394 | + "options": { |
1395 | + "fieldOptions": { |
1396 | + "calcs": [ |
1397 | + "mean" |
1398 | + ], |
1399 | + "defaults": { |
1400 | + "mappings": [ |
1401 | + { |
1402 | + "id": 0, |
1403 | + "op": "=", |
1404 | + "text": "N/A", |
1405 | + "type": 1, |
1406 | + "value": "null" |
1407 | + } |
1408 | + ], |
1409 | + "nullValueMode": "connected", |
1410 | + "thresholds": { |
1411 | + "mode": "absolute", |
1412 | + "steps": [ |
1413 | + { |
1414 | + "color": "green", |
1415 | + "value": null |
1416 | + }, |
1417 | + { |
1418 | + "color": "red", |
1419 | + "value": 80 |
1420 | + } |
1421 | + ] |
1422 | + }, |
1423 | + "title": "MB", |
1424 | + "unit": "none" |
1425 | + }, |
1426 | + "overrides": [], |
1427 | + "values": false |
1428 | + }, |
1429 | + "orientation": "horizontal", |
1430 | + "showThresholdLabels": false, |
1431 | + "showThresholdMarkers": true |
1432 | + }, |
1433 | + "pluginVersion": "6.7.0", |
1434 | + "targets": [ |
1435 | + { |
1436 | + "expr": "sum(libvirt_domain_block_stats_read_bytes_total)/1024/1024", |
1437 | + "format": "heatmap", |
1438 | + "hide": false, |
1439 | + "instant": false, |
1440 | + "intervalFactor": 1, |
1441 | + "legendFormat": "Read {{instance}}", |
1442 | + "refId": "A" |
1443 | + } |
1444 | + ], |
1445 | + "timeFrom": null, |
1446 | + "timeShift": null, |
1447 | + "title": "Disk Cumulative Read", |
1448 | + "type": "gauge" |
1449 | + } |
1450 | + ], |
1451 | + "title": "Disk", |
1452 | + "type": "row" |
1453 | + } |
1454 | + ], |
1455 | + "refresh": "5s", |
1456 | + "schemaVersion": 22, |
1457 | + "style": "dark", |
1458 | + "tags": [], |
1459 | + "templating": { |
1460 | + "list": [ |
1461 | + { |
1462 | + "allValue": null, |
1463 | + "current": { |
1464 | + "text": "All", |
1465 | + "value": [ |
1466 | + "$__all" |
1467 | + ] |
1468 | + }, |
1469 | + "datasource": "prometheus - Juju generated source", |
1470 | + "definition": "libvirt_up", |
1471 | + "hide": 0, |
1472 | + "includeAll": true, |
1473 | + "index": -1, |
1474 | + "label": "libvirt daemon", |
1475 | + "multi": true, |
1476 | + "name": "host", |
1477 | + "options": [], |
1478 | + "query": "libvirt_up", |
1479 | + "refresh": 1, |
1480 | + "regex": ".*instance=\"([^\"]+).*?\".*$", |
1481 | + "skipUrlSync": false, |
1482 | + "sort": 0, |
1483 | + "tagValuesQuery": "", |
1484 | + "tags": [], |
1485 | + "tagsQuery": "", |
1486 | + "type": "query", |
1487 | + "useTags": false |
1488 | + }, |
1489 | + { |
1490 | + "allValue": null, |
1491 | + "current": { |
1492 | + "tags": [], |
1493 | + "text": "All", |
1494 | + "value": [ |
1495 | + "$__all" |
1496 | + ] |
1497 | + }, |
1498 | + "datasource": "prometheus - Juju generated source", |
1499 | + "definition": "libvirt_domain_info_virtual_cpus", |
1500 | + "hide": 0, |
1501 | + "includeAll": true, |
1502 | + "index": -1, |
1503 | + "label": null, |
1504 | + "multi": true, |
1505 | + "name": "domain", |
1506 | + "options": [], |
1507 | + "query": "libvirt_domain_info_virtual_cpus", |
1508 | + "refresh": 1, |
1509 | + "regex": ".*domain=\"([^\"]+)\".*$", |
1510 | + "skipUrlSync": false, |
1511 | + "sort": 1, |
1512 | + "tagValuesQuery": "", |
1513 | + "tags": [], |
1514 | + "tagsQuery": "", |
1515 | + "type": "query", |
1516 | + "useTags": false |
1517 | + } |
1518 | + ] |
1519 | + }, |
1520 | + "time": { |
1521 | + "from": "now-1h", |
1522 | + "to": "now" |
1523 | + }, |
1524 | + "timepicker": { |
1525 | + "refresh_intervals": [ |
1526 | + "5s", |
1527 | + "10s", |
1528 | + "30s", |
1529 | + "1m", |
1530 | + "5m", |
1531 | + "15m", |
1532 | + "30m", |
1533 | + "1h", |
1534 | + "2h", |
1535 | + "1d" |
1536 | + ] |
1537 | + }, |
1538 | + "timezone": "", |
1539 | + "title": "libvirt", |
1540 | + "uid": "u_Zk_wuZk", |
1541 | + "variables": { |
1542 | + "list": [] |
1543 | + }, |
1544 | + "version": 288 |
1545 | + } |
1546 | +} |
1547 | diff --git a/icon.svg b/icon.svg |
1548 | new file mode 100644 |
1549 | index 0000000..96a5d0c |
1550 | --- /dev/null |
1551 | +++ b/icon.svg |
1552 | @@ -0,0 +1,279 @@ |
1553 | +<?xml version="1.0" encoding="UTF-8" standalone="no"?> |
1554 | +<!-- Created with Inkscape (http://www.inkscape.org/) --> |
1555 | + |
1556 | +<svg |
1557 | + xmlns:dc="http://purl.org/dc/elements/1.1/" |
1558 | + xmlns:cc="http://creativecommons.org/ns#" |
1559 | + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" |
1560 | + xmlns:svg="http://www.w3.org/2000/svg" |
1561 | + xmlns="http://www.w3.org/2000/svg" |
1562 | + xmlns:xlink="http://www.w3.org/1999/xlink" |
1563 | + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" |
1564 | + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" |
1565 | + width="96" |
1566 | + height="96" |
1567 | + id="svg6517" |
1568 | + version="1.1" |
1569 | + inkscape:version="0.48+devel r12274" |
1570 | + sodipodi:docname="Juju_charm_icon_template.svg"> |
1571 | + <defs |
1572 | + id="defs6519"> |
1573 | + <linearGradient |
1574 | + inkscape:collect="always" |
1575 | + xlink:href="#Background" |
1576 | + id="linearGradient6461" |
1577 | + gradientUnits="userSpaceOnUse" |
1578 | + x1="0" |
1579 | + y1="970.29498" |
1580 | + x2="144" |
1581 | + y2="970.29498" |
1582 | + gradientTransform="matrix(0,-0.66666669,0.6660448,0,-866.25992,731.29077)" /> |
1583 | + <linearGradient |
1584 | + id="Background"> |
1585 | + <stop |
1586 | + id="stop4178" |
1587 | + offset="0" |
1588 | + style="stop-color:#b8b8b8;stop-opacity:1" /> |
1589 | + <stop |
1590 | + id="stop4180" |
1591 | + offset="1" |
1592 | + style="stop-color:#c9c9c9;stop-opacity:1" /> |
1593 | + </linearGradient> |
1594 | + <filter |
1595 | + style="color-interpolation-filters:sRGB;" |
1596 | + inkscape:label="Inner Shadow" |
1597 | + id="filter1121"> |
1598 | + <feFlood |
1599 | + flood-opacity="0.59999999999999998" |
1600 | + flood-color="rgb(0,0,0)" |
1601 | + result="flood" |
1602 | + id="feFlood1123" /> |
1603 | + <feComposite |
1604 | + in="flood" |
1605 | + in2="SourceGraphic" |
1606 | + operator="out" |
1607 | + result="composite1" |
1608 | + id="feComposite1125" /> |
1609 | + <feGaussianBlur |
1610 | + in="composite1" |
1611 | + stdDeviation="1" |
1612 | + result="blur" |
1613 | + id="feGaussianBlur1127" /> |
1614 | + <feOffset |
1615 | + dx="0" |
1616 | + dy="2" |
1617 | + result="offset" |
1618 | + id="feOffset1129" /> |
1619 | + <feComposite |
1620 | + in="offset" |
1621 | + in2="SourceGraphic" |
1622 | + operator="atop" |
1623 | + result="composite2" |
1624 | + id="feComposite1131" /> |
1625 | + </filter> |
1626 | + <filter |
1627 | + style="color-interpolation-filters:sRGB;" |
1628 | + inkscape:label="Drop Shadow" |
1629 | + id="filter950"> |
1630 | + <feFlood |
1631 | + flood-opacity="0.25" |
1632 | + flood-color="rgb(0,0,0)" |
1633 | + result="flood" |
1634 | + id="feFlood952" /> |
1635 | + <feComposite |
1636 | + in="flood" |
1637 | + in2="SourceGraphic" |
1638 | + operator="in" |
1639 | + result="composite1" |
1640 | + id="feComposite954" /> |
1641 | + <feGaussianBlur |
1642 | + in="composite1" |
1643 | + stdDeviation="1" |
1644 | + result="blur" |
1645 | + id="feGaussianBlur956" /> |
1646 | + <feOffset |
1647 | + dx="0" |
1648 | + dy="1" |
1649 | + result="offset" |
1650 | + id="feOffset958" /> |
1651 | + <feComposite |
1652 | + in="SourceGraphic" |
1653 | + in2="offset" |
1654 | + operator="over" |
1655 | + result="composite2" |
1656 | + id="feComposite960" /> |
1657 | + </filter> |
1658 | + <clipPath |
1659 | + clipPathUnits="userSpaceOnUse" |
1660 | + id="clipPath873"> |
1661 | + <g |
1662 | + transform="matrix(0,-0.66666667,0.66604479,0,-258.25992,677.00001)" |
1663 | + id="g875" |
1664 | + inkscape:label="Layer 1" |
1665 | + style="fill:#ff00ff;fill-opacity:1;stroke:none;display:inline"> |
1666 | + <path |
1667 | + style="fill:#ff00ff;fill-opacity:1;stroke:none;display:inline" |
1668 | + 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" |
1669 | + id="path877" |
1670 | + inkscape:connector-curvature="0" |
1671 | + sodipodi:nodetypes="sssssssss" /> |
1672 | + </g> |
1673 | + </clipPath> |
1674 | + <filter |
1675 | + inkscape:collect="always" |
1676 | + id="filter891" |
1677 | + inkscape:label="Badge Shadow"> |
1678 | + <feGaussianBlur |
1679 | + inkscape:collect="always" |
1680 | + stdDeviation="0.71999962" |
1681 | + id="feGaussianBlur893" /> |
1682 | + </filter> |
1683 | + </defs> |
1684 | + <sodipodi:namedview |
1685 | + id="base" |
1686 | + pagecolor="#ffffff" |
1687 | + bordercolor="#666666" |
1688 | + borderopacity="1.0" |
1689 | + inkscape:pageopacity="0.0" |
1690 | + inkscape:pageshadow="2" |
1691 | + inkscape:zoom="4.0745362" |
1692 | + inkscape:cx="18.514671" |
1693 | + inkscape:cy="49.018169" |
1694 | + inkscape:document-units="px" |
1695 | + inkscape:current-layer="layer1" |
1696 | + showgrid="true" |
1697 | + fit-margin-top="0" |
1698 | + fit-margin-left="0" |
1699 | + fit-margin-right="0" |
1700 | + fit-margin-bottom="0" |
1701 | + inkscape:window-width="1920" |
1702 | + inkscape:window-height="1029" |
1703 | + inkscape:window-x="0" |
1704 | + inkscape:window-y="24" |
1705 | + inkscape:window-maximized="1" |
1706 | + showborder="true" |
1707 | + showguides="true" |
1708 | + inkscape:guide-bbox="true" |
1709 | + inkscape:showpageshadow="false"> |
1710 | + <inkscape:grid |
1711 | + type="xygrid" |
1712 | + id="grid821" /> |
1713 | + <sodipodi:guide |
1714 | + orientation="1,0" |
1715 | + position="16,48" |
1716 | + id="guide823" /> |
1717 | + <sodipodi:guide |
1718 | + orientation="0,1" |
1719 | + position="64,80" |
1720 | + id="guide825" /> |
1721 | + <sodipodi:guide |
1722 | + orientation="1,0" |
1723 | + position="80,40" |
1724 | + id="guide827" /> |
1725 | + <sodipodi:guide |
1726 | + orientation="0,1" |
1727 | + position="64,16" |
1728 | + id="guide829" /> |
1729 | + </sodipodi:namedview> |
1730 | + <metadata |
1731 | + id="metadata6522"> |
1732 | + <rdf:RDF> |
1733 | + <cc:Work |
1734 | + rdf:about=""> |
1735 | + <dc:format>image/svg+xml</dc:format> |
1736 | + <dc:type |
1737 | + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> |
1738 | + <dc:title></dc:title> |
1739 | + </cc:Work> |
1740 | + </rdf:RDF> |
1741 | + </metadata> |
1742 | + <g |
1743 | + inkscape:label="BACKGROUND" |
1744 | + inkscape:groupmode="layer" |
1745 | + id="layer1" |
1746 | + transform="translate(268,-635.29076)" |
1747 | + style="display:inline"> |
1748 | + <path |
1749 | + style="fill:url(#linearGradient6461);fill-opacity:1;stroke:none;display:inline;filter:url(#filter1121)" |
1750 | + 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" |
1751 | + id="path6455" |
1752 | + inkscape:connector-curvature="0" |
1753 | + sodipodi:nodetypes="sssssssss" /> |
1754 | + </g> |
1755 | + <g |
1756 | + inkscape:groupmode="layer" |
1757 | + id="layer3" |
1758 | + inkscape:label="PLACE YOUR PICTOGRAM HERE" |
1759 | + style="display:inline" /> |
1760 | + <g |
1761 | + inkscape:groupmode="layer" |
1762 | + id="layer2" |
1763 | + inkscape:label="BADGE" |
1764 | + style="display:none" |
1765 | + sodipodi:insensitive="true"> |
1766 | + <g |
1767 | + style="display:inline" |
1768 | + transform="translate(-340.00001,-581)" |
1769 | + id="g4394" |
1770 | + clip-path="none"> |
1771 | + <g |
1772 | + id="g855"> |
1773 | + <g |
1774 | + inkscape:groupmode="maskhelper" |
1775 | + id="g870" |
1776 | + clip-path="url(#clipPath873)" |
1777 | + style="opacity:0.6;filter:url(#filter891)"> |
1778 | + <path |
1779 | + transform="matrix(1.4999992,0,0,1.4999992,-29.999795,-237.54282)" |
1780 | + d="m 264,552.36218 a 12,12 0 1 1 -24,0 A 12,12 0 1 1 264,552.36218 Z" |
1781 | + sodipodi:ry="12" |
1782 | + sodipodi:rx="12" |
1783 | + sodipodi:cy="552.36218" |
1784 | + sodipodi:cx="252" |
1785 | + id="path844" |
1786 | + 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" |
1787 | + sodipodi:type="arc" /> |
1788 | + </g> |
1789 | + <g |
1790 | + id="g862"> |
1791 | + <path |
1792 | + sodipodi:type="arc" |
1793 | + 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" |
1794 | + id="path4398" |
1795 | + sodipodi:cx="252" |
1796 | + sodipodi:cy="552.36218" |
1797 | + sodipodi:rx="12" |
1798 | + sodipodi:ry="12" |
1799 | + d="m 264,552.36218 a 12,12 0 1 1 -24,0 A 12,12 0 1 1 264,552.36218 Z" |
1800 | + transform="matrix(1.4999992,0,0,1.4999992,-29.999795,-238.54282)" /> |
1801 | + <path |
1802 | + transform="matrix(1.25,0,0,1.25,33,-100.45273)" |
1803 | + d="m 264,552.36218 a 12,12 0 1 1 -24,0 A 12,12 0 1 1 264,552.36218 Z" |
1804 | + sodipodi:ry="12" |
1805 | + sodipodi:rx="12" |
1806 | + sodipodi:cy="552.36218" |
1807 | + sodipodi:cx="252" |
1808 | + id="path4400" |
1809 | + 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" |
1810 | + sodipodi:type="arc" /> |
1811 | + <path |
1812 | + sodipodi:type="star" |
1813 | + 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" |
1814 | + id="path4459" |
1815 | + sodipodi:sides="5" |
1816 | + sodipodi:cx="666.19574" |
1817 | + sodipodi:cy="589.50385" |
1818 | + sodipodi:r1="7.2431178" |
1819 | + sodipodi:r2="4.3458705" |
1820 | + sodipodi:arg1="1.0471976" |
1821 | + sodipodi:arg2="1.6755161" |
1822 | + inkscape:flatsided="false" |
1823 | + inkscape:rounded="0.1" |
1824 | + inkscape:randomized="0" |
1825 | + 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" |
1826 | + transform="matrix(1.511423,-0.16366377,0.16366377,1.511423,-755.37346,-191.93651)" /> |
1827 | + </g> |
1828 | + </g> |
1829 | + </g> |
1830 | + </g> |
1831 | +</svg> |
1832 | diff --git a/interfaces/.empty b/interfaces/.empty |
1833 | new file mode 100644 |
1834 | index 0000000..e69de29 |
1835 | --- /dev/null |
1836 | +++ b/interfaces/.empty |
1837 | diff --git a/layer.yaml b/layer.yaml |
1838 | index b289219..8617d82 100644 |
1839 | --- a/layer.yaml |
1840 | +++ b/layer.yaml |
1841 | @@ -1,6 +1,13 @@ |
1842 | -includes: ['layer:basic', 'interface:http', 'layer:snap'] |
1843 | +includes: |
1844 | + - layer:basic |
1845 | + - interface:http |
1846 | + - layer:snap |
1847 | + - interface:juju-info |
1848 | + - interface:nrpe-external-master |
1849 | + - interface:grafana-dashboard |
1850 | + - layer:leadership |
1851 | ignore: ['.*.swp' ] |
1852 | options: |
1853 | - basic: |
1854 | - use_venv: true |
1855 | + basic: |
1856 | + use_venv: true |
1857 | repo: https://git.launchpad.net/prometheus-libvirt-exporter-charm |
1858 | diff --git a/layers/.empty b/layers/.empty |
1859 | new file mode 100644 |
1860 | index 0000000..e69de29 |
1861 | --- /dev/null |
1862 | +++ b/layers/.empty |
1863 | diff --git a/metadata.yaml b/metadata.yaml |
1864 | index 1d2bfb4..3c8e44b 100644 |
1865 | --- a/metadata.yaml |
1866 | +++ b/metadata.yaml |
1867 | @@ -8,6 +8,7 @@ description: | |
1868 | series: |
1869 | - xenial |
1870 | - bionic |
1871 | + - focal |
1872 | tags: |
1873 | - monitoring |
1874 | subordinate: true |
1875 | @@ -18,8 +19,19 @@ requires: |
1876 | provides: |
1877 | scrape: |
1878 | interface: http |
1879 | + nrpe-external-master: |
1880 | + interface: nrpe-external-master |
1881 | + scope: container |
1882 | + dashboards: |
1883 | + interface: grafana-dashboard |
1884 | resources: |
1885 | prometheus-libvirt-exporter: |
1886 | type: file |
1887 | filename: prometheus-libvirt-exporter.snap |
1888 | description: Prometheus-libvirt-exporter snap |
1889 | + dashboards: |
1890 | + type: file |
1891 | + filename: grafana-dashboards.zip |
1892 | + description: |
1893 | + By default the charm is distributed with a dashboard that gets pushed to grafana. |
1894 | + You can override this dashboard with your own |
1895 | diff --git a/reactive/libvirt-exporter.py b/reactive/libvirt-exporter.py |
1896 | deleted file mode 100644 |
1897 | index 8727119..0000000 |
1898 | --- a/reactive/libvirt-exporter.py |
1899 | +++ /dev/null |
1900 | @@ -1,46 +0,0 @@ |
1901 | -from charmhelpers.core import hookenv, host |
1902 | -from charms.reactive import ( |
1903 | - when, when_not, set_state, remove_state |
1904 | -) |
1905 | -from charms.layer import snap |
1906 | -import subprocess |
1907 | - |
1908 | - |
1909 | -SNAP_NAME = 'prometheus-libvirt-exporter' |
1910 | -SVC_NAME = 'snap.prometheus-libvirt-exporter.daemon' |
1911 | -PORT_NUMBER = '9177' |
1912 | - |
1913 | - |
1914 | -@when_not('libvirt-exporter.installed') |
1915 | -def install_packages(): |
1916 | - hookenv.status_set('maintenance', 'Installing software') |
1917 | - config = hookenv.config() |
1918 | - channel = config.get('snap_channel', 'stable') |
1919 | - snap.install(SNAP_NAME, channel=channel, force_dangerous=False) |
1920 | - subprocess.check_call(['snap', 'connect', 'prometheus-libvirt-exporter:libvirt']) |
1921 | - hookenv.status_set('active', 'Exporter installed and connected to libvirt slot') |
1922 | - hookenv.open_port(PORT_NUMBER) |
1923 | - set_state('libvirt-exporter.installed') |
1924 | - |
1925 | - |
1926 | -@when('libvirt-exporter.installed') |
1927 | -def check_status(): |
1928 | - config = hookenv.config() |
1929 | - if config.changed('snap_channel'): |
1930 | - remove_state('libvirt-exporter.installed') |
1931 | - return |
1932 | - if not host.service_running(SVC_NAME): |
1933 | - hookenv.status_set('maintenance', 'Service is down, starting') |
1934 | - hookenv.log('Service {} is down, starting...'.format(SVC_NAME)) |
1935 | - host.service_start(SVC_NAME) |
1936 | - hookenv.status_set('active', 'Service started') |
1937 | - else: |
1938 | - hookenv.status_set('active', 'Service is up') |
1939 | - set_state('libvirt-exporter.started') |
1940 | - |
1941 | - |
1942 | -# Relations |
1943 | -@when('libvirt-exporter.started') |
1944 | -@when('scrape.available') |
1945 | -def configure_scrape_relation(scrape_service): |
1946 | - scrape_service.configure(PORT_NUMBER) |
1947 | diff --git a/reactive/prometheus-libvirt-exporter.py b/reactive/prometheus-libvirt-exporter.py |
1948 | new file mode 100644 |
1949 | index 0000000..1660481 |
1950 | --- /dev/null |
1951 | +++ b/reactive/prometheus-libvirt-exporter.py |
1952 | @@ -0,0 +1,185 @@ |
1953 | +#!/usr/bin/python3 |
1954 | +"""Installs and configures prometheus-libvirt-exporter.""" |
1955 | + |
1956 | +import os |
1957 | +from pathlib import Path |
1958 | +import shutil |
1959 | +import subprocess |
1960 | +from zipfile import BadZipFile, ZipFile |
1961 | + |
1962 | +from charmhelpers.contrib.charmsupport import nrpe |
1963 | +from charmhelpers.core import hookenv, host |
1964 | +from charms.layer import snap |
1965 | +from charms.reactive import ( |
1966 | + endpoint_from_flag, |
1967 | + hook, |
1968 | + remove_state, |
1969 | + set_state, |
1970 | + when, |
1971 | + when_all, |
1972 | + when_any, |
1973 | + when_not, |
1974 | + when_not_all |
1975 | +) |
1976 | + |
1977 | + |
1978 | +DASHBOARD_PATH = os.getcwd() + '/files/grafana-dashboards' |
1979 | +SNAP_NAME = 'prometheus-libvirt-exporter' |
1980 | +SVC_NAME = 'snap.prometheus-libvirt-exporter.daemon' |
1981 | +PORT_NUMBER = '9177' |
1982 | + |
1983 | + |
1984 | +@when('juju-info.connected') |
1985 | +@when_not_all('libvirt-exporter.installed', 'libvirt-exporter.started') |
1986 | +def install_packages(): |
1987 | + """Installs the prometheus-libvirt-exporter snap.""" |
1988 | + hookenv.status_set('maintenance', 'Installing software') |
1989 | + config = hookenv.config() |
1990 | + channel = config.get('snap_channel') |
1991 | + snap.install(SNAP_NAME, channel=channel, force_dangerous=False) |
1992 | + subprocess.check_call(['snap', 'connect', 'prometheus-libvirt-exporter:libvirt']) |
1993 | + hookenv.status_set('active', 'Exporter installed and connected to libvirt slot') |
1994 | + hookenv.open_port(PORT_NUMBER) |
1995 | + set_state('libvirt-exporter.installed') |
1996 | + |
1997 | + |
1998 | +@hook('upgrade-charm') |
1999 | +def upgrade(): |
2000 | + """Reset the install state on upgrade, to ensure resource extraction.""" |
2001 | + hookenv.status_set('maintenance', 'Charm upgrade in progress') |
2002 | + remove_state('libvirt-exporter.installed') |
2003 | + remove_state('libvirt-exporter.started') |
2004 | + update_dashboards_from_resource() |
2005 | + |
2006 | + |
2007 | +@when_not('libvirt-exporter.started') |
2008 | +@when_any('libvirt-exporter.installed', 'config.changed') |
2009 | +def start_snap(): |
2010 | + """Configure snap.prometheus-libvirt-exporter.daemon service.""" |
2011 | + if not host.service_running(SVC_NAME): |
2012 | + hookenv.status_set('maintenance', 'Service is down, starting') |
2013 | + hookenv.log('Service {} is down, starting...'.format(SVC_NAME)) |
2014 | + host.service_start(SVC_NAME) |
2015 | + hookenv.status_set('active', 'Service started') |
2016 | + hookenv.log('start_snap() Service started') |
2017 | + else: |
2018 | + hookenv.status_set('active', 'Ready') |
2019 | + set_state('libvirt-exporter.started') |
2020 | + hookenv.log('start_snap() libvirt-exporter.started') |
2021 | + |
2022 | + update_dashboards_from_resource() |
2023 | + |
2024 | + hookenv.log('Installed and set flag libvirt-exporter.started') |
2025 | + |
2026 | + |
2027 | +@when('config.changed.snap_channel') |
2028 | +def snap_channel_changed(): |
2029 | + """Remove the state libvirt.exporter.installed if the snap channel changes.""" |
2030 | + remove_state('libvirt-exporter.installed') |
2031 | + remove_state('libvirt-exporter.started') |
2032 | + |
2033 | + |
2034 | +@when_all('libvirt-exporter.started', 'scrape.available') |
2035 | +def configure_scrape_relation(scrape_service): |
2036 | + """Connect prometheus to the the exporter for consumption.""" |
2037 | + scrape_service.configure(PORT_NUMBER) |
2038 | + remove_state('libvirt-exporter.configured') |
2039 | + |
2040 | + |
2041 | +@when('nrpe-external-master.changed') |
2042 | +def nrpe_changed(): |
2043 | + """Trigger nrpe update.""" |
2044 | + remove_state('libvirt-exporter.configured') |
2045 | + |
2046 | + |
2047 | +@when('libvirt-exporter.changed') |
2048 | +def prometheus_changed(): |
2049 | + """Trigger prometheus update.""" |
2050 | + remove_state('libvirt-exporter.prometheus_relation_configured') |
2051 | + remove_state('libvirt-exporter.configured') |
2052 | + |
2053 | + |
2054 | +@when('nrpe-external-master.available') |
2055 | +@when_not('libvirt-exporter.configured') |
2056 | +def update_nrpe_config(svc): |
2057 | + """Configure the nrpe check for the service.""" |
2058 | + if not os.path.exists('/var/lib/nagios'): |
2059 | + hookenv.status_set('blocked', 'Waiting for nrpe package installation') |
2060 | + return |
2061 | + |
2062 | + hookenv.status_set('maintenance', 'Configuring nrpe checks') |
2063 | + |
2064 | + hostname = nrpe.get_nagios_hostname() |
2065 | + nrpe_setup = nrpe.NRPE(hostname=hostname) |
2066 | + nrpe_setup.add_check(shortname='prometheus_libvirt_exporter_http', |
2067 | + check_cmd='check_http -I 127.0.0.1 -p {} -u /metrics'.format(PORT_NUMBER), |
2068 | + description='Prometheus Libvirt Exporter HTTP check') |
2069 | + nrpe_setup.write() |
2070 | + hookenv.status_set('active', 'ready') |
2071 | + set_state('libvirt-exporter.configured') |
2072 | + |
2073 | + |
2074 | +@when('libvirt-exporter.installed') |
2075 | +@when_not('juju-info.available') |
2076 | +def remove_libvirt_exporter(): |
2077 | + """Uninstall the snap.""" |
2078 | + remove_state('libvirt-exporter.installed') |
2079 | + remove_state('libvirt-exporter.started') |
2080 | + snap.remove(SNAP_NAME) |
2081 | + |
2082 | + |
2083 | +@when('libvirt-exporter.configured') |
2084 | +@when_not('nrpe-external-master.available') |
2085 | +def remove_nrpe_check(): |
2086 | + """Remove the nrpe check.""" |
2087 | + hostname = nrpe.get_nagios_hostname() |
2088 | + nrpe_setup = nrpe.NRPE(hostname=hostname) |
2089 | + nrpe_setup.remove_check(shortname="prometheus_libvirt_exporter_http") |
2090 | + remove_state('libvirt-exporter.configured') |
2091 | + |
2092 | + |
2093 | +@when_all('leadership.is_leader', 'endpoint.dashboards.joined') |
2094 | +def register_grafana_dashboards(): |
2095 | + """After joining to grafana, push the dashboard.""" |
2096 | + grafana_endpoint = endpoint_from_flag('endpoint.dashboards.joined') |
2097 | + |
2098 | + if grafana_endpoint is None: |
2099 | + return |
2100 | + |
2101 | + hookenv.log('Grafana relation joined, push dashboard') |
2102 | + |
2103 | + # load pre-distributed dashboards, that may have been overwritten by resource |
2104 | + dash_dir = Path(DASHBOARD_PATH) |
2105 | + for dash_file in dash_dir.glob('*.json'): |
2106 | + dashboard = dash_file.read_text() |
2107 | + grafana_endpoint.register_dashboard(dash_file.stem, dashboard) |
2108 | + hookenv.log('Pushed {}'.format(dash_file)) |
2109 | + |
2110 | + |
2111 | +def update_dashboards_from_resource(): |
2112 | + """Extract resource zip file into templates directory.""" |
2113 | + dashboards_zip_resource = hookenv.resource_get('dashboards') |
2114 | + if not dashboards_zip_resource: |
2115 | + hookenv.log('No dashboards resource found', hookenv.DEBUG) |
2116 | + # no dashboards zip found, go with the default distributed dashboard |
2117 | + return |
2118 | + |
2119 | + hookenv.log('Installing dashboards from resource', hookenv.DEBUG) |
2120 | + try: |
2121 | + shutil.copy(dashboards_zip_resource, DASHBOARD_PATH) |
2122 | + except IOError as error: |
2123 | + hookenv.log('Problem copying resource: {}'.format(error), hookenv.ERROR) |
2124 | + return |
2125 | + |
2126 | + try: |
2127 | + with ZipFile(dashboards_zip_resource, 'r') as zipfile: |
2128 | + zipfile.extractall(path=DASHBOARD_PATH) |
2129 | + hookenv.log('Extracted dashboards from resource', hookenv.DEBUG) |
2130 | + except BadZipFile as error: |
2131 | + hookenv.log('BadZipFile: {}'.format(error), hookenv.ERROR) |
2132 | + return |
2133 | + except PermissionError as error: |
2134 | + hookenv.log('Unable to unzip the provided resource: {}'.format(error), hookenv.ERROR) |
2135 | + return |
2136 | + |
2137 | + register_grafana_dashboards() |
2138 | diff --git a/requirements.txt b/requirements.txt |
2139 | new file mode 100644 |
2140 | index 0000000..1713f68 |
2141 | --- /dev/null |
2142 | +++ b/requirements.txt |
2143 | @@ -0,0 +1 @@ |
2144 | +# Include python requirements here |
2145 | \ No newline at end of file |
2146 | diff --git a/tests/__init__.py b/tests/__init__.py |
2147 | new file mode 100644 |
2148 | index 0000000..d236d73 |
2149 | --- /dev/null |
2150 | +++ b/tests/__init__.py |
2151 | @@ -0,0 +1 @@ |
2152 | +"""Zaza tests.""" |
2153 | diff --git a/tests/bundles/bionic.yaml b/tests/bundles/bionic.yaml |
2154 | new file mode 100644 |
2155 | index 0000000..dcff425 |
2156 | --- /dev/null |
2157 | +++ b/tests/bundles/bionic.yaml |
2158 | @@ -0,0 +1,22 @@ |
2159 | +series: bionic |
2160 | +applications: |
2161 | + ubuntu: |
2162 | + charm: cs:ubuntu |
2163 | + num_units: 1 |
2164 | + prometheus-libvirt-exporter: |
2165 | + options: |
2166 | + snap_channel: stable |
2167 | + nrpe: |
2168 | + charm: cs:nrpe |
2169 | + prometheus: |
2170 | + charm: cs:prometheus2 |
2171 | + num_units: 1 |
2172 | +relations: |
2173 | + - - ubuntu |
2174 | + - prometheus-libvirt-exporter |
2175 | + - - ubuntu:juju-info |
2176 | + - nrpe:general-info |
2177 | + - - prometheus-libvirt-exporter:nrpe-external-master |
2178 | + - nrpe:nrpe-external-master |
2179 | + - - prometheus-libvirt-exporter:scrape |
2180 | + - prometheus:target |
2181 | \ No newline at end of file |
2182 | diff --git a/tests/bundles/focal.yaml b/tests/bundles/focal.yaml |
2183 | new file mode 100644 |
2184 | index 0000000..13bb440 |
2185 | --- /dev/null |
2186 | +++ b/tests/bundles/focal.yaml |
2187 | @@ -0,0 +1,22 @@ |
2188 | +series: focal |
2189 | +applications: |
2190 | + ubuntu: |
2191 | + charm: cs:ubuntu |
2192 | + num_units: 1 |
2193 | + prometheus-libvirt-exporter: |
2194 | + options: |
2195 | + snap_channel: stable |
2196 | + nrpe: |
2197 | + charm: cs:nrpe |
2198 | + prometheus: |
2199 | + charm: cs:prometheus2 |
2200 | + num_units: 1 |
2201 | +relations: |
2202 | + - - ubuntu |
2203 | + - prometheus-libvirt-exporter |
2204 | + - - ubuntu:juju-info |
2205 | + - nrpe:general-info |
2206 | + - - prometheus-libvirt-exporter:nrpe-external-master |
2207 | + - nrpe:nrpe-external-master |
2208 | + - - prometheus-libvirt-exporter:scrape |
2209 | + - prometheus:target |
2210 | \ No newline at end of file |
2211 | diff --git a/tests/bundles/overlays/local-charm-overlay.yaml.j2 b/tests/bundles/overlays/local-charm-overlay.yaml.j2 |
2212 | new file mode 100644 |
2213 | index 0000000..bfaaa2d |
2214 | --- /dev/null |
2215 | +++ b/tests/bundles/overlays/local-charm-overlay.yaml.j2 |
2216 | @@ -0,0 +1,3 @@ |
2217 | +applications: |
2218 | + prometheus-libvirt-exporter: |
2219 | + charm: "{{ CHARM_BUILD_DIR }}/{{ charm_name }}" |
2220 | diff --git a/tests/bundles/xenial.yaml b/tests/bundles/xenial.yaml |
2221 | new file mode 100644 |
2222 | index 0000000..aff59d8 |
2223 | --- /dev/null |
2224 | +++ b/tests/bundles/xenial.yaml |
2225 | @@ -0,0 +1,22 @@ |
2226 | +series: xenial |
2227 | +applications: |
2228 | + ubuntu: |
2229 | + charm: cs:ubuntu |
2230 | + num_units: 1 |
2231 | + prometheus-libvirt-exporter: |
2232 | + options: |
2233 | + snap_channel: stable |
2234 | + nrpe: |
2235 | + charm: cs:nrpe |
2236 | + prometheus: |
2237 | + charm: cs:prometheus2 |
2238 | + num_units: 1 |
2239 | +relations: |
2240 | + - - ubuntu |
2241 | + - prometheus-libvirt-exporter |
2242 | + - - ubuntu:juju-info |
2243 | + - nrpe:general-info |
2244 | + - - prometheus-libvirt-exporter:nrpe-external-master |
2245 | + - nrpe:nrpe-external-master |
2246 | + - - prometheus-libvirt-exporter:scrape |
2247 | + - prometheus:target |
2248 | \ No newline at end of file |
2249 | diff --git a/tests/requirements.txt b/tests/requirements.txt |
2250 | new file mode 100644 |
2251 | index 0000000..b7c9112 |
2252 | --- /dev/null |
2253 | +++ b/tests/requirements.txt |
2254 | @@ -0,0 +1 @@ |
2255 | +git+https://github.com/openstack-charmers/zaza.git#egg=zaza |
2256 | diff --git a/tests/test_prometheus_libvirt_exporter.py b/tests/test_prometheus_libvirt_exporter.py |
2257 | new file mode 100644 |
2258 | index 0000000..1cb865f |
2259 | --- /dev/null |
2260 | +++ b/tests/test_prometheus_libvirt_exporter.py |
2261 | @@ -0,0 +1,78 @@ |
2262 | +"""Encapsulate prometheus-libvirt-exporter testing.""" |
2263 | +import logging |
2264 | +import time |
2265 | +import unittest |
2266 | + |
2267 | +import zaza.model as model |
2268 | + |
2269 | + |
2270 | +CURL_TIMEOUT = 180 |
2271 | +REQ_TIMEOUT = 12 |
2272 | +DEFAULT_API_PORT = "9177" |
2273 | +DEFAULT_API_URL = "/metrics" |
2274 | + |
2275 | + |
2276 | +class BasePrometheusLibvirtExporterTest(unittest.TestCase): |
2277 | + """Base for Prometheus-libvirt-exporter charm tests.""" |
2278 | + |
2279 | + @classmethod |
2280 | + def setUpClass(cls): |
2281 | + """Set up tests.""" |
2282 | + super(BasePrometheusLibvirtExporterTest, cls).setUpClass() |
2283 | + cls.model_name = model.get_juju_model() |
2284 | + cls.application_name = "prometheus-libvirt-exporter" |
2285 | + cls.lead_unit_name = model.get_lead_unit_name( |
2286 | + cls.application_name, model_name=cls.model_name |
2287 | + ) |
2288 | + cls.units = model.get_units( |
2289 | + cls.application_name, model_name=cls.model_name |
2290 | + ) |
2291 | + cls.prometheus_libvirt_exporter_ip = model.get_app_ips(cls.application_name)[0] |
2292 | + |
2293 | + |
2294 | +class CharmOperationTest(BasePrometheusLibvirtExporterTest): |
2295 | + """Verify operations.""" |
2296 | + |
2297 | + def test_01_api_ready(self): |
2298 | + """Verify if the API is ready. |
2299 | + |
2300 | + Curl the api endpoint. |
2301 | + We'll retry until the CURL_TIMEOUT. |
2302 | + """ |
2303 | + curl_command = "curl http://localhost:{}/metrics".format(DEFAULT_API_PORT) |
2304 | + timeout = time.time() + CURL_TIMEOUT |
2305 | + while time.time() < timeout: |
2306 | + response = model.run_on_unit(self.lead_unit_name, curl_command) |
2307 | + if response["Code"] == "0": |
2308 | + return |
2309 | + logging.warning( |
2310 | + "Unexpected curl response: {}. Retrying in 30s.".format( |
2311 | + response |
2312 | + ) |
2313 | + ) |
2314 | + time.sleep(30) |
2315 | + |
2316 | + # we didn't get rc=0 in the allowed time, fail the test |
2317 | + self.fail( |
2318 | + "Prometheus-libvirt-exporter didn't respond to the command \n" |
2319 | + "'{curl_command}' as expected.\n" |
2320 | + "Result: {result}".format( |
2321 | + curl_command=curl_command, result=response |
2322 | + ) |
2323 | + ) |
2324 | + |
2325 | + def test_02_nrpe_http_check(self): |
2326 | + """Verify nrpe check exists.""" |
2327 | + expected_nrpe_check = "command[check_prometheus_libvirt_exporter_http]={} -I 127.0.0.1 -p {} -u {}".format( |
2328 | + "/usr/lib/nagios/plugins/check_http", |
2329 | + DEFAULT_API_PORT, |
2330 | + DEFAULT_API_URL |
2331 | + ) |
2332 | + logging.debug('Verify the nrpe check is created and has the required content...') |
2333 | + cmd = "cat /etc/nagios/nrpe.d/check_prometheus_libvirt_exporter_http.cfg" |
2334 | + result = model.run_on_unit(self.lead_unit_name, cmd) |
2335 | + code = result.get('Code') |
2336 | + if code != '0': |
2337 | + raise model.CommandRunFailed(cmd, result) |
2338 | + content = result.get('Stdout') |
2339 | + self.assertTrue(expected_nrpe_check in content) |
2340 | diff --git a/tests/tests.yaml b/tests/tests.yaml |
2341 | new file mode 100644 |
2342 | index 0000000..24ca291 |
2343 | --- /dev/null |
2344 | +++ b/tests/tests.yaml |
2345 | @@ -0,0 +1,11 @@ |
2346 | +charm_name: prometheus-libvirt-exporter |
2347 | +gate_bundles: |
2348 | + - xenial |
2349 | + - bionic |
2350 | + #- focal # Uncomment when nrpe and prometheus2 become available for focal |
2351 | +smoke_bundles: |
2352 | + - bionic |
2353 | +dev_bundles: |
2354 | + - bionic |
2355 | +tests: |
2356 | + - tests.test_prometheus_libvirt_exporter.CharmOperationTest |
2357 | diff --git a/tests/unit_tests/requirements.txt b/tests/unit_tests/requirements.txt |
2358 | new file mode 100644 |
2359 | index 0000000..8e404fb |
2360 | --- /dev/null |
2361 | +++ b/tests/unit_tests/requirements.txt |
2362 | @@ -0,0 +1,6 @@ |
2363 | +charmhelpers |
2364 | +charms.reactive |
2365 | +mock |
2366 | +pytest |
2367 | +pytest-cov |
2368 | +pytest-html |
2369 | \ No newline at end of file |
2370 | diff --git a/tox.ini b/tox.ini |
2371 | new file mode 100644 |
2372 | index 0000000..b50e481 |
2373 | --- /dev/null |
2374 | +++ b/tox.ini |
2375 | @@ -0,0 +1,65 @@ |
2376 | +[tox] |
2377 | +skipsdist=True |
2378 | +envlist = unit, functional |
2379 | +skip_missing_interpreters = True |
2380 | + |
2381 | +[testenv] |
2382 | +basepython = python3 |
2383 | +setenv = |
2384 | + PYTHONPATH = . |
2385 | + |
2386 | +[testenv:unit] |
2387 | +commands = pytest -v \ |
2388 | + --ignore {toxinidir}/tests/ \ |
2389 | + --ignore {toxinidir}/interfaces \ |
2390 | + --ignore {toxinidir}/layers \ |
2391 | + --cov=lib \ |
2392 | + --cov=actions \ |
2393 | + --cov-report=term \ |
2394 | + --cov-report=annotate:report/unit/coverage-annotated \ |
2395 | + --cov-report=html:report/unit/coverage-html \ |
2396 | + --html=report/unit/tests/index.html \ |
2397 | + --junitxml=report/unit/junit.xml |
2398 | +deps = -r{toxinidir}/tests/unit_tests/requirements.txt |
2399 | + -r{toxinidir}/tests/requirements.txt |
2400 | +setenv = PYTHONPATH={toxinidir}/lib |
2401 | + |
2402 | +[testenv:func] |
2403 | +commands = functest-run-suite --keep-model |
2404 | +deps = -r{toxinidir}/tests/requirements.txt |
2405 | +passenv = |
2406 | + HOME |
2407 | + CHARM_BUILD_DIR |
2408 | + MODEL_SETTINGS |
2409 | + |
2410 | +[testenv:lint] |
2411 | +commands = flake8 --format=html --htmldir=report/lint/ --tee |
2412 | +deps = |
2413 | + flake8 |
2414 | + flake8-colors |
2415 | + flake8-docstrings |
2416 | + flake8-html |
2417 | + flake8-import-order |
2418 | + pep8-naming |
2419 | + |
2420 | +[flake8] |
2421 | +exclude = |
2422 | + .git, |
2423 | + __pycache__, |
2424 | + .tox, |
2425 | + layers, |
2426 | + interfaces, |
2427 | +max-line-length = 120 |
2428 | +max-complexity = 10 |
2429 | +import-order-style = google |
2430 | + |
2431 | +[isort] |
2432 | +order_by_type = true |
2433 | +from_first = true |
2434 | +line_length = 120 |
2435 | + |
2436 | +[pytest] |
2437 | +markers = |
2438 | + deploy: mark deployment tests to allow running w/o redeploy |
2439 | +filterwarnings = |
2440 | + ignore::DeprecationWarning |
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