def setup(self, runtime_env: RuntimeEnv, context: RuntimeEnvContext, logger: Optional[logging.Logger] = default_logger): if not runtime_env.has_conda() and not runtime_env.has_pip(): return logger.debug("Setting up conda or pip for runtime_env: " f"{runtime_env.serialize()}") if runtime_env.conda_env_name(): conda_env_name = runtime_env.conda_env_name() else: conda_dict = get_conda_dict(runtime_env, self._resources_dir) protocol, hash = parse_uri(runtime_env.conda_uri()) conda_env_name = self._get_path_from_hash(hash) assert conda_dict is not None ray_pip = current_ray_pip_specifier(logger=logger) if ray_pip: extra_pip_dependencies = [ray_pip, "ray[default]"] elif runtime_env.get_extension("_inject_current_ray") == "True": extra_pip_dependencies = ( _resolve_install_from_source_ray_dependencies()) else: extra_pip_dependencies = [] conda_dict = inject_dependencies(conda_dict, _current_py_version(), extra_pip_dependencies) # It is not safe for multiple processes to install conda envs # concurrently, even if the envs are different, so use a global # lock for all conda installs. # See https://github.com/ray-project/ray/issues/17086 file_lock_name = "ray-conda-install.lock" with FileLock(os.path.join(self._resources_dir, file_lock_name)): try: conda_yaml_file = os.path.join(self._resources_dir, "environment.yml") with open(conda_yaml_file, "w") as file: yaml.dump(conda_dict, file) if conda_env_name in self._created_envs: logger.debug(f"Conda env {conda_env_name} already " "created, skipping creation.") else: create_conda_env(conda_yaml_file, prefix=conda_env_name, logger=logger) self._created_envs.add(conda_env_name) finally: os.remove(conda_yaml_file) if runtime_env.get_extension("_inject_current_ray"): _inject_ray_to_conda_site(conda_path=conda_env_name, logger=logger) context.py_executable = "python" context.command_prefix += get_conda_activate_commands(conda_env_name) logger.info( f"Finished setting up runtime environment at {conda_env_name}")
def setup_worker(input_args): # remaining_args contains the arguments to the original worker command, # minus the python executable, e.g. default_worker.py --node-ip-address=... args, remaining_args = parser.parse_known_args(args=input_args) commands = [] py_executable: str = sys.executable runtime_env: dict = json.loads(args.serialized_runtime_env or "{}") runtime_env_context: RuntimeEnvContext = None if args.serialized_runtime_env_context: runtime_env_context = RuntimeEnvContext.deserialize( args.serialized_runtime_env_context) # Ray client server setups runtime env by itself instead of agent. if runtime_env.get("conda") or runtime_env.get("pip"): if not args.serialized_runtime_env_context: runtime_env_context = RuntimeEnvContext(args.session_dir) setup_conda_or_pip(runtime_env, runtime_env_context, logger=logger) if runtime_env_context and runtime_env_context.working_dir is not None: commands += [f"cd {runtime_env_context.working_dir}"] # Insert the working_dir as the first entry in PYTHONPATH. This is # compatible with users providing their own PYTHONPATH in env_vars. env_vars = runtime_env.get("env_vars", None) or {} python_path = runtime_env_context.working_dir if "PYTHONPATH" in env_vars: python_path += os.pathsep + runtime_env["PYTHONPATH"] env_vars["PYTHONPATH"] = python_path runtime_env["env_vars"] = env_vars # Add a conda activate command prefix if using a conda env. if runtime_env_context and runtime_env_context.conda_env_name is not None: py_executable = "python" conda_activate_commands = get_conda_activate_commands( runtime_env_context.conda_env_name) if (conda_activate_commands): commands += conda_activate_commands elif runtime_env.get("conda"): logger.warning( "Conda env name is not found in context, " "but conda exists in runtime env. The runtime env %s, " "the context %s.", args.serialized_runtime_env, args.serialized_runtime_env_context) commands += [" ".join([f"exec {py_executable}"] + remaining_args)] command_str = " && ".join(commands) # update env vars if runtime_env.get("env_vars"): env_vars = runtime_env["env_vars"] os.environ.update(env_vars) os.execvp("bash", ["bash", "-c", command_str])
def setup_conda_or_pip(runtime_env: dict, context: RuntimeEnvContext, logger: Optional[logging.Logger] = None): if logger is None: logger = logging.getLogger(__name__) if not runtime_env.get("conda") and not runtime_env.get("pip"): return logger.debug(f"Setting up conda or pip for runtime_env: {runtime_env}") conda_dict = get_conda_dict(runtime_env, context.resources_dir) if isinstance(runtime_env.get("conda"), str): conda_env_name = runtime_env["conda"] else: assert conda_dict is not None ray_pip = current_ray_pip_specifier(logger) if ray_pip: extra_pip_dependencies = [ray_pip, "ray[default]"] elif runtime_env.get("_inject_current_ray"): extra_pip_dependencies = ( _resolve_install_from_source_ray_dependencies()) else: extra_pip_dependencies = [] conda_dict = inject_dependencies(conda_dict, _current_py_version(), extra_pip_dependencies) logger.info(f"Setting up conda environment with {runtime_env}") # It is not safe for multiple processes to install conda envs # concurrently, even if the envs are different, so use a global # lock for all conda installs. # See https://github.com/ray-project/ray/issues/17086 file_lock_name = "ray-conda-install.lock" with FileLock(os.path.join(context.resources_dir, file_lock_name)): conda_dir = os.path.join(context.resources_dir, "conda") try_to_create_directory(conda_dir) conda_yaml_path = os.path.join(conda_dir, "environment.yml") with open(conda_yaml_path, "w") as file: # Sort keys because we hash based on the file contents, # and we don't want the hash to depend on the order # of the dependencies. yaml.dump(conda_dict, file, sort_keys=True) conda_env_name = get_or_create_conda_env(conda_yaml_path, conda_dir, logger=logger) if runtime_env.get("_inject_current_ray"): conda_path = os.path.join(conda_dir, conda_env_name) _inject_ray_to_conda_site(conda_path, logger) context.py_executable = "python" context.command_prefix += get_conda_activate_commands(conda_env_name) logger.info(f"Finished setting up runtime environment at {conda_env_name}")
def modify_context( self, uri: str, runtime_env: "RuntimeEnv", # noqa: F821 context: RuntimeEnvContext, logger: Optional[logging.Logger] = default_logger, ): if not runtime_env.has_conda(): return if runtime_env.conda_env_name(): conda_env_name = runtime_env.conda_env_name() else: protocol, hash = parse_uri(runtime_env.conda_uri()) conda_env_name = self._get_path_from_hash(hash) context.py_executable = "python" context.command_prefix += get_conda_activate_commands(conda_env_name)