From 5ef42a14f766aa00a5917845ba1b3e04cc3c15f7 Mon Sep 17 00:00:00 2001 From: David Garcia Date: Tue, 29 Sep 2020 19:48:13 +0200 Subject: [PATCH] Fix bug 1216: Force model deletion Change-Id: I3f41eead305349eba5d404f5f3d61d33f0536aca Signed-off-by: David Garcia --- n2vc/libjuju.py | 88 +++++++++++++-------------------- n2vc/tests/unit/test_libjuju.py | 62 +++++++++++------------ n2vc/tests/unit/utils.py | 12 +++++ requirements.txt | 2 +- setup.py | 2 +- 5 files changed, 79 insertions(+), 87 deletions(-) diff --git a/n2vc/libjuju.py b/n2vc/libjuju.py index 28474a0..a457309 100644 --- a/n2vc/libjuju.py +++ b/n2vc/libjuju.py @@ -817,18 +817,6 @@ class Libjuju: self.log.debug("Destroying model {}".format(model_name)) uuid = model.info.uuid - # Destroy machines - machines = await model.get_machines() - for machine_id in machines: - try: - await self.destroy_machine( - model, machine_id=machine_id, total_timeout=total_timeout, - ) - except asyncio.CancelledError: - raise - except Exception: - pass - # Disconnect model await self.disconnect_model(model) @@ -836,32 +824,24 @@ class Libjuju: if model_name in self.models: self.models.remove(model_name) - await controller.destroy_model(uuid) + await controller.destroy_model(uuid, force=True, max_wait=0) # Wait until model is destroyed self.log.debug("Waiting for model {} to be destroyed...".format(model_name)) - last_exception = "" if total_timeout is None: total_timeout = 3600 end = time.time() + total_timeout while time.time() < end: - try: - models = await controller.list_models() - if model_name not in models: - self.log.debug( - "The model {} ({}) was destroyed".format(model_name, uuid) - ) - return - except asyncio.CancelledError: - raise - except Exception as e: - last_exception = e + models = await controller.list_models() + if model_name not in models: + self.log.debug( + "The model {} ({}) was destroyed".format(model_name, uuid) + ) + return await asyncio.sleep(5) raise Exception( - "Timeout waiting for model {} to be destroyed {}".format( - model_name, last_exception - ) + "Timeout waiting for model {} to be destroyed".format(model_name) ) finally: await self.disconnect_controller(controller) @@ -884,32 +864,32 @@ class Libjuju: else: self.log.warning("Application not found: {}".format(application_name)) - async def destroy_machine( - self, model: Model, machine_id: str, total_timeout: float = 3600 - ): - """ - Destroy machine - - :param: model: Model object - :param: machine_id: Machine id - :param: total_timeout: Timeout in seconds - """ - machines = await model.get_machines() - if machine_id in machines: - machine = machines[machine_id] - await machine.destroy(force=True) - # max timeout - end = time.time() + total_timeout - - # wait for machine removal - machines = await model.get_machines() - while machine_id in machines and time.time() < end: - self.log.debug("Waiting for machine {} is destroyed".format(machine_id)) - await asyncio.sleep(0.5) - machines = await model.get_machines() - self.log.debug("Machine destroyed: {}".format(machine_id)) - else: - self.log.debug("Machine not found: {}".format(machine_id)) + # async def destroy_machine( + # self, model: Model, machine_id: str, total_timeout: float = 3600 + # ): + # """ + # Destroy machine + + # :param: model: Model object + # :param: machine_id: Machine id + # :param: total_timeout: Timeout in seconds + # """ + # machines = await model.get_machines() + # if machine_id in machines: + # machine = machines[machine_id] + # await machine.destroy(force=True) + # # max timeout + # end = time.time() + total_timeout + + # # wait for machine removal + # machines = await model.get_machines() + # while machine_id in machines and time.time() < end: + # self.log.debug("Waiting for machine {} is destroyed".format(machine_id)) + # await asyncio.sleep(0.5) + # machines = await model.get_machines() + # self.log.debug("Machine destroyed: {}".format(machine_id)) + # else: + # self.log.debug("Machine not found: {}".format(machine_id)) async def configure_application( self, model_name: str, application_name: str, config: dict = None diff --git a/n2vc/tests/unit/test_libjuju.py b/n2vc/tests/unit/test_libjuju.py index 123da4a..a384e44 100644 --- a/n2vc/tests/unit/test_libjuju.py +++ b/n2vc/tests/unit/test_libjuju.py @@ -866,37 +866,37 @@ class AddRelationTest(LibjujuTestCase): # TODO destroy_model testcase -@asynctest.mock.patch("juju.model.Model.get_machines") -@asynctest.mock.patch("logging.Logger.debug") -class DestroyMachineTest(LibjujuTestCase): - def setUp(self): - super(DestroyMachineTest, self).setUp() - - def test_success( - self, mock_debug, mock_get_machines, - ): - mock_get_machines.side_effect = [ - {"machine": FakeMachine()}, - {"machine": FakeMachine()}, - {}, - ] - self.loop.run_until_complete( - self.libjuju.destroy_machine(juju.model.Model(), "machine", 2,) - ) - calls = [ - asynctest.call("Waiting for machine machine is destroyed"), - asynctest.call("Machine destroyed: machine"), - ] - mock_debug.assert_has_calls(calls) - - def test_no_machine( - self, mock_debug, mock_get_machines, - ): - mock_get_machines.return_value = {} - self.loop.run_until_complete( - self.libjuju.destroy_machine(juju.model.Model(), "machine", 2,) - ) - mock_debug.assert_called_with("Machine not found: machine") +# @asynctest.mock.patch("juju.model.Model.get_machines") +# @asynctest.mock.patch("logging.Logger.debug") +# class DestroyMachineTest(LibjujuTestCase): +# def setUp(self): +# super(DestroyMachineTest, self).setUp() + +# def test_success_manual_machine( +# self, mock_debug, mock_get_machines, +# ): +# mock_get_machines.side_effect = [ +# {"machine": FakeManualMachine()}, +# {"machine": FakeManualMachine()}, +# {}, +# ] +# self.loop.run_until_complete( +# self.libjuju.destroy_machine(juju.model.Model(), "machine", 2,) +# ) +# calls = [ +# asynctest.call("Waiting for machine machine is destroyed"), +# asynctest.call("Machine destroyed: machine"), +# ] +# mock_debug.assert_has_calls(calls) + +# def test_no_machine( +# self, mock_debug, mock_get_machines, +# ): +# mock_get_machines.return_value = {} +# self.loop.run_until_complete( +# self.libjuju.destroy_machine(juju.model.Model(), "machine", 2) +# ) +# mock_debug.assert_called_with("Machine not found: machine") @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller") diff --git a/n2vc/tests/unit/utils.py b/n2vc/tests/unit/utils.py index ee4dd96..d960c70 100644 --- a/n2vc/tests/unit/utils.py +++ b/n2vc/tests/unit/utils.py @@ -56,6 +56,18 @@ class FakeMachine(MagicMock): dns_name = "FAKE ENDPOINT" model_name = "FAKE MODEL" entity_type = "machine" + safe_data = {"instance-id": "myid"} + + async def destroy(self, force): + pass + + +class FakeManualMachine(MagicMock): + entity_id = "2" + dns_name = "FAKE ENDPOINT" + model_name = "FAKE MODEL" + entity_type = "machine" + safe_data = {"instance-id": "manual:myid"} async def destroy(self, force): pass diff --git a/requirements.txt b/requirements.txt index 4f467fb..e8c4db4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -13,6 +13,6 @@ # limitations under the License. git+https://osm.etsi.org/gerrit/osm/common.git#egg=osm-common -juju==2.8.2 +juju==2.8.4 pyasn1>=0.4.4 kubernetes==10.0.1 diff --git a/setup.py b/setup.py index 7a6b451..7a4fe87 100644 --- a/setup.py +++ b/setup.py @@ -23,7 +23,7 @@ setup( packages=find_packages( exclude=["*.tests", "*.tests.*", "tests.*", "tests"]), install_requires=[ - 'juju==2.8.2', + 'juju==2.8.4', 'pyasn1>=0.4.4', 'kubernetes==10.0.1' ], -- 2.25.1