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/chroot.py |
""" Module for chroot :maintainer: Alberto Planas <aplanas@suse.com> :maturity: new :depends: None :platform: Linux """ import copy import logging import os import sys import tempfile import salt import salt.client.ssh.state import salt.client.ssh.wrapper.state import salt.defaults.exitcodes import salt.exceptions import salt.utils.args import salt.utils.files __func_alias__ = {"apply_": "apply"} log = logging.getLogger(__name__) def __virtual__(): """ Chroot command is required. """ if __utils__["path.which"]("chroot") is not None: return True else: return (False, "Module chroot requires the command chroot") def exist(root): """ Return True if the chroot environment is present. root Path to the chroot environment CLI Example: .. code-block:: bash salt myminion chroot.exist /chroot """ dev = os.path.join(root, "dev") proc = os.path.join(root, "proc") sys = os.path.join(root, "sys") return all(os.path.isdir(i) for i in (root, dev, proc, sys)) def create(root): """ Create a basic chroot environment. Note that this environment is not functional. The caller needs to install the minimal required binaries, including Python if chroot.call is called. root Path to the chroot environment CLI Example: .. code-block:: bash salt myminion chroot.create /chroot """ if not exist(root): dev = os.path.join(root, "dev") proc = os.path.join(root, "proc") sys = os.path.join(root, "sys") try: os.makedirs(dev, mode=0o755) os.makedirs(proc, mode=0o555) os.makedirs(sys, mode=0o555) except OSError as e: log.error("Error when trying to create chroot directories: %s", e) return False return True def in_chroot(): """ Return True if the process is inside a chroot jail .. versionadded:: 3004 CLI Example: .. code-block:: bash salt myminion chroot.in_chroot """ result = False try: # We cannot assume that we are "root", so we cannot read # '/proc/1/root', that is required for the usual way of # detecting that we are in a chroot jail. We use the debian # ischroot method. with salt.utils.files.fopen( "/proc/1/mountinfo" ) as root_fd, salt.utils.files.fopen("/proc/self/mountinfo") as self_fd: root_mountinfo = root_fd.read() self_mountinfo = self_fd.read() result = root_mountinfo != self_mountinfo except OSError: pass return result def call(root, function, *args, **kwargs): """ Executes a Salt function inside a chroot environment. The chroot does not need to have Salt installed, but Python is required. root Path to the chroot environment function Salt execution module function CLI Example: .. code-block:: bash salt myminion chroot.call /chroot test.ping salt myminion chroot.call /chroot ssh.set_auth_key user key=mykey """ if not function: raise salt.exceptions.CommandExecutionError("Missing function parameter") if not exist(root): raise salt.exceptions.CommandExecutionError("Chroot environment not found") # Create a temporary directory inside the chroot where we can # untar salt-thin thin_dest_path = tempfile.mkdtemp(dir=root) thin_path = __utils__["thin.gen_thin"]( __opts__["cachedir"], extra_mods=__salt__["config.option"]("thin_extra_mods", ""), so_mods=__salt__["config.option"]("thin_so_mods", ""), ) # Some bug in Salt is preventing us to use `archive.tar` here. A # AsyncZeroMQReqChannel is not closed at the end of the salt-call, # and makes the client never exit. # # stdout = __salt__['archive.tar']('xzf', thin_path, dest=thin_dest_path) # stdout = __salt__["cmd.run"](["tar", "xzf", thin_path, "-C", thin_dest_path]) if stdout: __utils__["files.rm_rf"](thin_dest_path) return {"result": False, "comment": stdout} chroot_path = os.path.join(os.path.sep, os.path.relpath(thin_dest_path, root)) try: safe_kwargs = salt.utils.args.clean_kwargs(**kwargs) salt_argv = ( [ f"python{sys.version_info[0]}", os.path.join(chroot_path, "salt-call"), "--metadata", "--local", "--log-file", os.path.join(chroot_path, "log"), "--cachedir", os.path.join(chroot_path, "cache"), "--out", "json", "-l", "quiet", "--", function, ] + list(args) + [f"{k}={v}" for (k, v) in safe_kwargs.items()] ) ret = __salt__["cmd.run_chroot"](root, [str(x) for x in salt_argv]) # Process "real" result in stdout try: data = __utils__["json.find_json"](ret["stdout"]) local = data.get("local", data) if isinstance(local, dict) and "retcode" in local: __context__["retcode"] = local["retcode"] return local.get("return", data) except ValueError: return { "result": False, "retcode": ret["retcode"], "comment": {"stdout": ret["stdout"], "stderr": ret["stderr"]}, } finally: __utils__["files.rm_rf"](thin_dest_path) def apply_(root, mods=None, **kwargs): """ Apply an state inside a chroot. This function will call `chroot.highstate` or `chroot.sls` based on the arguments passed to this function. It exists as a more intuitive way of applying states. root Path to the chroot environment For a formal description of the possible parameters accepted in this function, check `state.apply_` documentation. CLI Example: .. code-block:: bash salt myminion chroot.apply /chroot salt myminion chroot.apply /chroot stuff salt myminion chroot.apply /chroot stuff pillar='{"foo": "bar"}' """ if mods: return sls(root, mods, **kwargs) return highstate(root, **kwargs) def _create_and_execute_salt_state(root, chunks, file_refs, test, hash_type): """ Create the salt_state tarball, and execute in the chroot """ # Create the tar containing the state pkg and relevant files. salt.client.ssh.wrapper.state._cleanup_slsmod_low_data(chunks) with salt.fileclient.get_file_client(__opts__) as client: trans_tar = salt.client.ssh.state.prep_trans_tar( client, chunks, file_refs, __pillar__.value(), root, ) trans_tar_sum = salt.utils.hashutils.get_hash(trans_tar, hash_type) ret = None # Create a temporary directory inside the chroot where we can move # the salt_state.tgz salt_state_path = tempfile.mkdtemp(dir=root) salt_state_path = os.path.join(salt_state_path, "salt_state.tgz") salt_state_path_in_chroot = salt_state_path.replace(root, "", 1) try: salt.utils.files.copyfile(trans_tar, salt_state_path) ret = call( root, "state.pkg", salt_state_path_in_chroot, test=test, pkg_sum=trans_tar_sum, hash_type=hash_type, ) finally: __utils__["files.rm_rf"](salt_state_path) return ret def sls(root, mods, saltenv="base", test=None, exclude=None, **kwargs): """ Execute the states in one or more SLS files inside the chroot. root Path to the chroot environment saltenv Specify a salt fileserver environment to be used when applying states mods List of states to execute test Run states in test-only (dry-run) mode exclude Exclude specific states from execution. Accepts a list of sls names, a comma-separated string of sls names, or a list of dictionaries containing ``sls`` or ``id`` keys. Glob-patterns may be used to match multiple states. For a formal description of the possible parameters accepted in this function, check `state.sls` documentation. CLI Example: .. code-block:: bash salt '*' chroot.sls /chroot stuff pillar='{"foo": "bar"}' """ # Get a copy of the pillar data, to avoid overwriting the current # pillar, instead the one delegated pillar = copy.deepcopy(__pillar__.value()) pillar.update(kwargs.get("pillar", {})) # Clone the options data and apply some default values. May not be # needed, as this module just delegate opts = salt.utils.state.get_sls_opts(__opts__, **kwargs) st_ = salt.client.ssh.state.SSHHighState( opts, pillar, __salt__, salt.fileclient.get_file_client(__opts__) ) if isinstance(mods, str): mods = mods.split(",") with st_: high_data, errors = st_.render_highstate({saltenv: mods}) if exclude: if isinstance(exclude, str): exclude = exclude.split(",") if "__exclude__" in high_data: high_data["__exclude__"].extend(exclude) else: high_data["__exclude__"] = exclude high_data, ext_errors = st_.state.reconcile_extend(high_data) errors += ext_errors errors += st_.state.verify_high(high_data) if errors: return errors high_data, req_in_errors = st_.state.requisite_in(high_data) errors += req_in_errors if errors: return errors high_data = st_.state.apply_exclude(high_data) # Compile and verify the raw chunks chunks = st_.state.compile_high_data(high_data) file_refs = salt.client.ssh.state.lowstate_file_refs( chunks, salt.client.ssh.wrapper.state._merge_extra_filerefs( kwargs.get("extra_filerefs", ""), opts.get("extra_filerefs", "") ), ) hash_type = opts["hash_type"] return _create_and_execute_salt_state(root, chunks, file_refs, test, hash_type) def highstate(root, **kwargs): """ Retrieve the state data from the salt master for this minion and execute it inside the chroot. root Path to the chroot environment For a formal description of the possible parameters accepted in this function, check `state.highstate` documentation. CLI Example: .. code-block:: bash salt myminion chroot.highstate /chroot salt myminion chroot.highstate /chroot pillar='{"foo": "bar"}' """ # Get a copy of the pillar data, to avoid overwriting the current # pillar, instead the one delegated pillar = copy.deepcopy(__pillar__.value()) pillar.update(kwargs.get("pillar", {})) # Clone the options data and apply some default values. May not be # needed, as this module just delegate opts = salt.utils.state.get_sls_opts(__opts__, **kwargs) with salt.client.ssh.state.SSHHighState( opts, pillar, __salt__, salt.fileclient.get_file_client(__opts__) ) as st_: # Compile and verify the raw chunks chunks = st_.compile_low_chunks() file_refs = salt.client.ssh.state.lowstate_file_refs( chunks, salt.client.ssh.wrapper.state._merge_extra_filerefs( kwargs.get("extra_filerefs", ""), opts.get("extra_filerefs", "") ), ) # Check for errors for chunk in chunks: if not isinstance(chunk, dict): __context__["retcode"] = 1 return chunks test = kwargs.pop("test", False) hash_type = opts["hash_type"] return _create_and_execute_salt_state(root, chunks, file_refs, test, hash_type)