From 9f43171ee0b7546eecf2b88ba0ffa35b7920caaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Hetk=C3=A4mper?= Date: Thu, 30 May 2024 22:25:04 +0200 Subject: [PATCH 1/3] Add tests for minion config option startup_states --- .../integration/minion/test_startup_states.py | 114 ++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 tests/pytests/integration/minion/test_startup_states.py diff --git a/tests/pytests/integration/minion/test_startup_states.py b/tests/pytests/integration/minion/test_startup_states.py new file mode 100644 index 000000000000..d3bc22041615 --- /dev/null +++ b/tests/pytests/integration/minion/test_startup_states.py @@ -0,0 +1,114 @@ +"""Test minion configuration option startup_states. + +There are four valid values for this option, which are validated by checking the jobs +executed after minion start. +""" + +import pytest + + +@pytest.fixture +def salt_minion_startup_states_empty_string(salt_master, salt_minion_id): + config_overrides = { + "startup_states": "", + } + factory = salt_master.salt_minion_daemon( + f"{salt_minion_id}-empty-string", + overrides=config_overrides, + ) + with factory.started(): + yield factory + + +@pytest.fixture +def salt_minion_startup_states_highstate(salt_master, salt_minion_id): + config_overrides = { + "startup_states": "highstate", + } + factory = salt_master.salt_minion_daemon( + f"{salt_minion_id}-highstate", + overrides=config_overrides, + ) + with factory.started(): + yield factory + + +@pytest.fixture +def salt_minion_startup_states_sls(salt_master, salt_minion_id): + config_overrides = {"startup_states": "sls", "sls_list": ["example-sls"]} + factory = salt_master.salt_minion_daemon( + f"{salt_minion_id}-sls", + overrides=config_overrides, + ) + with factory.started(): + yield factory + + +@pytest.fixture +def salt_minion_startup_states_top(salt_master, salt_minion_id): + config_overrides = {"startup_states": "top", "top_file": "example-top.sls"} + factory = salt_master.salt_minion_daemon( + f"{salt_minion_id}-top", + overrides=config_overrides, + ) + with factory.started(): + yield factory + + +def test_startup_states_empty_string( + salt_run_cli, salt_minion_startup_states_empty_string +): + # Get jobs for this minion + ret = salt_run_cli.run( + "jobs.list_jobs", f"search_target={salt_minion_startup_states_empty_string.id}" + ) + # Check no job was run + assert len(ret.data.keys()) == 0 + + +def test_startup_states_highstate(salt_run_cli, salt_minion_startup_states_highstate): + with salt_minion_startup_states_highstate: + # Get jobs for this minion + ret = salt_run_cli.run( + "jobs.list_jobs", f"search_target={salt_minion_startup_states_highstate.id}" + ) + # Check there is exactly one job + assert len(ret.data.keys()) == 1 + # Check that job executes state.highstate + job_ret = next(iter(ret.data.values())) + assert "Function" in job_ret + assert job_ret["Function"] == "state.highstate" + assert "Arguments" in job_ret + assert job_ret["Arguments"] == [] + + +def test_startup_states_sls(salt_run_cli, salt_minion_startup_states_sls): + with salt_minion_startup_states_sls: + # Get jobs for this minion + ret = salt_run_cli.run( + "jobs.list_jobs", f"search_target={salt_minion_startup_states_sls.id}" + ) + # Check there is exactly one job + assert len(ret.data.keys()) == 1 + # Check that job executes state.sls + job_ret = next(iter(ret.data.values())) + assert "Function" in job_ret + assert job_ret["Function"] == "state.sls" + assert "Arguments" in job_ret + assert job_ret["Arguments"] == [["example-sls"]] + + +def test_startup_states_top(salt_run_cli, salt_minion_startup_states_top): + with salt_minion_startup_states_top: + # Get jobs for this minion + ret = salt_run_cli.run( + "jobs.list_jobs", f"search_target={salt_minion_startup_states_top.id}" + ) + # Check there is exactly one job + assert len(ret.data.keys()) == 1 + # Check that job executes state.top + job_ret = next(iter(ret.data.values())) + assert "Function" in job_ret + assert job_ret["Function"] == "state.top" + assert "Arguments" in job_ret + assert job_ret["Arguments"] == ["example-top.sls"] From 7f4624d2e82bd2ed7eadb3a052bdd28ea0aa9663 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Hetk=C3=A4mper?= Date: Thu, 30 May 2024 22:27:02 +0200 Subject: [PATCH 2/3] Fix missing await and async def Fixes #66592 --- salt/minion.py | 10 +++++----- tests/pytests/unit/test_minion.py | 12 ++++++------ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/salt/minion.py b/salt/minion.py index 9a6484d91225..615000f9a4a3 100644 --- a/salt/minion.py +++ b/salt/minion.py @@ -1143,7 +1143,7 @@ async def _connect_minion(self, minion): minion.setup_scheduler(before_connect=True) if minion.opts.get("master_type", "str") != "disable": await minion.connect_master(failed=failed) - minion.tune_in(start=False) + await minion.tune_in(start=False) self.minions.append(minion) break except SaltClientError as exc: @@ -2404,7 +2404,7 @@ def timeout_handler(*_): log.trace("ret_val = %s", ret_val) # pylint: disable=no-member return ret_val - def _state_run(self): + async def _state_run(self): """ Execute a state run based on information set in the minion config file """ @@ -2429,7 +2429,7 @@ def _state_run(self): else: data["fun"] = "state.highstate" data["arg"] = [] - self._handle_decoded_payload(data) + await self._handle_decoded_payload(data) def _refresh_grains_watcher(self, refresh_interval_in_minutes): """ @@ -3108,7 +3108,7 @@ def remove_periodic_callback(self, name): return True # Main Minion Tune In - def tune_in(self, start=True): + async def tune_in(self, start=True): """ Lock onto the publisher. This is the main event loop for the minion :rtype : None @@ -3135,7 +3135,7 @@ def tune_in(self, start=True): salt.utils.win_functions.enable_ctrl_logoff_handler() # On first startup execute a state run if configured to do so - self._state_run() + await self._state_run() self.setup_beacons() self.setup_scheduler() diff --git a/tests/pytests/unit/test_minion.py b/tests/pytests/unit/test_minion.py index dfbf0b1d8bdf..e11304d68892 100644 --- a/tests/pytests/unit/test_minion.py +++ b/tests/pytests/unit/test_minion.py @@ -495,7 +495,7 @@ class SleepCalledException(Exception): @pytest.mark.slow_test -def test_beacons_before_connect(minion_opts): +async def test_beacons_before_connect(minion_opts): """ Tests that the 'beacons_before_connect' option causes the beacons to be initialized before connect. """ @@ -515,7 +515,7 @@ def test_beacons_before_connect(minion_opts): try: try: - minion.tune_in(start=True) + await minion.tune_in(start=True) except RuntimeError: pass @@ -527,7 +527,7 @@ def test_beacons_before_connect(minion_opts): @pytest.mark.slow_test -def test_scheduler_before_connect(minion_opts): +async def test_scheduler_before_connect(minion_opts): """ Tests that the 'scheduler_before_connect' option causes the scheduler to be initialized before connect. """ @@ -546,7 +546,7 @@ def test_scheduler_before_connect(minion_opts): minion = salt.minion.Minion(minion_opts, io_loop=io_loop) try: try: - minion.tune_in(start=True) + await minion.tune_in(start=True) except RuntimeError: pass @@ -616,7 +616,7 @@ def test_minion_module_refresh_beacons_refresh(minion_opts): @pytest.mark.slow_test -def test_when_ping_interval_is_set_the_callback_should_be_added_to_periodic_callbacks( +async def test_when_ping_interval_is_set_the_callback_should_be_added_to_periodic_callbacks( minion_opts, ): with patch("salt.minion.Minion.ctx", MagicMock(return_value={})), patch( @@ -636,7 +636,7 @@ def test_when_ping_interval_is_set_the_callback_should_be_added_to_periodic_call try: minion.connected = MagicMock(side_effect=(False, True)) minion._fire_master_minion_start = MagicMock() - minion.tune_in(start=False) + await minion.tune_in(start=False) except RuntimeError: pass From 4917f0da2b3a32413b09cd9ca53dba6eaad1eb29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Hetk=C3=A4mper?= Date: Thu, 30 May 2024 23:17:08 +0200 Subject: [PATCH 3/3] Add changelog file --- changelog/66592.fixed.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog/66592.fixed.md diff --git a/changelog/66592.fixed.md b/changelog/66592.fixed.md new file mode 100644 index 000000000000..228e35292b0b --- /dev/null +++ b/changelog/66592.fixed.md @@ -0,0 +1 @@ +Fix minion config option startup_states