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/roster/ |
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/roster/cache.py |
""" The ``cache`` roster provides a flexible interface to the Salt Masters' minion cache to access regular minions over ``salt-ssh``. .. versionadded:: 2017.7.0 - grains, pillar, mine data matching - SDB URLs - IPv6 support - roster_order per config key - default order changed to industry-wide best practices - CIDR range selection Targeting --------- This roster supports all matching and targeting of the Salt Master. The matching will be done using only the Salt Master's cache. The Roster Order ---------------- The roster's composition can be configured using ``roster_order``. In the ``roster_order`` you can define *any* roster key and fill it with a parameter overriding the one in ``roster_defaults``: .. code-block:: yaml roster_order: host: id # use the minion id as hostname You can define lists of parameters as well, the first result from the list will become the value. Selecting a host ================ .. code-block:: yaml # default roster_order: host: - ipv6-private # IPv6 addresses in private ranges - ipv6-global # IPv6 addresses in global ranges - ipv4-private # IPv4 addresses in private ranges - ipv4-public # IPv4 addresses in public ranges - ipv4-local # loopback addresses This is the default ``roster_order``. It prefers IPv6 over IPv4 addresses and private addresses over public ones. The relevant data will be fetched from the cache in-order, and the first match will fill the ``host`` key. Other address selection parameters are also possible: .. code-block:: yaml roster_order: host: - global|public|private|local # Both IPv6 and IPv4 addresses in that range - 2000::/3 # CIDR networks, both IPv4 and IPv6 are supported Using cached data ================= Several cached libraries can be selected using the ``library: `` prefix, followed by the library key. This can be referenced using the same ``:`` syntax as e.g. :py:func:`pillar.get <salt.modules.pillar.get>`. Lists of references are also supported during the lookup, as are Salt SDB URLs. This should be especially useful for the other roster keys: .. code-block:: yaml roster_order: host: - grain: fqdn_ip4 # Lookup this grain - mine: network.ip_addrs # Mine data lookup works the same password: sdb://vault/ssh_pass # Salt SDB URLs are also supported user: - pillar: ssh:auth:user # Lookup this pillar key - sdb://osenv/USER # Lookup this env var through sdb priv: - pillar: # Lists are also supported - salt:ssh:private_key - ssh:auth:private_key """ import copy import logging import re import salt.cache import salt.utils.data import salt.utils.minions from salt._compat import ipaddress log = logging.getLogger(__name__) def targets(tgt, tgt_type="glob", **kwargs): # pylint: disable=W0613 """ Return the targets from the Salt Masters' minion cache. All targets and matchers are supported. The resulting roster can be configured using ``roster_order`` and ``roster_default``. """ minions = salt.utils.minions.CkMinions(__opts__) _res = minions.check_minions(tgt, tgt_type) minions = _res["minions"] ret = {} if not minions: return ret # log.debug(minions) cache = salt.cache.Cache(__opts__) roster_order = __opts__.get( "roster_order", {"host": ("ipv6-private", "ipv6-global", "ipv4-private", "ipv4-public")}, ) ret = {} for minion_id in minions: try: minion = _load_minion(minion_id, cache) except LookupError: continue minion_res = copy.deepcopy(__opts__.get("roster_defaults", {})) for param, order in roster_order.items(): if not isinstance(order, (list, tuple)): order = [order] for key in order: kres = _minion_lookup(minion_id, key, minion) if kres: minion_res[param] = kres break if "host" in minion_res: ret[minion_id] = minion_res else: log.warning("Could not determine host information for minion %s", minion_id) log.debug("Roster lookup result: %s", ret) return ret def _load_minion(minion_id, cache): data_minion, grains, pillar = salt.utils.minions.get_minion_data( minion_id, __opts__ ) if minion_id != data_minion: log.error("Asked for minion %s, got %s", minion_id, data_minion) raise LookupError if not grains: log.warning("No grain data for minion id %s", minion_id) grains = {} if not pillar: log.warning("No pillar data for minion id %s", minion_id) pillar = {} addrs = { 4: sorted(ipaddress.IPv4Address(addr) for addr in grains.get("ipv4", [])), 6: sorted(ipaddress.IPv6Address(addr) for addr in grains.get("ipv6", [])), } mine = cache.fetch(f"minions/{minion_id}", "mine") return grains, pillar, addrs, mine def _data_lookup(ref, lookup): if isinstance(lookup, str): lookup = [lookup] res = [] for data_key in lookup: data = salt.utils.data.traverse_dict_and_list(ref, data_key, None) # log.debug('Fetched %s in %s: %s', data_key, ref, data) if data: res.append(data) return res def _minion_lookup(minion_id, key, minion): grains, pillar, addrs, mine = minion if key == "id": # Just paste in the minion ID return minion_id elif isinstance(key, dict): # Lookup the key in the dict for data_id, lookup in key.items(): ref = {"pillar": pillar, "grain": grains, "mine": mine} for k in _data_lookup(ref[data_id], lookup): if k: return k return None elif key.startswith("sdb://"): # It's a Salt SDB url return salt["sdb.get"](key) elif re.match(r"^[0-9a-fA-F:./]+$", key): # It smells like a CIDR block try: net = ipaddress.ip_network(key, strict=True) except ValueError: log.error("%s is an invalid CIDR network", key) return None for addr in addrs[net.version]: if addr in net: return str(addr) else: # Take the addresses from the grains and filter them filters = { "global": lambda addr: ( addr.is_global if addr.version == 6 else not addr.is_private ), "public": lambda addr: not addr.is_private, "private": lambda addr: addr.is_private and not addr.is_loopback and not addr.is_link_local, "local": lambda addr: addr.is_loopback, } ip_vers = [4, 6] if key.startswith("ipv"): ip_vers = [int(key[3])] key = key[5:] for ip_ver in ip_vers: try: for addr in addrs[ip_ver]: if filters[key](addr): return str(addr) except KeyError: raise KeyError(f"Invalid filter {key} specified in roster_order")