From af9510afb3ce53b3dd05136fdbb9f0a5cc048205 Mon Sep 17 00:00:00 2001 From: Tomas Jelinek Date: Fri, 31 May 2024 16:00:06 +0200 Subject: [PATCH] fix booth destroy for arbitrators --- pcs/lib/commands/booth.py | 35 ++++--- pcs/lib/pacemaker/live.py | 4 + pcs_test/tier0/lib/commands/test_booth.py | 110 ++++++++++++++++++++-- 3 files changed, 129 insertions(+), 20 deletions(-) diff --git a/pcs/lib/commands/booth.py b/pcs/lib/commands/booth.py index c961705b..f291a085 100644 --- a/pcs/lib/commands/booth.py +++ b/pcs/lib/commands/booth.py @@ -58,6 +58,7 @@ from pcs.lib.file.raw_file import ( ) from pcs.lib.interface.config import ParserErrorException from pcs.lib.node import get_existing_nodes_names +from pcs.lib.pacemaker.live import has_cib_xml from pcs.lib.resource_agent import ( ResourceAgentError, ResourceAgentFacade, @@ -165,20 +166,30 @@ def config_destroy( found_instance_name = booth_env.instance_name _ensure_live_env(env, booth_env) - booth_resource_list = resource.find_for_config( - get_resources(env.get_cib()), - booth_env.config_path, - ) - if booth_resource_list: - report_processor.report( - ReportItem.error( - reports.messages.BoothConfigIsUsed( - found_instance_name, - reports.const.BOOTH_CONFIG_USED_IN_CLUSTER_RESOURCE, - resource_name=str(booth_resource_list[0].get("id", "")), + if ( + has_cib_xml() + or env.service_manager.is_running("pacemaker") + or env.service_manager.is_running("pacemaker_remoted") + ): + # To allow destroying booth config on arbitrators, only check CIB if: + # * pacemaker is running and therefore we are able to get CIB + # * CIB is stored on disk - pcmk is not running but the node is in a + # cluster (don't checking corosync to cover remote and guest nodes) + # If CIB cannot be loaded in either case, fail with an error. + booth_resource_list = resource.find_for_config( + get_resources(env.get_cib()), + booth_env.config_path, + ) + if booth_resource_list: + report_processor.report( + ReportItem.error( + reports.messages.BoothConfigIsUsed( + found_instance_name, + reports.const.BOOTH_CONFIG_USED_IN_CLUSTER_RESOURCE, + resource_name=str(booth_resource_list[0].get("id", "")), + ) ) ) - ) # Only systemd is currently supported. Initd does not supports multiple # instances (here specified by name) if is_systemd(env.service_manager): diff --git a/pcs/lib/pacemaker/live.py b/pcs/lib/pacemaker/live.py index 301ce343..43197ac1 100644 --- a/pcs/lib/pacemaker/live.py +++ b/pcs/lib/pacemaker/live.py @@ -151,6 +151,10 @@ def get_ticket_status_text(runner: CommandRunner) -> Tuple[str, str, int]: ### cib +def has_cib_xml() -> bool: + return os.path.exists(os.path.join(settings.cib_dir, "cib.xml")) + + def get_cib_xml_cmd_results( runner: CommandRunner, scope: Optional[str] = None ) -> tuple[str, str, int]: diff --git a/pcs_test/tier0/lib/commands/test_booth.py b/pcs_test/tier0/lib/commands/test_booth.py index 4e945216..2957e378 100644 --- a/pcs_test/tier0/lib/commands/test_booth.py +++ b/pcs_test/tier0/lib/commands/test_booth.py @@ -524,10 +524,13 @@ class ConfigSetupAuthfileFix(TestCase, FixtureMixin): class ConfigDestroy(TestCase, FixtureMixin): + # pylint: disable=too-many-public-methods def setUp(self): self.env_assist, self.config = get_env_tools(self) + self.cib_path = os.path.join(settings.cib_dir, "cib.xml") def fixture_config_booth_not_used(self, instance_name="booth"): + self.config.fs.exists(self.cib_path, True) self.config.runner.cib.load() self.config.services.is_running( "booth", instance=instance_name, return_value=False @@ -536,6 +539,44 @@ class ConfigDestroy(TestCase, FixtureMixin): "booth", instance=instance_name, return_value=False ) + def fixture_config_booth_used( + self, + instance_name, + cib_exists=False, + pcmk_running=False, + pcmk_remote_running=False, + booth_running=False, + booth_enabled=False, + ): + cib_load_exception = False + self.config.fs.exists(self.cib_path, cib_exists) + if not cib_exists: + self.config.services.is_running( + "pacemaker", + return_value=pcmk_running, + name="services.is_running.pcmk", + ) + if not pcmk_running: + self.config.services.is_running( + "pacemaker_remoted", + return_value=pcmk_remote_running, + name="services.is_running.pcmk_remote", + ) + if cib_exists and not pcmk_running and not pcmk_remote_running: + self.config.runner.cib.load( + returncode=1, stderr="unable to get cib, pcmk is not running" + ) + cib_load_exception = True + elif pcmk_running or pcmk_remote_running: + self.config.runner.cib.load(resources=self.fixture_cib_resources()) + if not cib_load_exception: + self.config.services.is_running( + "booth", instance=instance_name, return_value=booth_running + ) + self.config.services.is_enabled( + "booth", instance=instance_name, return_value=booth_enabled + ) + def fixture_config_success(self, instance_name="booth"): self.fixture_config_booth_not_used(instance_name) self.config.raw_file.read( @@ -663,17 +704,29 @@ class ConfigDestroy(TestCase, FixtureMixin): expected_in_processor=False, ) - def test_booth_config_in_use(self): + def test_booth_config_in_use_cib_pcmk(self): instance_name = "booth" + self.fixture_config_booth_used(instance_name, pcmk_running=True) - self.config.runner.cib.load(resources=self.fixture_cib_resources()) - self.config.services.is_running( - "booth", instance=instance_name, return_value=True + self.env_assist.assert_raise_library_error( + lambda: commands.config_destroy(self.env_assist.get_env()), ) - self.config.services.is_enabled( - "booth", instance=instance_name, return_value=True + + self.env_assist.assert_reports( + [ + fixture.error( + reports.codes.BOOTH_CONFIG_IS_USED, + name=instance_name, + detail=reports.const.BOOTH_CONFIG_USED_IN_CLUSTER_RESOURCE, + resource_name="booth_resource", + ), + ] ) + def test_booth_config_in_use_cib_pcmk_remote(self): + instance_name = "booth" + self.fixture_config_booth_used(instance_name, pcmk_remote_running=True) + self.env_assist.assert_raise_library_error( lambda: commands.config_destroy(self.env_assist.get_env()), ) @@ -686,16 +739,57 @@ class ConfigDestroy(TestCase, FixtureMixin): detail=reports.const.BOOTH_CONFIG_USED_IN_CLUSTER_RESOURCE, resource_name="booth_resource", ), + ] + ) + + def test_pcmk_not_running(self): + instance_name = "booth" + self.fixture_config_booth_used(instance_name, cib_exists=True) + + self.env_assist.assert_raise_library_error( + lambda: commands.config_destroy(self.env_assist.get_env()), + [ + fixture.error( + reports.codes.CIB_LOAD_ERROR, + reason="unable to get cib, pcmk is not running", + ) + ], + expected_in_processor=False, + ) + + def test_booth_config_in_use_systemd_running(self): + instance_name = "booth" + self.fixture_config_booth_used(instance_name, booth_running=True) + + self.env_assist.assert_raise_library_error( + lambda: commands.config_destroy(self.env_assist.get_env()), + ) + + self.env_assist.assert_reports( + [ fixture.error( reports.codes.BOOTH_CONFIG_IS_USED, name=instance_name, - detail=reports.const.BOOTH_CONFIG_USED_ENABLED_IN_SYSTEMD, + detail=reports.const.BOOTH_CONFIG_USED_RUNNING_IN_SYSTEMD, resource_name=None, ), + ] + ) + + def test_booth_config_in_use_systemd_enabled(self): + instance_name = "booth" + self.fixture_config_booth_used(instance_name, booth_enabled=True) + + self.env_assist.assert_raise_library_error( + lambda: commands.config_destroy(self.env_assist.get_env()), + ) + + self.env_assist.assert_reports( + [ fixture.error( reports.codes.BOOTH_CONFIG_IS_USED, name=instance_name, - detail=reports.const.BOOTH_CONFIG_USED_RUNNING_IN_SYSTEMD, + detail=reports.const.BOOTH_CONFIG_USED_ENABLED_IN_SYSTEMD, resource_name=None, ), ] -- 2.25.1