Adding HA support for Grafana charm
[osm/devops.git] / installers / charm / grafana / tests / test_charm.py
1 #!/usr/bin/env python3
2 # Copyright 2020 Canonical Ltd.
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License"); you may
5 # not use this file except in compliance with the License. You may obtain
6 # a copy of the License at
7 #
8 # http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 # License for the specific language governing permissions and limitations
14 # under the License.
15 #
16 # For those usages not covered by the Apache License, Version 2.0 please
17 # contact: legal@canonical.com
18 #
19 # To get in touch with the maintainers, please contact:
20 # osm-charmers@lists.launchpad.net
21 ##
22
23 import sys
24 from typing import NoReturn
25 import unittest
26 from unittest.mock import patch
27
28 from charm import GrafanaCharm
29 from ops.model import ActiveStatus, BlockedStatus
30 from ops.testing import Harness
31
32
33 class TestCharm(unittest.TestCase):
34 """Prometheus Charm unit tests."""
35
36 def setUp(self) -> NoReturn:
37 """Test setup"""
38 self.image_info = sys.modules["oci_image"].OCIImageResource().fetch()
39 self.harness = Harness(GrafanaCharm)
40 self.harness.set_leader(is_leader=True)
41 self.harness.begin()
42 self.config = {
43 "max_file_size": 0,
44 "ingress_whitelist_source_range": "",
45 "tls_secret_name": "",
46 "site_url": "https://grafana.192.168.100.100.nip.io",
47 "cluster_issuer": "vault-issuer",
48 "osm_dashboards": True,
49 }
50 self.harness.update_config(self.config)
51
52 def test_config_changed(
53 self,
54 ) -> NoReturn:
55 """Test ingress resources without HTTP."""
56
57 self.harness.charm.on.config_changed.emit()
58
59 # Assertions
60 self.assertIsInstance(self.harness.charm.unit.status, BlockedStatus)
61 self.assertTrue("prometheus" in self.harness.charm.unit.status.message)
62
63 def test_config_changed_non_leader(
64 self,
65 ) -> NoReturn:
66 """Test ingress resources without HTTP."""
67 self.harness.set_leader(is_leader=False)
68 self.harness.charm.on.config_changed.emit()
69
70 # Assertions
71 self.assertIsInstance(self.harness.charm.unit.status, ActiveStatus)
72
73 @patch("opslib.osm.interfaces.grafana.GrafanaCluster.set_initial_password")
74 def test_with_db_relation_and_prometheus(self, _) -> NoReturn:
75 self.initialize_prometheus_relation()
76 self.initialize_mysql_relation()
77 self.assertIsInstance(self.harness.charm.unit.status, ActiveStatus)
78
79 @patch("opslib.osm.interfaces.grafana.GrafanaCluster.set_initial_password")
80 def test_with_db_config_and_prometheus(self, _) -> NoReturn:
81 self.initialize_prometheus_relation()
82 self.initialize_mysql_config()
83 self.assertIsInstance(self.harness.charm.unit.status, ActiveStatus)
84
85 def test_with_prometheus(
86 self,
87 ) -> NoReturn:
88 """Test to see if prometheus relation is updated."""
89 self.initialize_prometheus_relation()
90 # Verifying status
91 self.assertIsInstance(self.harness.charm.unit.status, BlockedStatus)
92
93 def test_with_db_config(self) -> NoReturn:
94 "Test with mysql config"
95 self.initialize_mysql_config()
96 # Verifying status
97 self.assertIsInstance(self.harness.charm.unit.status, BlockedStatus)
98
99 @patch("opslib.osm.interfaces.grafana.GrafanaCluster.set_initial_password")
100 def test_with_db_relations(self, _) -> NoReturn:
101 "Test with relations"
102 self.initialize_mysql_relation()
103 # Verifying status
104 self.assertIsInstance(self.harness.charm.unit.status, BlockedStatus)
105
106 def test_exception_db_relation_and_config(
107 self,
108 ) -> NoReturn:
109 "Test with relations and config. Must throw exception"
110 self.initialize_mysql_config()
111 self.initialize_mysql_relation()
112 # Verifying status
113 self.assertIsInstance(self.harness.charm.unit.status, BlockedStatus)
114
115 def initialize_prometheus_relation(self):
116 relation_id = self.harness.add_relation("prometheus", "prometheus")
117 self.harness.add_relation_unit(relation_id, "prometheus/0")
118 self.harness.update_relation_data(
119 relation_id,
120 "prometheus",
121 {"hostname": "prometheus", "port": 9090},
122 )
123
124 def initialize_mysql_config(self):
125 self.harness.update_config(
126 {"mysql_uri": "mysql://grafana:$grafanapw$@host:3606/db"}
127 )
128
129 def initialize_mysql_relation(self):
130 relation_id = self.harness.add_relation("db", "mysql")
131 self.harness.add_relation_unit(relation_id, "mysql/0")
132 self.harness.update_relation_data(
133 relation_id,
134 "mysql/0",
135 {
136 "host": "mysql",
137 "port": 3306,
138 "user": "mano",
139 "password": "manopw",
140 "root_password": "rootmanopw",
141 },
142 )
143
144
145 if __name__ == "__main__":
146 unittest.main()
147
148 # class TestCharm(unittest.TestCase):
149 # """Grafana Charm unit tests."""
150
151 # def setUp(self) -> NoReturn:
152 # """Test setup"""
153 # self.harness = Harness(GrafanaCharm)
154 # self.harness.set_leader(is_leader=True)
155 # self.harness.begin()
156
157 # def test_on_start_without_relations(self) -> NoReturn:
158 # """Test installation without any relation."""
159 # self.harness.charm.on.start.emit()
160
161 # # Verifying status
162 # self.assertIsInstance(self.harness.charm.unit.status, BlockedStatus)
163
164 # # Verifying status message
165 # self.assertGreater(len(self.harness.charm.unit.status.message), 0)
166 # self.assertTrue(
167 # self.harness.charm.unit.status.message.startswith("Waiting for ")
168 # )
169 # self.assertIn("prometheus", self.harness.charm.unit.status.message)
170 # self.assertTrue(self.harness.charm.unit.status.message.endswith(" relation"))
171
172 # def test_on_start_with_relations_without_http(self) -> NoReturn:
173 # """Test deployment."""
174 # expected_result = {
175 # "version": 3,
176 # "containers": [
177 # {
178 # "name": "grafana",
179 # "imageDetails": self.harness.charm.image.fetch(),
180 # "imagePullPolicy": "Always",
181 # "ports": [
182 # {
183 # "name": "grafana",
184 # "containerPort": 3000,
185 # "protocol": "TCP",
186 # }
187 # ],
188 # "envConfig": {},
189 # "volumeConfig": [
190 # {
191 # "name": "dashboards",
192 # "mountPath": "/etc/grafana/provisioning/dashboards/",
193 # "files": [
194 # {
195 # "path": "dashboard-osm.yml",
196 # "content": (
197 # "apiVersion: 1\n"
198 # "providers:\n"
199 # " - name: 'osm'\n"
200 # " orgId: 1\n"
201 # " folder: ''\n"
202 # " type: file\n"
203 # " options:\n"
204 # " path: /etc/grafana/provisioning/dashboards/\n"
205 # ),
206 # },
207 # ],
208 # },
209 # {
210 # "name": "datasources",
211 # "mountPath": "/etc/grafana/provisioning/datasources/",
212 # "files": [
213 # {
214 # "path": "datasource-prometheus.yml",
215 # "content": (
216 # "datasources:\n"
217 # " - access: proxy\n"
218 # " editable: true\n"
219 # " is_default: true\n"
220 # " name: osm_prometheus\n"
221 # " orgId: 1\n"
222 # " type: prometheus\n"
223 # " version: 1\n"
224 # " url: http://prometheus:9090\n"
225 # ),
226 # },
227 # ],
228 # },
229 # ],
230 # "kubernetes": {
231 # "readinessProbe": {
232 # "httpGet": {
233 # "path": "/api/health",
234 # "port": 3000,
235 # },
236 # "initialDelaySeconds": 10,
237 # "periodSeconds": 10,
238 # "timeoutSeconds": 5,
239 # "successThreshold": 1,
240 # "failureThreshold": 3,
241 # },
242 # "livenessProbe": {
243 # "httpGet": {
244 # "path": "/api/health",
245 # "port": 3000,
246 # },
247 # "initialDelaySeconds": 60,
248 # "timeoutSeconds": 30,
249 # "failureThreshold": 10,
250 # },
251 # },
252 # },
253 # ],
254 # "kubernetesResources": {"ingressResources": []},
255 # }
256
257 # self.harness.charm.on.start.emit()
258
259 # # Initializing the prometheus relation
260 # relation_id = self.harness.add_relation("prometheus", "prometheus")
261 # self.harness.add_relation_unit(relation_id, "prometheus/0")
262 # self.harness.update_relation_data(
263 # relation_id,
264 # "prometheus",
265 # {
266 # "hostname": "prometheus",
267 # "port": "9090",
268 # },
269 # )
270
271 # # Verifying status
272 # self.assertNotIsInstance(self.harness.charm.unit.status, BlockedStatus)
273
274 # pod_spec, _ = self.harness.get_pod_spec()
275
276 # self.assertDictEqual(expected_result, pod_spec)
277
278 # def test_ingress_resources_with_http(self) -> NoReturn:
279 # """Test ingress resources with HTTP."""
280 # expected_result = {
281 # "version": 3,
282 # "containers": [
283 # {
284 # "name": "grafana",
285 # "imageDetails": self.harness.charm.image.fetch(),
286 # "imagePullPolicy": "Always",
287 # "ports": [
288 # {
289 # "name": "grafana",
290 # "containerPort": 3000,
291 # "protocol": "TCP",
292 # }
293 # ],
294 # "envConfig": {},
295 # "volumeConfig": [
296 # {
297 # "name": "dashboards",
298 # "mountPath": "/etc/grafana/provisioning/dashboards/",
299 # "files": [
300 # {
301 # "path": "dashboard-osm.yml",
302 # "content": (
303 # "apiVersion: 1\n"
304 # "providers:\n"
305 # " - name: 'osm'\n"
306 # " orgId: 1\n"
307 # " folder: ''\n"
308 # " type: file\n"
309 # " options:\n"
310 # " path: /etc/grafana/provisioning/dashboards/\n"
311 # ),
312 # },
313 # ],
314 # },
315 # {
316 # "name": "datasources",
317 # "mountPath": "/etc/grafana/provisioning/datasources/",
318 # "files": [
319 # {
320 # "path": "datasource-prometheus.yml",
321 # "content": (
322 # "datasources:\n"
323 # " - access: proxy\n"
324 # " editable: true\n"
325 # " is_default: true\n"
326 # " name: osm_prometheus\n"
327 # " orgId: 1\n"
328 # " type: prometheus\n"
329 # " version: 1\n"
330 # " url: http://prometheus:9090\n"
331 # ),
332 # },
333 # ],
334 # },
335 # ],
336 # "kubernetes": {
337 # "readinessProbe": {
338 # "httpGet": {
339 # "path": "/api/health",
340 # "port": 3000,
341 # },
342 # "initialDelaySeconds": 10,
343 # "periodSeconds": 10,
344 # "timeoutSeconds": 5,
345 # "successThreshold": 1,
346 # "failureThreshold": 3,
347 # },
348 # "livenessProbe": {
349 # "httpGet": {
350 # "path": "/api/health",
351 # "port": 3000,
352 # },
353 # "initialDelaySeconds": 60,
354 # "timeoutSeconds": 30,
355 # "failureThreshold": 10,
356 # },
357 # },
358 # },
359 # ],
360 # "kubernetesResources": {
361 # "ingressResources": [
362 # {
363 # "name": "grafana-ingress",
364 # "annotations": {
365 # "nginx.ingress.kubernetes.io/proxy-body-size": "0",
366 # "nginx.ingress.kubernetes.io/ssl-redirect": "false",
367 # },
368 # "spec": {
369 # "rules": [
370 # {
371 # "host": "grafana",
372 # "http": {
373 # "paths": [
374 # {
375 # "path": "/",
376 # "backend": {
377 # "serviceName": "grafana",
378 # "servicePort": 3000,
379 # },
380 # }
381 # ]
382 # },
383 # }
384 # ]
385 # },
386 # }
387 # ],
388 # },
389 # }
390
391 # self.harness.charm.on.start.emit()
392
393 # # Initializing the prometheus relation
394 # relation_id = self.harness.add_relation("prometheus", "prometheus")
395 # self.harness.add_relation_unit(relation_id, "prometheus/0")
396 # self.harness.update_relation_data(
397 # relation_id,
398 # "prometheus",
399 # {
400 # "hostname": "prometheus",
401 # "port": "9090",
402 # },
403 # )
404
405 # self.harness.update_config({"site_url": "http://grafana"})
406
407 # pod_spec, _ = self.harness.get_pod_spec()
408
409 # self.assertDictEqual(expected_result, pod_spec)
410
411 # def test_ingress_resources_with_https(self) -> NoReturn:
412 # """Test ingress resources with HTTPS."""
413 # expected_result = {
414 # "version": 3,
415 # "containers": [
416 # {
417 # "name": "grafana",
418 # "imageDetails": self.harness.charm.image.fetch(),
419 # "imagePullPolicy": "Always",
420 # "ports": [
421 # {
422 # "name": "grafana",
423 # "containerPort": 3000,
424 # "protocol": "TCP",
425 # }
426 # ],
427 # "envConfig": {},
428 # "volumeConfig": [
429 # {
430 # "name": "dashboards",
431 # "mountPath": "/etc/grafana/provisioning/dashboards/",
432 # "files": [
433 # {
434 # "path": "dashboard-osm.yml",
435 # "content": (
436 # "apiVersion: 1\n"
437 # "providers:\n"
438 # " - name: 'osm'\n"
439 # " orgId: 1\n"
440 # " folder: ''\n"
441 # " type: file\n"
442 # " options:\n"
443 # " path: /etc/grafana/provisioning/dashboards/\n"
444 # ),
445 # },
446 # ],
447 # },
448 # {
449 # "name": "datasources",
450 # "mountPath": "/etc/grafana/provisioning/datasources/",
451 # "files": [
452 # {
453 # "path": "datasource-prometheus.yml",
454 # "content": (
455 # "datasources:\n"
456 # " - access: proxy\n"
457 # " editable: true\n"
458 # " is_default: true\n"
459 # " name: osm_prometheus\n"
460 # " orgId: 1\n"
461 # " type: prometheus\n"
462 # " version: 1\n"
463 # " url: http://prometheus:9090\n"
464 # ),
465 # },
466 # ],
467 # },
468 # ],
469 # "kubernetes": {
470 # "readinessProbe": {
471 # "httpGet": {
472 # "path": "/api/health",
473 # "port": 3000,
474 # },
475 # "initialDelaySeconds": 10,
476 # "periodSeconds": 10,
477 # "timeoutSeconds": 5,
478 # "successThreshold": 1,
479 # "failureThreshold": 3,
480 # },
481 # "livenessProbe": {
482 # "httpGet": {
483 # "path": "/api/health",
484 # "port": 3000,
485 # },
486 # "initialDelaySeconds": 60,
487 # "timeoutSeconds": 30,
488 # "failureThreshold": 10,
489 # },
490 # },
491 # },
492 # ],
493 # "kubernetesResources": {
494 # "ingressResources": [
495 # {
496 # "name": "grafana-ingress",
497 # "annotations": {
498 # "nginx.ingress.kubernetes.io/proxy-body-size": "0",
499 # },
500 # "spec": {
501 # "rules": [
502 # {
503 # "host": "grafana",
504 # "http": {
505 # "paths": [
506 # {
507 # "path": "/",
508 # "backend": {
509 # "serviceName": "grafana",
510 # "servicePort": 3000,
511 # },
512 # }
513 # ]
514 # },
515 # }
516 # ],
517 # "tls": [{"hosts": ["grafana"], "secretName": "grafana"}],
518 # },
519 # }
520 # ],
521 # },
522 # }
523
524 # self.harness.charm.on.start.emit()
525
526 # # Initializing the prometheus relation
527 # relation_id = self.harness.add_relation("prometheus", "prometheus")
528 # self.harness.add_relation_unit(relation_id, "prometheus/0")
529 # self.harness.update_relation_data(
530 # relation_id,
531 # "prometheus",
532 # {
533 # "hostname": "prometheus",
534 # "port": "9090",
535 # },
536 # )
537
538 # self.harness.update_config(
539 # {"site_url": "https://grafana", "tls_secret_name": "grafana"}
540 # )
541
542 # pod_spec, _ = self.harness.get_pod_spec()
543
544 # self.assertDictEqual(expected_result, pod_spec)
545
546 # def test_ingress_resources_with_https_and_ingress_whitelist(self) -> NoReturn:
547 # """Test ingress resources with HTTPS and ingress whitelist."""
548 # expected_result = {
549 # "version": 3,
550 # "containers": [
551 # {
552 # "name": "grafana",
553 # "imageDetails": self.harness.charm.image.fetch(),
554 # "imagePullPolicy": "Always",
555 # "ports": [
556 # {
557 # "name": "grafana",
558 # "containerPort": 3000,
559 # "protocol": "TCP",
560 # }
561 # ],
562 # "envConfig": {},
563 # "volumeConfig": [
564 # {
565 # "name": "dashboards",
566 # "mountPath": "/etc/grafana/provisioning/dashboards/",
567 # "files": [
568 # {
569 # "path": "dashboard-osm.yml",
570 # "content": (
571 # "apiVersion: 1\n"
572 # "providers:\n"
573 # " - name: 'osm'\n"
574 # " orgId: 1\n"
575 # " folder: ''\n"
576 # " type: file\n"
577 # " options:\n"
578 # " path: /etc/grafana/provisioning/dashboards/\n"
579 # ),
580 # },
581 # ],
582 # },
583 # {
584 # "name": "datasources",
585 # "mountPath": "/etc/grafana/provisioning/datasources/",
586 # "files": [
587 # {
588 # "path": "datasource-prometheus.yml",
589 # "content": (
590 # "datasources:\n"
591 # " - access: proxy\n"
592 # " editable: true\n"
593 # " is_default: true\n"
594 # " name: osm_prometheus\n"
595 # " orgId: 1\n"
596 # " type: prometheus\n"
597 # " version: 1\n"
598 # " url: http://prometheus:9090\n"
599 # ),
600 # },
601 # ],
602 # },
603 # ],
604 # "kubernetes": {
605 # "readinessProbe": {
606 # "httpGet": {
607 # "path": "/api/health",
608 # "port": 3000,
609 # },
610 # "initialDelaySeconds": 10,
611 # "periodSeconds": 10,
612 # "timeoutSeconds": 5,
613 # "successThreshold": 1,
614 # "failureThreshold": 3,
615 # },
616 # "livenessProbe": {
617 # "httpGet": {
618 # "path": "/api/health",
619 # "port": 3000,
620 # },
621 # "initialDelaySeconds": 60,
622 # "timeoutSeconds": 30,
623 # "failureThreshold": 10,
624 # },
625 # },
626 # },
627 # ],
628 # "kubernetesResources": {
629 # "ingressResources": [
630 # {
631 # "name": "grafana-ingress",
632 # "annotations": {
633 # "nginx.ingress.kubernetes.io/proxy-body-size": "0",
634 # "nginx.ingress.kubernetes.io/whitelist-source-range": "0.0.0.0/0",
635 # },
636 # "spec": {
637 # "rules": [
638 # {
639 # "host": "grafana",
640 # "http": {
641 # "paths": [
642 # {
643 # "path": "/",
644 # "backend": {
645 # "serviceName": "grafana",
646 # "servicePort": 3000,
647 # },
648 # }
649 # ]
650 # },
651 # }
652 # ],
653 # "tls": [{"hosts": ["grafana"], "secretName": "grafana"}],
654 # },
655 # }
656 # ],
657 # },
658 # }
659
660 # self.harness.charm.on.start.emit()
661
662 # # Initializing the prometheus relation
663 # relation_id = self.harness.add_relation("prometheus", "prometheus")
664 # self.harness.add_relation_unit(relation_id, "prometheus/0")
665 # self.harness.update_relation_data(
666 # relation_id,
667 # "prometheus",
668 # {
669 # "hostname": "prometheus",
670 # "port": "9090",
671 # },
672 # )
673
674 # self.harness.update_config(
675 # {
676 # "site_url": "https://grafana",
677 # "tls_secret_name": "grafana",
678 # "ingress_whitelist_source_range": "0.0.0.0/0",
679 # }
680 # )
681
682 # pod_spec, _ = self.harness.get_pod_spec()
683
684 # self.assertDictEqual(expected_result, pod_spec)
685
686 # def test_on_prometheus_unit_relation_changed(self) -> NoReturn:
687 # """Test to see if prometheus relation is updated."""
688 # self.harness.charm.on.start.emit()
689
690 # relation_id = self.harness.add_relation("prometheus", "prometheus")
691 # self.harness.add_relation_unit(relation_id, "prometheus/0")
692 # self.harness.update_relation_data(
693 # relation_id,
694 # "prometheus",
695 # {"hostname": "prometheus", "port": 9090},
696 # )
697
698 # # Verifying status
699 # self.assertNotIsInstance(self.harness.charm.unit.status, BlockedStatus)
700
701
702 if __name__ == "__main__":
703 unittest.main()