You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

233 lines
8.1 KiB

import logging
import re
import os
import subprocess
import sys
from uuid import UUID
from distutils.spawn import find_executable
PY3 = sys.version_info[0] == 3
levelNames = {
logging.ERROR : 'ERROR',
logging.WARNING : 'WARN',
logging.INFO : 'INFO'
}
if PY3:
string_types = str
else:
string_types = basestring
# keep consistent with DurationUtil.scala
duration_pattern = re.compile("^([1-9][0-9]*)\s*(s|sec|secs|second|seconds|m|min|mins|minute|minutes|h|hr|hrs|hour|hours|d|day|days|ms|cs|ds)$")
class MADRESTException(Exception):
def to_json(self):
return {"message": [{"type": self.level, "text": self.message}]}
def __init__(self, message, level, status_code=500):
super(MADRESTException, self).__init__(message)
self.message = message
self.status_code = status_code
self.level = levelNames[level]
def get_field(dict, field_name, default=None, is_optional=False):
"""
Get a field from a dictionary
return the value from `dict`, None if it does not exist and `is_optional` is set to true, otherwise raise exception
"""
try:
return dict[field_name]
except KeyError:
if default is None:
if is_optional:
return None
else:
raise MADRESTException("Required parameter '%s' must be given" % field_name, logging.ERROR, status_code=400)
else:
return default
def check_allowed_params(args_dict, arg_names):
extraneous_args = list(set(args_dict).difference(arg_names))
if len(extraneous_args) > 0:
raise MADRESTException("Unexpected parameter '%s'" % extraneous_args[0], logging.ERROR, status_code=400)
def check_arrays(args_dict, arg_names):
for arg in arg_names:
if not isinstance(args_dict[arg], list):
raise MADRESTException("Parameter '%s' must be an array" % arg, logging.ERROR, status_code=400)
def parse_bool_str(value):
if value == "0" or value.lower() == "false":
return False
elif value == "1" or value.lower() == "true":
return True
else:
raise ValueError("unable to parse value %s" % value)
def check_int(what, value):
if type(value) == int:
return value
else:
try:
if isinstance(value, string_types):
return int(value)
else:
raise ValueError("%s value %s can not be converted to integer" % (what, value))
except ValueError:
raise MADRESTException(what + " is not an integer, %s" % type(value), logging.ERROR, status_code=400)
def check_float(what, value):
if type(value) == float:
return value
else:
try:
if isinstance(value, (string_types, int)) and type(value) != bool:
return float(value)
else:
raise ValueError("%s value %s can not be converted to integer" % (what, value))
except ValueError:
raise MADRESTException(what + " is not a floating point number", logging.ERROR, status_code=400)
def check_flag(what, flag):
if type(flag) == bool:
return flag
else:
try:
if isinstance(flag, string_types):
return parse_bool_str(flag)
if isinstance(flag, int) and (flag == 0 or flag == 1):
return bool(flag)
else:
raise ValueError("unable to parse value %s" % flag)
except Exception:
raise MADRESTException("unsupported '%s' parameter: %s" % (what, flag), logging.ERROR, status_code=400)
def check_valid_uuid(uuid_str):
try:
UUID(uuid_str)
return uuid_str
except:
raise MADRESTException("%s is not a valid uuid" % uuid_str, logging.ERROR, status_code=400)
def check_duration(what, value):
if isinstance(value, string_types):
matches = duration_pattern.findall(value)
if len(matches) == 0:
raise MADRESTException("%s: %s is not a valid duration" % (what, value), logging.ERROR, status_code=400)
else:
return value
else:
raise MADRESTException(what + ": " + value + " is not a duration value", logging.ERROR, status_code=400)
def update_or_keep(updated, original, limits):
if updated is None:
return original
else:
return original.update(updated, limits)
def discover_jvm():
java_home_env = os.getenv("JAVA_HOME")
# distutil.spawn.findexecutable() auto add .exe for win32
java_cmd = "java"
found_jvm = {}
result = {}
jvm_details = get_jvm_details(java_cmd, True)
if jvm_details:
result["active"] = "PATH"
result["activeRunnable"] = jvm_details["status"]["runnable"]
found_jvm["PATH"] = jvm_details
if java_home_env is not None:
java_cmd = os.path.join(java_home_env, "bin", java_cmd)
jvm_details = get_jvm_details(java_cmd)
if jvm_details:
if "active" not in result or jvm_details["status"]["runnable"]:
result["active"] = "JAVA_HOME"
result["activeRunnable"] = jvm_details["status"]["runnable"]
found_jvm["JAVA_HOME"] = jvm_details
if len(found_jvm) > 0:
result["availableJVMs"] = found_jvm
return result
else:
result["ERROR"] = "No JVM Found"
raise MADRESTException("No JVM Found", logging.ERROR, 404)
def get_jvm_details(java_cmd, is_discovered=False):
jvm_details = {"path": java_cmd, "status": {"supported": False}}
fpath, fname = os.path.split(java_cmd)
try:
if fpath:
found_exec = find_executable(fname, fpath)
else:
found_exec = find_executable(fname)
if found_exec:
jvm_details["path"] = found_exec
jvm_details["status"]["runnable"] = True
if sys.platform == 'win32' and ' ' in found_exec:
found_exec = r'"{}"'.format(found_exec)
if PY3:
ver_output = subprocess.getoutput(' '.join([found_exec, "-version"]))
else:
ver_output = subprocess.check_output([found_exec, "-version"], stderr=subprocess.STDOUT)
jvm_ver_search = re.search(".*?version\\s+[\"]?((\\d+)([.](\\d+))?).*", ver_output)
if jvm_ver_search:
matched_groups = [g for g in jvm_ver_search.groups() if g]
jvm_ver_str = matched_groups[0]
jvm_details["version"] = jvm_ver_str
version_error_msg = "Unsupported JVM version: %s, require JVM 1.8+" % jvm_ver_str
if len(matched_groups) == 4:
# Version string has minor number
major_ver = int(matched_groups[1])
minor_ver = int(matched_groups[3])
if major_ver >= 9 or (major_ver == 1 and minor_ver == 8):
jvm_details["status"]["supported"] = True
else:
jvm_details["status"]["ERROR"] = version_error_msg
elif len(matched_groups) == 2:
# Version string only has major number, e.g. the openjdk downloaded from java.net
major_ver = int(matched_groups[1])
if major_ver >= 8 and major_ver <= 20:
jvm_details["status"]["supported"] = True
else:
jvm_details["status"]["ERROR"] = version_error_msg
else:
jvm_details["status"]["ERROR"] = "Unable to parse version number [%s] of the JVM" % jvm_ver_str
else:
jvm_details["status"]["ERROR"] = "Unable to parse JVM version output:\n %s" % ver_output
else:
jvm_details["status"]["runnable"] = False
if is_discovered:
return None
else:
jvm_details["status"]["ERROR"] = "Can't find java executable in the given path"
except OSError as ose:
jvm_details["status"]["runnable"] = False
jvm_details["status"]["ERROR"] = str(ose.strerror)
except Exception:
jvm_details["status"]["runnable"] = False
jvm_details["status"]["ERROR"] = "unable to validate java from %s" % java_cmd
return jvm_details