D7net
Home
Console
Upload
information
Create File
Create Folder
About
Tools
:
/
proc
/
self
/
root
/
opt
/
saltstack
/
salt
/
lib
/
python3.10
/
site-packages
/
salt
/
states
/
Filename :
virtualenv_mod.py
back
Copy
""" Setup of Python virtualenv sandboxes. .. versionadded:: 0.17.0 """ import logging import os import salt.utils.functools import salt.utils.platform import salt.utils.versions import salt.version from salt.exceptions import CommandExecutionError, CommandNotFoundError log = logging.getLogger(__name__) # Define the module's virtual name __virtualname__ = "virtualenv" def __virtual__(): if "virtualenv.create" in __salt__: return __virtualname__ return (False, "virtualenv module could not be loaded") def managed( name, venv_bin=None, requirements=None, system_site_packages=False, distribute=False, use_wheel=False, clear=False, python=None, extra_search_dir=None, never_download=None, prompt=None, user=None, cwd=None, index_url=None, extra_index_url=None, pre_releases=False, no_deps=False, pip_download=None, pip_download_cache=None, pip_exists_action=None, pip_ignore_installed=False, proxy=None, use_vt=False, env_vars=None, no_use_wheel=False, pip_upgrade=False, pip_pkgs=None, pip_no_cache_dir=False, pip_cache_dir=None, process_dependency_links=False, no_binary=None, **kwargs, ): """ Create a virtualenv and optionally manage it with pip name Path to the virtualenv. venv_bin: virtualenv The name (and optionally path) of the virtualenv command. This can also be set globally in the minion config file as ``virtualenv.venv_bin``. requirements: None Path to a pip requirements file. If the path begins with ``salt://`` the file will be transferred from the master file server. use_wheel: False Prefer wheel archives (requires pip >= 1.4). python: None Python executable used to build the virtualenv. When Salt is installed from a onedir package. You will likely want to specify which python interperter should be used. user: None The user under which to run virtualenv and pip. cwd: None Path to the working directory where `pip install` is executed. no_deps: False Pass `--no-deps` to `pip install`. pip_exists_action: None Default action of pip when a path already exists: (s)witch, (i)gnore, (w)ipe, (b)ackup. proxy: None Proxy address which is passed to `pip install`. env_vars: None Set environment variables that some builds will depend on. For example, a Python C-module may have a Makefile that needs INCLUDE_PATH set to pick up a header file while compiling. no_use_wheel: False Force to not use wheel archives (requires pip>=1.4) no_binary Force to not use binary packages (requires pip >= 7.0.0) Accepts either :all: to disable all binary packages, :none: to empty the set, or a list of one or more packages pip_upgrade: False Pass `--upgrade` to `pip install`. pip_pkgs: None As an alternative to `requirements`, pass a list of pip packages that should be installed. process_dependency_links: False Run pip install with the --process_dependency_links flag. .. versionadded:: 2017.7.0 Also accepts any kwargs that the virtualenv module will. However, some kwargs, such as the ``pip`` option, require ``- distribute: True``. .. code-block:: yaml /var/www/myvirtualenv.com: virtualenv.managed: - system_site_packages: False - requirements: salt://REQUIREMENTS.txt - env_vars: PATH_VAR: '/usr/local/bin/' Current versions of Salt use onedir packages and will use onedir python interpreter by default. If you've installed Salt via out package repository. You will likely want to provide the path to the interpreter with which you would like to be used to create the virtual environment. The interpreter can be specified by providing the `python` option. """ ret = {"name": name, "result": True, "comment": "", "changes": {}} if "virtualenv.create" not in __salt__: ret["result"] = False ret["comment"] = "Virtualenv was not detected on this system" return ret if salt.utils.platform.is_windows(): venv_py = os.path.join(name, "Scripts", "python.exe") else: venv_py = os.path.join(name, "bin", "python") venv_exists = os.path.exists(venv_py) # Bail out early if the specified requirements file can't be found if requirements and requirements.startswith("salt://"): cached_requirements = __salt__["cp.is_cached"](requirements, __env__) if not cached_requirements: # It's not cached, let's cache it. cached_requirements = __salt__["cp.cache_file"](requirements, __env__) # Check if the master version has changed. if cached_requirements and __salt__["cp.hash_file"]( requirements, __env__ ) != __salt__["cp.hash_file"](cached_requirements, __env__): cached_requirements = __salt__["cp.cache_file"](requirements, __env__) if not cached_requirements: ret.update( { "result": False, "comment": "pip requirements file '{}' not found".format( requirements ), } ) return ret requirements = cached_requirements # If it already exists, grab the version for posterity if venv_exists and clear: ret["changes"]["cleared_packages"] = __salt__["pip.freeze"](bin_env=name) ret["changes"]["old"] = __salt__["cmd.run_stderr"](f"{venv_py} -V").strip("\n") # Create (or clear) the virtualenv if __opts__["test"]: if venv_exists and clear: ret["result"] = None ret["comment"] = f"Virtualenv {name} is set to be cleared" return ret if venv_exists and not clear: ret["comment"] = f"Virtualenv {name} is already created" return ret ret["result"] = None ret["comment"] = f"Virtualenv {name} is set to be created" return ret if not venv_exists or (venv_exists and clear): try: venv_ret = __salt__["virtualenv.create"]( name, venv_bin=venv_bin, system_site_packages=system_site_packages, distribute=distribute, clear=clear, python=python, extra_search_dir=extra_search_dir, never_download=never_download, prompt=prompt, user=user, use_vt=use_vt, **kwargs, ) except CommandNotFoundError as err: ret["result"] = False ret["comment"] = f"Failed to create virtualenv: {err}" return ret if venv_ret["retcode"] != 0: ret["result"] = False ret["comment"] = venv_ret["stdout"] + venv_ret["stderr"] return ret ret["result"] = True ret["changes"]["new"] = __salt__["cmd.run_stderr"](f"{venv_py} -V").strip("\n") if clear: ret["comment"] = "Cleared existing virtualenv" else: ret["comment"] = "Created new virtualenv" elif venv_exists: ret["comment"] = "virtualenv exists" # Check that the pip binary supports the 'use_wheel' option if use_wheel: min_version = "1.4" max_version = "9.0.3" cur_version = __salt__["pip.version"](bin_env=name) too_low = salt.utils.versions.compare( ver1=cur_version, oper="<", ver2=min_version ) too_high = salt.utils.versions.compare( ver1=cur_version, oper=">", ver2=max_version ) if too_low or too_high: ret["result"] = False ret["comment"] = ( "The 'use_wheel' option is only supported in " "pip between {} and {}. The version of pip detected " "was {}.".format(min_version, max_version, cur_version) ) return ret # Check that the pip binary supports the 'no_use_wheel' option if no_use_wheel: min_version = "1.4" max_version = "9.0.3" cur_version = __salt__["pip.version"](bin_env=name) too_low = salt.utils.versions.compare( ver1=cur_version, oper="<", ver2=min_version ) too_high = salt.utils.versions.compare( ver1=cur_version, oper=">", ver2=max_version ) if too_low or too_high: ret["result"] = False ret["comment"] = ( "The 'no_use_wheel' option is only supported in " "pip between {} and {}. The version of pip detected " "was {}.".format(min_version, max_version, cur_version) ) return ret # Check that the pip binary supports the 'no_binary' option if no_binary: min_version = "7.0.0" cur_version = __salt__["pip.version"](bin_env=name) too_low = salt.utils.versions.compare( ver1=cur_version, oper="<", ver2=min_version ) if too_low: ret["result"] = False ret["comment"] = ( "The 'no_binary' option is only supported in " "pip {} and newer. The version of pip detected " "was {}.".format(min_version, cur_version) ) return ret # Populate the venv via a requirements file if requirements or pip_pkgs: try: before = set(__salt__["pip.freeze"](bin_env=name, user=user, use_vt=use_vt)) except CommandExecutionError as exc: ret["result"] = False ret["comment"] = exc.strerror return ret if requirements: if isinstance(requirements, str): req_canary = requirements.split(",")[0] elif isinstance(requirements, list): req_canary = requirements[0] else: raise TypeError("pip requirements must be either a string or a list") if req_canary != os.path.abspath(req_canary): cwd = os.path.dirname(os.path.abspath(req_canary)) pip_ret = __salt__["pip.install"]( pkgs=pip_pkgs, requirements=requirements, process_dependency_links=process_dependency_links, bin_env=name, use_wheel=use_wheel, no_use_wheel=no_use_wheel, no_binary=no_binary, user=user, cwd=cwd, index_url=index_url, extra_index_url=extra_index_url, download=pip_download, download_cache=pip_download_cache, pre_releases=pre_releases, exists_action=pip_exists_action, ignore_installed=pip_ignore_installed, upgrade=pip_upgrade, no_deps=no_deps, proxy=proxy, use_vt=use_vt, env_vars=env_vars, no_cache_dir=pip_no_cache_dir, cache_dir=pip_cache_dir, **kwargs, ) ret["result"] &= pip_ret["retcode"] == 0 if pip_ret["retcode"] > 0: ret["comment"] = "{}\n{}\n{}".format( ret["comment"], pip_ret["stdout"], pip_ret["stderr"] ) after = set(__salt__["pip.freeze"](bin_env=name)) new = list(after - before) old = list(before - after) if new or old: ret["changes"]["packages"] = { "new": new if new else "", "old": old if old else "", } return ret manage = salt.utils.functools.alias_function(managed, "manage")