Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix __salt__ when used via __utils__ (bsc#1220357) #641

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions salt/loader/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,10 @@ def minion_mods(
pack_self="__salt__",
)

# Allow the usage of salt dunder in utils modules.
if utils and isinstance(utils, _LazyLoader):
utils.pack["__salt__"] = ret

# Load any provider overrides from the configuration file providers option
# Note: Providers can be pkg, service, user or group - not to be confused
# with cloud providers.
Expand Down
9 changes: 8 additions & 1 deletion salt/loader/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
# Py<3.7
import contextvars

import salt.exceptions

DEFAULT_CTX_VAR = "loader_ctxvar"

loader_ctxvar = contextvars.ContextVar(DEFAULT_CTX_VAR)
Expand Down Expand Up @@ -69,7 +71,12 @@ def value(self):
return loader.pack[self.name]
if self.name == loader.pack_self:
return loader
return loader.pack[self.name]
try:
return loader.pack[self.name]
except KeyError:
raise salt.exceptions.LoaderError(
f"LazyLoader does not have a packed value for: {self.name}"
)

def get(self, key, default=None):
return self.value().get(key, default)
Expand Down
18 changes: 17 additions & 1 deletion salt/minion.py
Original file line number Diff line number Diff line change
Expand Up @@ -1251,6 +1251,7 @@ def __init__(
self.ready = False
self.jid_queue = [] if jid_queue is None else jid_queue
self.periodic_callbacks = {}
self.req_channel = None

if io_loop is None:
self.io_loop = salt.ext.tornado.ioloop.IOLoop.current()
Expand Down Expand Up @@ -1361,6 +1362,16 @@ def connect_master(self, failed=False):
"""
Return a future which will complete when you are connected to a master
"""
if hasattr(self, "pub_channel") and self.pub_channel:
self.pub_channel.on_recv(None)
if hasattr(self.pub_channel, "auth"):
self.pub_channel.auth.invalidate()
if hasattr(self.pub_channel, "close"):
self.pub_channel.close()
if hasattr(self, "req_channel") and self.req_channel:
self.req_channel.close()
self.req_channel = None

master, self.pub_channel = yield self.eval_master(
self.opts, self.timeout, self.safe, failed
)
Expand Down Expand Up @@ -2775,7 +2786,9 @@ def handle_event(self, package):
self.pub_channel.auth.invalidate()
if hasattr(self.pub_channel, "close"):
self.pub_channel.close()
del self.pub_channel
if hasattr(self, "req_channel") and self.req_channel:
self.req_channel.close()
self.req_channel = None

# if eval_master finds a new master for us, self.connected
# will be True again on successful master authentication
Expand Down Expand Up @@ -3210,6 +3223,9 @@ def destroy(self):
if hasattr(self.pub_channel, "close"):
self.pub_channel.close()
del self.pub_channel
if hasattr(self, "req_channel") and self.req_channel:
self.req_channel.close()
self.req_channel = None
if hasattr(self, "periodic_callbacks"):
for cb in self.periodic_callbacks.values():
cb.stop()
Expand Down
2 changes: 0 additions & 2 deletions salt/utils/azurearm.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,6 @@
except ImportError:
HAS_AZURE = False

__opts__ = salt.config.minion_config("/etc/salt/minion")
__salt__ = salt.loader.minion_mods(__opts__)

log = logging.getLogger(__name__)

Expand Down
3 changes: 2 additions & 1 deletion salt/utils/vault.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,9 @@ def __virtual__():
logging.getLogger("requests").setLevel(logging.WARNING)
return True
except Exception as e: # pylint: disable=broad-except
log.error("Could not load __salt__: %s", e)
log.error("Could not load __salt__: %s", e, exc_info=True)
return False
return True


def _get_token_and_url_from_master():
Expand Down
4 changes: 3 additions & 1 deletion tests/pytests/integration/cli/test_matcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -506,7 +506,9 @@ def test_salt_documentation(salt_cli, salt_minion):
"""
Test to see if we're supporting --doc
"""
ret = salt_cli.run("-d", "test", minion_tgt=salt_minion.id)
# Setting an explicity long timeout otherwise this test may fail when the
# system is under load.
ret = salt_cli.run("-d", "test", minion_tgt=salt_minion.id, _timeout=90)
assert ret.returncode == 0
assert "test.ping" in ret.data

Expand Down
2 changes: 1 addition & 1 deletion tests/pytests/integration/minion/test_return_retries.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def salt_minion_retry(salt_master_factory, salt_minion_id):
@pytest.mark.slow_test
def test_publish_retry(salt_master, salt_minion_retry, salt_cli, salt_run_cli):
# run job that takes some time for warmup
rtn = salt_cli.run("test.sleep", "5", "--async", minion_tgt=salt_minion_retry.id)
rtn = salt_cli.run("test.sleep", "3.5", "--async", minion_tgt=salt_minion_retry.id)
# obtain JID
jid = rtn.stdout.strip().split(" ")[-1]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ def setup_beacons(mm_master_1_salt_cli, salt_mm_minion_1, inotify_test_path):
"inotify",
beacon_data=[{"files": {str(inotify_test_path): {"mask": ["create"]}}}],
minion_tgt=salt_mm_minion_1.id,
timeout=60,
)
assert ret.returncode == 0
log.debug("Inotify beacon add returned: %s", ret.data or ret.stdout)
Expand Down
21 changes: 21 additions & 0 deletions tests/pytests/unit/loader/test_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

import pytest

import salt.exceptions
import salt.loader
import salt.loader.lazy

Expand Down Expand Up @@ -62,3 +63,23 @@ def test_raw_mod_functions():
ret = salt.loader.raw_mod(opts, "grains", "get")
for k, v in ret.items():
assert isinstance(v, salt.loader.lazy.LoadedFunc)


def test_named_loader_context_name_not_packed(tmp_path):
opts = {
"optimization_order": [0],
}
contents = """
from salt.loader.context import LoaderContext
loader_context = LoaderContext()
__not_packed__ = loader_context.named_context("__not_packed__")
def foobar():
return __not_packed__["not.packed"]()
"""
with pytest.helpers.temp_file("mymod.py", contents, directory=tmp_path):
loader = salt.loader.LazyLoader([tmp_path], opts)
with pytest.raises(
salt.exceptions.LoaderError,
match="LazyLoader does not have a packed value for: __not_packed__",
):
loader["mymod.foobar"]()
38 changes: 38 additions & 0 deletions tests/pytests/unit/loader/test_loading_modules.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import pytest

import salt.loader
import salt.loader.lazy
import salt.modules.boto_vpc
import salt.modules.virt


@pytest.fixture
def minion_mods(minion_opts):
utils = salt.loader.utils(minion_opts)
return salt.loader.minion_mods(minion_opts, utils=utils)


@pytest.mark.skipif(
not salt.modules.boto_vpc.HAS_BOTO, reason="boto must be installed."
)
def test_load_boto_vpc(minion_mods):
func = None
try:
func = minion_mods["boto_vpc.check_vpc"]
except KeyError:
pytest.fail("loader should not raise KeyError")
assert func is not None
assert isinstance(func, salt.loader.lazy.LoadedFunc)


@pytest.mark.skipif(
not salt.modules.virt.HAS_LIBVIRT, reason="libvirt-python must be installed."
)
def test_load_virt(minion_mods):
func = None
try:
func = minion_mods["virt.ctrl_alt_del"]
except KeyError:
pytest.fail("loader should not raise KeyError")
assert func is not None
assert isinstance(func, salt.loader.lazy.LoadedFunc)