X-Git-Url: https://osm.etsi.org/gitweb/?p=osm%2FN2VC.git;a=blobdiff_plain;f=n2vc%2Ftests%2Funit%2Ftest_libjuju.py;h=9ab6ddba45e7f2dac2d743964fb884b249e0548f;hp=454b87f7288a1d3d57e6af788429ba070bdc8a9f;hb=b0a8f409e149715bf37d30c414474888c8a499f3;hpb=667696ef11356f3267df58f2a81c6ecebb0e94b9 diff --git a/n2vc/tests/unit/test_libjuju.py b/n2vc/tests/unit/test_libjuju.py index 454b87f..9ab6ddb 100644 --- a/n2vc/tests/unit/test_libjuju.py +++ b/n2vc/tests/unit/test_libjuju.py @@ -24,7 +24,6 @@ from .utils import FakeN2VC, FakeMachine, FakeApplication from n2vc.libjuju import Libjuju from n2vc.exceptions import ( JujuControllerFailedConnecting, - JujuModelAlreadyExists, JujuMachineNotFound, JujuApplicationNotFound, JujuActionNotFound, @@ -32,6 +31,7 @@ from n2vc.exceptions import ( JujuInvalidK8sConfiguration, JujuLeaderUnitNotFound, ) +from n2vc.k8s_juju_conn import generate_rbac_id class LibjujuTestCase(asynctest.TestCase): @@ -237,10 +237,10 @@ class AddModelTest(LibjujuTestCase): ): mock_model_exists.return_value = True - with self.assertRaises(JujuModelAlreadyExists): - self.loop.run_until_complete( - self.libjuju.add_model("existing_model", "cloud") - ) + # This should not raise an exception + self.loop.run_until_complete( + self.libjuju.add_model("existing_model", "cloud") + ) mock_disconnect_controller.assert_called() @@ -272,7 +272,8 @@ class GetModelTest(LibjujuTestCase): super(GetModelTest, self).setUp() def test_get_model( - self, mock_get_model, + self, + mock_get_model, ): mock_get_model.return_value = juju.model.Model() model = self.loop.run_until_complete( @@ -288,7 +289,9 @@ class ModelExistsTest(LibjujuTestCase): super(ModelExistsTest, self).setUp() async def test_existing_model( - self, mock_list_models, mock_get_controller, + self, + mock_list_models, + mock_get_controller, ): mock_list_models.return_value = ["existing_model"] self.assertTrue( @@ -299,7 +302,10 @@ class ModelExistsTest(LibjujuTestCase): @asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller") async def test_no_controller( - self, mock_disconnect_controller, mock_list_models, mock_get_controller, + self, + mock_disconnect_controller, + mock_list_models, + mock_get_controller, ): mock_list_models.return_value = ["existing_model"] mock_get_controller.return_value = juju.controller.Controller() @@ -307,7 +313,9 @@ class ModelExistsTest(LibjujuTestCase): mock_disconnect_controller.assert_called_once() async def test_non_existing_model( - self, mock_list_models, mock_get_controller, + self, + mock_list_models, + mock_get_controller, ): mock_list_models.return_value = ["existing_model"] self.assertFalse( @@ -551,7 +559,12 @@ class DeployCharmTest(LibjujuTestCase): application = None with self.assertRaises(JujuApplicationExists): application = self.loop.run_until_complete( - self.libjuju.deploy_charm("existing_app", "path", "model", "machine",) + self.libjuju.deploy_charm( + "existing_app", + "path", + "model", + "machine", + ) ) self.assertIsNone(application) @@ -575,7 +588,12 @@ class DeployCharmTest(LibjujuTestCase): application = None with self.assertRaises(JujuMachineNotFound): application = self.loop.run_until_complete( - self.libjuju.deploy_charm("app", "path", "model", "machine",) + self.libjuju.deploy_charm( + "app", + "path", + "model", + "machine", + ) ) self.assertIsNone(application) @@ -601,7 +619,11 @@ class DeployCharmTest(LibjujuTestCase): mock_deploy.return_value = FakeApplication() application = self.loop.run_until_complete( self.libjuju.deploy_charm( - "app", "path", "model", "existing_machine", num_units=2, + "app", + "path", + "model", + "existing_machine", + num_units=2, ) ) @@ -651,7 +673,8 @@ class GetApplicationTest(LibjujuTestCase): super(GetApplicationTest, self).setUp() def test_existing_application( - self, mock_applications, + self, + mock_applications, ): mock_applications.return_value = {"existing_app": "exists"} model = juju.model.Model() @@ -659,7 +682,8 @@ class GetApplicationTest(LibjujuTestCase): self.assertEqual(result, "exists") def test_non_existing_application( - self, mock_applications, + self, + mock_applications, ): mock_applications.return_value = {"existing_app": "exists"} model = juju.model.Model() @@ -696,7 +720,11 @@ class ExecuteActionTest(LibjujuTestCase): status = None with self.assertRaises(JujuApplicationNotFound): output, status = self.loop.run_until_complete( - self.libjuju.execute_action("app", "model", "action",) + self.libjuju.execute_action( + "app", + "model", + "action", + ) ) self.assertIsNone(output) self.assertIsNone(status) @@ -722,7 +750,11 @@ class ExecuteActionTest(LibjujuTestCase): status = None with self.assertRaises(JujuActionNotFound): output, status = self.loop.run_until_complete( - self.libjuju.execute_action("app", "model", "action",) + self.libjuju.execute_action( + "app", + "model", + "action", + ) ) self.assertIsNone(output) self.assertIsNone(status) @@ -752,7 +784,11 @@ class ExecuteActionTest(LibjujuTestCase): status = None with self.assertRaises(JujuLeaderUnitNotFound): output, status = self.loop.run_until_complete( - self.libjuju.execute_action("app", "model", "action",) + self.libjuju.execute_action( + "app", + "model", + "action", + ) ) self.assertIsNone(output) self.assertIsNone(status) @@ -925,7 +961,11 @@ class AddRelationTest(LibjujuTestCase): mock_add_relation.side_effect = JujuAPIError(result) self.loop.run_until_complete( - self.libjuju.add_relation("model", "app1:relation1", "app2:relation2",) + self.libjuju.add_relation( + "model", + "app1:relation1", + "app2:relation2", + ) ) mock_warning.assert_called_with("Relation not found: not found") @@ -949,7 +989,11 @@ class AddRelationTest(LibjujuTestCase): mock_add_relation.side_effect = JujuAPIError(result) self.loop.run_until_complete( - self.libjuju.add_relation("model", "app1:relation1", "app2:relation2",) + self.libjuju.add_relation( + "model", + "app1:relation1", + "app2:relation2", + ) ) mock_warning.assert_called_with("Relation already exists: already exists") @@ -970,7 +1014,11 @@ class AddRelationTest(LibjujuTestCase): with self.assertRaises(JujuAPIError): self.loop.run_until_complete( - self.libjuju.add_relation("model", "app1:relation1", "app2:relation2",) + self.libjuju.add_relation( + "model", + "app1:relation1", + "app2:relation2", + ) ) mock_disconnect_controller.assert_called_once() @@ -987,7 +1035,11 @@ class AddRelationTest(LibjujuTestCase): mock_get_model.return_value = juju.model.Model() self.loop.run_until_complete( - self.libjuju.add_relation("model", "app1:relation1", "app2:relation2",) + self.libjuju.add_relation( + "model", + "app1:relation1", + "app2:relation2", + ) ) mock_add_relation.assert_called_with("app1:relation1", "app2:relation2") @@ -1005,7 +1057,11 @@ class AddRelationTest(LibjujuTestCase): mock_get_model.return_value = juju.model.Model() self.loop.run_until_complete( - self.libjuju.add_relation("model", "app1:relation1", "saas_name",) + self.libjuju.add_relation( + "model", + "app1:relation1", + "saas_name", + ) ) mock_add_relation.assert_called_with("app1:relation1", "saas_name") @@ -1070,7 +1126,11 @@ class ConfigureApplicationTest(LibjujuTestCase): mock_get_application.return_value = FakeApplication() self.loop.run_until_complete( - self.libjuju.configure_application("model", "app", {"config"},) + self.libjuju.configure_application( + "model", + "app", + {"config"}, + ) ) mock_get_application.assert_called_once() mock_disconnect_controller.assert_called_once() @@ -1089,11 +1149,64 @@ class ConfigureApplicationTest(LibjujuTestCase): with self.assertRaises(Exception): self.loop.run_until_complete( - self.libjuju.configure_application("model", "app", {"config"},) + self.libjuju.configure_application( + "model", + "app", + {"config"}, + ) ) mock_disconnect_controller.assert_called_once() mock_disconnect_model.assert_called_once() + def test_controller_exception( + self, + mock_get_application, + mock_disconnect_controller, + mock_disconnect_model, + mock_get_model, + mock_get_controller, + ): + + result = {"error": "not found", "response": "response", "request-id": 1} + + mock_get_controller.side_effect = JujuAPIError(result) + + with self.assertRaises(JujuAPIError): + self.loop.run_until_complete( + self.libjuju.configure_application( + "model", + "app", + {"config"}, + ) + ) + mock_get_model.assert_not_called() + mock_disconnect_controller.assert_not_called() + mock_disconnect_model.assert_not_called() + + def test_get_model_exception( + self, + mock_get_application, + mock_disconnect_controller, + mock_disconnect_model, + mock_get_model, + mock_get_controller, + ): + + result = {"error": "not found", "response": "response", "request-id": 1} + mock_get_model.side_effect = JujuAPIError(result) + + with self.assertRaises(JujuAPIError): + self.loop.run_until_complete( + self.libjuju.configure_application( + "model", + "app", + {"config"}, + ) + ) + mock_get_model.assert_called_once() + mock_disconnect_controller.assert_called_once() + mock_disconnect_model.assert_not_called() + # TODO _get_api_endpoints_db test case # TODO _update_api_endpoints_db test case @@ -1108,7 +1221,10 @@ class ListModelsTest(LibjujuTestCase): super(ListModelsTest, self).setUp() def test_containing( - self, mock_list_models, mock_disconnect_controller, mock_get_controller, + self, + mock_list_models, + mock_disconnect_controller, + mock_get_controller, ): mock_get_controller.return_value = juju.controller.Controller() mock_list_models.return_value = ["existingmodel"] @@ -1118,7 +1234,10 @@ class ListModelsTest(LibjujuTestCase): self.assertEquals(models, ["existingmodel"]) def test_not_containing( - self, mock_list_models, mock_disconnect_controller, mock_get_controller, + self, + mock_list_models, + mock_disconnect_controller, + mock_get_controller, ): mock_get_controller.return_value = juju.controller.Controller() mock_list_models.return_value = ["existingmodel", "model"] @@ -1128,7 +1247,10 @@ class ListModelsTest(LibjujuTestCase): self.assertEquals(models, []) def test_no_contains_arg( - self, mock_list_models, mock_disconnect_controller, mock_get_controller, + self, + mock_list_models, + mock_disconnect_controller, + mock_get_controller, ): mock_get_controller.return_value = juju.controller.Controller() mock_list_models.return_value = ["existingmodel", "model"] @@ -1180,7 +1302,10 @@ class ListOffers(LibjujuTestCase): super(ListOffers, self).setUp() def test_disconnect_controller( - self, mock_list_offers, mock_disconnect_controller, mock_get_controller, + self, + mock_list_offers, + mock_disconnect_controller, + mock_get_controller, ): mock_get_controller.return_value = juju.controller.Controller() mock_list_offers.side_effect = Exception() @@ -1189,7 +1314,10 @@ class ListOffers(LibjujuTestCase): mock_disconnect_controller.assert_called_once() def test_empty_list( - self, mock_list_offers, mock_disconnect_controller, mock_get_controller, + self, + mock_list_offers, + mock_disconnect_controller, + mock_get_controller, ): mock_get_controller.return_value = juju.controller.Controller() mock_list_offers.return_value = [] @@ -1198,7 +1326,10 @@ class ListOffers(LibjujuTestCase): mock_disconnect_controller.assert_called_once() def test_non_empty_list( - self, mock_list_offers, mock_disconnect_controller, mock_get_controller, + self, + mock_list_offers, + mock_disconnect_controller, + mock_get_controller, ): mock_get_controller.return_value = juju.controller.Controller() mock_list_offers.return_value = ["offer"] @@ -1300,45 +1431,56 @@ class ConsumeTest(LibjujuTestCase): class AddK8sTest(LibjujuTestCase): def setUp(self): super(AddK8sTest, self).setUp() - self.configuration = kubernetes.client.configuration.Configuration() + name = "cloud" + rbac_id = generate_rbac_id() + token = "token" + client_cert_data = "cert" + configuration = kubernetes.client.configuration.Configuration() + storage_class = "storage_class" + credential_name = name + + self._add_k8s_args = { + "name": name, + "rbac_id": rbac_id, + "token": token, + "client_cert_data": client_cert_data, + "configuration": configuration, + "storage_class": storage_class, + "credential_name": credential_name, + } def test_add_k8s(self, mock_add_cloud, mock_get_k8s_cloud_credential): - self.loop.run_until_complete( - self.libjuju.add_k8s("cloud", self.configuration, "storage_class") - ) + self.loop.run_until_complete(self.libjuju.add_k8s(**self._add_k8s_args)) mock_add_cloud.assert_called_once() mock_get_k8s_cloud_credential.assert_called_once() def test_add_k8s_exception(self, mock_add_cloud, mock_get_k8s_cloud_credential): mock_add_cloud.side_effect = Exception() with self.assertRaises(Exception): - self.loop.run_until_complete( - self.libjuju.add_k8s("cloud", self.configuration, "storage_class") - ) + self.loop.run_until_complete(self.libjuju.add_k8s(**self._add_k8s_args)) mock_add_cloud.assert_called_once() mock_get_k8s_cloud_credential.assert_called_once() def test_add_k8s_missing_name(self, mock_add_cloud, mock_get_k8s_cloud_credential): + self._add_k8s_args["name"] = "" with self.assertRaises(Exception): - self.loop.run_until_complete( - self.libjuju.add_k8s("", self.configuration, "storage_class") - ) + self.loop.run_until_complete(self.libjuju.add_k8s(**self._add_k8s_args)) mock_add_cloud.assert_not_called() def test_add_k8s_missing_storage_name( self, mock_add_cloud, mock_get_k8s_cloud_credential ): + self._add_k8s_args["storage_class"] = "" with self.assertRaises(Exception): - self.loop.run_until_complete( - self.libjuju.add_k8s("cloud", self.configuration, "") - ) + self.loop.run_until_complete(self.libjuju.add_k8s(**self._add_k8s_args)) mock_add_cloud.assert_not_called() def test_add_k8s_missing_configuration_keys( self, mock_add_cloud, mock_get_k8s_cloud_credential ): + self._add_k8s_args["configuration"] = None with self.assertRaises(Exception): - self.loop.run_until_complete(self.libjuju.add_k8s("cloud", None, "")) + self.loop.run_until_complete(self.libjuju.add_k8s(**self._add_k8s_args)) mock_add_cloud.assert_not_called() @@ -1435,7 +1577,10 @@ class RemoveCloudTest(LibjujuTestCase): super(RemoveCloudTest, self).setUp() def test_remove_cloud( - self, mock_remove_cloud, mock_disconnect_controller, mock_get_controller, + self, + mock_remove_cloud, + mock_disconnect_controller, + mock_get_controller, ): mock_get_controller.return_value = juju.controller.Controller() @@ -1444,7 +1589,10 @@ class RemoveCloudTest(LibjujuTestCase): mock_disconnect_controller.assert_called_once() def test_remove_cloud_exception( - self, mock_remove_cloud, mock_disconnect_controller, mock_get_controller, + self, + mock_remove_cloud, + mock_disconnect_controller, + mock_get_controller, ): mock_get_controller.return_value = juju.controller.Controller() mock_remove_cloud.side_effect = Exception() @@ -1459,6 +1607,8 @@ class RemoveCloudTest(LibjujuTestCase): class GetK8sCloudCredentials(LibjujuTestCase): def setUp(self): super(GetK8sCloudCredentials, self).setUp() + self.cert_data = "cert" + self.token = "token" @asynctest.mock.patch("n2vc.exceptions.JujuInvalidK8sConfiguration") def test_not_supported(self, mock_exception, mock_configuration): @@ -1468,12 +1618,19 @@ class GetK8sCloudCredentials(LibjujuTestCase): mock_configuration.cert_file = None mock_configuration.key_file = None exception_raised = False + self.token = None + self.cert_data = None try: - _ = self.libjuju.get_k8s_cloud_credential(mock_configuration) + _ = self.libjuju.get_k8s_cloud_credential( + mock_configuration, + self.cert_data, + self.token, + ) except JujuInvalidK8sConfiguration as e: exception_raised = True self.assertEqual( - e.message, "authentication method not supported", + e.message, + "authentication method not supported", ) self.assertTrue(exception_raised) @@ -1483,7 +1640,13 @@ class GetK8sCloudCredentials(LibjujuTestCase): mock_configuration.ssl_ca_cert = None mock_configuration.cert_file = None mock_configuration.key_file = None - credential = self.libjuju.get_k8s_cloud_credential(mock_configuration) + self.token = None + self.cert_data = None + credential = self.libjuju.get_k8s_cloud_credential( + mock_configuration, + self.cert_data, + self.token, + ) self.assertEqual( credential, juju.client._definitions.CloudCredential( @@ -1491,14 +1654,44 @@ class GetK8sCloudCredentials(LibjujuTestCase): ), ) + def test_user_pass_with_cert(self, mock_configuration): + mock_configuration.username = "admin" + mock_configuration.password = "admin" + mock_configuration.ssl_ca_cert = None + mock_configuration.cert_file = None + mock_configuration.key_file = None + self.token = None + credential = self.libjuju.get_k8s_cloud_credential( + mock_configuration, + self.cert_data, + self.token, + ) + self.assertEqual( + credential, + juju.client._definitions.CloudCredential( + attrs={ + "ClientCertificateData": self.cert_data, + "username": "admin", + "password": "admin", + }, + auth_type="userpasswithcert", + ), + ) + def test_user_no_pass(self, mock_configuration): mock_configuration.username = "admin" mock_configuration.password = "" mock_configuration.ssl_ca_cert = None mock_configuration.cert_file = None mock_configuration.key_file = None + self.token = None + self.cert_data = None with mock.patch.object(self.libjuju.log, "debug") as mock_debug: - credential = self.libjuju.get_k8s_cloud_credential(mock_configuration) + credential = self.libjuju.get_k8s_cloud_credential( + mock_configuration, + self.cert_data, + self.token, + ) self.assertEqual( credential, juju.client._definitions.CloudCredential( @@ -1509,28 +1702,6 @@ class GetK8sCloudCredentials(LibjujuTestCase): "credential for user admin has empty password" ) - def test_user_pass_with_cert(self, mock_configuration): - mock_configuration.username = "admin" - mock_configuration.password = "admin" - ssl_ca_cert = tempfile.NamedTemporaryFile() - with open(ssl_ca_cert.name, "w") as ssl_ca_cert_file: - ssl_ca_cert_file.write("cacert") - mock_configuration.ssl_ca_cert = ssl_ca_cert.name - mock_configuration.cert_file = None - mock_configuration.key_file = None - credential = self.libjuju.get_k8s_cloud_credential(mock_configuration) - self.assertEqual( - credential, - juju.client._definitions.CloudCredential( - attrs={ - "username": "admin", - "password": "admin", - "ClientCertificateData": "cacert", - }, - auth_type="userpasswithcert", - ), - ) - def test_cert(self, mock_configuration): mock_configuration.username = "" mock_configuration.password = "" @@ -1541,69 +1712,67 @@ class GetK8sCloudCredentials(LibjujuTestCase): mock_configuration.ssl_ca_cert = ssl_ca_cert.name mock_configuration.cert_file = None mock_configuration.key_file = None - credential = self.libjuju.get_k8s_cloud_credential(mock_configuration) - self.assertEqual( - credential, - juju.client._definitions.CloudCredential( - attrs={"ClientCertificateData": "cacert", "Token": "Token"}, - auth_type="certificate", - ), + credential = self.libjuju.get_k8s_cloud_credential( + mock_configuration, + self.cert_data, + self.token, ) - - def test_oauth2(self, mock_configuration): - mock_configuration.username = "" - mock_configuration.password = "" - mock_configuration.api_key = {"authorization": "Bearer Token"} - key = tempfile.NamedTemporaryFile() - with open(key.name, "w") as key_file: - key_file.write("key") - mock_configuration.ssl_ca_cert = None - mock_configuration.cert_file = None - mock_configuration.key_file = key.name - credential = self.libjuju.get_k8s_cloud_credential(mock_configuration) self.assertEqual( credential, juju.client._definitions.CloudCredential( - attrs={"ClientKeyData": "key", "Token": "Token"}, auth_type="oauth2", + attrs={"ClientCertificateData": self.cert_data, "Token": self.token}, + auth_type="certificate", ), ) - @asynctest.mock.patch("n2vc.exceptions.JujuInvalidK8sConfiguration") - def test_oauth2_missing_token(self, mock_exception, mock_configuration): - mock_configuration.username = "" - mock_configuration.password = "" - key = tempfile.NamedTemporaryFile() - with open(key.name, "w") as key_file: - key_file.write("key") - mock_configuration.ssl_ca_cert = None - mock_configuration.cert_file = None - mock_configuration.key_file = key.name - exception_raised = False - try: - _ = self.libjuju.get_k8s_cloud_credential(mock_configuration) - except JujuInvalidK8sConfiguration as e: - exception_raised = True - self.assertEqual( - e.message, "missing token for auth type oauth2", - ) - self.assertTrue(exception_raised) - - def test_unknown_api_key(self, mock_configuration): - mock_configuration.username = "" - mock_configuration.password = "" - mock_configuration.api_key = {"authorization": "Bearer Token Wrong"} - mock_configuration.ssl_ca_cert = None - mock_configuration.cert_file = None - mock_configuration.key_file = None - exception_raised = False - try: - _ = self.libjuju.get_k8s_cloud_credential(mock_configuration) - except JujuInvalidK8sConfiguration as e: - exception_raised = True - self.assertEqual( - e.message, "unknown format of api_key", - ) - self.assertTrue(exception_raised) + # TODO: Fix this test when oauth authentication is supported + # def test_oauth2(self, mock_configuration): + # mock_configuration.username = "" + # mock_configuration.password = "" + # mock_configuration.api_key = {"authorization": "Bearer Token"} + # key = tempfile.NamedTemporaryFile() + # with open(key.name, "w") as key_file: + # key_file.write("key") + # mock_configuration.ssl_ca_cert = None + # mock_configuration.cert_file = None + # mock_configuration.key_file = key.name + # credential = self.libjuju.get_k8s_cloud_credential( + # mock_configuration, + # self.cert_data, + # self.token, + # ) + # self.assertEqual( + # credential, + # juju.client._definitions.CloudCredential( + # attrs={"ClientKeyData": "key", "Token": "Token"}, + # auth_type="oauth2", + # ), + # ) + + # @asynctest.mock.patch("n2vc.exceptions.JujuInvalidK8sConfiguration") + # def test_oauth2_missing_token(self, mock_exception, mock_configuration): + # mock_configuration.username = "" + # mock_configuration.password = "" + # key = tempfile.NamedTemporaryFile() + # with open(key.name, "w") as key_file: + # key_file.write("key") + # mock_configuration.ssl_ca_cert = None + # mock_configuration.cert_file = None + # mock_configuration.key_file = key.name + # exception_raised = False + # try: + # _ = self.libjuju.get_k8s_cloud_credential( + # mock_configuration, + # self.cert_data, + # self.token, + # ) + # except JujuInvalidK8sConfiguration as e: + # exception_raised = True + # self.assertEqual( + # e.message, + # "missing token for auth type oauth2", + # ) + # self.assertTrue(exception_raised) def test_exception_cannot_set_token_and_userpass(self, mock_configuration): mock_configuration.username = "admin" @@ -1614,10 +1783,15 @@ class GetK8sCloudCredentials(LibjujuTestCase): mock_configuration.key_file = None exception_raised = False try: - _ = self.libjuju.get_k8s_cloud_credential(mock_configuration) + _ = self.libjuju.get_k8s_cloud_credential( + mock_configuration, + self.cert_data, + self.token, + ) except JujuInvalidK8sConfiguration as e: exception_raised = True self.assertEqual( - e.message, "Cannot set both token and user/pass", + e.message, + "Cannot set both token and user/pass", ) self.assertTrue(exception_raised)