move env helpers out of the config package (#24648)
CI / AMD64 Build (push) Waiting to run
CI / AMD64 Smoke Test (push) Blocked by required conditions
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions

go2rtc's create_config.py imported frigate.config.env, which ran the frigate.config package init and loaded every detector plugin. Since the onnxruntime 1.30 bump, importing onnxruntime takes about 5s on some hosts, so go2rtc started after Frigate's cameras and every ffmpeg process failed to connect to the restream until it came up. The env helpers now live in frigate.util.env, so go2rtc's config script no longer imports onnxruntime.
This commit is contained in:
Josh Hawkins
2026-10-12 14:54:50 -05:00
committed by GitHub
parent ff9eb8f184
commit e61ad52b67
13 changed files with 26 additions and 21 deletions
@@ -8,13 +8,13 @@ from typing import Any
from ruamel.yaml import YAML from ruamel.yaml import YAML
sys.path.insert(0, "/opt/frigate") sys.path.insert(0, "/opt/frigate")
from frigate.config.env import apply_config_env_vars, substitute_frigate_vars
from frigate.const import ( from frigate.const import (
BIRDSEYE_PIPE, BIRDSEYE_PIPE,
LIBAVFORMAT_VERSION_MAJOR, LIBAVFORMAT_VERSION_MAJOR,
) )
from frigate.ffmpeg_presets import parse_preset_hardware_acceleration_encode from frigate.ffmpeg_presets import parse_preset_hardware_acceleration_encode
from frigate.util.config import find_config_file, resolve_ffmpeg_path from frigate.util.config import find_config_file, resolve_ffmpeg_path
from frigate.util.env import apply_config_env_vars, substitute_frigate_vars
from frigate.util.live_streams import raw_transcode_streams from frigate.util.live_streams import raw_transcode_streams
from frigate.util.services import ( from frigate.util.services import (
is_go2rtc_arbitrary_exec_allowed, is_go2rtc_arbitrary_exec_allowed,
+1 -1
View File
@@ -33,11 +33,11 @@ from frigate.config.camera.updater import (
CameraConfigUpdateEnum, CameraConfigUpdateEnum,
CameraConfigUpdateTopic, CameraConfigUpdateTopic,
) )
from frigate.config.env import UnknownVariableError, substitute_frigate_vars
from frigate.models import User from frigate.models import User
from frigate.util.builtin import clean_camera_user_pass, get_record_segment_time from frigate.util.builtin import clean_camera_user_pass, get_record_segment_time
from frigate.util.camera_cleanup import cleanup_camera_db, cleanup_camera_files from frigate.util.camera_cleanup import cleanup_camera_db, cleanup_camera_files
from frigate.util.config import find_config_file from frigate.util.config import find_config_file
from frigate.util.env import UnknownVariableError, substitute_frigate_vars
from frigate.util.image import run_ffmpeg_snapshot from frigate.util.image import run_ffmpeg_snapshot
from frigate.util.live_streams import ( from frigate.util.live_streams import (
generated_transcode_streams, generated_transcode_streams,
+1 -1
View File
@@ -3,9 +3,9 @@ from enum import Enum
from pydantic import Field, field_validator from pydantic import Field, field_validator
from frigate.util.config import resolve_ffmpeg_path from frigate.util.config import resolve_ffmpeg_path
from frigate.util.env import EnvString
from ..base import FrigateBaseModel from ..base import FrigateBaseModel
from ..env import EnvString
__all__ = [ __all__ = [
"CameraFfmpegConfig", "CameraFfmpegConfig",
+2 -1
View File
@@ -3,8 +3,9 @@ from typing import Any, Self
from pydantic import Field, model_validator from pydantic import Field, model_validator
from frigate.util.env import EnvString
from ..base import FrigateBaseModel from ..base import FrigateBaseModel
from ..env import EnvString
__all__ = ["GenAIConfig", "GenAIProviderEnum", "GenAIRoleEnum"] __all__ = ["GenAIConfig", "GenAIProviderEnum", "GenAIRoleEnum"]
+2 -1
View File
@@ -1,7 +1,8 @@
from pydantic import Field from pydantic import Field
from frigate.util.env import EnvString
from ..base import FrigateBaseModel from ..base import FrigateBaseModel
from ..env import EnvString
__all__ = ["NotificationConfig"] __all__ = ["NotificationConfig"]
+2 -1
View File
@@ -2,8 +2,9 @@ from enum import Enum
from pydantic import Field, field_validator from pydantic import Field, field_validator
from frigate.util.env import EnvString
from ..base import FrigateBaseModel from ..base import FrigateBaseModel
from ..env import EnvString
from .objects import DEFAULT_TRACKED_OBJECTS from .objects import DEFAULT_TRACKED_OBJECTS
__all__ = ["OnvifConfig", "PtzAutotrackConfig", "ZoomingModeEnum"] __all__ = ["OnvifConfig", "PtzAutotrackConfig", "ZoomingModeEnum"]
+1 -1
View File
@@ -34,6 +34,7 @@ from frigate.util.config import (
get_relative_coordinates, get_relative_coordinates,
migrate_frigate_config, migrate_frigate_config,
) )
from frigate.util.env import EnvVars, reload_sources
from frigate.util.image import create_mask from frigate.util.image import create_mask
from frigate.util.live_streams import ( from frigate.util.live_streams import (
default_transcode_source, default_transcode_source,
@@ -71,7 +72,6 @@ from .classification import (
SemanticSearchModelEnum, SemanticSearchModelEnum,
) )
from .database import DatabaseConfig from .database import DatabaseConfig
from .env import EnvVars, reload_sources
from .logger import LoggerConfig from .logger import LoggerConfig
from .mqtt import MqttConfig from .mqtt import MqttConfig
from .network import NetworkingConfig from .network import NetworkingConfig
+1 -1
View File
@@ -3,9 +3,9 @@ from typing import Self
from pydantic import Field, ValidationInfo, model_validator from pydantic import Field, ValidationInfo, model_validator
from frigate.const import FREQUENCY_STATS_POINTS from frigate.const import FREQUENCY_STATS_POINTS
from frigate.util.env import EnvString
from .base import FrigateBaseModel from .base import FrigateBaseModel
from .env import EnvString
__all__ = ["MqttConfig"] __all__ = ["MqttConfig"]
+2 -1
View File
@@ -1,7 +1,8 @@
from pydantic import Field, field_validator from pydantic import Field, field_validator
from frigate.util.env import EnvString
from .base import FrigateBaseModel from .base import FrigateBaseModel
from .env import EnvString
__all__ = ["ProxyConfig", "HeaderMappingConfig"] __all__ = ["ProxyConfig", "HeaderMappingConfig"]
+1 -1
View File
@@ -4,12 +4,12 @@ from unittest.mock import Mock, patch
import frigate.genai import frigate.genai
from frigate.config import GenAIProviderEnum from frigate.config import GenAIProviderEnum
from frigate.config.env import FRIGATE_ENV_VARS
from frigate.const import MODEL_CACHE_DIR, REDACTED_CREDENTIAL_SENTINEL from frigate.const import MODEL_CACHE_DIR, REDACTED_CREDENTIAL_SENTINEL
from frigate.genai import GenAIClient from frigate.genai import GenAIClient
from frigate.models import Event, Recordings, ReviewSegment from frigate.models import Event, Recordings, ReviewSegment
from frigate.stats.emitter import StatsEmitter from frigate.stats.emitter import StatsEmitter
from frigate.test.http_api.base_http_test import AuthTestClient, BaseTestHttp from frigate.test.http_api.base_http_test import AuthTestClient, BaseTestHttp
from frigate.util.env import FRIGATE_ENV_VARS
class TestHttpApp(BaseTestHttp): class TestHttpApp(BaseTestHttp):
+11 -10
View File
@@ -7,8 +7,9 @@ from unittest.mock import MagicMock, patch
from pydantic import ValidationError from pydantic import ValidationError
from frigate.config import FrigateConfig, env from frigate.config import FrigateConfig
from frigate.config.env import ( from frigate.util import env
from frigate.util.env import (
FRIGATE_ENV_VARS, FRIGATE_ENV_VARS,
validate_env_string, validate_env_string,
validate_env_vars, validate_env_vars,
@@ -301,14 +302,14 @@ class TestVariableSources(unittest.TestCase):
def test_collision_warns_once_naming_the_winner(self): def test_collision_warns_once_naming_the_winner(self):
"""A key from two sources logs one warning naming the source that won.""" """A key from two sources logs one warning naming the source that won."""
with patch.dict(env._CONTAINER_ENV, {"FRIGATE_MQTT_HOST": "from_env"}): with patch.dict(env._CONTAINER_ENV, {"FRIGATE_MQTT_HOST": "from_env"}):
with self.assertLogs("frigate.config.env", level="WARNING") as logs: with self.assertLogs("frigate.util.env", level="WARNING") as logs:
env.apply_config_env_vars({"FRIGATE_MQTT_HOST": "from_config"}) env.apply_config_env_vars({"FRIGATE_MQTT_HOST": "from_config"})
self.assertEqual(len(logs.output), 1) self.assertEqual(len(logs.output), 1)
self.assertIn("FRIGATE_MQTT_HOST", logs.output[0]) self.assertIn("FRIGATE_MQTT_HOST", logs.output[0])
self.assertIn("using the value from container environment", logs.output[0]) self.assertIn("using the value from container environment", logs.output[0])
self.assertNotIn("environment_vars", logs.output[0]) self.assertNotIn("environment_vars", logs.output[0])
with self.assertNoLogs("frigate.config.env", level="WARNING"): with self.assertNoLogs("frigate.util.env", level="WARNING"):
env._rebuild() env._rebuild()
@@ -360,7 +361,7 @@ class TestSecretsFile(unittest.TestCase):
def test_unprefixed_key_is_ignored_with_a_warning(self): def test_unprefixed_key_is_ignored_with_a_warning(self):
"""Names must start with FRIGATE_, matching the credentials directory.""" """Names must start with FRIGATE_, matching the credentials directory."""
self._write("cam_pass: hunter2\nFRIGATE_CAM_PASS: hunter2\n") self._write("cam_pass: hunter2\nFRIGATE_CAM_PASS: hunter2\n")
with self.assertLogs("frigate.config.env", level="WARNING") as logs: with self.assertLogs("frigate.util.env", level="WARNING") as logs:
values = env._load_secrets_file() values = env._load_secrets_file()
self.assertEqual(values, {"FRIGATE_CAM_PASS": "hunter2"}) self.assertEqual(values, {"FRIGATE_CAM_PASS": "hunter2"})
self.assertIn("cam_pass", logs.output[0]) self.assertIn("cam_pass", logs.output[0])
@@ -483,10 +484,10 @@ class TestSourceRobustness(unittest.TestCase):
env.reload_sources() env.reload_sources()
env._CONFIG_ENV_VARS["FRIGATE_DUPE"] = "from_config" env._CONFIG_ENV_VARS["FRIGATE_DUPE"] = "from_config"
with self.assertNoLogs("frigate.config.env", level="WARNING"): with self.assertNoLogs("frigate.util.env", level="WARNING"):
env._rebuild(warn=False) env._rebuild(warn=False)
with self.assertLogs("frigate.config.env", level="WARNING") as logs: with self.assertLogs("frigate.util.env", level="WARNING") as logs:
env._rebuild() env._rebuild()
self.assertIn("FRIGATE_DUPE", logs.output[0]) self.assertIn("FRIGATE_DUPE", logs.output[0])
@@ -496,7 +497,7 @@ class TestSourceRobustness(unittest.TestCase):
env.reload_sources() env.reload_sources()
self._write_secrets("FRIGATE_CAMS:\n alley: hunter2\n") self._write_secrets("FRIGATE_CAMS:\n alley: hunter2\n")
with self.assertLogs("frigate.config.env", level="ERROR") as logs: with self.assertLogs("frigate.util.env", level="ERROR") as logs:
env.reload_sources() env.reload_sources()
self.assertIn("FRIGATE_CAMS", logs.output[0]) self.assertIn("FRIGATE_CAMS", logs.output[0])
@@ -505,7 +506,7 @@ class TestSourceRobustness(unittest.TestCase):
def test_duplicate_key_error_does_not_log_the_values(self): def test_duplicate_key_error_does_not_log_the_values(self):
"""ruamel's duplicate key message quotes both values; the log must not.""" """ruamel's duplicate key message quotes both values; the log must not."""
self._write_secrets("FRIGATE_CAM_PASS: hunter2\nFRIGATE_CAM_PASS: hunter3\n") self._write_secrets("FRIGATE_CAM_PASS: hunter2\nFRIGATE_CAM_PASS: hunter3\n")
with self.assertLogs("frigate.config.env", level="ERROR") as logs: with self.assertLogs("frigate.util.env", level="ERROR") as logs:
env.reload_sources() env.reload_sources()
self.assertNotIn("hunter2", logs.output[0]) self.assertNotIn("hunter2", logs.output[0])
@@ -535,7 +536,7 @@ class TestSourceRobustness(unittest.TestCase):
with open(os.path.join(self._creds.name, "FRIGATE_CRED"), "w") as f: with open(os.path.join(self._creds.name, "FRIGATE_CRED"), "w") as f:
f.write("from_creds\n") f.write("from_creds\n")
with self.assertLogs("frigate.config.env", level="WARNING") as logs: with self.assertLogs("frigate.util.env", level="WARNING") as logs:
env.reload_sources() env.reload_sources()
self.assertIn("FRIGATE_NOT_A_FILE", logs.output[0]) self.assertIn("FRIGATE_NOT_A_FILE", logs.output[0])
+1 -1
View File
@@ -4,7 +4,7 @@ from pydantic import ValidationError
from frigate.api.auth import resolve_role from frigate.api.auth import resolve_role
from frigate.config import AuthConfig, HeaderMappingConfig, ProxyConfig from frigate.config import AuthConfig, HeaderMappingConfig, ProxyConfig
from frigate.config.env import FRIGATE_ENV_VARS from frigate.util.env import FRIGATE_ENV_VARS
class TestProxyRoleResolution(unittest.TestCase): class TestProxyRoleResolution(unittest.TestCase):