mirror of
https://github.com/saltstack/salt.git
synced 2025-04-16 09:40:20 +00:00
Merge pull request #64038 from dmurphy18/dt_fix_63148_3006x
[3006.x] Populate user data / name within runners and for runner events on the event bus
This commit is contained in:
commit
eb81faea5b
7 changed files with 217 additions and 7 deletions
1
changelog/63148.fixed.md
Normal file
1
changelog/63148.fixed.md
Normal file
|
@ -0,0 +1 @@
|
||||||
|
User responsible for the runner is now correctly reported in the events on the event bus for the runner.
|
|
@ -246,6 +246,8 @@ class SyncClientMixin(ClientStateMixin):
|
||||||
self.functions[fun], arglist, pub_data
|
self.functions[fun], arglist, pub_data
|
||||||
)
|
)
|
||||||
low = {"fun": fun, "arg": args, "kwarg": kwargs}
|
low = {"fun": fun, "arg": args, "kwarg": kwargs}
|
||||||
|
if "user" in pub_data:
|
||||||
|
low["__user__"] = pub_data["user"]
|
||||||
return self.low(fun, low, print_event=print_event, full_return=full_return)
|
return self.low(fun, low, print_event=print_event, full_return=full_return)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|
|
@ -1730,8 +1730,10 @@ def runner(
|
||||||
arg = []
|
arg = []
|
||||||
if kwarg is None:
|
if kwarg is None:
|
||||||
kwarg = {}
|
kwarg = {}
|
||||||
|
pub_data = {}
|
||||||
jid = kwargs.pop("__orchestration_jid__", jid)
|
jid = kwargs.pop("__orchestration_jid__", jid)
|
||||||
saltenv = kwargs.pop("__env__", saltenv)
|
saltenv = kwargs.pop("__env__", saltenv)
|
||||||
|
pub_data["user"] = kwargs.pop("__pub_user", "UNKNOWN")
|
||||||
kwargs = salt.utils.args.clean_kwargs(**kwargs)
|
kwargs = salt.utils.args.clean_kwargs(**kwargs)
|
||||||
if kwargs:
|
if kwargs:
|
||||||
kwarg.update(kwargs)
|
kwarg.update(kwargs)
|
||||||
|
@ -1760,7 +1762,12 @@ def runner(
|
||||||
)
|
)
|
||||||
|
|
||||||
return rclient.cmd(
|
return rclient.cmd(
|
||||||
name, arg=arg, kwarg=kwarg, print_event=False, full_return=full_return
|
name,
|
||||||
|
arg=arg,
|
||||||
|
pub_data=pub_data,
|
||||||
|
kwarg=kwarg,
|
||||||
|
print_event=False,
|
||||||
|
full_return=full_return,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -101,6 +101,16 @@ def orchestrate(
|
||||||
salt-run state.orchestrate webserver pillar_enc=gpg pillar="$(cat somefile.json)"
|
salt-run state.orchestrate webserver pillar_enc=gpg pillar="$(cat somefile.json)"
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
try:
|
||||||
|
orig_user = __opts__["user"]
|
||||||
|
__opts__["user"] = __user__
|
||||||
|
log.debug(
|
||||||
|
f"changed opts user from original '{orig_user}' to global user '{__user__}'"
|
||||||
|
)
|
||||||
|
except NameError:
|
||||||
|
log.debug("unable to find global user __user__")
|
||||||
|
|
||||||
if pillar is not None and not isinstance(pillar, dict):
|
if pillar is not None and not isinstance(pillar, dict):
|
||||||
raise SaltInvocationError("Pillar data must be formatted as a dictionary")
|
raise SaltInvocationError("Pillar data must be formatted as a dictionary")
|
||||||
__opts__["file_client"] = "local"
|
__opts__["file_client"] = "local"
|
||||||
|
|
|
@ -2293,6 +2293,7 @@ class State:
|
||||||
initial_ret={"full": state_func_name},
|
initial_ret={"full": state_func_name},
|
||||||
expected_extra_kws=STATE_INTERNAL_KEYWORDS,
|
expected_extra_kws=STATE_INTERNAL_KEYWORDS,
|
||||||
)
|
)
|
||||||
|
|
||||||
inject_globals = {
|
inject_globals = {
|
||||||
# Pass a copy of the running dictionary, the low state chunks and
|
# Pass a copy of the running dictionary, the low state chunks and
|
||||||
# the current state dictionaries.
|
# the current state dictionaries.
|
||||||
|
@ -2302,6 +2303,7 @@ class State:
|
||||||
"__running__": immutabletypes.freeze(running) if running else {},
|
"__running__": immutabletypes.freeze(running) if running else {},
|
||||||
"__instance_id__": self.instance_id,
|
"__instance_id__": self.instance_id,
|
||||||
"__lowstate__": immutabletypes.freeze(chunks) if chunks else {},
|
"__lowstate__": immutabletypes.freeze(chunks) if chunks else {},
|
||||||
|
"__user__": self.opts.get("user", "UNKNOWN"),
|
||||||
}
|
}
|
||||||
|
|
||||||
if "__env__" in low:
|
if "__env__" in low:
|
||||||
|
|
|
@ -125,7 +125,7 @@ def state(
|
||||||
subset=None,
|
subset=None,
|
||||||
orchestration_jid=None,
|
orchestration_jid=None,
|
||||||
failhard=None,
|
failhard=None,
|
||||||
**kwargs
|
**kwargs,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Invoke a state run on a given target
|
Invoke a state run on a given target
|
||||||
|
@ -454,7 +454,7 @@ def function(
|
||||||
batch=None,
|
batch=None,
|
||||||
subset=None,
|
subset=None,
|
||||||
failhard=None,
|
failhard=None,
|
||||||
**kwargs
|
**kwargs,
|
||||||
): # pylint: disable=unused-argument
|
): # pylint: disable=unused-argument
|
||||||
"""
|
"""
|
||||||
Execute a single module function on a remote minion via salt or salt-ssh
|
Execute a single module function on a remote minion via salt or salt-ssh
|
||||||
|
@ -780,6 +780,14 @@ def runner(name, **kwargs):
|
||||||
log.debug("Unable to fire args event due to missing __orchestration_jid__")
|
log.debug("Unable to fire args event due to missing __orchestration_jid__")
|
||||||
jid = None
|
jid = None
|
||||||
|
|
||||||
|
try:
|
||||||
|
kwargs["__pub_user"] = __user__
|
||||||
|
log.debug(
|
||||||
|
f"added __pub_user to kwargs using dunder user '{__user__}', kwargs '{kwargs}'"
|
||||||
|
)
|
||||||
|
except NameError:
|
||||||
|
log.warning("unable to find user for fire args event due to missing __user__")
|
||||||
|
|
||||||
if __opts__.get("test", False):
|
if __opts__.get("test", False):
|
||||||
ret = {
|
ret = {
|
||||||
"name": name,
|
"name": name,
|
||||||
|
@ -899,7 +907,7 @@ def parallel_runners(name, runners, **kwargs): # pylint: disable=unused-argumen
|
||||||
__orchestration_jid__=jid,
|
__orchestration_jid__=jid,
|
||||||
__env__=__env__,
|
__env__=__env__,
|
||||||
full_return=True,
|
full_return=True,
|
||||||
**(runner_config.get("kwarg", {}))
|
**(runner_config.get("kwarg", {})),
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -4,16 +4,93 @@ Tests for orchestration events
|
||||||
import concurrent.futures
|
import concurrent.futures
|
||||||
import functools
|
import functools
|
||||||
import json
|
import json
|
||||||
|
import logging
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
import attr
|
||||||
import pytest
|
import pytest
|
||||||
|
from saltfactories.utils import random_string
|
||||||
|
|
||||||
import salt.utils.jid
|
import salt.utils.jid
|
||||||
import salt.utils.platform
|
import salt.utils.platform
|
||||||
|
import salt.utils.pycrypto
|
||||||
|
|
||||||
pytestmark = [
|
log = logging.getLogger(__name__)
|
||||||
pytest.mark.slow_test,
|
|
||||||
]
|
|
||||||
|
@attr.s(kw_only=True, slots=True)
|
||||||
|
class TestMasterAccount:
|
||||||
|
username = attr.ib()
|
||||||
|
password = attr.ib()
|
||||||
|
_delete_account = attr.ib(init=False, repr=False, default=False)
|
||||||
|
|
||||||
|
@username.default
|
||||||
|
def _default_username(self):
|
||||||
|
return random_string("account-", uppercase=False)
|
||||||
|
|
||||||
|
@password.default
|
||||||
|
def _default_password(self):
|
||||||
|
return random_string("pwd-", size=8)
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __exit__(self, *args):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="session")
|
||||||
|
def salt_auth_account_m_factory():
|
||||||
|
return TestMasterAccount(username="saltdev-auth-m")
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="module")
|
||||||
|
def salt_auth_account_m(salt_auth_account_m_factory):
|
||||||
|
with salt_auth_account_m_factory as account:
|
||||||
|
yield account
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="module")
|
||||||
|
def runner_master_config(salt_auth_account_m):
|
||||||
|
return {
|
||||||
|
"external_auth": {
|
||||||
|
"pam": {salt_auth_account_m.username: [{"*": [".*"]}, "@runner", "@wheel"]}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="module")
|
||||||
|
def runner_salt_master(salt_factories, runner_master_config):
|
||||||
|
factory = salt_factories.salt_master_daemon(
|
||||||
|
"runner-master", defaults=runner_master_config
|
||||||
|
)
|
||||||
|
with factory.started():
|
||||||
|
yield factory
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="module")
|
||||||
|
def runner_salt_run_cli(runner_salt_master):
|
||||||
|
return runner_salt_master.salt_run_cli()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="module")
|
||||||
|
def runner_salt_call_cli(runner_salt_minion):
|
||||||
|
return runner_salt_minion.salt_call_cli()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="module")
|
||||||
|
def runner_add_user(runner_salt_run_cli, salt_auth_account_m):
|
||||||
|
## create user on master to use
|
||||||
|
ret = runner_salt_run_cli.run("salt.cmd", "user.add", salt_auth_account_m.username)
|
||||||
|
assert ret.returncode == 0
|
||||||
|
|
||||||
|
yield
|
||||||
|
|
||||||
|
## remove user on master
|
||||||
|
ret = runner_salt_run_cli.run(
|
||||||
|
"salt.cmd", "user.delete", salt_auth_account_m.username
|
||||||
|
)
|
||||||
|
assert ret.returncode == 0
|
||||||
|
|
||||||
|
|
||||||
def test_state_event(salt_run_cli, salt_cli, salt_minion):
|
def test_state_event(salt_run_cli, salt_cli, salt_minion):
|
||||||
|
@ -335,3 +412,106 @@ def test_orchestration_onchanges_and_prereq(
|
||||||
# After the file was created, running again in test mode should have
|
# After the file was created, running again in test mode should have
|
||||||
# shown no changes.
|
# shown no changes.
|
||||||
assert not state_data["changes"]
|
assert not state_data["changes"]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.slow_test
|
||||||
|
@pytest.mark.skip_if_not_root
|
||||||
|
@pytest.mark.skip_on_windows
|
||||||
|
@pytest.mark.skip_on_darwin
|
||||||
|
def test_unknown_in_runner_event(
|
||||||
|
runner_salt_run_cli,
|
||||||
|
runner_salt_master,
|
||||||
|
salt_minion,
|
||||||
|
salt_auth_account_m,
|
||||||
|
runner_add_user,
|
||||||
|
event_listener,
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Test to confirm that the ret event for the orchestration contains the
|
||||||
|
jid for the jobs spawned.
|
||||||
|
"""
|
||||||
|
file_roots_base_dir = runner_salt_master.config["file_roots"]["base"][0]
|
||||||
|
test_top_file_contents = """
|
||||||
|
base:
|
||||||
|
'{minion_id}':
|
||||||
|
- {file_roots}
|
||||||
|
""".format(
|
||||||
|
minion_id=salt_minion.id, file_roots=file_roots_base_dir
|
||||||
|
)
|
||||||
|
test_init_state_contents = """
|
||||||
|
always-passes-with-any-kwarg:
|
||||||
|
test.nop:
|
||||||
|
- name: foo
|
||||||
|
- something: else
|
||||||
|
- foo: bar
|
||||||
|
always-passes:
|
||||||
|
test.succeed_without_changes:
|
||||||
|
- name: foo
|
||||||
|
always-changes-and-succeeds:
|
||||||
|
test.succeed_with_changes:
|
||||||
|
- name: foo
|
||||||
|
{{slspath}}:
|
||||||
|
test.nop
|
||||||
|
"""
|
||||||
|
test_orch_contents = """
|
||||||
|
test_highstate:
|
||||||
|
salt.state:
|
||||||
|
- tgt: {minion_id}
|
||||||
|
- highstate: True
|
||||||
|
test_runner_metasyntetic:
|
||||||
|
salt.runner:
|
||||||
|
- name: test.metasyntactic
|
||||||
|
- locality: us
|
||||||
|
""".format(
|
||||||
|
minion_id=salt_minion.id
|
||||||
|
)
|
||||||
|
with runner_salt_master.state_tree.base.temp_file(
|
||||||
|
"top.sls", test_top_file_contents
|
||||||
|
), runner_salt_master.state_tree.base.temp_file(
|
||||||
|
"init.sls", test_init_state_contents
|
||||||
|
), runner_salt_master.state_tree.base.temp_file(
|
||||||
|
"orch.sls", test_orch_contents
|
||||||
|
):
|
||||||
|
ret = runner_salt_run_cli.run(
|
||||||
|
"salt.cmd", "shadow.gen_password", salt_auth_account_m.password
|
||||||
|
)
|
||||||
|
assert ret.returncode == 0
|
||||||
|
|
||||||
|
gen_pwd = ret.stdout
|
||||||
|
ret = runner_salt_run_cli.run(
|
||||||
|
"salt.cmd", "shadow.set_password", salt_auth_account_m.username, gen_pwd
|
||||||
|
)
|
||||||
|
assert ret.returncode == 0
|
||||||
|
|
||||||
|
jid = salt.utils.jid.gen_jid(runner_salt_master.config)
|
||||||
|
start_time = time.time()
|
||||||
|
|
||||||
|
ret = runner_salt_run_cli.run(
|
||||||
|
"--jid",
|
||||||
|
jid,
|
||||||
|
"-a",
|
||||||
|
"pam",
|
||||||
|
"--username",
|
||||||
|
salt_auth_account_m.username,
|
||||||
|
"--password",
|
||||||
|
salt_auth_account_m.password,
|
||||||
|
"state.orchestrate",
|
||||||
|
"orch",
|
||||||
|
)
|
||||||
|
assert not ret.stdout.startswith("Authentication failure")
|
||||||
|
|
||||||
|
expected_new_event_tag = "salt/run/*/new"
|
||||||
|
event_pattern = (runner_salt_master.id, expected_new_event_tag)
|
||||||
|
found_events = event_listener.get_events([event_pattern], after_time=start_time)
|
||||||
|
|
||||||
|
for event in found_events:
|
||||||
|
if event.data["fun"] == "runner.test.metasyntactic":
|
||||||
|
assert event.data["user"] == salt_auth_account_m.username
|
||||||
|
|
||||||
|
expected_ret_event_tag = "salt/run/*/ret"
|
||||||
|
event_pattern = (runner_salt_master.id, expected_ret_event_tag)
|
||||||
|
found_events = event_listener.get_events([event_pattern], after_time=start_time)
|
||||||
|
|
||||||
|
for event in found_events:
|
||||||
|
if event.data["fun"] == "runner.test.metasyntactic":
|
||||||
|
assert event.data["user"] == salt_auth_account_m.username
|
||||||
|
|
Loading…
Add table
Reference in a new issue