From 9e68719c084c82c5fa05b18739f52ed9083fc3a6 Mon Sep 17 00:00:00 2001 From: George Tsiamasiotis Date: Sat, 28 Sep 2024 09:31:25 +0300 Subject: [PATCH] Install config global state early --- frigate/__main__.py | 2 +- frigate/app.py | 1 - frigate/config.py | 62 +++++++++++++++++++++++++++------------------ 3 files changed, 38 insertions(+), 27 deletions(-) diff --git a/frigate/__main__.py b/frigate/__main__.py index ec82739e6..b086d33b3 100644 --- a/frigate/__main__.py +++ b/frigate/__main__.py @@ -32,7 +32,7 @@ def main() -> None: # Load the configuration. try: - config = FrigateConfig.load() + config = FrigateConfig.load(install=True) except ValidationError as e: print("*************************************************************") print("*************************************************************") diff --git a/frigate/app.py b/frigate/app.py index be80a0cf8..eaacd627f 100644 --- a/frigate/app.py +++ b/frigate/app.py @@ -569,7 +569,6 @@ class FrigateApp: # Ensure global state. self.ensure_dirs() - self.config.install() # Start frigate services. self.init_camera_metrics() diff --git a/frigate/config.py b/frigate/config.py index 13de9873c..c89d68ad9 100644 --- a/frigate/config.py +++ b/frigate/config.py @@ -137,6 +137,17 @@ def validate_env_string(v: str) -> str: EnvString = Annotated[str, AfterValidator(validate_env_string)] +def validate_env_vars(v: dict[str, str], info: ValidationInfo) -> dict[str, str]: + if isinstance(info.context, dict) and info.context.get("install", False): + for k, v in v: + os.environ[k] = v + + return v + + +EnvVars = Annotated[dict[str, str], AfterValidator(validate_env_vars)] + + class UIConfig(FrigateBaseModel): timezone: Optional[str] = Field(default=None, title="Override UI timezone.") time_format: TimeFormatEnum = Field( @@ -1311,18 +1322,19 @@ class LoggerConfig(FrigateBaseModel): default_factory=dict, title="Log level for specified processes." ) - def install(self): - """Install global logging state.""" - logging.getLogger().setLevel(self.default.value.upper()) + @model_validator(mode="after") + def post_validation(self, info: ValidationInfo) -> Self: + if isinstance(info.context, dict) and info.context.get("install", False): + logging.getLogger().setLevel(self.default.value.upper()) - log_levels = { - "werkzeug": LogLevelEnum.error, - "ws4py": LogLevelEnum.error, - **self.logs, - } + log_levels = { + "werkzeug": LogLevelEnum.error, + "ws4py": LogLevelEnum.error, + **self.logs, + } - for log, level in log_levels.items(): - logging.getLogger(log).setLevel(level.value.upper()) + for log, level in log_levels.items(): + logging.getLogger(log).setLevel(level.value.upper()) class CameraGroupConfig(FrigateBaseModel): @@ -1466,6 +1478,15 @@ def verify_motion_and_detect(camera_config: CameraConfig) -> ValueError | None: class FrigateConfig(FrigateBaseModel): + # Fields that install global state should be defined first, so that their validators run first. + environment_vars: EnvVars = Field( + default_factory=dict, title="Frigate environment variables." + ) + logger: LoggerConfig = Field( + default_factory=LoggerConfig, title="Logging configuration." + ) + + # Rest of the fields mqtt: MqttConfig = Field(title="MQTT configuration.") database: DatabaseConfig = Field( default_factory=DatabaseConfig, title="Database configuration." @@ -1475,9 +1496,6 @@ class FrigateConfig(FrigateBaseModel): default_factory=ProxyConfig, title="Proxy configuration." ) auth: AuthConfig = Field(default_factory=AuthConfig, title="Auth configuration.") - environment_vars: Dict[str, str] = Field( - default_factory=dict, title="Frigate environment variables." - ) ui: UIConfig = Field(default_factory=UIConfig, title="UI configuration.") notifications: NotificationConfig = Field( default_factory=NotificationConfig, title="Notification Config" @@ -1492,9 +1510,6 @@ class FrigateConfig(FrigateBaseModel): default=DEFAULT_DETECTORS, title="Detector hardware configuration.", ) - logger: LoggerConfig = Field( - default_factory=LoggerConfig, title="Logging configuration." - ) record: RecordConfig = Field( default_factory=RecordConfig, title="Global record configuration." ) @@ -1873,12 +1888,9 @@ class FrigateConfig(FrigateBaseModel): return cls.parse(config_yaml, is_json=False, **context) @classmethod - def parse_object(cls, obj: Any, *, plus_api: Optional[PlusApi] = None): - return cls.model_validate(obj, context={"plus_api": plus_api}) - - def install(self): - """Install global state from the config.""" - self.logger.install() - - for key, value in self.environment_vars.items(): - os.environ[key] = value + def parse_object( + cls, obj: Any, *, plus_api: Optional[PlusApi] = None, install: bool = False + ): + return cls.model_validate( + obj, context={"plus_api": plus_api, "install": install} + )