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