From: Dario Faccin Date: Mon, 10 Jul 2023 07:57:37 +0000 (+0200) Subject: OSMENG-1090 OSMENG-1091: Remove model and check model is removed X-Git-Url: https://osm.etsi.org/gitweb/?a=commitdiff_plain;h=b012fe0fac605b8810003dc3d70a3f579c843349;p=osm%2FLCM.git OSMENG-1090 OSMENG-1091: Remove model and check model is removed Change-Id: Id106d8cfe7e4847712b5da79b1c56e72a673fe8e Signed-off-by: Dario Faccin Signed-off-by: Mark Beierl --- diff --git a/osm_lcm/temporal/juju_paas_activities.py b/osm_lcm/temporal/juju_paas_activities.py index 7714470..e770b6e 100644 --- a/osm_lcm/temporal/juju_paas_activities.py +++ b/osm_lcm/temporal/juju_paas_activities.py @@ -26,9 +26,11 @@ from osm_common.temporal.activities.paas import ( TestVimConnectivity, CheckCharmStatus, CheckCharmIsRemoved, + CheckModelIsRemoved, CreateModel, DeployCharm, RemoveCharm, + RemoveModel, ResolveCharmErrors, ) from osm_common.temporal.dataclasses_common import ( @@ -308,6 +310,34 @@ class CheckCharmIsRemovedImpl(CheckCharmIsRemoved): await asyncio.sleep(activity_input.poll_interval) +@activity.defn(name=RemoveModel.__name__) +class RemoveModelImpl(RemoveModel): + async def __call__(self, activity_input: RemoveModel.Input) -> None: + model_name = activity_input.model_name + controller: Controller = await self.juju_controller._get_controller( + activity_input.vim_uuid + ) + if model_name not in (await controller.list_models()): + return + await controller.destroy_models( + model_name, + destroy_storage=True, + force=activity_input.force_remove, + ) + + +@activity.defn(name=CheckModelIsRemoved.__name__) +class CheckModelIsRemovedImpl(CheckModelIsRemoved): + async def __call__(self, activity_input: CheckModelIsRemoved.Input) -> None: + model_name = activity_input.model_name + controller: Controller = await self.juju_controller._get_controller( + activity_input.vim_uuid + ) + while model_name in (await controller.list_models()): + activity.heartbeat() + await asyncio.sleep(activity_input.poll_interval) + + @activity.defn(name=ResolveCharmErrors.__name__) class ResolveCharmErrorsImpl(ResolveCharmErrors): async def __call__(self, activity_input: ResolveCharmErrors.Input) -> None: diff --git a/osm_lcm/tests/test_juju_paas_activities.py b/osm_lcm/tests/test_juju_paas_activities.py index 1381c33..7d5e997 100644 --- a/osm_lcm/tests/test_juju_paas_activities.py +++ b/osm_lcm/tests/test_juju_paas_activities.py @@ -31,7 +31,9 @@ from osm_lcm.temporal.juju_paas_activities import ( CreateModelImpl, CheckCharmStatusImpl, CheckCharmIsRemovedImpl, + CheckModelIsRemovedImpl, RemoveCharmImpl, + RemoveModelImpl, ResolveCharmErrorsImpl, ) from osm_common.temporal.workflows.vdu import VduInstantiateWorkflow @@ -580,6 +582,93 @@ class TestCheckCharmIsRemoved(TestJujuPaasActivitiesBase): self.controller.get_model.assert_not_called() +class TestRemoveModel(TestJujuPaasActivitiesBase): + def setUp(self) -> None: + super().setUp() + self.remove_model = RemoveModelImpl(self.juju_paas) + + @parameterized.expand([False, True]) + async def test_remove_model__nominal_case(self, is_forced): + remove_model_input = RemoveModelImpl.Input( + vim_uuid=vim_content["_id"], + model_name=namespace, + force_remove=is_forced, + ) + self.controller.list_models.return_value = [namespace] + await self.env.run( + self.remove_model, + remove_model_input, + ) + self.controller.destroy_models.assert_called_once_with( + namespace, + destroy_storage=True, + force=is_forced, + ) + + async def test_remove_model__model_does_not_exist(self): + remove_model_input = RemoveModelImpl.Input( + vim_uuid=vim_content["_id"], + model_name="not-existing-model", + force_remove=False, + ) + self.controller.list_models.return_value = [namespace] + await self.env.run( + self.remove_model, + remove_model_input, + ) + self.controller.destroy_models.assert_not_called() + + async def test_remove_model__juju_error_occurred__model_is_not_removed(self): + remove_model_input = RemoveModelImpl.Input( + vim_uuid=vim_content["_id"], + model_name=namespace, + force_remove=False, + ) + self.controller.list_models.side_effect = JujuError() + with self.assertRaises(JujuError): + await self.env.run( + self.remove_model, + remove_model_input, + ) + self.controller.destroy_models.assert_not_called() + + +class TestCheckModelIsRemoved(TestJujuPaasActivitiesBase): + def setUp(self) -> None: + super().setUp() + self.env.on_heartbeat = self.on_heartbeat + self.heartbeat_count = 0 + self.heartbeat_maximum = 5 + self.check_model_is_removed = CheckModelIsRemovedImpl(self.juju_paas) + + def on_heartbeat(self, *args, **kwargs): + self.heartbeat_count += 1 + if self.heartbeat_count > self.heartbeat_maximum: + self.env.cancel() + + async def test_check_is_model_removed__nominal_case(self): + arg = CheckModelIsRemovedImpl.Input( + model_name=namespace, + vim_uuid="vim-uuid", + poll_interval=0, + ) + self.controller.list_models.return_value = [] + + await self.env.run(self.check_model_is_removed.__call__, arg) + + async def test_check_is_model_removed__cancel(self): + arg = CheckModelIsRemovedImpl.Input( + model_name=namespace, + vim_uuid="vim-uuid", + poll_interval=0, + ) + + self.controller.list_models.return_value = [namespace] + + with self.assertRaises(asyncio.exceptions.CancelledError): + await self.env.run(self.check_model_is_removed.__call__, arg) + + class TestResolveCharmErrors(TestJujuPaasActivitiesBase): app_name = "my_app_name"