Stop loading imported functions.

Fixes #62190

Signed-off-by: Pedro Algarvio <palgarvio@vmware.com>
This commit is contained in:
Pedro Algarvio 2022-06-17 13:17:40 +01:00 committed by Megan Wilhite
parent a0d4340fd1
commit 97afb78694
7 changed files with 123 additions and 5 deletions

1
changelog/62190.fixed Normal file
View file

@ -0,0 +1 @@
Only functions defined on the modules being loaded will be added to the lazy loader, functions imported from other modules, unless they are properly namespaced, are not included.

View file

@ -938,18 +938,34 @@ class LazyLoader(salt.utils.lazy.LazyDict):
self.missing_modules[name] = err_string
return False
if getattr(mod, "__load__", False) is not False:
log.info(
try:
funcs_to_load = mod.__load__
log.debug(
"The functions from module '%s' are being loaded from the "
"provided __load__ attribute",
module_name,
)
except AttributeError:
try:
funcs_to_load = mod.__all__
log.debug(
"The functions from module '%s' are being loaded from the "
"provided __all__ attribute",
module_name,
)
except AttributeError:
funcs_to_load = dir(mod)
log.debug(
"The functions from module '%s' are being loaded by "
"dir() on the loaded module",
module_name,
)
# If we had another module by the same virtual name, we should put any
# new functions under the existing dictionary.
mod_names = [module_name] + list(virtual_aliases)
for attr in getattr(mod, "__load__", dir(mod)):
for attr in funcs_to_load:
if attr.startswith("_"):
# private functions are skipped
continue
@ -957,6 +973,12 @@ class LazyLoader(salt.utils.lazy.LazyDict):
if not inspect.isfunction(func) and not isinstance(func, functools.partial):
# Not a function!? Skip it!!!
continue
if not func.__module__.startswith(self.loaded_base_name):
# We're not interested in imported functions, only
# functions defined(or namespaced) on the loaded module.
continue
# Let's get the function name.
# If the module has the __func_alias__ attribute, it must be a
# dictionary mapping in the form of(key -> value):

View file

@ -211,7 +211,8 @@ salt/config/*:
salt/loader/*:
- integration.loader.test_ext_grains
- integration.loader.test_ext_modules
- pytests.functional.test_loader
- pytests.functional.loader.test_loader
- pytests.functional.loader.test_loaded_base_name
salt/minion.py:
- integration.client.test_syndic

View file

@ -0,0 +1,94 @@
import warnings
import pytest
import salt.config
import salt.loader
from salt.loader.lazy import LazyLoader
from saltfactories.utils import random_string
@pytest.fixture(scope="module")
def loaded_base_name():
return random_string("{}.".format(__name__), digits=False, uppercase=False)
@pytest.fixture(scope="module")
def opts(loaded_base_name):
return salt.config.minion_config(None)
def _loader_id(value):
return value[0]
@pytest.fixture(
params=(
("static_loader", ("modules", "test")),
("raw_mod", ("test", None)),
("minion_mods", ()),
("metaproxy", ()),
("matchers", ()),
("engines", (None, None, None)),
("proxy", ()),
("returners", (None,)),
("utils", ()),
("pillars", (None,)),
("tops", ()),
("wheels", ()),
("outputters", ()),
("serializers", ()),
("eauth_tokens", ()),
("auth", ()),
("fileserver", (None,)),
("roster", ()),
("thorium", (None, None)),
("states", (None, None, None)),
("beacons", (None,)),
("log_handlers", ()),
("ssh_wrapper", ()),
("render", (None,)),
("grain_funcs", ()),
("runner", ()),
("queues", ()),
("sdb", ()),
("pkgdb", ()),
("pkgfiles", ()),
("clouds", ()),
("netapi", ()),
("executors", ()),
("cache", ()),
),
ids=_loader_id,
)
def loader(request, opts, loaded_base_name):
loader_name, loader_args = request.param
loader = getattr(salt.loader, loader_name)(
opts, *loader_args, loaded_base_name=loaded_base_name
)
try:
with warnings.catch_warnings():
warnings.simplefilter("ignore")
# Force loading all functions
list(loader)
yield loader
finally:
if not isinstance(loader, LazyLoader):
for loaded_func in loader.values():
loader = loaded_func.loader
break
if isinstance(loader, LazyLoader):
loader.clean_modules()
def test_loader(loader, loaded_base_name):
if not isinstance(loader, LazyLoader):
for loaded_func in loader.values():
loader = loaded_func.loader
assert loader.loaded_base_name == loaded_base_name
module_name = loaded_func.func.__module__
assert module_name.startswith(loaded_base_name)
else:
assert loader.loaded_base_name == loaded_base_name
for func_name in list(loader._dict):
module_name = loader[func_name].__module__
assert module_name.startswith(loaded_base_name)

View file

@ -1364,7 +1364,7 @@ class LoaderGlobalsTest(ModuleCase):
global_vars = {}
for val in mod_dict.values():
# only find salty globals
if val.__module__.startswith("salt.loaded"):
if val.__module__.startswith(salt.loader.lazy.LOADED_BASE_NAME):
if hasattr(val, "__globals__"):
if hasattr(val, "__wrapped__") or "__wrapped__" in val.__globals__:
global_vars[val.__module__] = sys.modules[