blob: 2a4759e6bc4222cd7030328a4b62b9a899a915a5 [file]
import os
import re
from solrorbit.exceptions import SystemSetupError
from solrorbit.utils import io
class JdkResolver:
SYS_PROP_REGEX = r".*%s.*=\s?(.*)"
def __init__(self, executor):
self.executor = executor
def resolve_jdk_path(self, host, majors):
"""
Resolves the path to the JDK with the provided major version(s). It checks the versions in the same order specified in ``majors``
and will return the first match. To achieve this, it first checks the major version x in the environment variable ``JAVAx_HOME``
and falls back to ``JAVA_HOME``. It also ensures that the environment variable points to the right JDK version.
If no appropriate version is found, a ``SystemSetupError`` is raised.
:param host: The host on which to resolve the JDK path
:param majors: Either a list of major versions to check or a single version as an ``int``.
:return: A tuple of (major version, path to Java home directory).
"""
if isinstance(majors, int):
return majors, self._resolve_jdk_path(host, [majors])
else:
return majors, self._resolve_jdk_path(host, majors)
def _resolve_jdk_path(self, host, majors):
"""
Resolves the path to a JDK with one of the provided major versions.
:param majors: The major versions to check.
:return: The resolved path to the JDK
"""
defined_env_vars = self._get_defined_env_vars(host)
java_home_env_var_names = [f"JAVA{major}_HOME" for major in majors]
java_home_env_var_names.append("JAVA_HOME")
resolved_major_to_java_home_path = {}
for java_home_env_var_name in java_home_env_var_names:
if java_home_env_var_name in defined_env_vars:
major_to_java_home_path = self._resolve_major_from_java_home(host, java_home_env_var_name,
defined_env_vars[java_home_env_var_name])
if major_to_java_home_path:
resolved_major_to_java_home_path.update(major_to_java_home_path)
for major in majors:
if major in resolved_major_to_java_home_path:
return resolved_major_to_java_home_path[major]
checked_env_vars = self._checked_env_vars(majors)
raise SystemSetupError(f"Install a JDK with one of the versions {majors} and point to it with one of {checked_env_vars}.")
def _get_defined_env_vars(self, host):
env_vars_as_strings = self.executor.execute(host, "printenv", output=True)
return dict(env_var_as_string.split("=") for env_var_as_string in env_vars_as_strings)
def _resolve_major_from_java_home(self, host, java_home_env_var_name, java_home_env_var_value):
if java_home_env_var_value:
major_version = self._major_version(host, java_home_env_var_value)
if java_home_env_var_name in ("JAVA_HOME", f"JAVA{major_version}_HOME"):
return {major_version: java_home_env_var_value}
def _major_version(self, host, java_home):
"""
Determines the major version number of JDK available at the provided JAVA_HOME directory.
:param java_home: The JAVA_HOME directory to check.
:return: An int, representing the major version number of the JDK available at ``java_home``.
"""
version = self._system_property(host, java_home, "java.vm.specification.version")
# are we under the "old" (pre Java 9) or the new (Java 9+) version scheme?
if version.startswith("1."):
return int(version[2])
else:
return int(version)
def _system_property(self, host, java_home, system_property_name):
lines = self.executor.execute(host, f"{self._java(java_home)} -XshowSettings:properties -version", output=True)
# matches e.g. " java.runtime.version = 1.8.0_121-b13" and captures "1.8.0_121-b13"
sys_prop_pattern = re.compile(JdkResolver.SYS_PROP_REGEX % system_property_name)
for line in lines:
m = sys_prop_pattern.match(line)
if m:
return m.group(1)
return None
def _java(self, java_home):
return io.escape_path(os.path.join(java_home, "bin", "java"))
def _checked_env_vars(self, majors):
"""
Provides a list of environment variables that are checked for the given list of major versions.
:param majors: A list of major versions.
:return: A list of checked environment variables.
"""
checked = [f"JAVA{major}_HOME" for major in majors]
checked.append("JAVA_HOME")
return checked