5bbd15be927f110ed76ac204785fc2ceee9d0a00
[osm/devops.git] / installers / charm / grafana / tests / test_charm.py
1 #!/usr/bin/env python3
2 # Copyright 2021 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 from typing import NoReturn
24 import unittest
25
26 from ops.model import BlockedStatus
27 from ops.testing import Harness
28
29 from charm import GrafanaCharm
30
31
32 class TestCharm(unittest.TestCase):
33 """Grafana Charm unit tests."""
34
35 def setUp(self) -> NoReturn:
36 """Test setup"""
37 self.harness = Harness(GrafanaCharm)
38 self.harness.set_leader(is_leader=True)
39 self.harness.begin()
40
41 def test_on_start_without_relations(self) -> NoReturn:
42 """Test installation without any relation."""
43 self.harness.charm.on.start.emit()
44
45 # Verifying status
46 self.assertIsInstance(self.harness.charm.unit.status, BlockedStatus)
47
48 # Verifying status message
49 self.assertGreater(len(self.harness.charm.unit.status.message), 0)
50 self.assertTrue(
51 self.harness.charm.unit.status.message.startswith("Waiting for ")
52 )
53 self.assertIn("prometheus", self.harness.charm.unit.status.message)
54 self.assertTrue(self.harness.charm.unit.status.message.endswith(" relation"))
55
56 def test_on_start_with_relations_without_http(self) -> NoReturn:
57 """Test deployment."""
58 expected_result = {
59 "version": 3,
60 "containers": [
61 {
62 "name": "grafana",
63 "imageDetails": self.harness.charm.image.fetch(),
64 "imagePullPolicy": "Always",
65 "ports": [
66 {
67 "name": "grafana",
68 "containerPort": 3000,
69 "protocol": "TCP",
70 }
71 ],
72 "envConfig": {},
73 "volumeConfig": [
74 {
75 "name": "dashboards",
76 "mountPath": "/etc/grafana/provisioning/dashboards/",
77 "files": [
78 {
79 "path": "dashboard-osm.yml",
80 "content": (
81 "apiVersion: 1\n"
82 "providers:\n"
83 " - name: 'osm'\n"
84 " orgId: 1\n"
85 " folder: ''\n"
86 " type: file\n"
87 " options:\n"
88 " path: /etc/grafana/provisioning/dashboards/\n"
89 ),
90 },
91 ],
92 },
93 {
94 "name": "datasources",
95 "mountPath": "/etc/grafana/provisioning/datasources/",
96 "files": [
97 {
98 "path": "datasource-prometheus.yml",
99 "content": (
100 "datasources:\n"
101 " - access: proxy\n"
102 " editable: true\n"
103 " is_default: true\n"
104 " name: osm_prometheus\n"
105 " orgId: 1\n"
106 " type: prometheus\n"
107 " version: 1\n"
108 " url: http://prometheus:9090\n"
109 ),
110 },
111 ],
112 },
113 ],
114 "kubernetes": {
115 "readinessProbe": {
116 "httpGet": {
117 "path": "/api/health",
118 "port": 3000,
119 },
120 "initialDelaySeconds": 10,
121 "periodSeconds": 10,
122 "timeoutSeconds": 5,
123 "successThreshold": 1,
124 "failureThreshold": 3,
125 },
126 "livenessProbe": {
127 "httpGet": {
128 "path": "/api/health",
129 "port": 3000,
130 },
131 "initialDelaySeconds": 60,
132 "timeoutSeconds": 30,
133 "failureThreshold": 10,
134 },
135 },
136 },
137 ],
138 "kubernetesResources": {"ingressResources": []},
139 }
140
141 self.harness.charm.on.start.emit()
142
143 # Initializing the prometheus relation
144 relation_id = self.harness.add_relation("prometheus", "prometheus")
145 self.harness.add_relation_unit(relation_id, "prometheus/0")
146 self.harness.update_relation_data(
147 relation_id,
148 "prometheus/0",
149 {
150 "host": "prometheus",
151 "port": "9090",
152 },
153 )
154
155 # Verifying status
156 self.assertNotIsInstance(self.harness.charm.unit.status, BlockedStatus)
157
158 pod_spec, _ = self.harness.get_pod_spec()
159
160 self.assertDictEqual(expected_result, pod_spec)
161
162 def test_ingress_resources_with_http(self) -> NoReturn:
163 """Test ingress resources with HTTP."""
164 expected_result = {
165 "version": 3,
166 "containers": [
167 {
168 "name": "grafana",
169 "imageDetails": self.harness.charm.image.fetch(),
170 "imagePullPolicy": "Always",
171 "ports": [
172 {
173 "name": "grafana",
174 "containerPort": 3000,
175 "protocol": "TCP",
176 }
177 ],
178 "envConfig": {},
179 "volumeConfig": [
180 {
181 "name": "dashboards",
182 "mountPath": "/etc/grafana/provisioning/dashboards/",
183 "files": [
184 {
185 "path": "dashboard-osm.yml",
186 "content": (
187 "apiVersion: 1\n"
188 "providers:\n"
189 " - name: 'osm'\n"
190 " orgId: 1\n"
191 " folder: ''\n"
192 " type: file\n"
193 " options:\n"
194 " path: /etc/grafana/provisioning/dashboards/\n"
195 ),
196 },
197 ],
198 },
199 {
200 "name": "datasources",
201 "mountPath": "/etc/grafana/provisioning/datasources/",
202 "files": [
203 {
204 "path": "datasource-prometheus.yml",
205 "content": (
206 "datasources:\n"
207 " - access: proxy\n"
208 " editable: true\n"
209 " is_default: true\n"
210 " name: osm_prometheus\n"
211 " orgId: 1\n"
212 " type: prometheus\n"
213 " version: 1\n"
214 " url: http://prometheus:9090\n"
215 ),
216 },
217 ],
218 },
219 ],
220 "kubernetes": {
221 "readinessProbe": {
222 "httpGet": {
223 "path": "/api/health",
224 "port": 3000,
225 },
226 "initialDelaySeconds": 10,
227 "periodSeconds": 10,
228 "timeoutSeconds": 5,
229 "successThreshold": 1,
230 "failureThreshold": 3,
231 },
232 "livenessProbe": {
233 "httpGet": {
234 "path": "/api/health",
235 "port": 3000,
236 },
237 "initialDelaySeconds": 60,
238 "timeoutSeconds": 30,
239 "failureThreshold": 10,
240 },
241 },
242 },
243 ],
244 "kubernetesResources": {
245 "ingressResources": [
246 {
247 "name": "grafana-ingress",
248 "annotations": {
249 "nginx.ingress.kubernetes.io/proxy-body-size": "0",
250 "nginx.ingress.kubernetes.io/ssl-redirect": "false",
251 },
252 "spec": {
253 "rules": [
254 {
255 "host": "grafana",
256 "http": {
257 "paths": [
258 {
259 "path": "/",
260 "backend": {
261 "serviceName": "grafana",
262 "servicePort": 3000,
263 },
264 }
265 ]
266 },
267 }
268 ]
269 },
270 }
271 ],
272 },
273 }
274
275 self.harness.charm.on.start.emit()
276
277 # Initializing the prometheus relation
278 relation_id = self.harness.add_relation("prometheus", "prometheus")
279 self.harness.add_relation_unit(relation_id, "prometheus/0")
280 self.harness.update_relation_data(
281 relation_id,
282 "prometheus/0",
283 {
284 "host": "prometheus",
285 "port": "9090",
286 },
287 )
288
289 self.harness.update_config({"site_url": "http://grafana"})
290
291 pod_spec, _ = self.harness.get_pod_spec()
292
293 self.assertDictEqual(expected_result, pod_spec)
294
295 def test_ingress_resources_with_https(self) -> NoReturn:
296 """Test ingress resources with HTTPS."""
297 expected_result = {
298 "version": 3,
299 "containers": [
300 {
301 "name": "grafana",
302 "imageDetails": self.harness.charm.image.fetch(),
303 "imagePullPolicy": "Always",
304 "ports": [
305 {
306 "name": "grafana",
307 "containerPort": 3000,
308 "protocol": "TCP",
309 }
310 ],
311 "envConfig": {},
312 "volumeConfig": [
313 {
314 "name": "dashboards",
315 "mountPath": "/etc/grafana/provisioning/dashboards/",
316 "files": [
317 {
318 "path": "dashboard-osm.yml",
319 "content": (
320 "apiVersion: 1\n"
321 "providers:\n"
322 " - name: 'osm'\n"
323 " orgId: 1\n"
324 " folder: ''\n"
325 " type: file\n"
326 " options:\n"
327 " path: /etc/grafana/provisioning/dashboards/\n"
328 ),
329 },
330 ],
331 },
332 {
333 "name": "datasources",
334 "mountPath": "/etc/grafana/provisioning/datasources/",
335 "files": [
336 {
337 "path": "datasource-prometheus.yml",
338 "content": (
339 "datasources:\n"
340 " - access: proxy\n"
341 " editable: true\n"
342 " is_default: true\n"
343 " name: osm_prometheus\n"
344 " orgId: 1\n"
345 " type: prometheus\n"
346 " version: 1\n"
347 " url: http://prometheus:9090\n"
348 ),
349 },
350 ],
351 },
352 ],
353 "kubernetes": {
354 "readinessProbe": {
355 "httpGet": {
356 "path": "/api/health",
357 "port": 3000,
358 },
359 "initialDelaySeconds": 10,
360 "periodSeconds": 10,
361 "timeoutSeconds": 5,
362 "successThreshold": 1,
363 "failureThreshold": 3,
364 },
365 "livenessProbe": {
366 "httpGet": {
367 "path": "/api/health",
368 "port": 3000,
369 },
370 "initialDelaySeconds": 60,
371 "timeoutSeconds": 30,
372 "failureThreshold": 10,
373 },
374 },
375 },
376 ],
377 "kubernetesResources": {
378 "ingressResources": [
379 {
380 "name": "grafana-ingress",
381 "annotations": {
382 "nginx.ingress.kubernetes.io/proxy-body-size": "0",
383 },
384 "spec": {
385 "rules": [
386 {
387 "host": "grafana",
388 "http": {
389 "paths": [
390 {
391 "path": "/",
392 "backend": {
393 "serviceName": "grafana",
394 "servicePort": 3000,
395 },
396 }
397 ]
398 },
399 }
400 ],
401 "tls": [{"hosts": ["grafana"], "secretName": "grafana"}],
402 },
403 }
404 ],
405 },
406 }
407
408 self.harness.charm.on.start.emit()
409
410 # Initializing the prometheus relation
411 relation_id = self.harness.add_relation("prometheus", "prometheus")
412 self.harness.add_relation_unit(relation_id, "prometheus/0")
413 self.harness.update_relation_data(
414 relation_id,
415 "prometheus/0",
416 {
417 "host": "prometheus",
418 "port": "9090",
419 },
420 )
421
422 self.harness.update_config(
423 {"site_url": "https://grafana", "tls_secret_name": "grafana"}
424 )
425
426 pod_spec, _ = self.harness.get_pod_spec()
427
428 self.assertDictEqual(expected_result, pod_spec)
429
430 def test_ingress_resources_with_https_and_ingress_whitelist(self) -> NoReturn:
431 """Test ingress resources with HTTPS and ingress whitelist."""
432 expected_result = {
433 "version": 3,
434 "containers": [
435 {
436 "name": "grafana",
437 "imageDetails": self.harness.charm.image.fetch(),
438 "imagePullPolicy": "Always",
439 "ports": [
440 {
441 "name": "grafana",
442 "containerPort": 3000,
443 "protocol": "TCP",
444 }
445 ],
446 "envConfig": {},
447 "volumeConfig": [
448 {
449 "name": "dashboards",
450 "mountPath": "/etc/grafana/provisioning/dashboards/",
451 "files": [
452 {
453 "path": "dashboard-osm.yml",
454 "content": (
455 "apiVersion: 1\n"
456 "providers:\n"
457 " - name: 'osm'\n"
458 " orgId: 1\n"
459 " folder: ''\n"
460 " type: file\n"
461 " options:\n"
462 " path: /etc/grafana/provisioning/dashboards/\n"
463 ),
464 },
465 ],
466 },
467 {
468 "name": "datasources",
469 "mountPath": "/etc/grafana/provisioning/datasources/",
470 "files": [
471 {
472 "path": "datasource-prometheus.yml",
473 "content": (
474 "datasources:\n"
475 " - access: proxy\n"
476 " editable: true\n"
477 " is_default: true\n"
478 " name: osm_prometheus\n"
479 " orgId: 1\n"
480 " type: prometheus\n"
481 " version: 1\n"
482 " url: http://prometheus:9090\n"
483 ),
484 },
485 ],
486 },
487 ],
488 "kubernetes": {
489 "readinessProbe": {
490 "httpGet": {
491 "path": "/api/health",
492 "port": 3000,
493 },
494 "initialDelaySeconds": 10,
495 "periodSeconds": 10,
496 "timeoutSeconds": 5,
497 "successThreshold": 1,
498 "failureThreshold": 3,
499 },
500 "livenessProbe": {
501 "httpGet": {
502 "path": "/api/health",
503 "port": 3000,
504 },
505 "initialDelaySeconds": 60,
506 "timeoutSeconds": 30,
507 "failureThreshold": 10,
508 },
509 },
510 },
511 ],
512 "kubernetesResources": {
513 "ingressResources": [
514 {
515 "name": "grafana-ingress",
516 "annotations": {
517 "nginx.ingress.kubernetes.io/proxy-body-size": "0",
518 "nginx.ingress.kubernetes.io/whitelist-source-range": "0.0.0.0/0",
519 },
520 "spec": {
521 "rules": [
522 {
523 "host": "grafana",
524 "http": {
525 "paths": [
526 {
527 "path": "/",
528 "backend": {
529 "serviceName": "grafana",
530 "servicePort": 3000,
531 },
532 }
533 ]
534 },
535 }
536 ],
537 "tls": [{"hosts": ["grafana"], "secretName": "grafana"}],
538 },
539 }
540 ],
541 },
542 }
543
544 self.harness.charm.on.start.emit()
545
546 # Initializing the prometheus relation
547 relation_id = self.harness.add_relation("prometheus", "prometheus")
548 self.harness.add_relation_unit(relation_id, "prometheus/0")
549 self.harness.update_relation_data(
550 relation_id,
551 "prometheus/0",
552 {
553 "host": "prometheus",
554 "port": "9090",
555 },
556 )
557
558 self.harness.update_config(
559 {
560 "site_url": "https://grafana",
561 "tls_secret_name": "grafana",
562 "ingress_whitelist_source_range": "0.0.0.0/0",
563 }
564 )
565
566 pod_spec, _ = self.harness.get_pod_spec()
567
568 self.assertDictEqual(expected_result, pod_spec)
569
570 def test_on_prometheus_unit_relation_changed(self) -> NoReturn:
571 """Test to see if prometheus relation is updated."""
572 self.harness.charm.on.start.emit()
573
574 relation_id = self.harness.add_relation("prometheus", "prometheus")
575 self.harness.add_relation_unit(relation_id, "prometheus/0")
576 self.harness.update_relation_data(
577 relation_id,
578 "prometheus/0",
579 {
580 "host": "prometheus",
581 "port": "9090",
582 },
583 )
584
585 # Verifying status
586 self.assertNotIsInstance(self.harness.charm.unit.status, BlockedStatus)
587
588
589 if __name__ == "__main__":
590 unittest.main()