177 lines
5.5 KiB
Python
177 lines
5.5 KiB
Python
# SPDX-License-Identifier: Apache-2.0
|
|
"""
|
|
LMCache Controller Configuration
|
|
|
|
Configuration system for LMCache Controller that:
|
|
- Loads configuration from YAML file or environment variables
|
|
- Supports command-line parameter overrides
|
|
- Provides thread-safe singleton pattern for global access
|
|
"""
|
|
|
|
# Standard
|
|
from typing import Any, Dict, Optional
|
|
import json
|
|
|
|
# First Party
|
|
from lmcache.logging import init_logger
|
|
from lmcache.v1.config_base import (
|
|
create_config_class,
|
|
create_singleton_config,
|
|
load_config_with_overrides,
|
|
)
|
|
|
|
logger = init_logger(__name__)
|
|
|
|
|
|
# Controller-specific configuration definitions
|
|
_CONTROLLER_CONFIG_DEFINITIONS: dict[str, dict[str, Any]] = {
|
|
# Basic controller configurations
|
|
"controller_monitor_ports": {
|
|
"type": Optional[dict],
|
|
"default": '{"pull": 8300, "reply": 8400}',
|
|
"env_converter": lambda x: (
|
|
x if isinstance(x, dict) else json.loads(x) if x else None
|
|
),
|
|
"description": "JSON string of monitor ports",
|
|
},
|
|
"controller_host": {
|
|
"type": str,
|
|
"default": "0.0.0.0",
|
|
"env_converter": str,
|
|
"description": "Controller host address",
|
|
},
|
|
"controller_port": {
|
|
"type": int,
|
|
"default": 9000,
|
|
"env_converter": int,
|
|
"description": "Controller API server port",
|
|
},
|
|
"health_check_interval": {
|
|
"type": int,
|
|
"default": -1,
|
|
"env_converter": int,
|
|
"description": "Health check interval in seconds (-1 = disabled)",
|
|
},
|
|
"lmcache_worker_timeout": {
|
|
"type": int,
|
|
"default": 300,
|
|
"env_converter": int,
|
|
"description": "LMCache worker timeout in seconds",
|
|
},
|
|
# Extra configurations
|
|
"extra_config": {
|
|
"type": Optional[dict],
|
|
"default": None,
|
|
"env_converter": lambda x: (
|
|
x if isinstance(x, dict) else json.loads(x) if x else None
|
|
),
|
|
"description": "Extra configuration parameters",
|
|
},
|
|
}
|
|
|
|
|
|
# Specialized methods that are unique to ControllerConfig
|
|
def _validate_config(self):
|
|
"""Validate configuration parameters"""
|
|
# Validate timeouts
|
|
if self.health_check_interval != -1 and self.health_check_interval < 1:
|
|
raise ValueError(f"Invalid health_check_interval: {self.health_check_interval}")
|
|
return self
|
|
|
|
|
|
def _log_config(self):
|
|
"""Log configuration"""
|
|
config_dict = {}
|
|
for name in _CONTROLLER_CONFIG_DEFINITIONS:
|
|
value = getattr(self, name)
|
|
config_dict[name] = value
|
|
|
|
logger.info(f"Controller Configuration: {config_dict}")
|
|
return self
|
|
|
|
|
|
def _post_init(self):
|
|
"""Post-initialization setup"""
|
|
pass
|
|
|
|
|
|
# Create configuration class using the base utility
|
|
ControllerConfig = create_config_class(
|
|
config_name="ControllerConfig",
|
|
config_definitions=_CONTROLLER_CONFIG_DEFINITIONS,
|
|
namespace_extras={
|
|
"validate": _validate_config,
|
|
"log_config": _log_config,
|
|
"__post_init__": _post_init,
|
|
},
|
|
env_prefix="LMCACHE_CONTROLLER_",
|
|
)
|
|
|
|
|
|
# Create singleton getter using the base utility
|
|
controller_get_or_create_config = create_singleton_config(
|
|
getter_func_name="controller_get_or_create_config",
|
|
config_class=ControllerConfig,
|
|
config_env_var="LMCACHE_CONTROLLER_CONFIG_FILE",
|
|
)
|
|
|
|
|
|
def override_controller_config_from_dict(
|
|
config: "ControllerConfig", # type: ignore[valid-type]
|
|
overrides: dict[str, Any],
|
|
):
|
|
"""Override configuration with dictionary"""
|
|
for key, value in overrides.items():
|
|
if hasattr(config, key):
|
|
old_value = getattr(config, key)
|
|
|
|
# Check if this field has an env_converter in the definitions
|
|
if key in _CONTROLLER_CONFIG_DEFINITIONS:
|
|
env_converter = _CONTROLLER_CONFIG_DEFINITIONS[key].get("env_converter")
|
|
if env_converter:
|
|
try:
|
|
# Apply the env_converter to the value
|
|
converted_value = env_converter(value)
|
|
setattr(config, key, converted_value)
|
|
except (ValueError, json.JSONDecodeError) as e:
|
|
logger.warning(f"Failed to convert {key}={value!r}: {e}")
|
|
# Keep the original value if conversion fails
|
|
setattr(config, key, value)
|
|
else:
|
|
setattr(config, key, value)
|
|
else:
|
|
setattr(config, key, value)
|
|
|
|
new_value = getattr(config, key)
|
|
if old_value != new_value:
|
|
logger.info(
|
|
f"Override controller config: {key} = {new_value} (was {old_value})"
|
|
)
|
|
else:
|
|
logger.warning(f"Unknown controller config key: {key}, ignoring")
|
|
|
|
|
|
def load_controller_config_with_overrides(
|
|
config_file_path: Optional[str] = None,
|
|
overrides: Optional[Dict[str, Any]] = None,
|
|
) -> "ControllerConfig": # type: ignore[valid-type]
|
|
"""
|
|
Load controller configuration with support for file, env vars, and overrides.
|
|
|
|
This function uses the generic load_config_with_overrides utility from
|
|
config_base.py to reduce code duplication.
|
|
|
|
Args:
|
|
config_file_path: Optional direct path to config file
|
|
overrides: Optional dictionary of configuration overrides
|
|
|
|
Returns:
|
|
Loaded and validated ControllerConfig instance
|
|
"""
|
|
return load_config_with_overrides(
|
|
config_class=ControllerConfig,
|
|
config_file_env_var="LMCACHE_CONTROLLER_CONFIG_FILE",
|
|
config_file_path=config_file_path,
|
|
overrides=overrides,
|
|
)
|