From 85fab706c913cc8752988f6d9ef1a5f31cae0de4 Mon Sep 17 00:00:00 2001 From: "Gareth J. Greenaway" Date: Thu, 17 Nov 2022 12:27:55 -0800 Subject: [PATCH] Need to move the creation of the proxy object for the ProxyMinion further down in the initialization for sub proxies to ensure that all modules, especially any custom proxy modules, are available before attempting to run the init function. --- changelog/61805.fixed | 1 + salt/metaproxy/deltaproxy.py | 11 +- .../integration/cli/test_salt_deltaproxy.py | 134 ++++++++++++++++++ 3 files changed, 142 insertions(+), 4 deletions(-) create mode 100644 changelog/61805.fixed diff --git a/changelog/61805.fixed b/changelog/61805.fixed new file mode 100644 index 00000000000..1a0339fb6a6 --- /dev/null +++ b/changelog/61805.fixed @@ -0,0 +1 @@ +Need to move the creation of the proxy object for the ProxyMinion further down in the initialization for sub proxies to ensure that all modules, especially any custom proxy modules, are available before attempting to run the init function. diff --git a/salt/metaproxy/deltaproxy.py b/salt/metaproxy/deltaproxy.py index 206cfce5cf4..c3003b368f7 100644 --- a/salt/metaproxy/deltaproxy.py +++ b/salt/metaproxy/deltaproxy.py @@ -428,10 +428,6 @@ def subproxy_post_master_init(minion_id, uid, opts, main_proxy, main_utils): _proxy_minion = ProxyMinion(proxyopts) _proxy_minion.proc_dir = salt.minion.get_proc_dir(proxyopts["cachedir"], uid=uid) - _proxy_minion.proxy = salt.loader.proxy( - proxyopts, utils=main_utils, context=proxy_context - ) - # And load the modules ( _proxy_minion.functions, @@ -461,6 +457,13 @@ def subproxy_post_master_init(minion_id, uid, opts, main_proxy, main_utils): context=proxy_context, ) + # Create this after modules are synced to ensure + # any custom modules, eg. custom proxy modules + # are avaiable. + _proxy_minion.proxy = salt.loader.proxy( + proxyopts, utils=main_utils, context=proxy_context + ) + _proxy_minion.functions.pack["__proxy__"] = _proxy_minion.proxy _proxy_minion.proxy.pack["__salt__"] = _proxy_minion.functions _proxy_minion.proxy.pack["__ret__"] = _proxy_minion.returners diff --git a/tests/pytests/integration/cli/test_salt_deltaproxy.py b/tests/pytests/integration/cli/test_salt_deltaproxy.py index 59bf3c59fae..1520fc46c5a 100644 --- a/tests/pytests/integration/cli/test_salt_deltaproxy.py +++ b/tests/pytests/integration/cli/test_salt_deltaproxy.py @@ -452,3 +452,137 @@ def test_invalid_connection( assert not factory.is_running() assert ret.returncode == salt.defaults.exitcodes.EX_OK, ret + + +@pytest.mark.skip_on_windows(reason=PRE_PYTEST_SKIP_REASON) +@pytest.mark.parametrize( + "parallel_startup", + [True, False], + ids=["parallel_startup=True", "parallel_startup=False"], +) +def test_custom_proxy_module( + salt_master, + salt_cli, + proxy_minion_id, + parallel_startup, + integration_files_dir, +): + """ + Ensure the salt-proxy control proxy starts and + is able to respond to test.ping, additionally ensure that + the proxies being controlled also respond to test.ping. + + Finally ensure correct exit status when salt-proxy exits correctly. + + Skip on Windows because daemonization not supported + """ + + config_defaults = { + "metaproxy": "deltaproxy", + } + proxy_one = "custom_dummy_proxy_one" + proxy_two = "custom_dummy_proxy_two" + + top_file = """ + base: + {control}: + - controlproxy + {one}: + - {one} + {two}: + - {two} + """.format( + control=proxy_minion_id, + one=proxy_one, + two=proxy_two, + ) + controlproxy_pillar_file = """ + proxy: + proxytype: deltaproxy + parallel_startup: {} + ids: + - {} + - {} + """.format( + parallel_startup, proxy_one, proxy_two + ) + + dummy_proxy_one_pillar_file = """ + proxy: + proxytype: custom_dummy + """ + + dummy_proxy_two_pillar_file = """ + proxy: + proxytype: custom_dummy + """ + + module_contents = """ +__proxyenabled__ = ["custom_dummy"] + +def __virtual__(): + return True + +def init(opts): + return True + +def ping(): + return True + """ + + top_tempfile = salt_master.pillar_tree.base.temp_file("top.sls", top_file) + controlproxy_tempfile = salt_master.pillar_tree.base.temp_file( + "controlproxy.sls", controlproxy_pillar_file + ) + dummy_proxy_one_tempfile = salt_master.pillar_tree.base.temp_file( + "{}.sls".format(proxy_one), + dummy_proxy_one_pillar_file, + ) + dummy_proxy_two_tempfile = salt_master.pillar_tree.base.temp_file( + "{}.sls".format(proxy_two), + dummy_proxy_two_pillar_file, + ) + + custom_proxy_module = salt_master.state_tree.base.temp_file( + "_proxy/custom_dummy.py", module_contents + ) + with top_tempfile, controlproxy_tempfile, dummy_proxy_one_tempfile, dummy_proxy_two_tempfile, custom_proxy_module: + factory = salt_master.salt_proxy_minion_daemon( + proxy_minion_id, + defaults=config_defaults, + extra_cli_arguments_after_first_start_failure=["--log-level=debug"], + start_timeout=240, + ) + + for minion_id in (proxy_minion_id, proxy_one, proxy_two): + factory.before_start( + pytest.helpers.remove_stale_proxy_minion_cache_file, factory, minion_id + ) + factory.after_terminate( + pytest.helpers.remove_stale_minion_key, salt_master, minion_id + ) + factory.after_terminate( + pytest.helpers.remove_stale_proxy_minion_cache_file, factory, minion_id + ) + + with factory.started(): + assert factory.is_running() + + # Let's issue a ping the control proxy + ret = salt_cli.run("test.ping", minion_tgt=proxy_minion_id) + assert ret.returncode == 0 + assert ret.data is True + + # Let's issue a ping to one of the controlled proxies + ret = salt_cli.run("test.ping", minion_tgt=proxy_one) + assert ret.returncode == 0 + assert ret.data is True + + # Let's issue a ping to one of the controlled proxies + ret = salt_cli.run("test.ping", minion_tgt=proxy_two) + assert ret.returncode == 0 + assert ret.data is True + + # Terminate the proxy minion + ret = factory.terminate() + assert ret.returncode == salt.defaults.exitcodes.EX_OK, ret