From dc43277d4cab1f218a2b5d7e7743a1d2423c8c77 Mon Sep 17 00:00:00 2001 From: Matej Matuska Date: Wed, 16 Nov 2022 14:01:45 +0100 Subject: [PATCH 26/32] systemd: Move (enable|disable|reenable)_unit functions to the shared library The functions are used to enable, disable, or re-enable the given systemd unit. Originaly they were part of setsystemdservicesstate actor, however we have realized they are needed in other actors too in rare cases. --- .../libraries/setsystemdservicesstate.py | 25 +++++----- .../tests/test_setsystemdservicesstate.py | 48 +++++++++++------- .../common/libraries/systemd.py | 50 +++++++++++++++++++ 3 files changed, 93 insertions(+), 30 deletions(-) diff --git a/repos/system_upgrade/common/actors/systemd/setsystemdservicesstates/libraries/setsystemdservicesstate.py b/repos/system_upgrade/common/actors/systemd/setsystemdservicesstates/libraries/setsystemdservicesstate.py index 01272438..641605db 100644 --- a/repos/system_upgrade/common/actors/systemd/setsystemdservicesstates/libraries/setsystemdservicesstate.py +++ b/repos/system_upgrade/common/actors/systemd/setsystemdservicesstates/libraries/setsystemdservicesstate.py @@ -1,17 +1,8 @@ -from leapp.libraries.stdlib import api, CalledProcessError, run +from leapp.libraries.common import systemd +from leapp.libraries.stdlib import api, CalledProcessError from leapp.models import SystemdServicesTasks -def _try_set_service_state(command, service): - try: - # it is possible to call this on multiple units at once, - # but failing to enable one service would cause others to not enable as well - run(['systemctl', command, service]) - except CalledProcessError as err: - api.current_logger().error('Failed to {} systemd unit "{}". Message: {}'.format(command, service, str(err))) - # TODO(mmatuska) produce post-upgrade report - - def process(): services_to_enable = set() services_to_disable = set() @@ -25,7 +16,15 @@ def process(): api.current_logger().error(msg) for service in services_to_enable: - _try_set_service_state('enable', service) + try: + systemd.enable_unit(service) + except CalledProcessError: + # TODO(mmatuska) produce post-upgrade report + pass for service in services_to_disable: - _try_set_service_state('disable', service) + try: + systemd.disable_unit(service) + except CalledProcessError: + # TODO(mmatuska) produce post-upgrade report + pass diff --git a/repos/system_upgrade/common/actors/systemd/setsystemdservicesstates/tests/test_setsystemdservicesstate.py b/repos/system_upgrade/common/actors/systemd/setsystemdservicesstates/tests/test_setsystemdservicesstate.py index dd153329..14d07537 100644 --- a/repos/system_upgrade/common/actors/systemd/setsystemdservicesstates/tests/test_setsystemdservicesstate.py +++ b/repos/system_upgrade/common/actors/systemd/setsystemdservicesstates/tests/test_setsystemdservicesstate.py @@ -2,50 +2,60 @@ import pytest from leapp.libraries import stdlib from leapp.libraries.actor import setsystemdservicesstate +from leapp.libraries.common import systemd from leapp.libraries.common.testutils import CurrentActorMocked, logger_mocked from leapp.libraries.stdlib import api, CalledProcessError from leapp.models import SystemdServicesTasks -class MockedRun(object): +class MockedSystemdCmd(object): def __init__(self): - self.commands = [] + self.units = [] - def __call__(self, cmd, *args, **kwargs): - self.commands.append(cmd) + def __call__(self, unit, *args, **kwargs): + self.units.append(unit) return {} @pytest.mark.parametrize( - ('msgs', 'expected_calls'), + ('msgs', 'expect_enable_units', 'expect_disable_units'), [ ( [SystemdServicesTasks(to_enable=['hello.service'], to_disable=['getty.service'])], - [['systemctl', 'enable', 'hello.service'], ['systemctl', 'disable', 'getty.service']] + ['hello.service'], + ['getty.service'] ), ( [SystemdServicesTasks(to_disable=['getty.service'])], - [['systemctl', 'disable', 'getty.service']] + [], + ['getty.service'] ), ( [SystemdServicesTasks(to_enable=['hello.service'])], - [['systemctl', 'enable', 'hello.service']] + ['hello.service'], + [] ), ( [SystemdServicesTasks()], + [], [] ), ] ) -def test_process(monkeypatch, msgs, expected_calls): - mocked_run = MockedRun() - monkeypatch.setattr(setsystemdservicesstate, 'run', mocked_run) +def test_process(monkeypatch, msgs, expect_enable_units, expect_disable_units): + mocked_enable = MockedSystemdCmd() + monkeypatch.setattr(systemd, 'enable_unit', mocked_enable) + + mocked_disable = MockedSystemdCmd() + monkeypatch.setattr(systemd, 'disable_unit', mocked_disable) + monkeypatch.setattr(api, 'current_actor', CurrentActorMocked(msgs=msgs)) setsystemdservicesstate.process() - assert mocked_run.commands == expected_calls + assert mocked_enable.units == expect_enable_units + assert mocked_disable.units == expect_disable_units def test_process_invalid(monkeypatch): @@ -57,7 +67,7 @@ def test_process_invalid(monkeypatch): msgs = [SystemdServicesTasks(to_enable=['invalid.service'])] - monkeypatch.setattr(setsystemdservicesstate, 'run', mocked_run) + monkeypatch.setattr(systemd, 'run', mocked_run) monkeypatch.setattr(api, 'current_actor', CurrentActorMocked(msgs=msgs)) monkeypatch.setattr(api, 'current_logger', logger_mocked()) @@ -69,10 +79,14 @@ def test_process_invalid(monkeypatch): def test_enable_disable_conflict_logged(monkeypatch): - msgs = [SystemdServicesTasks(to_enable=['hello.service'], - to_disable=['hello.service'])] - mocked_run = MockedRun() - monkeypatch.setattr(setsystemdservicesstate, 'run', mocked_run) + msgs = [SystemdServicesTasks(to_enable=['hello.service'], to_disable=['hello.service'])] + + mocked_enable = MockedSystemdCmd() + monkeypatch.setattr(systemd, 'enable_unit', mocked_enable) + + mocked_disable = MockedSystemdCmd() + monkeypatch.setattr(systemd, 'disable_unit', mocked_disable) + monkeypatch.setattr(api, 'current_actor', CurrentActorMocked(msgs=msgs)) monkeypatch.setattr(api, 'current_logger', logger_mocked()) diff --git a/repos/system_upgrade/common/libraries/systemd.py b/repos/system_upgrade/common/libraries/systemd.py index bbf71af7..c709f233 100644 --- a/repos/system_upgrade/common/libraries/systemd.py +++ b/repos/system_upgrade/common/libraries/systemd.py @@ -32,6 +32,56 @@ def get_broken_symlinks(): raise +def _try_call_unit_command(command, unit): + try: + # it is possible to call this on multiple units at once, + # but failing to enable one service would cause others to not enable as well + run(['systemctl', command, unit]) + except CalledProcessError as err: + msg = 'Failed to {} systemd unit "{}". Message: {}'.format(command, unit, str(err)) + api.current_logger().error(msg) + raise err + + +def enable_unit(unit): + """ + Enable a systemd unit + + It is strongly recommended to produce SystemdServicesTasks message instead, + unless it is absolutely necessary to handle failure yourself. + + :param unit: The systemd unit to enable + :raises CalledProcessError: In case of failure + """ + _try_call_unit_command('enable', unit) + + +def disable_unit(unit): + """ + Disable a systemd unit + + It is strongly recommended to produce SystemdServicesTasks message instead, + unless it is absolutely necessary to handle failure yourself. + + :param unit: The systemd unit to disable + :raises CalledProcessError: In case of failure + """ + _try_call_unit_command('disable', unit) + + +def reenable_unit(unit): + """ + Re-enable a systemd unit + + It is strongly recommended to produce SystemdServicesTasks message, unless it + is absolutely necessary to handle failure yourself. + + :param unit: The systemd unit to re-enable + :raises CalledProcessError: In case of failure + """ + _try_call_unit_command('reenable', unit) + + def get_service_files(): """ Get list of unit files of systemd services on the system -- 2.38.1