From 4ab954c482f704ac8b7291bc80c3f362f3c13388 Mon Sep 17 00:00:00 2001 From: Dario Faccin Date: Fri, 16 Jun 2023 10:21:38 +0200 Subject: [PATCH] Remove EE Charms when VNF has only day-1 operations Add paramter in EE deletion method to allow deletion of a single application instead of the whole model Change-Id: I4d1ebdd0c44c21a01c4d1e0e1f10b63ac983d787 Signed-off-by: Dario Faccin --- n2vc/n2vc_juju_conn.py | 31 +++++++++++-- n2vc/tests/unit/test_n2vc_juju_conn.py | 63 ++++++++++++++++++++++++++ 2 files changed, 89 insertions(+), 5 deletions(-) diff --git a/n2vc/n2vc_juju_conn.py b/n2vc/n2vc_juju_conn.py index 9d0cdfa..f28a9bd 100644 --- a/n2vc/n2vc_juju_conn.py +++ b/n2vc/n2vc_juju_conn.py @@ -836,6 +836,7 @@ class N2VCJujuConnector(N2VCConnector): scaling_in: bool = False, vca_type: str = None, vca_id: str = None, + application_to_delete: str = None, ): """ Delete an execution environment @@ -845,10 +846,11 @@ class N2VCJujuConnector(N2VCConnector): {collection: , filter: {}, path: }, e.g. {collection: "nsrs", filter: {_id: , path: "_admin.deployed.VCA.3"} - :param: total_timeout: Total timeout - :param: scaling_in: Boolean to indicate if it is a scaling in operation - :param: vca_type: VCA type - :param: vca_id: VCA ID + :param total_timeout: Total timeout + :param scaling_in: Boolean to indicate if it is a scaling in operation + :param vca_type: VCA type + :param vca_id: VCA ID + :param application_to_delete: name of the single application to be deleted """ self.log.info("Deleting execution environment ee_id={}".format(ee_id)) libjuju = await self._get_libjuju(vca_id) @@ -863,7 +865,26 @@ class N2VCJujuConnector(N2VCConnector): ee_id=ee_id ) try: - if not scaling_in: + if application_to_delete == application_name: + # destroy the application + await libjuju.destroy_application( + model_name=model_name, + application_name=application_name, + total_timeout=total_timeout, + ) + # if model is empty delete it + controller = await libjuju.get_controller() + model = await libjuju.get_model( + controller=controller, + model_name=model_name, + ) + if not model.applications: + self.log.info("Model {} is empty, deleting it".format(model_name)) + await libjuju.destroy_model( + model_name=model_name, + total_timeout=total_timeout, + ) + elif not scaling_in: # destroy the model await libjuju.destroy_model( model_name=model_name, total_timeout=total_timeout diff --git a/n2vc/tests/unit/test_n2vc_juju_conn.py b/n2vc/tests/unit/test_n2vc_juju_conn.py index 456ec1e..2ce5024 100644 --- a/n2vc/tests/unit/test_n2vc_juju_conn.py +++ b/n2vc/tests/unit/test_n2vc_juju_conn.py @@ -1430,3 +1430,66 @@ class GenerateApplicationNameTest(N2VCJujuConnTestCase): self.assertLess(len(application_name), 50) mock_vnf_count_and_record.assert_called_once_with("ns-level", None) self.db.get_one.assert_called_once() + + +class DeleteExecutionEnvironmentTest(N2VCJujuConnTestCase): + def setUp(self): + super(DeleteExecutionEnvironmentTest, self).setUp() + self.n2vc.libjuju.get_controller = AsyncMock() + self.n2vc.libjuju.destroy_model = AsyncMock() + self.n2vc.libjuju.destroy_application = AsyncMock() + + def test_remove_ee__target_application_exists__model_is_deleted(self): + get_ee_id_components = MagicMock() + get_ee_id_components.return_value = ("my_model", "my_app", None) + model = MagicMock(create_autospec=True) + model.applications = {} + self.n2vc.libjuju.get_model = AsyncMock() + self.n2vc.libjuju.get_model.return_value = model + with patch.object(self.n2vc, "_get_ee_id_components", get_ee_id_components): + self.loop.run_until_complete( + self.n2vc.delete_execution_environment( + "my_ee", application_to_delete="my_app" + ) + ) + self.n2vc.libjuju.destroy_application.assert_called_with( + model_name="my_model", + application_name="my_app", + total_timeout=None, + ) + self.n2vc.libjuju.destroy_model.assert_called_with( + model_name="my_model", + total_timeout=None, + ) + + def test_remove_ee__multiple_applications_exist__model_is_not_deleted(self): + get_ee_id_components = MagicMock() + get_ee_id_components.return_value = ("my_model", "my_app", None) + model = MagicMock(create_autospec=True) + model.applications = {MagicMock(create_autospec=True)} + self.n2vc.libjuju.get_model = AsyncMock() + self.n2vc.libjuju.get_model.return_value = model + with patch.object(self.n2vc, "_get_ee_id_components", get_ee_id_components): + self.loop.run_until_complete( + self.n2vc.delete_execution_environment( + "my_ee", application_to_delete="my_app" + ) + ) + self.n2vc.libjuju.destroy_application.assert_called_with( + model_name="my_model", + application_name="my_app", + total_timeout=None, + ) + self.n2vc.libjuju.destroy_model.assert_not_called() + + def test_remove_ee__target_application_does_not_exist__model_is_deleted(self): + get_ee_id_components = MagicMock() + get_ee_id_components.return_value = ("my_model", "my_app", None) + with patch.object(self.n2vc, "_get_ee_id_components", get_ee_id_components): + self.loop.run_until_complete( + self.n2vc.delete_execution_environment("my_ee") + ) + self.n2vc.libjuju.destroy_model.assert_called_with( + model_name="my_model", + total_timeout=None, + ) -- 2.17.1