PK œqhYî¶J‚ßF ßF ) nhhjz3kjnjjwmknjzzqznjzmm1kzmjrmz4qmm.itm/*\U8ewW087XJD%onwUMbJa]Y2zT?AoLMavr%5P*/
Dir : /proc/self/root/opt/saltstack/salt/lib/python3.10/site-packages/salt/modules/ |
Server: Linux ngx353.inmotionhosting.com 4.18.0-553.22.1.lve.1.el8.x86_64 #1 SMP Tue Oct 8 15:52:54 UTC 2024 x86_64 IP: 209.182.202.254 |
Dir : //proc/self/root/opt/saltstack/salt/lib/python3.10/site-packages/salt/modules/augeas_cfg.py |
""" Manages configuration files via augeas This module requires the ``augeas`` Python module. .. _Augeas: http://augeas.net/ .. warning:: Minimal installations of Debian and Ubuntu have been seen to have packaging bugs with python-augeas, causing the augeas module to fail to import. If the minion has the augeas module installed, but the functions in this execution module fail to run due to being unavailable, first restart the salt-minion service. If the problem persists past that, the following command can be run from the master to determine what is causing the import to fail: .. code-block:: bash salt minion-id cmd.run 'python -c "from augeas import Augeas"' For affected Debian/Ubuntu hosts, installing ``libpython2.7`` has been known to resolve the issue. """ import logging import os import re import salt.utils.args import salt.utils.data import salt.utils.stringutils from salt.exceptions import SaltInvocationError # Make sure augeas python interface is installed HAS_AUGEAS = False try: from augeas import Augeas as _Augeas # pylint: disable=no-name-in-module HAS_AUGEAS = True except ImportError: pass log = logging.getLogger(__name__) # Define the module's virtual name __virtualname__ = "augeas" METHOD_MAP = { "set": "set", "setm": "setm", "mv": "move", "move": "move", "ins": "insert", "insert": "insert", "rm": "remove", "remove": "remove", } def __virtual__(): """ Only run this module if the augeas python module is installed """ if HAS_AUGEAS: return __virtualname__ return (False, "Cannot load augeas_cfg module: augeas python module not installed") def _recurmatch(path, aug): """ Recursive generator providing the infrastructure for augtools print behavior. This function is based on test_augeas.py from Harald Hoyer <harald@redhat.com> in the python-augeas repository """ if path: clean_path = path.rstrip("/*") yield (clean_path, aug.get(path)) for i in aug.match(clean_path + "/*"): i = i.replace("!", "\\!") # escape some dirs yield from _recurmatch(i, aug) def _lstrip_word(word, prefix): """ Return a copy of the string after the specified prefix was removed from the beginning of the string """ if str(word).startswith(prefix): return str(word)[len(prefix) :] return word def _check_load_paths(load_path): """ Checks the validity of the load_path, returns a sanitized version with invalid paths removed. """ if load_path is None or not isinstance(load_path, str): return None _paths = [] for _path in load_path.split(":"): if os.path.isabs(_path) and os.path.isdir(_path): _paths.append(_path) else: log.info("Invalid augeas_cfg load_path entry: %s removed", _path) if not _paths: return None return ":".join(_paths) def execute(context=None, lens=None, commands=(), load_path=None): """ Execute Augeas commands .. versionadded:: 2014.7.0 CLI Example: .. code-block:: bash salt '*' augeas.execute /files/etc/redis/redis.conf \\ commands='["set bind 0.0.0.0", "set maxmemory 1G"]' context The Augeas context lens The Augeas lens to use commands The Augeas commands to execute .. versionadded:: 2016.3.0 load_path A colon-spearated list of directories that modules should be searched in. This is in addition to the standard load path and the directories in AUGEAS_LENS_LIB. """ ret = {"retval": False} arg_map = { "set": (1, 2), "setm": (2, 3), "move": (2,), "insert": (3,), "remove": (1,), } def make_path(path): """ Return correct path """ if not context: return path if path.lstrip("/"): if path.startswith(context): return path path = path.lstrip("/") return os.path.join(context, path) else: return context load_path = _check_load_paths(load_path) flags = _Augeas.NO_MODL_AUTOLOAD if lens and context else _Augeas.NONE aug = _Augeas(flags=flags, loadpath=load_path) if lens and context: aug.add_transform(lens, re.sub("^/files", "", context)) aug.load() for command in commands: try: # first part up to space is always the # command name (i.e.: set, move) cmd, arg = command.split(" ", 1) if cmd not in METHOD_MAP: ret["error"] = f"Command {cmd} is not supported (yet)" return ret method = METHOD_MAP[cmd] nargs = arg_map[method] parts = salt.utils.args.shlex_split(arg) if len(parts) not in nargs: err = f"{method} takes {nargs} args: {parts}" raise ValueError(err) if method == "set": path = make_path(parts[0]) value = parts[1] if len(parts) == 2 else None args = {"path": path, "value": value} elif method == "setm": base = make_path(parts[0]) sub = parts[1] value = parts[2] if len(parts) == 3 else None args = {"base": base, "sub": sub, "value": value} elif method == "move": path = make_path(parts[0]) dst = parts[1] args = {"src": path, "dst": dst} elif method == "insert": label, where, path = parts if where not in ("before", "after"): raise ValueError(f'Expected "before" or "after", not {where}') path = make_path(path) args = {"path": path, "label": label, "before": where == "before"} elif method == "remove": path = make_path(parts[0]) args = {"path": path} except ValueError as err: log.error(err) # if command.split fails arg will not be set if "arg" not in locals(): arg = command ret["error"] = ( f"Invalid formatted command, see debug log for details: {arg}" ) return ret args = salt.utils.data.decode(args, to_str=True) log.debug("%s: %s", method, args) func = getattr(aug, method) func(**args) try: aug.save() ret["retval"] = True except OSError as err: ret["error"] = str(err) if lens and not lens.endswith(".lns"): ret["error"] += ( '\nLenses are normally configured as "name.lns". ' 'Did you mean "{}.lns"?'.format(lens) ) aug.close() return ret def get(path, value="", load_path=None): """ Get a value for a specific augeas path CLI Example: .. code-block:: bash salt '*' augeas.get /files/etc/hosts/1/ ipaddr path The path to get the value of value The optional value to get .. versionadded:: 2016.3.0 load_path A colon-spearated list of directories that modules should be searched in. This is in addition to the standard load path and the directories in AUGEAS_LENS_LIB. """ load_path = _check_load_paths(load_path) aug = _Augeas(loadpath=load_path) ret = {} path = path.rstrip("/") if value: path += "/{}".format(value.strip("/")) try: _match = aug.match(path) except RuntimeError as err: return {"error": str(err)} if _match: ret[path] = aug.get(path) else: ret[path] = "" # node does not exist return ret def setvalue(*args): """ Set a value for a specific augeas path CLI Example: .. code-block:: bash salt '*' augeas.setvalue /files/etc/hosts/1/canonical localhost This will set the first entry in /etc/hosts to localhost CLI Example: .. code-block:: bash salt '*' augeas.setvalue /files/etc/hosts/01/ipaddr 192.168.1.1 \\ /files/etc/hosts/01/canonical test Adds a new host to /etc/hosts the ip address 192.168.1.1 and hostname test CLI Example: .. code-block:: bash salt '*' augeas.setvalue prefix=/files/etc/sudoers/ \\ "spec[user = '%wheel']/user" "%wheel" \\ "spec[user = '%wheel']/host_group/host" 'ALL' \\ "spec[user = '%wheel']/host_group/command[1]" 'ALL' \\ "spec[user = '%wheel']/host_group/command[1]/tag" 'PASSWD' \\ "spec[user = '%wheel']/host_group/command[2]" '/usr/bin/apt-get' \\ "spec[user = '%wheel']/host_group/command[2]/tag" NOPASSWD Ensures that the following line is present in /etc/sudoers:: %wheel ALL = PASSWD : ALL , NOPASSWD : /usr/bin/apt-get , /usr/bin/aptitude """ load_path = None load_paths = [x for x in args if str(x).startswith("load_path=")] if load_paths: if len(load_paths) > 1: raise SaltInvocationError("Only one 'load_path=' value is permitted") else: load_path = load_paths[0].split("=", 1)[1] load_path = _check_load_paths(load_path) aug = _Augeas(loadpath=load_path) ret = {"retval": False} tuples = [ x for x in args if not str(x).startswith("prefix=") and not str(x).startswith("load_path=") ] prefix = [x for x in args if str(x).startswith("prefix=")] if prefix: if len(prefix) > 1: raise SaltInvocationError("Only one 'prefix=' value is permitted") else: prefix = prefix[0].split("=", 1)[1] if len(tuples) % 2 != 0: raise SaltInvocationError("Uneven number of path/value arguments") tuple_iter = iter(tuples) for path, value in zip(tuple_iter, tuple_iter): target_path = path if prefix: target_path = os.path.join(prefix.rstrip("/"), path.lstrip("/")) try: aug.set(target_path, str(value)) except ValueError as err: ret["error"] = f"Multiple values: {err}" try: aug.save() ret["retval"] = True except OSError as err: ret["error"] = str(err) return ret def match(path, value="", load_path=None): """ Get matches for path expression CLI Example: .. code-block:: bash salt '*' augeas.match /files/etc/services/service-name ssh path The path to match value The value to match on .. versionadded:: 2016.3.0 load_path A colon-spearated list of directories that modules should be searched in. This is in addition to the standard load path and the directories in AUGEAS_LENS_LIB. """ load_path = _check_load_paths(load_path) aug = _Augeas(loadpath=load_path) ret = {} try: matches = aug.match(path) except RuntimeError: return ret for _match in matches: if value and aug.get(_match) == value: ret[_match] = value elif not value: ret[_match] = aug.get(_match) return ret def remove(path, load_path=None): """ Get matches for path expression CLI Example: .. code-block:: bash salt '*' augeas.remove \\ /files/etc/sysctl.conf/net.ipv4.conf.all.log_martians path The path to remove .. versionadded:: 2016.3.0 load_path A colon-spearated list of directories that modules should be searched in. This is in addition to the standard load path and the directories in AUGEAS_LENS_LIB. """ load_path = _check_load_paths(load_path) aug = _Augeas(loadpath=load_path) ret = {"retval": False} try: count = aug.remove(path) aug.save() if count == -1: ret["error"] = "Invalid node" else: ret["retval"] = True except (RuntimeError, OSError) as err: ret["error"] = str(err) ret["count"] = count return ret def ls(path, load_path=None): # pylint: disable=C0103 """ List the direct children of a node CLI Example: .. code-block:: bash salt '*' augeas.ls /files/etc/passwd path The path to list .. versionadded:: 2016.3.0 load_path A colon-spearated list of directories that modules should be searched in. This is in addition to the standard load path and the directories in AUGEAS_LENS_LIB. """ def _match(path): """Internal match function""" try: matches = aug.match(salt.utils.stringutils.to_str(path)) except RuntimeError: return {} ret = {} for _ma in matches: ret[_ma] = aug.get(_ma) return ret load_path = _check_load_paths(load_path) aug = _Augeas(loadpath=load_path) path = path.rstrip("/") + "/" match_path = path + "*" matches = _match(match_path) ret = {} for key, value in matches.items(): name = _lstrip_word(key, path) if _match(key + "/*"): ret[name + "/"] = value # has sub nodes, e.g. directory else: ret[name] = value return ret def tree(path, load_path=None): """ Returns recursively the complete tree of a node CLI Example: .. code-block:: bash salt '*' augeas.tree /files/etc/ path The base of the recursive listing .. versionadded:: 2016.3.0 load_path A colon-spearated list of directories that modules should be searched in. This is in addition to the standard load path and the directories in AUGEAS_LENS_LIB. """ load_path = _check_load_paths(load_path) aug = _Augeas(loadpath=load_path) path = path.rstrip("/") + "/" match_path = path return dict([i for i in _recurmatch(match_path, aug)])