a384e447c1a0cb9b3c7e205e054593d8fee34cfb
[osm/N2VC.git] / n2vc / tests / unit / test_libjuju.py
1 # Copyright 2020 Canonical Ltd.
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 import asyncio
16 import asynctest
17 import tempfile
18 from unittest import mock
19 import juju
20 import kubernetes
21 from juju.errors import JujuAPIError
22 import logging
23 from .utils import FakeN2VC, FakeMachine, FakeApplication
24 from n2vc.libjuju import Libjuju
25 from n2vc.exceptions import (
26 JujuControllerFailedConnecting,
27 JujuModelAlreadyExists,
28 JujuMachineNotFound,
29 JujuApplicationNotFound,
30 JujuActionNotFound,
31 JujuApplicationExists,
32 JujuInvalidK8sConfiguration,
33 JujuLeaderUnitNotFound,
34 )
35
36
37 class LibjujuTestCase(asynctest.TestCase):
38 @asynctest.mock.patch("juju.controller.Controller.update_endpoints")
39 @asynctest.mock.patch("juju.client.connector.Connector.connect")
40 @asynctest.mock.patch("juju.controller.Controller.connection")
41 @asynctest.mock.patch("n2vc.libjuju.Libjuju._get_api_endpoints_db")
42 def setUp(
43 self,
44 mock__get_api_endpoints_db=None,
45 mock_connection=None,
46 mock_connect=None,
47 mock_update_endpoints=None,
48 ):
49 loop = asyncio.get_event_loop()
50 n2vc = FakeN2VC()
51 mock__get_api_endpoints_db.return_value = ["127.0.0.1:17070"]
52 endpoints = "127.0.0.1:17070"
53 username = "admin"
54 password = "secret"
55 cacert = """
56 -----BEGIN CERTIFICATE-----
57 SOMECERT
58 -----END CERTIFICATE-----"""
59 self.libjuju = Libjuju(
60 endpoints,
61 "192.168.0.155:17070",
62 username,
63 password,
64 cacert,
65 loop,
66 log=None,
67 db={"get_one": []},
68 n2vc=n2vc,
69 apt_mirror="192.168.0.100",
70 enable_os_upgrade=True,
71 )
72 logging.disable(logging.CRITICAL)
73 loop.run_until_complete(self.libjuju.disconnect())
74
75
76 @asynctest.mock.patch("juju.controller.Controller.connect")
77 @asynctest.mock.patch(
78 "juju.controller.Controller.api_endpoints",
79 new_callable=asynctest.CoroutineMock(return_value=["127.0.0.1:17070"]),
80 )
81 @asynctest.mock.patch("n2vc.libjuju.Libjuju._update_api_endpoints_db")
82 class GetControllerTest(LibjujuTestCase):
83 def setUp(self):
84 super(GetControllerTest, self).setUp()
85
86 def test_diff_endpoint(
87 self, mock__update_api_endpoints_db, mock_api_endpoints, mock_connect
88 ):
89 self.libjuju.endpoints = []
90 controller = self.loop.run_until_complete(self.libjuju.get_controller())
91 mock__update_api_endpoints_db.assert_called_once_with(["127.0.0.1:17070"])
92 self.assertIsInstance(controller, juju.controller.Controller)
93
94 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
95 def test_exception(
96 self,
97 mock_disconnect_controller,
98 mock__update_api_endpoints_db,
99 mock_api_endpoints,
100 mock_connect,
101 ):
102 self.libjuju.endpoints = []
103 mock__update_api_endpoints_db.side_effect = Exception()
104 controller = None
105 with self.assertRaises(JujuControllerFailedConnecting):
106 controller = self.loop.run_until_complete(self.libjuju.get_controller())
107 self.assertIsNone(controller)
108 mock_disconnect_controller.assert_called_once()
109
110 def test_same_endpoint_get_controller(
111 self, mock__update_api_endpoints_db, mock_api_endpoints, mock_connect
112 ):
113 self.libjuju.endpoints = ["127.0.0.1:17070"]
114 controller = self.loop.run_until_complete(self.libjuju.get_controller())
115 mock__update_api_endpoints_db.assert_not_called()
116 self.assertIsInstance(controller, juju.controller.Controller)
117
118
119 class DisconnectTest(LibjujuTestCase):
120 def setUp(self):
121 super(DisconnectTest, self).setUp()
122
123 @asynctest.mock.patch("juju.model.Model.disconnect")
124 def test_disconnect_model(self, mock_disconnect):
125 self.loop.run_until_complete(self.libjuju.disconnect_model(juju.model.Model()))
126 mock_disconnect.assert_called_once()
127
128 @asynctest.mock.patch("juju.controller.Controller.disconnect")
129 def test_disconnect_controller(self, mock_disconnect):
130 self.loop.run_until_complete(
131 self.libjuju.disconnect_controller(juju.controller.Controller())
132 )
133 mock_disconnect.assert_called_once()
134
135
136 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
137 @asynctest.mock.patch("n2vc.libjuju.Libjuju.model_exists")
138 @asynctest.mock.patch("juju.controller.Controller.add_model")
139 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
140 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
141 class AddModelTest(LibjujuTestCase):
142 def setUp(self):
143 super(AddModelTest, self).setUp()
144
145 def test_existing_model(
146 self,
147 mock_disconnect_model,
148 mock_disconnect_controller,
149 mock_add_model,
150 mock_model_exists,
151 mock_get_controller,
152 ):
153 mock_model_exists.return_value = True
154
155 with self.assertRaises(JujuModelAlreadyExists):
156 self.loop.run_until_complete(
157 self.libjuju.add_model("existing_model", "cloud")
158 )
159
160 mock_disconnect_controller.assert_called()
161
162 # TODO Check two job executing at the same time and one returning without doing anything.
163
164 def test_non_existing_model(
165 self,
166 mock_disconnect_model,
167 mock_disconnect_controller,
168 mock_add_model,
169 mock_model_exists,
170 mock_get_controller,
171 ):
172 mock_model_exists.return_value = False
173 mock_get_controller.return_value = juju.controller.Controller()
174
175 self.loop.run_until_complete(
176 self.libjuju.add_model("nonexisting_model", "cloud")
177 )
178
179 mock_add_model.assert_called_once()
180 mock_disconnect_controller.assert_called()
181 mock_disconnect_model.assert_called()
182
183
184 @asynctest.mock.patch("juju.controller.Controller.get_model")
185 class GetModelTest(LibjujuTestCase):
186 def setUp(self):
187 super(GetModelTest, self).setUp()
188
189 def test_get_model(
190 self, mock_get_model,
191 ):
192 mock_get_model.return_value = juju.model.Model()
193 model = self.loop.run_until_complete(
194 self.libjuju.get_model(juju.controller.Controller(), "model")
195 )
196 self.assertIsInstance(model, juju.model.Model)
197
198
199 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
200 @asynctest.mock.patch("juju.controller.Controller.list_models")
201 class ModelExistsTest(LibjujuTestCase):
202 def setUp(self):
203 super(ModelExistsTest, self).setUp()
204
205 async def test_existing_model(
206 self, mock_list_models, mock_get_controller,
207 ):
208 mock_list_models.return_value = ["existing_model"]
209 self.assertTrue(
210 await self.libjuju.model_exists(
211 "existing_model", juju.controller.Controller()
212 )
213 )
214
215 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
216 async def test_no_controller(
217 self, mock_disconnect_controller, mock_list_models, mock_get_controller,
218 ):
219 mock_list_models.return_value = ["existing_model"]
220 mock_get_controller.return_value = juju.controller.Controller()
221 self.assertTrue(await self.libjuju.model_exists("existing_model"))
222 mock_disconnect_controller.assert_called_once()
223
224 async def test_non_existing_model(
225 self, mock_list_models, mock_get_controller,
226 ):
227 mock_list_models.return_value = ["existing_model"]
228 self.assertFalse(
229 await self.libjuju.model_exists(
230 "not_existing_model", juju.controller.Controller()
231 )
232 )
233
234
235 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
236 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
237 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
238 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
239 @asynctest.mock.patch("juju.model.Model.get_status")
240 class GetModelStatusTest(LibjujuTestCase):
241 def setUp(self):
242 super(GetModelStatusTest, self).setUp()
243
244 def test_success(
245 self,
246 mock_get_status,
247 mock_disconnect_controller,
248 mock_disconnect_model,
249 mock_get_model,
250 mock_get_controller,
251 ):
252 mock_get_model.return_value = juju.model.Model()
253 mock_get_status.return_value = {"status"}
254
255 status = self.loop.run_until_complete(self.libjuju.get_model_status("model"))
256
257 mock_get_status.assert_called_once()
258 mock_disconnect_controller.assert_called_once()
259 mock_disconnect_model.assert_called_once()
260
261 self.assertEqual(status, {"status"})
262
263 def test_exception(
264 self,
265 mock_get_status,
266 mock_disconnect_controller,
267 mock_disconnect_model,
268 mock_get_model,
269 mock_get_controller,
270 ):
271 mock_get_model.return_value = juju.model.Model()
272 mock_get_status.side_effect = Exception()
273 status = None
274 with self.assertRaises(Exception):
275 status = self.loop.run_until_complete(
276 self.libjuju.get_model_status("model")
277 )
278
279 mock_disconnect_controller.assert_called_once()
280 mock_disconnect_model.assert_called_once()
281
282 self.assertIsNone(status)
283
284
285 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
286 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
287 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
288 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
289 @asynctest.mock.patch("juju.model.Model.get_machines")
290 @asynctest.mock.patch("juju.model.Model.add_machine")
291 @asynctest.mock.patch("n2vc.juju_watcher.JujuModelWatcher.wait_for")
292 class CreateMachineTest(LibjujuTestCase):
293 def setUp(self):
294 super(CreateMachineTest, self).setUp()
295
296 def test_existing_machine(
297 self,
298 mock_wait_for,
299 mock_add_machine,
300 mock_get_machines,
301 mock_disconnect_controller,
302 mock_disconnect_model,
303 mock_get_model,
304 mock_get_controller,
305 ):
306 mock_get_model.return_value = juju.model.Model()
307 mock_get_machines.return_value = {"existing_machine": FakeMachine()}
308 machine, bool_res = self.loop.run_until_complete(
309 self.libjuju.create_machine("model", "existing_machine")
310 )
311
312 self.assertIsInstance(machine, FakeMachine)
313 self.assertFalse(bool_res)
314
315 mock_disconnect_controller.assert_called()
316 mock_disconnect_model.assert_called()
317
318 def test_non_existing_machine(
319 self,
320 mock_wait_for,
321 mock_add_machine,
322 mock_get_machines,
323 mock_disconnect_controller,
324 mock_disconnect_model,
325 mock_get_model,
326 mock_get_controller,
327 ):
328 machine = None
329 bool_res = None
330 mock_get_model.return_value = juju.model.Model()
331 with self.assertRaises(JujuMachineNotFound):
332 machine, bool_res = self.loop.run_until_complete(
333 self.libjuju.create_machine("model", "non_existing_machine")
334 )
335 self.assertIsNone(machine)
336 self.assertIsNone(bool_res)
337
338 mock_disconnect_controller.assert_called()
339 mock_disconnect_model.assert_called()
340
341 def test_no_machine(
342 self,
343 mock_wait_for,
344 mock_add_machine,
345 mock_get_machines,
346 mock_disconnect_controller,
347 mock_disconnect_model,
348 mock_get_model,
349 mock_get_controller,
350 ):
351 mock_get_model.return_value = juju.model.Model()
352 mock_add_machine.return_value = FakeMachine()
353
354 machine, bool_res = self.loop.run_until_complete(
355 self.libjuju.create_machine("model")
356 )
357
358 self.assertIsInstance(machine, FakeMachine)
359 self.assertTrue(bool_res)
360
361 mock_wait_for.assert_called_once()
362 mock_add_machine.assert_called_once()
363
364 mock_disconnect_controller.assert_called()
365 mock_disconnect_model.assert_called()
366
367
368 # TODO test provision machine
369
370
371 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
372 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
373 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
374 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
375 @asynctest.mock.patch(
376 "juju.model.Model.applications", new_callable=asynctest.PropertyMock
377 )
378 @asynctest.mock.patch("juju.model.Model.machines", new_callable=asynctest.PropertyMock)
379 @asynctest.mock.patch("juju.model.Model.deploy")
380 @asynctest.mock.patch("n2vc.juju_watcher.JujuModelWatcher.wait_for")
381 @asynctest.mock.patch("n2vc.libjuju.Libjuju.create_machine")
382 class DeployCharmTest(LibjujuTestCase):
383 def setUp(self):
384 super(DeployCharmTest, self).setUp()
385
386 def test_existing_app(
387 self,
388 mock_create_machine,
389 mock_wait_for,
390 mock_deploy,
391 mock_machines,
392 mock_applications,
393 mock_disconnect_controller,
394 mock_disconnect_model,
395 mock_get_model,
396 mock_get_controller,
397 ):
398 mock_get_model.return_value = juju.model.Model()
399 mock_applications.return_value = {"existing_app"}
400
401 application = None
402 with self.assertRaises(JujuApplicationExists):
403 application = self.loop.run_until_complete(
404 self.libjuju.deploy_charm("existing_app", "path", "model", "machine",)
405 )
406 self.assertIsNone(application)
407
408 mock_disconnect_controller.assert_called()
409 mock_disconnect_model.assert_called()
410
411 def test_non_existing_machine(
412 self,
413 mock_create_machine,
414 mock_wait_for,
415 mock_deploy,
416 mock_machines,
417 mock_applications,
418 mock_disconnect_controller,
419 mock_disconnect_model,
420 mock_get_model,
421 mock_get_controller,
422 ):
423 mock_get_model.return_value = juju.model.Model()
424 mock_machines.return_value = {"existing_machine": FakeMachine()}
425 application = None
426 with self.assertRaises(JujuMachineNotFound):
427 application = self.loop.run_until_complete(
428 self.libjuju.deploy_charm("app", "path", "model", "machine",)
429 )
430
431 self.assertIsNone(application)
432
433 mock_disconnect_controller.assert_called()
434 mock_disconnect_model.assert_called()
435
436 def test_2_units(
437 self,
438 mock_create_machine,
439 mock_wait_for,
440 mock_deploy,
441 mock_machines,
442 mock_applications,
443 mock_disconnect_controller,
444 mock_disconnect_model,
445 mock_get_model,
446 mock_get_controller,
447 ):
448 mock_get_model.return_value = juju.model.Model()
449 mock_machines.return_value = {"existing_machine": FakeMachine()}
450 mock_create_machine.return_value = (FakeMachine(), "other")
451 mock_deploy.return_value = FakeApplication()
452 application = self.loop.run_until_complete(
453 self.libjuju.deploy_charm(
454 "app", "path", "model", "existing_machine", num_units=2,
455 )
456 )
457
458 self.assertIsInstance(application, FakeApplication)
459
460 mock_deploy.assert_called_once()
461 mock_wait_for.assert_called_once()
462
463 mock_create_machine.assert_called_once()
464
465 mock_disconnect_controller.assert_called()
466 mock_disconnect_model.assert_called()
467
468 def test_1_unit(
469 self,
470 mock_create_machine,
471 mock_wait_for,
472 mock_deploy,
473 mock_machines,
474 mock_applications,
475 mock_disconnect_controller,
476 mock_disconnect_model,
477 mock_get_model,
478 mock_get_controller,
479 ):
480 mock_get_model.return_value = juju.model.Model()
481 mock_machines.return_value = {"existing_machine": FakeMachine()}
482 mock_deploy.return_value = FakeApplication()
483 application = self.loop.run_until_complete(
484 self.libjuju.deploy_charm("app", "path", "model", "existing_machine")
485 )
486
487 self.assertIsInstance(application, FakeApplication)
488
489 mock_deploy.assert_called_once()
490 mock_wait_for.assert_called_once()
491
492 mock_disconnect_controller.assert_called()
493 mock_disconnect_model.assert_called()
494
495
496 @asynctest.mock.patch(
497 "juju.model.Model.applications", new_callable=asynctest.PropertyMock
498 )
499 class GetApplicationTest(LibjujuTestCase):
500 def setUp(self):
501 super(GetApplicationTest, self).setUp()
502
503 def test_existing_application(
504 self, mock_applications,
505 ):
506 mock_applications.return_value = {"existing_app": "exists"}
507 model = juju.model.Model()
508 result = self.libjuju._get_application(model, "existing_app")
509 self.assertEqual(result, "exists")
510
511 def test_non_existing_application(
512 self, mock_applications,
513 ):
514 mock_applications.return_value = {"existing_app": "exists"}
515 model = juju.model.Model()
516 result = self.libjuju._get_application(model, "nonexisting_app")
517 self.assertIsNone(result)
518
519
520 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
521 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
522 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
523 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
524 @asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
525 @asynctest.mock.patch("n2vc.juju_watcher.JujuModelWatcher.wait_for")
526 @asynctest.mock.patch("juju.model.Model.get_action_output")
527 @asynctest.mock.patch("juju.model.Model.get_action_status")
528 class ExecuteActionTest(LibjujuTestCase):
529 def setUp(self):
530 super(ExecuteActionTest, self).setUp()
531
532 def test_no_application(
533 self,
534 mock_get_action_status,
535 mock_get_action_output,
536 mock_wait_for,
537 mock__get_application,
538 mock_disconnect_controller,
539 mock_disconnect_model,
540 mock_get_model,
541 mock_get_controller,
542 ):
543 mock__get_application.return_value = None
544 mock_get_model.return_value = juju.model.Model()
545 output = None
546 status = None
547 with self.assertRaises(JujuApplicationNotFound):
548 output, status = self.loop.run_until_complete(
549 self.libjuju.execute_action("app", "model", "action",)
550 )
551 self.assertIsNone(output)
552 self.assertIsNone(status)
553
554 mock_disconnect_controller.assert_called()
555 mock_disconnect_model.assert_called()
556
557 def test_no_action(
558 self,
559 mock_get_action_status,
560 mock_get_action_output,
561 mock_wait_for,
562 mock__get_application,
563 mock_disconnect_controller,
564 mock_disconnect_model,
565 mock_get_model,
566 mock_get_controller,
567 ):
568
569 mock_get_model.return_value = juju.model.Model()
570 mock__get_application.return_value = FakeApplication()
571 output = None
572 status = None
573 with self.assertRaises(JujuActionNotFound):
574 output, status = self.loop.run_until_complete(
575 self.libjuju.execute_action("app", "model", "action",)
576 )
577 self.assertIsNone(output)
578 self.assertIsNone(status)
579
580 mock_disconnect_controller.assert_called()
581 mock_disconnect_model.assert_called()
582
583 @asynctest.mock.patch("asyncio.sleep")
584 @asynctest.mock.patch("n2vc.tests.unit.utils.FakeUnit.is_leader_from_status")
585 def test_no_leader(
586 self,
587 mock_is_leader_from_status,
588 mock_sleep,
589 mock_get_action_status,
590 mock_get_action_output,
591 mock_wait_for,
592 mock__get_application,
593 mock_disconnect_controller,
594 mock_disconnect_model,
595 mock_get_model,
596 mock_get_controller,
597 ):
598 mock_get_model.return_value = juju.model.Model()
599 mock__get_application.return_value = FakeApplication()
600 mock_is_leader_from_status.return_value = False
601 output = None
602 status = None
603 with self.assertRaises(JujuLeaderUnitNotFound):
604 output, status = self.loop.run_until_complete(
605 self.libjuju.execute_action("app", "model", "action",)
606 )
607 self.assertIsNone(output)
608 self.assertIsNone(status)
609
610 mock_disconnect_controller.assert_called()
611 mock_disconnect_model.assert_called()
612
613 def test_succesful_exec(
614 self,
615 mock_get_action_status,
616 mock_get_action_output,
617 mock_wait_for,
618 mock__get_application,
619 mock_disconnect_controller,
620 mock_disconnect_model,
621 mock_get_model,
622 mock_get_controller,
623 ):
624 mock_get_model.return_value = juju.model.Model()
625 mock__get_application.return_value = FakeApplication()
626 mock_get_action_output.return_value = "output"
627 mock_get_action_status.return_value = {"id": "status"}
628 output, status = self.loop.run_until_complete(
629 self.libjuju.execute_action("app", "model", "existing_action")
630 )
631 self.assertEqual(output, "output")
632 self.assertEqual(status, "status")
633
634 mock_wait_for.assert_called_once()
635
636 mock_disconnect_controller.assert_called()
637 mock_disconnect_model.assert_called()
638
639
640 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
641 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
642 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
643 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
644 @asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
645 class GetActionTest(LibjujuTestCase):
646 def setUp(self):
647 super(GetActionTest, self).setUp()
648
649 def test_exception(
650 self,
651 mock_get_application,
652 mock_disconnect_controller,
653 mock_disconnect_model,
654 mock_get_model,
655 mock_get_controller,
656 ):
657 mock_get_application.side_effect = Exception()
658 actions = None
659 with self.assertRaises(Exception):
660 actions = self.loop.run_until_complete(
661 self.libjuju.get_actions("app", "model")
662 )
663
664 self.assertIsNone(actions)
665 mock_disconnect_controller.assert_called_once()
666 mock_disconnect_model.assert_called_once()
667
668 def test_success(
669 self,
670 mock_get_application,
671 mock_disconnect_controller,
672 mock_disconnect_model,
673 mock_get_model,
674 mock_get_controller,
675 ):
676 mock_get_application.return_value = FakeApplication()
677
678 actions = self.loop.run_until_complete(self.libjuju.get_actions("app", "model"))
679
680 self.assertEqual(actions, ["existing_action"])
681
682 mock_get_controller.assert_called_once()
683 mock_get_model.assert_called_once()
684 mock_disconnect_controller.assert_called_once()
685 mock_disconnect_model.assert_called_once()
686
687
688 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
689 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
690 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
691 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
692 @asynctest.mock.patch("juju.application.Application.get_metrics")
693 @asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
694 class GetMetricsTest(LibjujuTestCase):
695 def setUp(self):
696 super(GetMetricsTest, self).setUp()
697
698 def test_get_metrics_success(
699 self,
700 mock_get_application,
701 mock_get_metrics,
702 mock_disconnect_controller,
703 mock_disconnect_model,
704 mock_get_model,
705 mock_get_controller,
706 ):
707 mock_get_application.return_value = FakeApplication()
708 mock_get_model.return_value = juju.model.Model()
709
710 self.loop.run_until_complete(self.libjuju.get_metrics("model", "app1"))
711
712 mock_disconnect_controller.assert_called_once()
713 mock_disconnect_model.assert_called_once()
714
715 def test_get_metrics_exception(
716 self,
717 mock_get_application,
718 mock_get_metrics,
719 mock_disconnect_controller,
720 mock_disconnect_model,
721 mock_get_model,
722 mock_get_controller,
723 ):
724 mock_get_model.return_value = juju.model.Model()
725 mock_get_metrics.side_effect = Exception()
726 with self.assertRaises(Exception):
727 self.loop.run_until_complete(self.libjuju.get_metrics("model", "app1"))
728
729 mock_disconnect_controller.assert_called_once()
730 mock_disconnect_model.assert_called_once()
731
732 def test_missing_args_exception(
733 self,
734 mock_get_application,
735 mock_get_metrics,
736 mock_disconnect_controller,
737 mock_disconnect_model,
738 mock_get_model,
739 mock_get_controller,
740 ):
741 mock_get_model.return_value = juju.model.Model()
742
743 with self.assertRaises(Exception):
744 self.loop.run_until_complete(self.libjuju.get_metrics("", ""))
745
746 mock_get_controller.assert_not_called()
747 mock_get_model.assert_not_called()
748 mock_disconnect_controller.assert_not_called()
749 mock_disconnect_model.assert_not_called()
750
751
752 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
753 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
754 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
755 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
756 @asynctest.mock.patch("juju.model.Model.add_relation")
757 class AddRelationTest(LibjujuTestCase):
758 def setUp(self):
759 super(AddRelationTest, self).setUp()
760
761 @asynctest.mock.patch("logging.Logger.warning")
762 def test_not_found(
763 self,
764 mock_warning,
765 mock_add_relation,
766 mock_disconnect_controller,
767 mock_disconnect_model,
768 mock_get_model,
769 mock_get_controller,
770 ):
771 # TODO in libjuju.py should this fail only with a log message?
772 result = {"error": "not found", "response": "response", "request-id": 1}
773
774 mock_get_model.return_value = juju.model.Model()
775 mock_add_relation.side_effect = JujuAPIError(result)
776
777 self.loop.run_until_complete(
778 self.libjuju.add_relation("model", "app1:relation1", "app2:relation2",)
779 )
780
781 mock_warning.assert_called_with("Relation not found: not found")
782 mock_disconnect_controller.assert_called_once()
783 mock_disconnect_model.assert_called_once()
784
785 @asynctest.mock.patch("logging.Logger.warning")
786 def test_already_exists(
787 self,
788 mock_warning,
789 mock_add_relation,
790 mock_disconnect_controller,
791 mock_disconnect_model,
792 mock_get_model,
793 mock_get_controller,
794 ):
795 # TODO in libjuju.py should this fail silently?
796 result = {"error": "already exists", "response": "response", "request-id": 1}
797
798 mock_get_model.return_value = juju.model.Model()
799 mock_add_relation.side_effect = JujuAPIError(result)
800
801 self.loop.run_until_complete(
802 self.libjuju.add_relation("model", "app1:relation1", "app2:relation2",)
803 )
804
805 mock_warning.assert_called_with("Relation already exists: already exists")
806 mock_disconnect_controller.assert_called_once()
807 mock_disconnect_model.assert_called_once()
808
809 def test_exception(
810 self,
811 mock_add_relation,
812 mock_disconnect_controller,
813 mock_disconnect_model,
814 mock_get_model,
815 mock_get_controller,
816 ):
817 mock_get_model.return_value = juju.model.Model()
818 result = {"error": "", "response": "response", "request-id": 1}
819 mock_add_relation.side_effect = JujuAPIError(result)
820
821 with self.assertRaises(JujuAPIError):
822 self.loop.run_until_complete(
823 self.libjuju.add_relation("model", "app1:relation1", "app2:relation2",)
824 )
825
826 mock_disconnect_controller.assert_called_once()
827 mock_disconnect_model.assert_called_once()
828
829 def test_success(
830 self,
831 mock_add_relation,
832 mock_disconnect_controller,
833 mock_disconnect_model,
834 mock_get_model,
835 mock_get_controller,
836 ):
837 mock_get_model.return_value = juju.model.Model()
838
839 self.loop.run_until_complete(
840 self.libjuju.add_relation("model", "app1:relation1", "app2:relation2",)
841 )
842
843 mock_add_relation.assert_called_with("app1:relation1", "app2:relation2")
844 mock_disconnect_controller.assert_called_once()
845 mock_disconnect_model.assert_called_once()
846
847 def test_saas(
848 self,
849 mock_add_relation,
850 mock_disconnect_controller,
851 mock_disconnect_model,
852 mock_get_model,
853 mock_get_controller,
854 ):
855 mock_get_model.return_value = juju.model.Model()
856
857 self.loop.run_until_complete(
858 self.libjuju.add_relation("model", "app1:relation1", "saas_name",)
859 )
860
861 mock_add_relation.assert_called_with("app1:relation1", "saas_name")
862 mock_disconnect_controller.assert_called_once()
863 mock_disconnect_model.assert_called_once()
864
865
866 # TODO destroy_model testcase
867
868
869 # @asynctest.mock.patch("juju.model.Model.get_machines")
870 # @asynctest.mock.patch("logging.Logger.debug")
871 # class DestroyMachineTest(LibjujuTestCase):
872 # def setUp(self):
873 # super(DestroyMachineTest, self).setUp()
874
875 # def test_success_manual_machine(
876 # self, mock_debug, mock_get_machines,
877 # ):
878 # mock_get_machines.side_effect = [
879 # {"machine": FakeManualMachine()},
880 # {"machine": FakeManualMachine()},
881 # {},
882 # ]
883 # self.loop.run_until_complete(
884 # self.libjuju.destroy_machine(juju.model.Model(), "machine", 2,)
885 # )
886 # calls = [
887 # asynctest.call("Waiting for machine machine is destroyed"),
888 # asynctest.call("Machine destroyed: machine"),
889 # ]
890 # mock_debug.assert_has_calls(calls)
891
892 # def test_no_machine(
893 # self, mock_debug, mock_get_machines,
894 # ):
895 # mock_get_machines.return_value = {}
896 # self.loop.run_until_complete(
897 # self.libjuju.destroy_machine(juju.model.Model(), "machine", 2)
898 # )
899 # mock_debug.assert_called_with("Machine not found: machine")
900
901
902 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
903 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
904 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
905 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
906 @asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
907 class ConfigureApplicationTest(LibjujuTestCase):
908 def setUp(self):
909 super(ConfigureApplicationTest, self).setUp()
910
911 def test_success(
912 self,
913 mock_get_application,
914 mock_disconnect_controller,
915 mock_disconnect_model,
916 mock_get_model,
917 mock_get_controller,
918 ):
919
920 mock_get_application.return_value = FakeApplication()
921
922 self.loop.run_until_complete(
923 self.libjuju.configure_application("model", "app", {"config"},)
924 )
925 mock_get_application.assert_called_once()
926 mock_disconnect_controller.assert_called_once()
927 mock_disconnect_model.assert_called_once()
928
929 def test_exception(
930 self,
931 mock_get_application,
932 mock_disconnect_controller,
933 mock_disconnect_model,
934 mock_get_model,
935 mock_get_controller,
936 ):
937
938 mock_get_application.side_effect = Exception()
939
940 with self.assertRaises(Exception):
941 self.loop.run_until_complete(
942 self.libjuju.configure_application("model", "app", {"config"},)
943 )
944 mock_disconnect_controller.assert_called_once()
945 mock_disconnect_model.assert_called_once()
946
947
948 # TODO _get_api_endpoints_db test case
949 # TODO _update_api_endpoints_db test case
950 # TODO healthcheck test case
951
952
953 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
954 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
955 @asynctest.mock.patch("juju.controller.Controller.list_models")
956 class ListModelsTest(LibjujuTestCase):
957 def setUp(self):
958 super(ListModelsTest, self).setUp()
959
960 def test_containing(
961 self, mock_list_models, mock_disconnect_controller, mock_get_controller,
962 ):
963 mock_get_controller.return_value = juju.controller.Controller()
964 mock_list_models.return_value = ["existingmodel"]
965 models = self.loop.run_until_complete(self.libjuju.list_models("existing"))
966
967 mock_disconnect_controller.assert_called_once()
968 self.assertEquals(models, ["existingmodel"])
969
970 def test_not_containing(
971 self, mock_list_models, mock_disconnect_controller, mock_get_controller,
972 ):
973 mock_get_controller.return_value = juju.controller.Controller()
974 mock_list_models.return_value = ["existingmodel", "model"]
975 models = self.loop.run_until_complete(self.libjuju.list_models("mdl"))
976
977 mock_disconnect_controller.assert_called_once()
978 self.assertEquals(models, [])
979
980 def test_no_contains_arg(
981 self, mock_list_models, mock_disconnect_controller, mock_get_controller,
982 ):
983 mock_get_controller.return_value = juju.controller.Controller()
984 mock_list_models.return_value = ["existingmodel", "model"]
985 models = self.loop.run_until_complete(self.libjuju.list_models())
986
987 mock_disconnect_controller.assert_called_once()
988 self.assertEquals(models, ["existingmodel", "model"])
989
990
991 @asynctest.mock.patch("n2vc.libjuju.Libjuju.list_models")
992 class ModelsExistTest(LibjujuTestCase):
993 def setUp(self):
994 super(ModelsExistTest, self).setUp()
995
996 def test_model_names_none(self, mock_list_models):
997 mock_list_models.return_value = []
998 with self.assertRaises(Exception):
999 self.loop.run_until_complete(self.libjuju.models_exist(None))
1000
1001 def test_model_names_empty(self, mock_list_models):
1002 mock_list_models.return_value = []
1003 with self.assertRaises(Exception):
1004 (exist, non_existing_models) = self.loop.run_until_complete(
1005 self.libjuju.models_exist([])
1006 )
1007
1008 def test_model_names_not_existing(self, mock_list_models):
1009 mock_list_models.return_value = ["prometheus", "grafana"]
1010 (exist, non_existing_models) = self.loop.run_until_complete(
1011 self.libjuju.models_exist(["prometheus2", "grafana"])
1012 )
1013 self.assertFalse(exist)
1014 self.assertEqual(non_existing_models, ["prometheus2"])
1015
1016 def test_model_names_exist(self, mock_list_models):
1017 mock_list_models.return_value = ["prometheus", "grafana"]
1018 (exist, non_existing_models) = self.loop.run_until_complete(
1019 self.libjuju.models_exist(["prometheus", "grafana"])
1020 )
1021 self.assertTrue(exist)
1022 self.assertEqual(non_existing_models, [])
1023
1024
1025 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
1026 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1027 @asynctest.mock.patch("juju.controller.Controller.list_offers")
1028 class ListOffers(LibjujuTestCase):
1029 def setUp(self):
1030 super(ListOffers, self).setUp()
1031
1032 def test_disconnect_controller(
1033 self, mock_list_offers, mock_disconnect_controller, mock_get_controller,
1034 ):
1035 mock_get_controller.return_value = juju.controller.Controller()
1036 mock_list_offers.side_effect = Exception()
1037 with self.assertRaises(Exception):
1038 self.loop.run_until_complete(self.libjuju.list_offers("model"))
1039 mock_disconnect_controller.assert_called_once()
1040
1041 def test_empty_list(
1042 self, mock_list_offers, mock_disconnect_controller, mock_get_controller,
1043 ):
1044 mock_get_controller.return_value = juju.controller.Controller()
1045 mock_list_offers.return_value = []
1046 offers = self.loop.run_until_complete(self.libjuju.list_offers("model"))
1047 self.assertEqual(offers, [])
1048 mock_disconnect_controller.assert_called_once()
1049
1050 def test_non_empty_list(
1051 self, mock_list_offers, mock_disconnect_controller, mock_get_controller,
1052 ):
1053 mock_get_controller.return_value = juju.controller.Controller()
1054 mock_list_offers.return_value = ["offer"]
1055 offers = self.loop.run_until_complete(self.libjuju.list_offers("model"))
1056 self.assertEqual(offers, ["offer"])
1057 mock_disconnect_controller.assert_called_once()
1058
1059
1060 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
1061 @asynctest.mock.patch("juju.controller.Controller.get_model")
1062 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
1063 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1064 @asynctest.mock.patch("juju.model.Model.consume")
1065 class ConsumeTest(LibjujuTestCase):
1066 def setUp(self):
1067 super(ConsumeTest, self).setUp()
1068
1069 def test_consume(
1070 self,
1071 mock_consume,
1072 mock_disconnect_controller,
1073 mock_disconnect_model,
1074 mock_get_model,
1075 mock_get_controller,
1076 ):
1077 mock_get_controller.return_value = juju.controller.Controller()
1078 mock_get_model.return_value = juju.model.Model()
1079
1080 self.loop.run_until_complete(self.libjuju.consume("offer_url", "model_name"))
1081 mock_consume.assert_called_once()
1082 mock_disconnect_model.assert_called_once()
1083 mock_disconnect_controller.assert_called_once()
1084
1085 def test_parsing_error_exception(
1086 self,
1087 mock_consume,
1088 mock_disconnect_controller,
1089 mock_disconnect_model,
1090 mock_get_model,
1091 mock_get_controller,
1092 ):
1093 mock_get_controller.return_value = juju.controller.Controller()
1094 mock_get_model.return_value = juju.model.Model()
1095 mock_consume.side_effect = juju.offerendpoints.ParseError("")
1096
1097 with self.assertRaises(juju.offerendpoints.ParseError):
1098 self.loop.run_until_complete(
1099 self.libjuju.consume("offer_url", "model_name")
1100 )
1101 mock_consume.assert_called_once()
1102 mock_disconnect_model.assert_called_once()
1103 mock_disconnect_controller.assert_called_once()
1104
1105 def test_juju_error_exception(
1106 self,
1107 mock_consume,
1108 mock_disconnect_controller,
1109 mock_disconnect_model,
1110 mock_get_model,
1111 mock_get_controller,
1112 ):
1113 mock_get_controller.return_value = juju.controller.Controller()
1114 mock_get_model.return_value = juju.model.Model()
1115 mock_consume.side_effect = juju.errors.JujuError("")
1116
1117 with self.assertRaises(juju.errors.JujuError):
1118 self.loop.run_until_complete(
1119 self.libjuju.consume("offer_url", "model_name")
1120 )
1121 mock_consume.assert_called_once()
1122 mock_disconnect_model.assert_called_once()
1123 mock_disconnect_controller.assert_called_once()
1124
1125 def test_juju_api_error_exception(
1126 self,
1127 mock_consume,
1128 mock_disconnect_controller,
1129 mock_disconnect_model,
1130 mock_get_model,
1131 mock_get_controller,
1132 ):
1133 mock_get_controller.return_value = juju.controller.Controller()
1134 mock_get_model.return_value = juju.model.Model()
1135 mock_consume.side_effect = juju.errors.JujuAPIError(
1136 {"error": "", "response": "", "request-id": ""}
1137 )
1138
1139 with self.assertRaises(juju.errors.JujuAPIError):
1140 self.loop.run_until_complete(
1141 self.libjuju.consume("offer_url", "model_name")
1142 )
1143 mock_consume.assert_called_once()
1144 mock_disconnect_model.assert_called_once()
1145 mock_disconnect_controller.assert_called_once()
1146
1147
1148 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_k8s_cloud_credential")
1149 @asynctest.mock.patch("n2vc.libjuju.Libjuju.add_cloud")
1150 class AddK8sTest(LibjujuTestCase):
1151 def setUp(self):
1152 super(AddK8sTest, self).setUp()
1153 self.configuration = kubernetes.client.configuration.Configuration()
1154
1155 def test_add_k8s(self, mock_add_cloud, mock_get_k8s_cloud_credential):
1156 self.loop.run_until_complete(
1157 self.libjuju.add_k8s("cloud", self.configuration, "storage_class")
1158 )
1159 mock_add_cloud.assert_called_once()
1160 mock_get_k8s_cloud_credential.assert_called_once()
1161
1162 def test_add_k8s_exception(self, mock_add_cloud, mock_get_k8s_cloud_credential):
1163 mock_add_cloud.side_effect = Exception()
1164 with self.assertRaises(Exception):
1165 self.loop.run_until_complete(
1166 self.libjuju.add_k8s("cloud", self.configuration, "storage_class")
1167 )
1168 mock_add_cloud.assert_called_once()
1169 mock_get_k8s_cloud_credential.assert_called_once()
1170
1171 def test_add_k8s_missing_name(self, mock_add_cloud, mock_get_k8s_cloud_credential):
1172 with self.assertRaises(Exception):
1173 self.loop.run_until_complete(
1174 self.libjuju.add_k8s("", self.configuration, "storage_class")
1175 )
1176 mock_add_cloud.assert_not_called()
1177
1178 def test_add_k8s_missing_storage_name(
1179 self, mock_add_cloud, mock_get_k8s_cloud_credential
1180 ):
1181 with self.assertRaises(Exception):
1182 self.loop.run_until_complete(
1183 self.libjuju.add_k8s("cloud", self.configuration, "")
1184 )
1185 mock_add_cloud.assert_not_called()
1186
1187 def test_add_k8s_missing_configuration_keys(
1188 self, mock_add_cloud, mock_get_k8s_cloud_credential
1189 ):
1190 with self.assertRaises(Exception):
1191 self.loop.run_until_complete(self.libjuju.add_k8s("cloud", None, ""))
1192 mock_add_cloud.assert_not_called()
1193
1194
1195 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
1196 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1197 @asynctest.mock.patch("juju.controller.Controller.add_cloud")
1198 @asynctest.mock.patch("juju.controller.Controller.add_credential")
1199 class AddCloudTest(LibjujuTestCase):
1200 def setUp(self):
1201 super(AddCloudTest, self).setUp()
1202 self.cloud = juju.client.client.Cloud()
1203 self.credential = juju.client.client.CloudCredential()
1204
1205 def test_add_cloud_with_credential(
1206 self,
1207 mock_add_credential,
1208 mock_add_cloud,
1209 mock_disconnect_controller,
1210 mock_get_controller,
1211 ):
1212 mock_get_controller.return_value = juju.controller.Controller()
1213
1214 cloud = self.loop.run_until_complete(
1215 self.libjuju.add_cloud("cloud", self.cloud, credential=self.credential)
1216 )
1217 self.assertEqual(cloud, self.cloud)
1218 mock_add_cloud.assert_called_once_with("cloud", self.cloud)
1219 mock_add_credential.assert_called_once_with(
1220 "cloud", credential=self.credential, cloud="cloud"
1221 )
1222 mock_disconnect_controller.assert_called_once()
1223
1224 def test_add_cloud_no_credential(
1225 self,
1226 mock_add_credential,
1227 mock_add_cloud,
1228 mock_disconnect_controller,
1229 mock_get_controller,
1230 ):
1231 mock_get_controller.return_value = juju.controller.Controller()
1232
1233 cloud = self.loop.run_until_complete(
1234 self.libjuju.add_cloud("cloud", self.cloud)
1235 )
1236 self.assertEqual(cloud, self.cloud)
1237 mock_add_cloud.assert_called_once_with("cloud", self.cloud)
1238 mock_add_credential.assert_not_called()
1239 mock_disconnect_controller.assert_called_once()
1240
1241 def test_add_cloud_exception(
1242 self,
1243 mock_add_credential,
1244 mock_add_cloud,
1245 mock_disconnect_controller,
1246 mock_get_controller,
1247 ):
1248 mock_get_controller.return_value = juju.controller.Controller()
1249 mock_add_cloud.side_effect = Exception()
1250 with self.assertRaises(Exception):
1251 self.loop.run_until_complete(
1252 self.libjuju.add_cloud("cloud", self.cloud, credential=self.credential)
1253 )
1254
1255 mock_add_cloud.assert_called_once_with("cloud", self.cloud)
1256 mock_add_credential.assert_not_called()
1257 mock_disconnect_controller.assert_called_once()
1258
1259 def test_add_credential_exception(
1260 self,
1261 mock_add_credential,
1262 mock_add_cloud,
1263 mock_disconnect_controller,
1264 mock_get_controller,
1265 ):
1266 mock_get_controller.return_value = juju.controller.Controller()
1267 mock_add_credential.side_effect = Exception()
1268 with self.assertRaises(Exception):
1269 self.loop.run_until_complete(
1270 self.libjuju.add_cloud("cloud", self.cloud, credential=self.credential)
1271 )
1272
1273 mock_add_cloud.assert_called_once_with("cloud", self.cloud)
1274 mock_add_credential.assert_called_once_with(
1275 "cloud", credential=self.credential, cloud="cloud"
1276 )
1277 mock_disconnect_controller.assert_called_once()
1278
1279
1280 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
1281 @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
1282 @asynctest.mock.patch("juju.controller.Controller.remove_cloud")
1283 class RemoveCloudTest(LibjujuTestCase):
1284 def setUp(self):
1285 super(RemoveCloudTest, self).setUp()
1286
1287 def test_remove_cloud(
1288 self, mock_remove_cloud, mock_disconnect_controller, mock_get_controller,
1289 ):
1290 mock_get_controller.return_value = juju.controller.Controller()
1291
1292 self.loop.run_until_complete(self.libjuju.remove_cloud("cloud"))
1293 mock_remove_cloud.assert_called_once_with("cloud")
1294 mock_disconnect_controller.assert_called_once()
1295
1296 def test_remove_cloud_exception(
1297 self, mock_remove_cloud, mock_disconnect_controller, mock_get_controller,
1298 ):
1299 mock_get_controller.return_value = juju.controller.Controller()
1300 mock_remove_cloud.side_effect = Exception()
1301
1302 with self.assertRaises(Exception):
1303 self.loop.run_until_complete(self.libjuju.remove_cloud("cloud"))
1304 mock_remove_cloud.assert_called_once_with("cloud")
1305 mock_disconnect_controller.assert_called_once()
1306
1307
1308 @asynctest.mock.patch("kubernetes.client.configuration.Configuration")
1309 class GetK8sCloudCredentials(LibjujuTestCase):
1310 def setUp(self):
1311 super(GetK8sCloudCredentials, self).setUp()
1312
1313 @asynctest.mock.patch("n2vc.exceptions.JujuInvalidK8sConfiguration")
1314 def test_not_supported(self, mock_exception, mock_configuration):
1315 mock_configuration.username = ""
1316 mock_configuration.password = ""
1317 mock_configuration.ssl_ca_cert = None
1318 mock_configuration.cert_file = None
1319 mock_configuration.key_file = None
1320 exception_raised = False
1321 try:
1322 _ = self.libjuju.get_k8s_cloud_credential(mock_configuration)
1323 except JujuInvalidK8sConfiguration as e:
1324 exception_raised = True
1325 self.assertEqual(
1326 e.message, "authentication method not supported",
1327 )
1328 self.assertTrue(exception_raised)
1329
1330 def test_user_pass(self, mock_configuration):
1331 mock_configuration.username = "admin"
1332 mock_configuration.password = "admin"
1333 mock_configuration.ssl_ca_cert = None
1334 mock_configuration.cert_file = None
1335 mock_configuration.key_file = None
1336 credential = self.libjuju.get_k8s_cloud_credential(mock_configuration)
1337 self.assertEqual(
1338 credential,
1339 juju.client._definitions.CloudCredential(
1340 attrs={"username": "admin", "password": "admin"}, auth_type="userpass"
1341 ),
1342 )
1343
1344 def test_user_no_pass(self, mock_configuration):
1345 mock_configuration.username = "admin"
1346 mock_configuration.password = ""
1347 mock_configuration.ssl_ca_cert = None
1348 mock_configuration.cert_file = None
1349 mock_configuration.key_file = None
1350 with mock.patch.object(self.libjuju.log, "debug") as mock_debug:
1351 credential = self.libjuju.get_k8s_cloud_credential(mock_configuration)
1352 self.assertEqual(
1353 credential,
1354 juju.client._definitions.CloudCredential(
1355 attrs={"username": "admin", "password": ""}, auth_type="userpass"
1356 ),
1357 )
1358 mock_debug.assert_called_once_with(
1359 "credential for user admin has empty password"
1360 )
1361
1362 def test_user_pass_with_cert(self, mock_configuration):
1363 mock_configuration.username = "admin"
1364 mock_configuration.password = "admin"
1365 ssl_ca_cert = tempfile.NamedTemporaryFile()
1366 with open(ssl_ca_cert.name, "w") as ssl_ca_cert_file:
1367 ssl_ca_cert_file.write("cacert")
1368 mock_configuration.ssl_ca_cert = ssl_ca_cert.name
1369 mock_configuration.cert_file = None
1370 mock_configuration.key_file = None
1371 credential = self.libjuju.get_k8s_cloud_credential(mock_configuration)
1372 self.assertEqual(
1373 credential,
1374 juju.client._definitions.CloudCredential(
1375 attrs={
1376 "username": "admin",
1377 "password": "admin",
1378 "ClientCertificateData": "cacert",
1379 },
1380 auth_type="userpasswithcert",
1381 ),
1382 )
1383
1384 def test_cert(self, mock_configuration):
1385 mock_configuration.username = ""
1386 mock_configuration.password = ""
1387 mock_configuration.api_key = {"authorization": "Bearer Token"}
1388 ssl_ca_cert = tempfile.NamedTemporaryFile()
1389 with open(ssl_ca_cert.name, "w") as ssl_ca_cert_file:
1390 ssl_ca_cert_file.write("cacert")
1391 mock_configuration.ssl_ca_cert = ssl_ca_cert.name
1392 mock_configuration.cert_file = None
1393 mock_configuration.key_file = None
1394 credential = self.libjuju.get_k8s_cloud_credential(mock_configuration)
1395 self.assertEqual(
1396 credential,
1397 juju.client._definitions.CloudCredential(
1398 attrs={"ClientCertificateData": "cacert", "Token": "Token"},
1399 auth_type="certificate",
1400 ),
1401 )
1402
1403 def test_oauth2(self, mock_configuration):
1404 mock_configuration.username = ""
1405 mock_configuration.password = ""
1406 mock_configuration.api_key = {"authorization": "Bearer Token"}
1407 key = tempfile.NamedTemporaryFile()
1408 with open(key.name, "w") as key_file:
1409 key_file.write("key")
1410 mock_configuration.ssl_ca_cert = None
1411 mock_configuration.cert_file = None
1412 mock_configuration.key_file = key.name
1413 credential = self.libjuju.get_k8s_cloud_credential(mock_configuration)
1414 self.assertEqual(
1415 credential,
1416 juju.client._definitions.CloudCredential(
1417 attrs={"ClientKeyData": "key", "Token": "Token"}, auth_type="oauth2",
1418 ),
1419 )
1420
1421 @asynctest.mock.patch("n2vc.exceptions.JujuInvalidK8sConfiguration")
1422 def test_oauth2_missing_token(self, mock_exception, mock_configuration):
1423 mock_configuration.username = ""
1424 mock_configuration.password = ""
1425 key = tempfile.NamedTemporaryFile()
1426 with open(key.name, "w") as key_file:
1427 key_file.write("key")
1428 mock_configuration.ssl_ca_cert = None
1429 mock_configuration.cert_file = None
1430 mock_configuration.key_file = key.name
1431 exception_raised = False
1432 try:
1433 _ = self.libjuju.get_k8s_cloud_credential(mock_configuration)
1434 except JujuInvalidK8sConfiguration as e:
1435 exception_raised = True
1436 self.assertEqual(
1437 e.message, "missing token for auth type oauth2",
1438 )
1439 self.assertTrue(exception_raised)
1440
1441 def test_unknown_api_key(self, mock_configuration):
1442 mock_configuration.username = ""
1443 mock_configuration.password = ""
1444 mock_configuration.api_key = {"authorization": "Bearer Token Wrong"}
1445 mock_configuration.ssl_ca_cert = None
1446 mock_configuration.cert_file = None
1447 mock_configuration.key_file = None
1448 exception_raised = False
1449 try:
1450 _ = self.libjuju.get_k8s_cloud_credential(mock_configuration)
1451 except JujuInvalidK8sConfiguration as e:
1452 exception_raised = True
1453 self.assertEqual(
1454 e.message, "unknown format of api_key",
1455 )
1456 self.assertTrue(exception_raised)
1457
1458 def test_exception_cannot_set_token_and_userpass(self, mock_configuration):
1459 mock_configuration.username = "admin"
1460 mock_configuration.password = "pass"
1461 mock_configuration.api_key = {"authorization": "No_bearer_token"}
1462 mock_configuration.ssl_ca_cert = None
1463 mock_configuration.cert_file = None
1464 mock_configuration.key_file = None
1465 exception_raised = False
1466 try:
1467 _ = self.libjuju.get_k8s_cloud_credential(mock_configuration)
1468 except JujuInvalidK8sConfiguration as e:
1469 exception_raised = True
1470 self.assertEqual(
1471 e.message, "Cannot set both token and user/pass",
1472 )
1473 self.assertTrue(exception_raised)