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/freebsdports.py |
""" Install software from the FreeBSD ``ports(7)`` system .. versionadded:: 2014.1.0 This module allows you to install ports using ``BATCH=yes`` to bypass configuration prompts. It is recommended to use the :mod:`ports state <salt.states.freebsdports>` to install ports, but it is also possible to use this module exclusively from the command line. .. code-block:: bash salt minion-id ports.config security/nmap IPV6=off salt minion-id ports.install security/nmap """ import fnmatch import logging import os import re import salt.utils.data import salt.utils.files import salt.utils.path from salt.exceptions import CommandExecutionError, SaltInvocationError log = logging.getLogger(__name__) # Define the module's virtual name __virtualname__ = "ports" def __virtual__(): """ Only runs on FreeBSD systems """ if __grains__["os"] == "FreeBSD": return __virtualname__ return ( False, "The freebsdports execution module cannot be loaded: " "only available on FreeBSD systems.", ) def _portsnap(): """ Return 'portsnap --interactive' for FreeBSD 10, otherwise 'portsnap' """ ret = ["portsnap"] if float(__grains__["osrelease"]) >= 10: ret.append("--interactive") return ret def _check_portname(name): """ Check if portname is valid and whether or not the directory exists in the ports tree. """ if not isinstance(name, str) or "/" not in name: raise SaltInvocationError(f"Invalid port name '{name}' (category required)") path = os.path.join("/usr/ports", name) if not os.path.isdir(path): raise SaltInvocationError(f"Path '{path}' does not exist") return path def _options_dir(name): """ Retrieve the path to the dir containing OPTIONS file for a given port """ _check_portname(name) _root = "/var/db/ports" # New path: /var/db/ports/category_portname new_dir = os.path.join(_root, name.replace("/", "_")) # Old path: /var/db/ports/portname old_dir = os.path.join(_root, name.split("/")[-1]) if os.path.isdir(old_dir): return old_dir return new_dir def _options_file_exists(name): """ Returns True/False based on whether or not the options file for the specified port exists. """ return os.path.isfile(os.path.join(_options_dir(name), "options")) def _write_options(name, configuration): """ Writes a new OPTIONS file """ _check_portname(name) pkg = next(iter(configuration)) conf_ptr = configuration[pkg] dirname = _options_dir(name) if not os.path.isdir(dirname): try: os.makedirs(dirname) except OSError as exc: raise CommandExecutionError(f"Unable to make {dirname}: {exc}") with salt.utils.files.fopen(os.path.join(dirname, "options"), "w") as fp_: sorted_options = list(conf_ptr) sorted_options.sort() fp_.write( salt.utils.stringutils.to_str( "# This file was auto-generated by Salt (http://saltstack.com)\n" "# Options for {0}\n" "_OPTIONS_READ={0}\n" "_FILE_COMPLETE_OPTIONS_LIST={1}\n".format( pkg, " ".join(sorted_options) ) ) ) opt_tmpl = "OPTIONS_FILE_{0}SET+={1}\n" for opt in sorted_options: fp_.write( salt.utils.stringutils.to_str( opt_tmpl.format("" if conf_ptr[opt] == "on" else "UN", opt) ) ) def _normalize(val): """ Fix Salt's yaml-ification of on/off, and otherwise normalize the on/off values to be used in writing the options file """ if isinstance(val, bool): return "on" if val else "off" return str(val).lower() def install(name, clean=True): """ Install a port from the ports tree. Installs using ``BATCH=yes`` for non-interactive building. To set config options for a given port, use :mod:`ports.config <salt.modules.freebsdports.config>`. clean : True If ``True``, cleans after installation. Equivalent to running ``make install clean BATCH=yes``. .. note:: It may be helpful to run this function using the ``-t`` option to set a higher timeout, since compiling a port may cause the Salt command to exceed the default timeout. CLI Example: .. code-block:: bash salt -t 1200 '*' ports.install security/nmap """ portpath = _check_portname(name) old = __salt__["pkg.list_pkgs"]() if old.get(name.rsplit("/")[-1]): deinstall(name) cmd = ["make", "install"] if clean: cmd.append("clean") cmd.append("BATCH=yes") result = __salt__["cmd.run_all"]( cmd, cwd=portpath, reset_system_locale=False, python_shell=False ) if result["retcode"] != 0: __context__["ports.install_error"] = result["stderr"] __context__.pop("pkg.list_pkgs", None) new = __salt__["pkg.list_pkgs"]() ret = salt.utils.data.compare_dicts(old, new) if not ret and result["retcode"] == 0: # No change in package list, but the make install was successful. # Assume that the installation was a recompile with new options, and # set return dict so that changes are detected by the ports.installed # state. ret = {name: {"old": old.get(name, ""), "new": new.get(name, "")}} return ret def deinstall(name): """ De-install a port. CLI Example: .. code-block:: bash salt '*' ports.deinstall security/nmap """ portpath = _check_portname(name) old = __salt__["pkg.list_pkgs"]() result = __salt__["cmd.run_all"]( ["make", "deinstall", "BATCH=yes"], cwd=portpath, python_shell=False ) __context__.pop("pkg.list_pkgs", None) new = __salt__["pkg.list_pkgs"]() return salt.utils.data.compare_dicts(old, new) def rmconfig(name): """ Clear the cached options for the specified port; run a ``make rmconfig`` name The name of the port to clear CLI Example: .. code-block:: bash salt '*' ports.rmconfig security/nmap """ portpath = _check_portname(name) return __salt__["cmd.run"](["make", "rmconfig"], cwd=portpath, python_shell=False) def showconfig(name, default=False, dict_return=False): """ Show the configuration options for a given port. default : False Show the default options for a port (not necessarily the same as the current configuration) dict_return : False Instead of returning the output of ``make showconfig``, return the data in an dictionary CLI Example: .. code-block:: bash salt '*' ports.showconfig security/nmap salt '*' ports.showconfig security/nmap default=True """ portpath = _check_portname(name) if default and _options_file_exists(name): saved_config = showconfig(name, default=False, dict_return=True) rmconfig(name) if _options_file_exists(name): raise CommandExecutionError("Unable to get default configuration") default_config = showconfig(name, default=False, dict_return=dict_return) _write_options(name, saved_config) return default_config try: result = __salt__["cmd.run_all"]( ["make", "showconfig"], cwd=portpath, python_shell=False ) output = result["stdout"].splitlines() if result["retcode"] != 0: error = result["stderr"] else: error = "" except TypeError: error = result if error: msg = f"Error running 'make showconfig' for {name}: {error}" log.error(msg) raise SaltInvocationError(msg) if not dict_return: return "\n".join(output) if (not output) or ("configuration options" not in output[0]): return {} try: pkg = output[0].split()[-1].rstrip(":") except (IndexError, AttributeError, TypeError) as exc: log.error("Unable to get pkg-version string: %s", exc) return {} ret = {pkg: {}} output = output[1:] for line in output: try: opt, val, desc = re.match(r"\s+([^=]+)=(off|on): (.+)", line).groups() except AttributeError: continue ret[pkg][opt] = val if not ret[pkg]: return {} return ret def config(name, reset=False, **kwargs): """ Modify configuration options for a given port. Multiple options can be specified. To see the available options for a port, use :mod:`ports.showconfig <salt.modules.freebsdports.showconfig>`. name The port name, in ``category/name`` format reset : False If ``True``, runs a ``make rmconfig`` for the port, clearing its configuration before setting the desired options CLI Examples: .. code-block:: bash salt '*' ports.config security/nmap IPV6=off """ portpath = _check_portname(name) if reset: rmconfig(name) configuration = showconfig(name, dict_return=True) if not configuration: raise CommandExecutionError(f"Unable to get port configuration for '{name}'") # Get top-level key for later reference pkg = next(iter(configuration)) conf_ptr = configuration[pkg] opts = {str(x): _normalize(kwargs[x]) for x in kwargs if not x.startswith("_")} bad_opts = [x for x in opts if x not in conf_ptr] if bad_opts: raise SaltInvocationError( "The following opts are not valid for port {}: {}".format( name, ", ".join(bad_opts) ) ) bad_vals = [f"{x}={y}" for x, y in opts.items() if y not in ("on", "off")] if bad_vals: raise SaltInvocationError( "The following key/value pairs are invalid: {}".format(", ".join(bad_vals)) ) conf_ptr.update(opts) _write_options(name, configuration) new_config = showconfig(name, dict_return=True) try: new_config = new_config[next(iter(new_config))] except (StopIteration, TypeError): return False return all(conf_ptr[x] == new_config.get(x) for x in conf_ptr) def update(extract=False): """ Update the ports tree extract : False If ``True``, runs a ``portsnap extract`` after fetching, should be used for first-time installation of the ports tree. CLI Example: .. code-block:: bash salt '*' ports.update """ result = __salt__["cmd.run_all"](_portsnap() + ["fetch"], python_shell=False) if not result["retcode"] == 0: raise CommandExecutionError( "Unable to fetch ports snapshot: {}".format(result["stderr"]) ) ret = [] try: patch_count = re.search(r"Fetching (\d+) patches", result["stdout"]).group(1) except AttributeError: patch_count = 0 try: new_port_count = re.search( r"Fetching (\d+) new ports or files", result["stdout"] ).group(1) except AttributeError: new_port_count = 0 ret.append(f"Applied {patch_count} new patches") ret.append(f"Fetched {new_port_count} new ports or files") if extract: result = __salt__["cmd.run_all"](_portsnap() + ["extract"], python_shell=False) if not result["retcode"] == 0: raise CommandExecutionError( "Unable to extract ports snapshot {}".format(result["stderr"]) ) result = __salt__["cmd.run_all"](_portsnap() + ["update"], python_shell=False) if not result["retcode"] == 0: raise CommandExecutionError( "Unable to apply ports snapshot: {}".format(result["stderr"]) ) __context__.pop("ports.list_all", None) return "\n".join(ret) def list_all(): """ Lists all ports available. CLI Example: .. code-block:: bash salt '*' ports.list_all .. warning:: Takes a while to run, and returns a **LOT** of output """ if "ports.list_all" not in __context__: __context__["ports.list_all"] = [] for path, dirs, files in salt.utils.path.os_walk("/usr/ports"): stripped = path[len("/usr/ports") :] if stripped.count("/") != 2 or stripped.endswith("/CVS"): continue __context__["ports.list_all"].append(stripped[1:]) return __context__["ports.list_all"] def search(name): """ Search for matches in the ports tree. Globs are supported, and the category is optional CLI Examples: .. code-block:: bash salt '*' ports.search 'security/*' salt '*' ports.search 'security/n*' salt '*' ports.search nmap .. warning:: Takes a while to run """ name = str(name) all_ports = list_all() if "/" in name: if name.count("/") > 1: raise SaltInvocationError( "Invalid search string '{0}'. Port names cannot have more " "than one slash" ) else: return fnmatch.filter(all_ports, name) else: ret = [] for port in all_ports: if fnmatch.fnmatch(port.rsplit("/")[-1], name): ret.append(port) return ret