c2dd1e25eb368a0774019f6207f3d15aee6fc1b9
[osm/devops.git] / installers / charm / mysqld-exporter / tests / test_pod_spec.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 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 = 9104
35
36 expected_result = [
37 {
38 "name": "mysqld-exporter",
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 """Teting make pod envconfig."""
50 config = {}
51 relation_state = {
52 "mysql_host": "mysql",
53 "mysql_port": "3306",
54 "mysql_user": "mano",
55 "mysql_password": "manopw",
56 "mysql_root_password": "rootpw",
57 }
58
59 expected_result = {
60 "DATA_SOURCE_NAME": "root:{mysql_root_password}@({mysql_host}:{mysql_port})/".format(
61 **relation_state
62 )
63 }
64
65 pod_envconfig = pod_spec._make_pod_envconfig(config, relation_state)
66
67 self.assertDictEqual(expected_result, pod_envconfig)
68
69 def test_make_pod_ingress_resources_without_site_url(self) -> NoReturn:
70 """Testing make pod ingress resources without site_url."""
71 config = {"site_url": ""}
72 app_name = "mysqld-exporter"
73 port = 9104
74
75 pod_ingress_resources = pod_spec._make_pod_ingress_resources(
76 config, app_name, port
77 )
78
79 self.assertIsNone(pod_ingress_resources)
80
81 def test_make_pod_ingress_resources(self) -> NoReturn:
82 """Testing make pod ingress resources."""
83 config = {
84 "site_url": "http://mysqld-exporter",
85 "ingress_whitelist_source_range": "",
86 }
87 app_name = "mysqld-exporter"
88 port = 9104
89
90 expected_result = [
91 {
92 "name": f"{app_name}-ingress",
93 "annotations": {
94 "nginx.ingress.kubernetes.io/ssl-redirect": "false",
95 },
96 "spec": {
97 "rules": [
98 {
99 "host": app_name,
100 "http": {
101 "paths": [
102 {
103 "path": "/",
104 "backend": {
105 "serviceName": app_name,
106 "servicePort": port,
107 },
108 }
109 ]
110 },
111 }
112 ]
113 },
114 }
115 ]
116
117 pod_ingress_resources = pod_spec._make_pod_ingress_resources(
118 config, app_name, port
119 )
120
121 self.assertListEqual(expected_result, pod_ingress_resources)
122
123 def test_make_pod_ingress_resources_with_whitelist_source_range(self) -> NoReturn:
124 """Testing make pod ingress resources with whitelist_source_range."""
125 config = {
126 "site_url": "http://mysqld-exporter",
127 "ingress_whitelist_source_range": "0.0.0.0/0",
128 }
129 app_name = "mysqld-exporter"
130 port = 9104
131
132 expected_result = [
133 {
134 "name": f"{app_name}-ingress",
135 "annotations": {
136 "nginx.ingress.kubernetes.io/ssl-redirect": "false",
137 "nginx.ingress.kubernetes.io/whitelist-source-range": config[
138 "ingress_whitelist_source_range"
139 ],
140 },
141 "spec": {
142 "rules": [
143 {
144 "host": app_name,
145 "http": {
146 "paths": [
147 {
148 "path": "/",
149 "backend": {
150 "serviceName": app_name,
151 "servicePort": port,
152 },
153 }
154 ]
155 },
156 }
157 ]
158 },
159 }
160 ]
161
162 pod_ingress_resources = pod_spec._make_pod_ingress_resources(
163 config, app_name, port
164 )
165
166 self.assertListEqual(expected_result, pod_ingress_resources)
167
168 def test_make_pod_ingress_resources_with_https(self) -> NoReturn:
169 """Testing make pod ingress resources with HTTPs."""
170 config = {
171 "site_url": "https://mysqld-exporter",
172 "ingress_whitelist_source_range": "",
173 "tls_secret_name": "",
174 }
175 app_name = "mysqld-exporter"
176 port = 9104
177
178 expected_result = [
179 {
180 "name": f"{app_name}-ingress",
181 "annotations": {},
182 "spec": {
183 "rules": [
184 {
185 "host": app_name,
186 "http": {
187 "paths": [
188 {
189 "path": "/",
190 "backend": {
191 "serviceName": app_name,
192 "servicePort": port,
193 },
194 }
195 ]
196 },
197 }
198 ],
199 "tls": [{"hosts": [app_name]}],
200 },
201 }
202 ]
203
204 pod_ingress_resources = pod_spec._make_pod_ingress_resources(
205 config, app_name, port
206 )
207
208 self.assertListEqual(expected_result, pod_ingress_resources)
209
210 def test_make_pod_ingress_resources_with_https_tls_secret_name(self) -> NoReturn:
211 """Testing make pod ingress resources with HTTPs and TLS secret name."""
212 config = {
213 "site_url": "https://mysqld-exporter",
214 "ingress_whitelist_source_range": "",
215 "tls_secret_name": "secret_name",
216 }
217 app_name = "mysqld-exporter"
218 port = 9104
219
220 expected_result = [
221 {
222 "name": f"{app_name}-ingress",
223 "annotations": {},
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_readiness_probe(self) -> NoReturn:
255 """Testing make readiness probe."""
256 port = 9104
257
258 expected_result = {
259 "httpGet": {
260 "path": "/api/health",
261 "port": port,
262 },
263 "initialDelaySeconds": 10,
264 "periodSeconds": 10,
265 "timeoutSeconds": 5,
266 "successThreshold": 1,
267 "failureThreshold": 3,
268 }
269
270 readiness_probe = pod_spec._make_readiness_probe(port)
271
272 self.assertDictEqual(expected_result, readiness_probe)
273
274 def test_make_liveness_probe(self) -> NoReturn:
275 """Testing make liveness probe."""
276 port = 9104
277
278 expected_result = {
279 "httpGet": {
280 "path": "/api/health",
281 "port": port,
282 },
283 "initialDelaySeconds": 60,
284 "timeoutSeconds": 30,
285 "failureThreshold": 10,
286 }
287
288 liveness_probe = pod_spec._make_liveness_probe(port)
289
290 self.assertDictEqual(expected_result, liveness_probe)
291
292 def test_make_pod_spec(self) -> NoReturn:
293 """Testing make pod spec."""
294 image_info = {"upstream-source": "bitnami/mysqld-exporter:latest"}
295 config = {
296 "site_url": "",
297 }
298 relation_state = {
299 "mysql_host": "mysql",
300 "mysql_port": "3306",
301 "mysql_user": "mano",
302 "mysql_password": "manopw",
303 "mysql_root_password": "rootpw",
304 }
305 app_name = "mysqld-exporter"
306 port = 9104
307
308 expected_result = {
309 "version": 3,
310 "containers": [
311 {
312 "name": app_name,
313 "imageDetails": image_info,
314 "imagePullPolicy": "Always",
315 "ports": [
316 {
317 "name": app_name,
318 "containerPort": port,
319 "protocol": "TCP",
320 }
321 ],
322 "envConfig": {
323 "DATA_SOURCE_NAME": "root:{mysql_root_password}@({mysql_host}:{mysql_port})/".format(
324 **relation_state
325 )
326 },
327 "kubernetes": {
328 "readinessProbe": {
329 "httpGet": {
330 "path": "/api/health",
331 "port": port,
332 },
333 "initialDelaySeconds": 10,
334 "periodSeconds": 10,
335 "timeoutSeconds": 5,
336 "successThreshold": 1,
337 "failureThreshold": 3,
338 },
339 "livenessProbe": {
340 "httpGet": {
341 "path": "/api/health",
342 "port": port,
343 },
344 "initialDelaySeconds": 60,
345 "timeoutSeconds": 30,
346 "failureThreshold": 10,
347 },
348 },
349 }
350 ],
351 "kubernetesResources": {"ingressResources": []},
352 }
353
354 spec = pod_spec.make_pod_spec(
355 image_info, config, relation_state, app_name, port
356 )
357
358 self.assertDictEqual(expected_result, spec)
359
360 def test_make_pod_spec_with_ingress(self) -> NoReturn:
361 """Testing make pod spec."""
362 image_info = {"upstream-source": "bitnami/mysqld-exporter:latest"}
363 config = {
364 "site_url": "https://mysqld-exporter",
365 "tls_secret_name": "mysqld-exporter",
366 "ingress_whitelist_source_range": "0.0.0.0/0",
367 }
368 relation_state = {
369 "mysql_host": "mysql",
370 "mysql_port": "3306",
371 "mysql_user": "mano",
372 "mysql_password": "manopw",
373 "mysql_root_password": "rootpw",
374 }
375 app_name = "mysqld-exporter"
376 port = 9104
377
378 expected_result = {
379 "version": 3,
380 "containers": [
381 {
382 "name": app_name,
383 "imageDetails": image_info,
384 "imagePullPolicy": "Always",
385 "ports": [
386 {
387 "name": app_name,
388 "containerPort": port,
389 "protocol": "TCP",
390 }
391 ],
392 "envConfig": {
393 "DATA_SOURCE_NAME": "root:{mysql_root_password}@({mysql_host}:{mysql_port})/".format(
394 **relation_state
395 )
396 },
397 "kubernetes": {
398 "readinessProbe": {
399 "httpGet": {
400 "path": "/api/health",
401 "port": port,
402 },
403 "initialDelaySeconds": 10,
404 "periodSeconds": 10,
405 "timeoutSeconds": 5,
406 "successThreshold": 1,
407 "failureThreshold": 3,
408 },
409 "livenessProbe": {
410 "httpGet": {
411 "path": "/api/health",
412 "port": port,
413 },
414 "initialDelaySeconds": 60,
415 "timeoutSeconds": 30,
416 "failureThreshold": 10,
417 },
418 },
419 }
420 ],
421 "kubernetesResources": {
422 "ingressResources": [
423 {
424 "name": "{}-ingress".format(app_name),
425 "annotations": {
426 "nginx.ingress.kubernetes.io/whitelist-source-range": config.get(
427 "ingress_whitelist_source_range"
428 ),
429 },
430 "spec": {
431 "rules": [
432 {
433 "host": app_name,
434 "http": {
435 "paths": [
436 {
437 "path": "/",
438 "backend": {
439 "serviceName": app_name,
440 "servicePort": port,
441 },
442 }
443 ]
444 },
445 }
446 ],
447 "tls": [
448 {
449 "hosts": [app_name],
450 "secretName": config.get("tls_secret_name"),
451 }
452 ],
453 },
454 }
455 ],
456 },
457 }
458
459 spec = pod_spec.make_pod_spec(
460 image_info, config, relation_state, app_name, port
461 )
462
463 self.assertDictEqual(expected_result, spec)
464
465 def test_make_pod_spec_without_image_info(self) -> NoReturn:
466 """Testing make pod spec without image_info."""
467 image_info = None
468 config = {
469 "site_url": "",
470 }
471 relation_state = {
472 "mysql_host": "mysql",
473 "mysql_port": 3306,
474 "mysql_user": "mano",
475 "mysql_password": "manopw",
476 "mysql_root_password": "rootpw",
477 }
478 app_name = "mysqld-exporter"
479 port = 9104
480
481 spec = pod_spec.make_pod_spec(
482 image_info, config, relation_state, app_name, port
483 )
484
485 self.assertIsNone(spec)
486
487 def test_make_pod_spec_without_relation_state(self) -> NoReturn:
488 """Testing make pod spec without relation_state."""
489 image_info = {"upstream-source": "bitnami/mysqld-exporter:latest"}
490 config = {
491 "site_url": "",
492 }
493 relation_state = {}
494 app_name = "mysqld-exporter"
495 port = 9104
496
497 with self.assertRaises(ValueError):
498 pod_spec.make_pod_spec(image_info, config, relation_state, app_name, port)
499
500
501 if __name__ == "__main__":
502 unittest.main()