"""Kernel parameter validation helpers for deployment config."""
import re
KERNEL_PARAMETER_WHITELIST = {
"DATA_BUFFER_SIZE": {"type": "size", "range": "[64M,32T]"},
"TEMP_BUFFER_SIZE": {"type": "size", "range": "[32M,4T]"},
"SHARED_POOL_SIZE": {"type": "size", "range": "[82M,32T]"},
"LOG_BUFFER_SIZE": {"type": "size", "range": "[1M,110M]"},
"LOG_BUFFER_COUNT": {"type": "integer", "range": "(0,16]"},
"CR_POOL_SIZE": {"type": "size", "range": "[16M,32T]"},
"CR_POOL_COUNT": {"type": "integer", "range": "[1,256]"},
"BUF_POOL_NUM": {"type": "integer", "range": "[1,128]"},
"TEMP_POOL_NUM": {"type": "integer", "range": "[1,128]"},
"LARGE_POOL_SIZE": {"type": "size", "range": "[4M,32T]"},
"VARIANT_MEMORY_AREA_SIZE": {"type": "size", "range": "[4M,32T]"},
"LARGE_VARIANT_MEMORY_AREA_SIZE": {"type": "size", "range": "[1M,32T]"},
"PMA_BUFFER_SIZE": {"type": "size", "range": "[0,1T]"},
"HASH_AREA_SIZE": {"type": "size", "range": "[0,1T]"},
"_INDEX_BUFFER_SIZE": {"type": "size", "range": "[16K,32T]"},
"_VARIANT_AREA_SIZE": {"type": "size", "range": "[256K,64M]"},
"_AGENT_STACK_SIZE": {"type": "size", "range": "[512K,4G)"},
"SESSIONS": {"type": "integer", "range": "[59,19380]"},
"OPEN_CURSORS": {"type": "integer", "range": "[1,16384]"},
"OPTIMIZED_WORKER_THREADS": {"type": "integer", "range": "[2,10000]"},
"MAX_WORKER_THREADS": {"type": "integer", "range": "[2,10000]"},
"MES_POOL_SIZE": {"type": "integer", "range": "[256,16384]"},
}
def parse_size_to_kb(value):
text = str(value).strip()
if text == "0":
return 0
match = re.fullmatch(r"(\d+)([KkMmGgTt])", text)
if not match:
return None
number = int(match.group(1))
unit = match.group(2).upper()
multipliers = {"K": 1, "M": 1024, "G": 1024 * 1024, "T": 1024 * 1024 * 1024}
return number * multipliers[unit]
def _parse_bound(value, value_type):
if value_type == "size":
return parse_size_to_kb(value)
try:
return int(value)
except (TypeError, ValueError):
return None
def _parse_range(range_text, value_type):
pattern = r"([\[\(])\s*([^,]+)\s*,\s*([^\]\)]+)\s*([\]\)])"
match = re.fullmatch(pattern, range_text)
if not match:
return None
lower_mark, lower_text, upper_text, upper_mark = match.groups()
lower = _parse_bound(lower_text, value_type)
upper = _parse_bound(upper_text, value_type)
if lower is None or upper is None:
return None
return lower_mark, lower, upper, upper_mark
def value_in_range(value, value_type, range_text):
parsed_range = _parse_range(range_text, value_type)
actual = _parse_bound(value, value_type)
if parsed_range is None or actual is None:
return False
lower_mark, lower, upper, upper_mark = parsed_range
lower_ok = actual >= lower if lower_mark == "[" else actual > lower
upper_ok = actual <= upper if upper_mark == "]" else actual < upper
return lower_ok and upper_ok
def normalize_kernel_parameter_name(name):
return str(name).strip().upper()
def iter_normalized_kernel_parameters(kernel_params):
for key in sorted(kernel_params):
param_name = normalize_kernel_parameter_name(key)
param_value = str(kernel_params[key]).strip()
yield param_name, param_value
def validate_kernel_parameters(value):
"""Return (is_valid, error_message) for config_params_lun.json kernel_parameters."""
if value in ("", None):
return True, ""
if not isinstance(value, dict):
return False, "kernel_parameters must be a JSON object"
for raw_key, raw_value in value.items():
key = normalize_kernel_parameter_name(raw_key)
param_value = str(raw_value).strip()
if not key or not param_value:
return False, "kernel_parameters contains empty key or value"
if any(ch in key for ch in ("=", "\n", "\r")):
return False, f"kernel parameter name '{key}' contains invalid characters"
if any(ch in param_value for ch in ("\n", "\r")):
return False, f"kernel parameter '{key}' contains invalid value characters"
meta = KERNEL_PARAMETER_WHITELIST.get(key)
if meta is None:
return False, f"unsupported kernel parameter: {key}"
if not value_in_range(param_value, meta["type"], meta["range"]):
return (
False,
f"invalid value for kernel parameter {key}: {param_value}, "
f"expected {meta['range']}",
)
return True, ""
def is_generated_kernel_parameter(key):
match = re.fullmatch(r"Z_KERNEL_PARAMETER(\d+)", key)
return match is not None and int(match.group(1)) >= 3