22f6bf546a2f311e860a7261880e19ac490616e7
[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 print(expected_result, pod_envconfig)
290 self.assertListEqual(expected_result, pod_envconfig)
291
292 def test_make_readiness_probe(self) -> NoReturn:
293 """Testing make readiness probe."""
294 port = 9090
295
296 expected_result = {
297 "httpGet": {
298 "path": "/-/ready",
299 "port": port,
300 },
301 "initialDelaySeconds": 10,
302 "timeoutSeconds": 30,
303 }
304
305 readiness_probe = pod_spec._make_readiness_probe(port)
306
307 self.assertDictEqual(expected_result, readiness_probe)
308
309 def test_make_liveness_probe(self) -> NoReturn:
310 """Testing make liveness probe."""
311 port = 9090
312
313 expected_result = {
314 "httpGet": {
315 "path": "/-/healthy",
316 "port": port,
317 },
318 "initialDelaySeconds": 30,
319 "periodSeconds": 30,
320 }
321
322 liveness_probe = pod_spec._make_liveness_probe(port)
323
324 self.assertDictEqual(expected_result, liveness_probe)
325
326 def test_make_pod_command(self) -> NoReturn:
327 """Testing make pod command."""
328 port = 9090
329 config = {
330 "web_subpath": "/",
331 "default_target": "",
332 "site_url": "",
333 }
334
335 expected_result = [
336 "/bin/prometheus",
337 "--config.file=/etc/prometheus/prometheus.yml",
338 "--storage.tsdb.path=/prometheus",
339 "--web.console.libraries=/usr/share/prometheus/console_libraries",
340 "--web.console.templates=/usr/share/prometheus/consoles",
341 "--web.route-prefix={}".format(config.get("web_subpath")),
342 "--web.external-url=http://localhost:{}{}".format(
343 port, config.get("web_subpath")
344 ),
345 ]
346
347 pod_envconfig = pod_spec._make_pod_command(config, port)
348
349 self.assertListEqual(expected_result, pod_envconfig)
350
351 def test_make_pod_command_with_web_admin_api_enabled(self) -> NoReturn:
352 """Testing make pod command."""
353 port = 9090
354 config = {
355 "web_subpath": "/",
356 "default_target": "",
357 "site_url": "",
358 "enable_web_admin_api": True,
359 }
360
361 expected_result = [
362 "/bin/prometheus",
363 "--config.file=/etc/prometheus/prometheus.yml",
364 "--storage.tsdb.path=/prometheus",
365 "--web.console.libraries=/usr/share/prometheus/console_libraries",
366 "--web.console.templates=/usr/share/prometheus/consoles",
367 "--web.route-prefix={}".format(config.get("web_subpath")),
368 "--web.external-url=http://localhost:{}{}".format(
369 port, config.get("web_subpath")
370 ),
371 "--web.enable-admin-api",
372 ]
373
374 pod_envconfig = pod_spec._make_pod_command(config, port)
375
376 self.assertListEqual(expected_result, pod_envconfig)
377
378 def test_make_pod_spec(self) -> NoReturn:
379 """Testing make pod spec."""
380 image_info = {"upstream-source": "ubuntu/prometheus:latest"}
381 config = {
382 "web_subpath": "/",
383 "default_target": "",
384 "site_url": "",
385 "enable_web_admin_api": False,
386 }
387 relation_state = {}
388 app_name = "prometheus"
389 port = 9090
390
391 expected_result = {
392 "version": 3,
393 "containers": [
394 {
395 "name": app_name,
396 "imageDetails": image_info,
397 "imagePullPolicy": "Always",
398 "ports": [
399 {
400 "name": app_name,
401 "containerPort": port,
402 "protocol": "TCP",
403 }
404 ],
405 "envConfig": {},
406 "volumeConfig": [
407 {
408 "name": "config",
409 "mountPath": "/etc/prometheus",
410 "files": [
411 {
412 "path": "prometheus.yml",
413 "content": (
414 "global:\n"
415 " scrape_interval: 15s\n"
416 " evaluation_interval: 15s\n"
417 "alerting:\n"
418 " alertmanagers:\n"
419 " - static_configs:\n"
420 " - targets:\n"
421 "rule_files:\n"
422 "scrape_configs:\n"
423 " - job_name: 'prometheus'\n"
424 " static_configs:\n"
425 " - targets: [{}]\n".format(
426 config.get("default_target")
427 )
428 ),
429 }
430 ],
431 }
432 ],
433 "command": [
434 "/bin/prometheus",
435 "--config.file=/etc/prometheus/prometheus.yml",
436 "--storage.tsdb.path=/prometheus",
437 "--web.console.libraries=/usr/share/prometheus/console_libraries",
438 "--web.console.templates=/usr/share/prometheus/consoles",
439 "--web.route-prefix={}".format(config.get("web_subpath")),
440 "--web.external-url=http://localhost:{}{}".format(
441 port, config.get("web_subpath")
442 ),
443 ],
444 "kubernetes": {
445 "readinessProbe": {
446 "httpGet": {
447 "path": "/-/ready",
448 "port": port,
449 },
450 "initialDelaySeconds": 10,
451 "timeoutSeconds": 30,
452 },
453 "livenessProbe": {
454 "httpGet": {
455 "path": "/-/healthy",
456 "port": port,
457 },
458 "initialDelaySeconds": 30,
459 "periodSeconds": 30,
460 },
461 },
462 }
463 ],
464 "kubernetesResources": {"ingressResources": []},
465 }
466
467 spec = pod_spec.make_pod_spec(
468 image_info, config, relation_state, app_name, port
469 )
470
471 self.assertDictEqual(expected_result, spec)
472
473 def test_make_pod_spec_with_ingress(self) -> NoReturn:
474 """Testing make pod spec."""
475 image_info = {"upstream-source": "ubuntu/prometheus:latest"}
476 config = {
477 "web_subpath": "/",
478 "default_target": "",
479 "site_url": "https://prometheus",
480 "tls_secret_name": "prometheus",
481 "max_file_size": 0,
482 "ingress_whitelist_source_range": "0.0.0.0/0",
483 "enable_web_admin_api": False,
484 }
485 relation_state = {}
486 app_name = "prometheus"
487 port = 9090
488
489 expected_result = {
490 "version": 3,
491 "containers": [
492 {
493 "name": app_name,
494 "imageDetails": image_info,
495 "imagePullPolicy": "Always",
496 "ports": [
497 {
498 "name": app_name,
499 "containerPort": port,
500 "protocol": "TCP",
501 }
502 ],
503 "envConfig": {},
504 "volumeConfig": [
505 {
506 "name": "config",
507 "mountPath": "/etc/prometheus",
508 "files": [
509 {
510 "path": "prometheus.yml",
511 "content": (
512 "global:\n"
513 " scrape_interval: 15s\n"
514 " evaluation_interval: 15s\n"
515 "alerting:\n"
516 " alertmanagers:\n"
517 " - static_configs:\n"
518 " - targets:\n"
519 "rule_files:\n"
520 "scrape_configs:\n"
521 " - job_name: 'prometheus'\n"
522 " static_configs:\n"
523 " - targets: [{}]\n".format(
524 config.get("default_target")
525 )
526 ),
527 }
528 ],
529 }
530 ],
531 "command": [
532 "/bin/prometheus",
533 "--config.file=/etc/prometheus/prometheus.yml",
534 "--storage.tsdb.path=/prometheus",
535 "--web.console.libraries=/usr/share/prometheus/console_libraries",
536 "--web.console.templates=/usr/share/prometheus/consoles",
537 "--web.route-prefix={}".format(config.get("web_subpath")),
538 "--web.external-url=http://localhost:{}{}".format(
539 port, config.get("web_subpath")
540 ),
541 ],
542 "kubernetes": {
543 "readinessProbe": {
544 "httpGet": {
545 "path": "/-/ready",
546 "port": port,
547 },
548 "initialDelaySeconds": 10,
549 "timeoutSeconds": 30,
550 },
551 "livenessProbe": {
552 "httpGet": {
553 "path": "/-/healthy",
554 "port": port,
555 },
556 "initialDelaySeconds": 30,
557 "periodSeconds": 30,
558 },
559 },
560 }
561 ],
562 "kubernetesResources": {
563 "ingressResources": [
564 {
565 "name": "{}-ingress".format(app_name),
566 "annotations": {
567 "nginx.ingress.kubernetes.io/proxy-body-size": str(
568 config.get("max_file_size")
569 ),
570 "nginx.ingress.kubernetes.io/whitelist-source-range": config.get(
571 "ingress_whitelist_source_range"
572 ),
573 },
574 "spec": {
575 "rules": [
576 {
577 "host": app_name,
578 "http": {
579 "paths": [
580 {
581 "path": "/",
582 "backend": {
583 "serviceName": app_name,
584 "servicePort": port,
585 },
586 }
587 ]
588 },
589 }
590 ],
591 "tls": [
592 {
593 "hosts": [app_name],
594 "secretName": config.get("tls_secret_name"),
595 }
596 ],
597 },
598 }
599 ],
600 },
601 }
602
603 spec = pod_spec.make_pod_spec(
604 image_info, config, relation_state, app_name, port
605 )
606
607 self.assertDictEqual(expected_result, spec)
608
609 def test_make_pod_spec_without_image_info(self) -> NoReturn:
610 """Testing make pod spec without image_info."""
611 image_info = None
612 config = {
613 "web_subpath": "/",
614 "default_target": "",
615 "site_url": "",
616 "enable_web_admin_api": False,
617 }
618 relation_state = {}
619 app_name = "prometheus"
620 port = 9090
621
622 spec = pod_spec.make_pod_spec(
623 image_info, config, relation_state, app_name, port
624 )
625
626 self.assertIsNone(spec)
627
628 def test_make_pod_spec_without_config(self) -> NoReturn:
629 """Testing make pod spec without config."""
630 image_info = {"upstream-source": "ubuntu/prometheus:latest"}
631 config = {}
632 relation_state = {}
633 app_name = "prometheus"
634 port = 9090
635
636 with self.assertRaises(ValueError):
637 pod_spec.make_pod_spec(image_info, config, relation_state, app_name, port)
638
639
640 if __name__ == "__main__":
641 unittest.main()