Major improvement in OSM charms
[osm/devops.git] / installers / charm / prometheus / tests / test_pod_spec.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 from typing import NoReturn
24 import unittest
25
26 import pod_spec
27
28
29 class TestPodSpec(unittest.TestCase):
30 """Pod spec unit tests."""
31
32 def test_make_pod_ports(self) -> NoReturn:
33 """Testing make pod ports."""
34 port = 9090
35
36 expected_result = [
37 {
38 "name": "prometheus",
39 "containerPort": port,
40 "protocol": "TCP",
41 }
42 ]
43
44 pod_ports = pod_spec._make_pod_ports(port)
45
46 self.assertListEqual(expected_result, pod_ports)
47
48 def test_make_pod_envconfig(self) -> NoReturn:
49 """Testing make pod envconfig."""
50 config = {}
51 relation_state = {}
52
53 expected_result = {}
54
55 pod_envconfig = pod_spec._make_pod_envconfig(config, relation_state)
56
57 self.assertDictEqual(expected_result, pod_envconfig)
58
59 def test_make_pod_ingress_resources_without_site_url(self) -> NoReturn:
60 """Testing make pod ingress resources without site_url."""
61 config = {"site_url": ""}
62 app_name = "prometheus"
63 port = 9090
64
65 pod_ingress_resources = pod_spec._make_pod_ingress_resources(
66 config, app_name, port
67 )
68
69 self.assertIsNone(pod_ingress_resources)
70
71 def test_make_pod_ingress_resources(self) -> NoReturn:
72 """Testing make pod ingress resources."""
73 config = {
74 "site_url": "http://prometheus",
75 "max_file_size": 0,
76 "ingress_whitelist_source_range": "",
77 }
78 app_name = "prometheus"
79 port = 9090
80
81 expected_result = [
82 {
83 "name": f"{app_name}-ingress",
84 "annotations": {
85 "nginx.ingress.kubernetes.io/proxy-body-size": f"{config['max_file_size']}",
86 "nginx.ingress.kubernetes.io/ssl-redirect": "false",
87 },
88 "spec": {
89 "rules": [
90 {
91 "host": app_name,
92 "http": {
93 "paths": [
94 {
95 "path": "/",
96 "backend": {
97 "serviceName": app_name,
98 "servicePort": port,
99 },
100 }
101 ]
102 },
103 }
104 ]
105 },
106 }
107 ]
108
109 pod_ingress_resources = pod_spec._make_pod_ingress_resources(
110 config, app_name, port
111 )
112
113 self.assertListEqual(expected_result, pod_ingress_resources)
114
115 def test_make_pod_ingress_resources_with_whitelist_source_range(self) -> NoReturn:
116 """Testing make pod ingress resources with whitelist_source_range."""
117 config = {
118 "site_url": "http://prometheus",
119 "max_file_size": 0,
120 "ingress_whitelist_source_range": "0.0.0.0/0",
121 }
122 app_name = "prometheus"
123 port = 9090
124
125 expected_result = [
126 {
127 "name": f"{app_name}-ingress",
128 "annotations": {
129 "nginx.ingress.kubernetes.io/proxy-body-size": f"{config['max_file_size']}",
130 "nginx.ingress.kubernetes.io/ssl-redirect": "false",
131 "nginx.ingress.kubernetes.io/whitelist-source-range": config[
132 "ingress_whitelist_source_range"
133 ],
134 },
135 "spec": {
136 "rules": [
137 {
138 "host": app_name,
139 "http": {
140 "paths": [
141 {
142 "path": "/",
143 "backend": {
144 "serviceName": app_name,
145 "servicePort": port,
146 },
147 }
148 ]
149 },
150 }
151 ]
152 },
153 }
154 ]
155
156 pod_ingress_resources = pod_spec._make_pod_ingress_resources(
157 config, app_name, port
158 )
159
160 self.assertListEqual(expected_result, pod_ingress_resources)
161
162 def test_make_pod_ingress_resources_with_https(self) -> NoReturn:
163 """Testing make pod ingress resources with HTTPs."""
164 config = {
165 "site_url": "https://prometheus",
166 "max_file_size": 0,
167 "ingress_whitelist_source_range": "",
168 "tls_secret_name": "",
169 }
170 app_name = "prometheus"
171 port = 9090
172
173 expected_result = [
174 {
175 "name": f"{app_name}-ingress",
176 "annotations": {
177 "nginx.ingress.kubernetes.io/proxy-body-size": f"{config['max_file_size']}",
178 },
179 "spec": {
180 "rules": [
181 {
182 "host": app_name,
183 "http": {
184 "paths": [
185 {
186 "path": "/",
187 "backend": {
188 "serviceName": app_name,
189 "servicePort": port,
190 },
191 }
192 ]
193 },
194 }
195 ],
196 "tls": [{"hosts": [app_name]}],
197 },
198 }
199 ]
200
201 pod_ingress_resources = pod_spec._make_pod_ingress_resources(
202 config, app_name, port
203 )
204
205 self.assertListEqual(expected_result, pod_ingress_resources)
206
207 def test_make_pod_ingress_resources_with_https_tls_secret_name(self) -> NoReturn:
208 """Testing make pod ingress resources with HTTPs and TLS secret name."""
209 config = {
210 "site_url": "https://prometheus",
211 "max_file_size": 0,
212 "ingress_whitelist_source_range": "",
213 "tls_secret_name": "secret_name",
214 }
215 app_name = "prometheus"
216 port = 9090
217
218 expected_result = [
219 {
220 "name": f"{app_name}-ingress",
221 "annotations": {
222 "nginx.ingress.kubernetes.io/proxy-body-size": f"{config['max_file_size']}",
223 },
224 "spec": {
225 "rules": [
226 {
227 "host": app_name,
228 "http": {
229 "paths": [
230 {
231 "path": "/",
232 "backend": {
233 "serviceName": app_name,
234 "servicePort": port,
235 },
236 }
237 ]
238 },
239 }
240 ],
241 "tls": [
242 {"hosts": [app_name], "secretName": config["tls_secret_name"]}
243 ],
244 },
245 }
246 ]
247
248 pod_ingress_resources = pod_spec._make_pod_ingress_resources(
249 config, app_name, port
250 )
251
252 self.assertListEqual(expected_result, pod_ingress_resources)
253
254 def test_make_pod_files(self) -> NoReturn:
255 """Testing make pod files."""
256 config = {
257 "web_subpath": "/",
258 "default_target": "",
259 "site_url": "",
260 }
261
262 expected_result = [
263 {
264 "name": "config",
265 "mountPath": "/etc/prometheus",
266 "files": [
267 {
268 "path": "prometheus.yml",
269 "content": (
270 "global:\n"
271 " scrape_interval: 15s\n"
272 " evaluation_interval: 15s\n"
273 "alerting:\n"
274 " alertmanagers:\n"
275 " - static_configs:\n"
276 " - targets:\n"
277 "rule_files:\n"
278 "scrape_configs:\n"
279 " - job_name: 'prometheus'\n"
280 " static_configs:\n"
281 " - targets: [{}]\n".format(config["default_target"])
282 ),
283 }
284 ],
285 }
286 ]
287
288 pod_envconfig = pod_spec._make_pod_files(config)
289 self.assertListEqual(expected_result, pod_envconfig)
290
291 def test_make_readiness_probe(self) -> NoReturn:
292 """Testing make readiness probe."""
293 port = 9090
294
295 expected_result = {
296 "httpGet": {
297 "path": "/-/ready",
298 "port": port,
299 },
300 "initialDelaySeconds": 10,
301 "timeoutSeconds": 30,
302 }
303
304 readiness_probe = pod_spec._make_readiness_probe(port)
305
306 self.assertDictEqual(expected_result, readiness_probe)
307
308 def test_make_liveness_probe(self) -> NoReturn:
309 """Testing make liveness probe."""
310 port = 9090
311
312 expected_result = {
313 "httpGet": {
314 "path": "/-/healthy",
315 "port": port,
316 },
317 "initialDelaySeconds": 30,
318 "periodSeconds": 30,
319 }
320
321 liveness_probe = pod_spec._make_liveness_probe(port)
322
323 self.assertDictEqual(expected_result, liveness_probe)
324
325 def test_make_pod_command(self) -> NoReturn:
326 """Testing make pod command."""
327 port = 9090
328 config = {
329 "web_subpath": "/",
330 "default_target": "",
331 "site_url": "",
332 }
333
334 expected_result = [
335 "/bin/prometheus",
336 "--config.file=/etc/prometheus/prometheus.yml",
337 "--storage.tsdb.path=/prometheus",
338 "--web.console.libraries=/usr/share/prometheus/console_libraries",
339 "--web.console.templates=/usr/share/prometheus/consoles",
340 "--web.route-prefix={}".format(config.get("web_subpath")),
341 "--web.external-url=http://localhost:{}{}".format(
342 port, config.get("web_subpath")
343 ),
344 ]
345
346 pod_envconfig = pod_spec._make_pod_command(config, port)
347
348 self.assertListEqual(expected_result, pod_envconfig)
349
350 def test_make_pod_command_with_web_admin_api_enabled(self) -> NoReturn:
351 """Testing make pod command."""
352 port = 9090
353 config = {
354 "web_subpath": "/",
355 "default_target": "",
356 "site_url": "",
357 "enable_web_admin_api": True,
358 }
359
360 expected_result = [
361 "/bin/prometheus",
362 "--config.file=/etc/prometheus/prometheus.yml",
363 "--storage.tsdb.path=/prometheus",
364 "--web.console.libraries=/usr/share/prometheus/console_libraries",
365 "--web.console.templates=/usr/share/prometheus/consoles",
366 "--web.route-prefix={}".format(config.get("web_subpath")),
367 "--web.external-url=http://localhost:{}{}".format(
368 port, config.get("web_subpath")
369 ),
370 "--web.enable-admin-api",
371 ]
372
373 pod_envconfig = pod_spec._make_pod_command(config, port)
374
375 self.assertListEqual(expected_result, pod_envconfig)
376
377 def test_make_pod_spec(self) -> NoReturn:
378 """Testing make pod spec."""
379 image_info = {"upstream-source": "ubuntu/prometheus:latest"}
380 config = {
381 "web_subpath": "/",
382 "default_target": "",
383 "site_url": "",
384 "enable_web_admin_api": False,
385 }
386 relation_state = {}
387 app_name = "prometheus"
388 port = 9090
389
390 expected_result = {
391 "version": 3,
392 "containers": [
393 {
394 "name": app_name,
395 "imageDetails": image_info,
396 "imagePullPolicy": "Always",
397 "ports": [
398 {
399 "name": app_name,
400 "containerPort": port,
401 "protocol": "TCP",
402 }
403 ],
404 "envConfig": {},
405 "volumeConfig": [
406 {
407 "name": "config",
408 "mountPath": "/etc/prometheus",
409 "files": [
410 {
411 "path": "prometheus.yml",
412 "content": (
413 "global:\n"
414 " scrape_interval: 15s\n"
415 " evaluation_interval: 15s\n"
416 "alerting:\n"
417 " alertmanagers:\n"
418 " - static_configs:\n"
419 " - targets:\n"
420 "rule_files:\n"
421 "scrape_configs:\n"
422 " - job_name: 'prometheus'\n"
423 " static_configs:\n"
424 " - targets: [{}]\n".format(
425 config.get("default_target")
426 )
427 ),
428 }
429 ],
430 }
431 ],
432 "command": [
433 "/bin/prometheus",
434 "--config.file=/etc/prometheus/prometheus.yml",
435 "--storage.tsdb.path=/prometheus",
436 "--web.console.libraries=/usr/share/prometheus/console_libraries",
437 "--web.console.templates=/usr/share/prometheus/consoles",
438 "--web.route-prefix={}".format(config.get("web_subpath")),
439 "--web.external-url=http://localhost:{}{}".format(
440 port, config.get("web_subpath")
441 ),
442 ],
443 "kubernetes": {
444 "readinessProbe": {
445 "httpGet": {
446 "path": "/-/ready",
447 "port": port,
448 },
449 "initialDelaySeconds": 10,
450 "timeoutSeconds": 30,
451 },
452 "livenessProbe": {
453 "httpGet": {
454 "path": "/-/healthy",
455 "port": port,
456 },
457 "initialDelaySeconds": 30,
458 "periodSeconds": 30,
459 },
460 },
461 }
462 ],
463 "kubernetesResources": {"ingressResources": []},
464 }
465
466 spec = pod_spec.make_pod_spec(
467 image_info, config, relation_state, app_name, port
468 )
469
470 self.assertDictEqual(expected_result, spec)
471
472 def test_make_pod_spec_with_ingress(self) -> NoReturn:
473 """Testing make pod spec."""
474 image_info = {"upstream-source": "ubuntu/prometheus:latest"}
475 config = {
476 "web_subpath": "/",
477 "default_target": "",
478 "site_url": "https://prometheus",
479 "tls_secret_name": "prometheus",
480 "max_file_size": 0,
481 "ingress_whitelist_source_range": "0.0.0.0/0",
482 "enable_web_admin_api": False,
483 }
484 relation_state = {}
485 app_name = "prometheus"
486 port = 9090
487
488 expected_result = {
489 "version": 3,
490 "containers": [
491 {
492 "name": app_name,
493 "imageDetails": image_info,
494 "imagePullPolicy": "Always",
495 "ports": [
496 {
497 "name": app_name,
498 "containerPort": port,
499 "protocol": "TCP",
500 }
501 ],
502 "envConfig": {},
503 "volumeConfig": [
504 {
505 "name": "config",
506 "mountPath": "/etc/prometheus",
507 "files": [
508 {
509 "path": "prometheus.yml",
510 "content": (
511 "global:\n"
512 " scrape_interval: 15s\n"
513 " evaluation_interval: 15s\n"
514 "alerting:\n"
515 " alertmanagers:\n"
516 " - static_configs:\n"
517 " - targets:\n"
518 "rule_files:\n"
519 "scrape_configs:\n"
520 " - job_name: 'prometheus'\n"
521 " static_configs:\n"
522 " - targets: [{}]\n".format(
523 config.get("default_target")
524 )
525 ),
526 }
527 ],
528 }
529 ],
530 "command": [
531 "/bin/prometheus",
532 "--config.file=/etc/prometheus/prometheus.yml",
533 "--storage.tsdb.path=/prometheus",
534 "--web.console.libraries=/usr/share/prometheus/console_libraries",
535 "--web.console.templates=/usr/share/prometheus/consoles",
536 "--web.route-prefix={}".format(config.get("web_subpath")),
537 "--web.external-url=http://localhost:{}{}".format(
538 port, config.get("web_subpath")
539 ),
540 ],
541 "kubernetes": {
542 "readinessProbe": {
543 "httpGet": {
544 "path": "/-/ready",
545 "port": port,
546 },
547 "initialDelaySeconds": 10,
548 "timeoutSeconds": 30,
549 },
550 "livenessProbe": {
551 "httpGet": {
552 "path": "/-/healthy",
553 "port": port,
554 },
555 "initialDelaySeconds": 30,
556 "periodSeconds": 30,
557 },
558 },
559 }
560 ],
561 "kubernetesResources": {
562 "ingressResources": [
563 {
564 "name": "{}-ingress".format(app_name),
565 "annotations": {
566 "nginx.ingress.kubernetes.io/proxy-body-size": str(
567 config.get("max_file_size")
568 ),
569 "nginx.ingress.kubernetes.io/whitelist-source-range": config.get(
570 "ingress_whitelist_source_range"
571 ),
572 },
573 "spec": {
574 "rules": [
575 {
576 "host": app_name,
577 "http": {
578 "paths": [
579 {
580 "path": "/",
581 "backend": {
582 "serviceName": app_name,
583 "servicePort": port,
584 },
585 }
586 ]
587 },
588 }
589 ],
590 "tls": [
591 {
592 "hosts": [app_name],
593 "secretName": config.get("tls_secret_name"),
594 }
595 ],
596 },
597 }
598 ],
599 },
600 }
601
602 spec = pod_spec.make_pod_spec(
603 image_info, config, relation_state, app_name, port
604 )
605
606 self.assertDictEqual(expected_result, spec)
607
608 def test_make_pod_spec_without_image_info(self) -> NoReturn:
609 """Testing make pod spec without image_info."""
610 image_info = None
611 config = {
612 "web_subpath": "/",
613 "default_target": "",
614 "site_url": "",
615 "enable_web_admin_api": False,
616 }
617 relation_state = {}
618 app_name = "prometheus"
619 port = 9090
620
621 spec = pod_spec.make_pod_spec(
622 image_info, config, relation_state, app_name, port
623 )
624
625 self.assertIsNone(spec)
626
627 def test_make_pod_spec_without_config(self) -> NoReturn:
628 """Testing make pod spec without config."""
629 image_info = {"upstream-source": "ubuntu/prometheus:latest"}
630 config = {}
631 relation_state = {}
632 app_name = "prometheus"
633 port = 9090
634
635 with self.assertRaises(ValueError):
636 pod_spec.make_pod_spec(image_info, config, relation_state, app_name, port)
637
638
639 if __name__ == "__main__":
640 unittest.main()