Refactoring Prometheus Charm to use Operator Framework
[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:"
271 " scrape_interval: 15s"
272 " evaluation_interval: 15s"
273 "alerting:"
274 " alertmanagers:"
275 " - static_configs:"
276 " - targets:"
277 "rule_files:"
278 "scrape_configs:"
279 " - job_name: 'prometheus'"
280 " static_configs:"
281 " - targets: [{}]".format(config["default_target"])
282 ),
283 }
284 ],
285 }
286 ]
287
288 pod_envconfig = pod_spec._make_pod_files(config)
289
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 "sh",
337 "-c",
338 "/bin/prometheus",
339 "--config.file=/etc/prometheus/prometheus.yml",
340 "--storage.tsdb.path=/prometheus",
341 "--web.console.libraries=/usr/share/prometheus/console_libraries",
342 "--web.console.templates=/usr/share/prometheus/consoles",
343 "--web.route-prefix={}".format(config.get("web_subpath")),
344 "--web.external-url=http://localhost:{}{}".format(
345 port, config.get("web_subpath")
346 ),
347 ]
348
349 pod_envconfig = pod_spec._make_pod_command(config, port)
350
351 self.assertListEqual(expected_result, pod_envconfig)
352
353 def test_make_pod_spec(self) -> NoReturn:
354 """Testing make pod spec."""
355 image_info = {"upstream-source": "ubuntu/prometheus:latest"}
356 config = {
357 "web_subpath": "/",
358 "default_target": "",
359 "site_url": "",
360 }
361 relation_state = {}
362 app_name = "prometheus"
363 port = 9090
364
365 expected_result = {
366 "version": 3,
367 "containers": [
368 {
369 "name": app_name,
370 "imageDetails": image_info,
371 "imagePullPolicy": "Always",
372 "ports": [
373 {
374 "name": app_name,
375 "containerPort": port,
376 "protocol": "TCP",
377 }
378 ],
379 "envConfig": {},
380 "volumeConfig": [
381 {
382 "name": "config",
383 "mountPath": "/etc/prometheus",
384 "files": [
385 {
386 "path": "prometheus.yml",
387 "content": (
388 "global:"
389 " scrape_interval: 15s"
390 " evaluation_interval: 15s"
391 "alerting:"
392 " alertmanagers:"
393 " - static_configs:"
394 " - targets:"
395 "rule_files:"
396 "scrape_configs:"
397 " - job_name: 'prometheus'"
398 " static_configs:"
399 " - targets: [{}]".format(
400 config.get("default_target")
401 )
402 ),
403 }
404 ],
405 }
406 ],
407 "command": [
408 "sh",
409 "-c",
410 "/bin/prometheus",
411 "--config.file=/etc/prometheus/prometheus.yml",
412 "--storage.tsdb.path=/prometheus",
413 "--web.console.libraries=/usr/share/prometheus/console_libraries",
414 "--web.console.templates=/usr/share/prometheus/consoles",
415 "--web.route-prefix={}".format(config.get("web_subpath")),
416 "--web.external-url=http://localhost:{}{}".format(
417 port, config.get("web_subpath")
418 ),
419 ],
420 "kubernetes": {
421 "readinessProbe": {
422 "httpGet": {
423 "path": "/-/ready",
424 "port": port,
425 },
426 "initialDelaySeconds": 10,
427 "timeoutSeconds": 30,
428 },
429 "livenessProbe": {
430 "httpGet": {
431 "path": "/-/healthy",
432 "port": port,
433 },
434 "initialDelaySeconds": 30,
435 "periodSeconds": 30,
436 },
437 },
438 }
439 ],
440 "kubernetesResources": {"ingressResources": []},
441 }
442
443 spec = pod_spec.make_pod_spec(
444 image_info, config, relation_state, app_name, port
445 )
446
447 self.assertDictEqual(expected_result, spec)
448
449 def test_make_pod_spec_with_ingress(self) -> NoReturn:
450 """Testing make pod spec."""
451 image_info = {"upstream-source": "ubuntu/prometheus:latest"}
452 config = {
453 "web_subpath": "/",
454 "default_target": "",
455 "site_url": "https://prometheus",
456 "tls_secret_name": "prometheus",
457 "max_file_size": 0,
458 "ingress_whitelist_source_range": "0.0.0.0/0",
459 }
460 relation_state = {}
461 app_name = "prometheus"
462 port = 9090
463
464 expected_result = {
465 "version": 3,
466 "containers": [
467 {
468 "name": app_name,
469 "imageDetails": image_info,
470 "imagePullPolicy": "Always",
471 "ports": [
472 {
473 "name": app_name,
474 "containerPort": port,
475 "protocol": "TCP",
476 }
477 ],
478 "envConfig": {},
479 "volumeConfig": [
480 {
481 "name": "config",
482 "mountPath": "/etc/prometheus",
483 "files": [
484 {
485 "path": "prometheus.yml",
486 "content": (
487 "global:"
488 " scrape_interval: 15s"
489 " evaluation_interval: 15s"
490 "alerting:"
491 " alertmanagers:"
492 " - static_configs:"
493 " - targets:"
494 "rule_files:"
495 "scrape_configs:"
496 " - job_name: 'prometheus'"
497 " static_configs:"
498 " - targets: [{}]".format(
499 config.get("default_target")
500 )
501 ),
502 }
503 ],
504 }
505 ],
506 "command": [
507 "sh",
508 "-c",
509 "/bin/prometheus",
510 "--config.file=/etc/prometheus/prometheus.yml",
511 "--storage.tsdb.path=/prometheus",
512 "--web.console.libraries=/usr/share/prometheus/console_libraries",
513 "--web.console.templates=/usr/share/prometheus/consoles",
514 "--web.route-prefix={}".format(config.get("web_subpath")),
515 "--web.external-url=http://localhost:{}{}".format(
516 port, config.get("web_subpath")
517 ),
518 ],
519 "kubernetes": {
520 "readinessProbe": {
521 "httpGet": {
522 "path": "/-/ready",
523 "port": port,
524 },
525 "initialDelaySeconds": 10,
526 "timeoutSeconds": 30,
527 },
528 "livenessProbe": {
529 "httpGet": {
530 "path": "/-/healthy",
531 "port": port,
532 },
533 "initialDelaySeconds": 30,
534 "periodSeconds": 30,
535 },
536 },
537 }
538 ],
539 "kubernetesResources": {
540 "ingressResources": [
541 {
542 "name": "{}-ingress".format(app_name),
543 "annotations": {
544 "nginx.ingress.kubernetes.io/proxy-body-size": str(
545 config.get("max_file_size")
546 ),
547 "nginx.ingress.kubernetes.io/whitelist-source-range": config.get(
548 "ingress_whitelist_source_range"
549 ),
550 },
551 "spec": {
552 "rules": [
553 {
554 "host": app_name,
555 "http": {
556 "paths": [
557 {
558 "path": "/",
559 "backend": {
560 "serviceName": app_name,
561 "servicePort": port,
562 },
563 }
564 ]
565 },
566 }
567 ],
568 "tls": [
569 {
570 "hosts": [app_name],
571 "secretName": config.get("tls_secret_name"),
572 }
573 ],
574 },
575 }
576 ],
577 },
578 }
579
580 spec = pod_spec.make_pod_spec(
581 image_info, config, relation_state, app_name, port
582 )
583
584 self.assertDictEqual(expected_result, spec)
585
586 def test_make_pod_spec_without_image_info(self) -> NoReturn:
587 """Testing make pod spec without image_info."""
588 image_info = None
589 config = {
590 "web_subpath": "/",
591 "default_target": "",
592 "site_url": "",
593 }
594 relation_state = {}
595 app_name = "prometheus"
596 port = 9090
597
598 spec = pod_spec.make_pod_spec(
599 image_info, config, relation_state, app_name, port
600 )
601
602 self.assertIsNone(spec)
603
604 def test_make_pod_spec_without_config(self) -> NoReturn:
605 """Testing make pod spec without config."""
606 image_info = {"upstream-source": "ubuntu/prometheus:latest"}
607 config = {}
608 relation_state = {}
609 app_name = "prometheus"
610 port = 9090
611
612 with self.assertRaises(ValueError):
613 pod_spec.make_pod_spec(image_info, config, relation_state, app_name, port)
614
615
616 if __name__ == "__main__":
617 unittest.main()