Rename safe mode to recovery mode (#102580)
This commit is contained in:
parent
7a009ed6cd
commit
c481fdb7d0
17 changed files with 67 additions and 65 deletions
|
@ -93,7 +93,9 @@ def get_arguments() -> argparse.Namespace:
|
|||
help="Directory that contains the Home Assistant configuration",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--safe-mode", action="store_true", help="Start Home Assistant in safe mode"
|
||||
"--recovery-mode",
|
||||
action="store_true",
|
||||
help="Start Home Assistant in recovery mode",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--debug", action="store_true", help="Start Home Assistant in debug mode"
|
||||
|
@ -193,7 +195,7 @@ def main() -> int:
|
|||
log_no_color=args.log_no_color,
|
||||
skip_pip=args.skip_pip,
|
||||
skip_pip_packages=args.skip_pip_packages,
|
||||
safe_mode=args.safe_mode,
|
||||
recovery_mode=args.recovery_mode,
|
||||
debug=args.debug,
|
||||
open_ui=args.open_ui,
|
||||
)
|
||||
|
|
|
@ -137,14 +137,14 @@ async def async_setup_hass(
|
|||
config_dict = None
|
||||
basic_setup_success = False
|
||||
|
||||
if not (safe_mode := runtime_config.safe_mode):
|
||||
if not (recovery_mode := runtime_config.recovery_mode):
|
||||
await hass.async_add_executor_job(conf_util.process_ha_config_upgrade, hass)
|
||||
|
||||
try:
|
||||
config_dict = await conf_util.async_hass_config_yaml(hass)
|
||||
except HomeAssistantError as err:
|
||||
_LOGGER.error(
|
||||
"Failed to parse configuration.yaml: %s. Activating safe mode",
|
||||
"Failed to parse configuration.yaml: %s. Activating recovery mode",
|
||||
err,
|
||||
)
|
||||
else:
|
||||
|
@ -156,24 +156,24 @@ async def async_setup_hass(
|
|||
)
|
||||
|
||||
if config_dict is None:
|
||||
safe_mode = True
|
||||
recovery_mode = True
|
||||
|
||||
elif not basic_setup_success:
|
||||
_LOGGER.warning("Unable to set up core integrations. Activating safe mode")
|
||||
safe_mode = True
|
||||
_LOGGER.warning("Unable to set up core integrations. Activating recovery mode")
|
||||
recovery_mode = True
|
||||
|
||||
elif (
|
||||
"frontend" in hass.data.get(DATA_SETUP, {})
|
||||
and "frontend" not in hass.config.components
|
||||
):
|
||||
_LOGGER.warning("Detected that frontend did not load. Activating safe mode")
|
||||
_LOGGER.warning("Detected that frontend did not load. Activating recovery mode")
|
||||
# Ask integrations to shut down. It's messy but we can't
|
||||
# do a clean stop without knowing what is broken
|
||||
with contextlib.suppress(asyncio.TimeoutError):
|
||||
async with hass.timeout.async_timeout(10):
|
||||
await hass.async_stop()
|
||||
|
||||
safe_mode = True
|
||||
recovery_mode = True
|
||||
old_config = hass.config
|
||||
old_logging = hass.data.get(DATA_LOGGING)
|
||||
|
||||
|
@ -187,9 +187,9 @@ async def async_setup_hass(
|
|||
# Setup loader cache after the config dir has been set
|
||||
loader.async_setup(hass)
|
||||
|
||||
if safe_mode:
|
||||
_LOGGER.info("Starting in safe mode")
|
||||
hass.config.safe_mode = True
|
||||
if recovery_mode:
|
||||
_LOGGER.info("Starting in recovery mode")
|
||||
hass.config.recovery_mode = True
|
||||
|
||||
http_conf = (await http.async_get_last_config(hass)) or {}
|
||||
|
||||
|
@ -471,7 +471,7 @@ def _get_domains(hass: core.HomeAssistant, config: dict[str, Any]) -> set[str]:
|
|||
domains = {key.partition(" ")[0] for key in config if key != core.DOMAIN}
|
||||
|
||||
# Add config entry domains
|
||||
if not hass.config.safe_mode:
|
||||
if not hass.config.recovery_mode:
|
||||
domains.update(hass.config_entries.async_domains())
|
||||
|
||||
# Make sure the Hass.io component is loaded
|
||||
|
|
|
@ -658,18 +658,18 @@ def websocket_get_themes(
|
|||
hass: HomeAssistant, connection: ActiveConnection, msg: dict[str, Any]
|
||||
) -> None:
|
||||
"""Handle get themes command."""
|
||||
if hass.config.safe_mode:
|
||||
if hass.config.recovery_mode:
|
||||
connection.send_message(
|
||||
websocket_api.result_message(
|
||||
msg["id"],
|
||||
{
|
||||
"themes": {
|
||||
"safe_mode": {
|
||||
"recovery_mode": {
|
||||
"primary-color": "#db4437",
|
||||
"accent-color": "#ffca28",
|
||||
}
|
||||
},
|
||||
"default_theme": "safe_mode",
|
||||
"default_theme": "recovery_mode",
|
||||
},
|
||||
)
|
||||
)
|
||||
|
|
|
@ -445,7 +445,7 @@ class HomeAssistantHTTP:
|
|||
context = ssl_util.server_context_modern()
|
||||
context.load_cert_chain(self.ssl_certificate, self.ssl_key)
|
||||
except OSError as error:
|
||||
if not self.hass.config.safe_mode:
|
||||
if not self.hass.config.recovery_mode:
|
||||
raise HomeAssistantError(
|
||||
f"Could not use SSL certificate from {self.ssl_certificate}:"
|
||||
f" {error}"
|
||||
|
@ -465,7 +465,7 @@ class HomeAssistantHTTP:
|
|||
context = None
|
||||
else:
|
||||
_LOGGER.critical(
|
||||
"Home Assistant is running in safe mode with an emergency self"
|
||||
"Home Assistant is running in recovery mode with an emergency self"
|
||||
" signed ssl certificate because the configured SSL certificate was"
|
||||
" not usable"
|
||||
)
|
||||
|
@ -572,7 +572,7 @@ async def start_http_server_and_save_config(
|
|||
"""Startup the http server and save the config."""
|
||||
await server.start()
|
||||
|
||||
# If we are set up successful, we store the HTTP settings for safe mode.
|
||||
# If we are set up successful, we store the HTTP settings for recovery mode.
|
||||
store: storage.Store[dict[str, Any]] = storage.Store(
|
||||
hass, STORAGE_VERSION, STORAGE_KEY
|
||||
)
|
||||
|
|
|
@ -144,7 +144,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
|||
"yaml_dashboards": config[DOMAIN].get(CONF_DASHBOARDS, {}),
|
||||
}
|
||||
|
||||
if hass.config.safe_mode:
|
||||
if hass.config.recovery_mode:
|
||||
return True
|
||||
|
||||
async def storage_dashboard_changed(change_type, item_id, item):
|
||||
|
|
|
@ -114,7 +114,7 @@ class LovelaceStorage(LovelaceConfig):
|
|||
|
||||
async def async_load(self, force):
|
||||
"""Load config."""
|
||||
if self.hass.config.safe_mode:
|
||||
if self.hass.config.recovery_mode:
|
||||
raise ConfigNotFound
|
||||
|
||||
if self._data is None:
|
||||
|
@ -127,8 +127,8 @@ class LovelaceStorage(LovelaceConfig):
|
|||
|
||||
async def async_save(self, config):
|
||||
"""Save config."""
|
||||
if self.hass.config.safe_mode:
|
||||
raise HomeAssistantError("Saving not supported in safe mode")
|
||||
if self.hass.config.recovery_mode:
|
||||
raise HomeAssistantError("Saving not supported in recovery mode")
|
||||
|
||||
if self._data is None:
|
||||
await self._load()
|
||||
|
@ -138,8 +138,8 @@ class LovelaceStorage(LovelaceConfig):
|
|||
|
||||
async def async_delete(self):
|
||||
"""Delete config."""
|
||||
if self.hass.config.safe_mode:
|
||||
raise HomeAssistantError("Deleting not supported in safe mode")
|
||||
if self.hass.config.recovery_mode:
|
||||
raise HomeAssistantError("Deleting not supported in recovery mode")
|
||||
|
||||
await self._store.async_remove()
|
||||
self._data = None
|
||||
|
|
|
@ -2129,8 +2129,8 @@ class Config:
|
|||
# Dictionary of Media folders that integrations may use
|
||||
self.media_dirs: dict[str, str] = {}
|
||||
|
||||
# If Home Assistant is running in safe mode
|
||||
self.safe_mode: bool = False
|
||||
# If Home Assistant is running in recovery mode
|
||||
self.recovery_mode: bool = False
|
||||
|
||||
# Use legacy template behavior
|
||||
self.legacy_templates: bool = False
|
||||
|
@ -2208,7 +2208,7 @@ class Config:
|
|||
"allowlist_external_urls": self.allowlist_external_urls,
|
||||
"version": __version__,
|
||||
"config_source": self.config_source,
|
||||
"safe_mode": self.safe_mode,
|
||||
"recovery_mode": self.recovery_mode,
|
||||
"state": self.hass.state.value,
|
||||
"external_url": self.external_url,
|
||||
"internal_url": self.internal_url,
|
||||
|
|
|
@ -127,7 +127,7 @@ async def async_check_ha_config_file( # noqa: C901
|
|||
try:
|
||||
integration = await async_get_integration_with_requirements(hass, domain)
|
||||
except loader.IntegrationNotFound as ex:
|
||||
if not hass.config.safe_mode:
|
||||
if not hass.config.recovery_mode:
|
||||
result.add_error(f"Integration error: {domain} - {ex}")
|
||||
continue
|
||||
except RequirementsNotFound as ex:
|
||||
|
@ -216,7 +216,7 @@ async def async_check_ha_config_file( # noqa: C901
|
|||
)
|
||||
platform = p_integration.get_platform(domain)
|
||||
except loader.IntegrationNotFound as ex:
|
||||
if not hass.config.safe_mode:
|
||||
if not hass.config.recovery_mode:
|
||||
result.add_error(f"Platform error {domain}.{p_name} - {ex}")
|
||||
continue
|
||||
except (
|
||||
|
|
|
@ -188,7 +188,7 @@ async def _async_get_custom_components(
|
|||
hass: HomeAssistant,
|
||||
) -> dict[str, Integration]:
|
||||
"""Return list of custom integrations."""
|
||||
if hass.config.safe_mode:
|
||||
if hass.config.recovery_mode:
|
||||
return {}
|
||||
|
||||
try:
|
||||
|
@ -1179,7 +1179,7 @@ def _async_mount_config_dir(hass: HomeAssistant) -> None:
|
|||
|
||||
def _lookup_path(hass: HomeAssistant) -> list[str]:
|
||||
"""Return the lookup paths for legacy lookups."""
|
||||
if hass.config.safe_mode:
|
||||
if hass.config.recovery_mode:
|
||||
return [PACKAGE_BUILTIN]
|
||||
return [PACKAGE_CUSTOM_COMPONENTS, PACKAGE_BUILTIN]
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ class RuntimeConfig:
|
|||
config_dir: str
|
||||
skip_pip: bool = False
|
||||
skip_pip_packages: list[str] = dataclasses.field(default_factory=list)
|
||||
safe_mode: bool = False
|
||||
recovery_mode: bool = False
|
||||
|
||||
verbose: bool = False
|
||||
|
||||
|
|
|
@ -177,14 +177,14 @@ async def test_themes_api(hass: HomeAssistant, themes_ws_client) -> None:
|
|||
assert msg["result"]["default_dark_theme"] is None
|
||||
assert msg["result"]["themes"] == MOCK_THEMES
|
||||
|
||||
# safe mode
|
||||
hass.config.safe_mode = True
|
||||
# recovery mode
|
||||
hass.config.recovery_mode = True
|
||||
await themes_ws_client.send_json({"id": 6, "type": "frontend/get_themes"})
|
||||
msg = await themes_ws_client.receive_json()
|
||||
|
||||
assert msg["result"]["default_theme"] == "safe_mode"
|
||||
assert msg["result"]["default_theme"] == "recovery_mode"
|
||||
assert msg["result"]["themes"] == {
|
||||
"safe_mode": {"primary-color": "#db4437", "accent-color": "#ffca28"}
|
||||
"recovery_mode": {"primary-color": "#db4437", "accent-color": "#ffca28"}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -289,7 +289,7 @@ async def test_emergency_ssl_certificate_when_invalid(
|
|||
_setup_broken_ssl_pem_files, tmp_path
|
||||
)
|
||||
|
||||
hass.config.safe_mode = True
|
||||
hass.config.recovery_mode = True
|
||||
assert (
|
||||
await async_setup_component(
|
||||
hass,
|
||||
|
@ -304,17 +304,17 @@ async def test_emergency_ssl_certificate_when_invalid(
|
|||
await hass.async_start()
|
||||
await hass.async_block_till_done()
|
||||
assert (
|
||||
"Home Assistant is running in safe mode with an emergency self signed ssl certificate because the configured SSL certificate was not usable"
|
||||
"Home Assistant is running in recovery mode with an emergency self signed ssl certificate because the configured SSL certificate was not usable"
|
||||
in caplog.text
|
||||
)
|
||||
|
||||
assert hass.http.site is not None
|
||||
|
||||
|
||||
async def test_emergency_ssl_certificate_not_used_when_not_safe_mode(
|
||||
async def test_emergency_ssl_certificate_not_used_when_not_recovery_mode(
|
||||
hass: HomeAssistant, tmp_path: Path, caplog: pytest.LogCaptureFixture
|
||||
) -> None:
|
||||
"""Test an emergency cert is only used in safe mode."""
|
||||
"""Test an emergency cert is only used in recovery mode."""
|
||||
|
||||
cert_path, key_path = await hass.async_add_executor_job(
|
||||
_setup_broken_ssl_pem_files, tmp_path
|
||||
|
@ -338,7 +338,7 @@ async def test_emergency_ssl_certificate_when_invalid_get_url_fails(
|
|||
cert_path, key_path = await hass.async_add_executor_job(
|
||||
_setup_broken_ssl_pem_files, tmp_path
|
||||
)
|
||||
hass.config.safe_mode = True
|
||||
hass.config.recovery_mode = True
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.http.get_url", side_effect=NoURLAvailableError
|
||||
|
@ -358,7 +358,7 @@ async def test_emergency_ssl_certificate_when_invalid_get_url_fails(
|
|||
|
||||
assert len(mock_get_url.mock_calls) == 1
|
||||
assert (
|
||||
"Home Assistant is running in safe mode with an emergency self signed ssl certificate because the configured SSL certificate was not usable"
|
||||
"Home Assistant is running in recovery mode with an emergency self signed ssl certificate because the configured SSL certificate was not usable"
|
||||
in caplog.text
|
||||
)
|
||||
|
||||
|
@ -373,7 +373,7 @@ async def test_invalid_ssl_and_cannot_create_emergency_cert(
|
|||
cert_path, key_path = await hass.async_add_executor_job(
|
||||
_setup_broken_ssl_pem_files, tmp_path
|
||||
)
|
||||
hass.config.safe_mode = True
|
||||
hass.config.recovery_mode = True
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.http.x509.CertificateBuilder", side_effect=OSError
|
||||
|
@ -410,7 +410,7 @@ async def test_invalid_ssl_and_cannot_create_emergency_cert_with_ssl_peer_cert(
|
|||
cert_path, key_path = await hass.async_add_executor_job(
|
||||
_setup_broken_ssl_pem_files, tmp_path
|
||||
)
|
||||
hass.config.safe_mode = True
|
||||
hass.config.recovery_mode = True
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.http.x509.CertificateBuilder", side_effect=OSError
|
||||
|
|
|
@ -48,8 +48,8 @@ async def test_lovelace_from_storage(
|
|||
|
||||
assert response["result"] == {"yo": "hello"}
|
||||
|
||||
# Test with safe mode
|
||||
hass.config.safe_mode = True
|
||||
# Test with recovery mode
|
||||
hass.config.recovery_mode = True
|
||||
await client.send_json({"id": 8, "type": "lovelace/config"})
|
||||
response = await client.receive_json()
|
||||
assert not response["success"]
|
||||
|
|
|
@ -112,11 +112,11 @@ async def test_component_requirement_not_found(hass: HomeAssistant) -> None:
|
|||
assert not res.errors
|
||||
|
||||
|
||||
async def test_component_not_found_safe_mode(hass: HomeAssistant) -> None:
|
||||
"""Test no errors if component not found in safe mode."""
|
||||
async def test_component_not_found_recovery_mode(hass: HomeAssistant) -> None:
|
||||
"""Test no errors if component not found in recovery mode."""
|
||||
# Make sure they don't exist
|
||||
files = {YAML_CONFIG_FILE: BASE_CONFIG + "beer:"}
|
||||
hass.config.safe_mode = True
|
||||
hass.config.recovery_mode = True
|
||||
with patch("os.path.isfile", return_value=True), patch_yaml_files(files):
|
||||
res = await async_check_ha_config_file(hass)
|
||||
log_ha_config(res)
|
||||
|
@ -145,11 +145,11 @@ async def test_component_platform_not_found_2(hass: HomeAssistant) -> None:
|
|||
assert not res.errors
|
||||
|
||||
|
||||
async def test_platform_not_found_safe_mode(hass: HomeAssistant) -> None:
|
||||
"""Test no errors if platform not found in safe_mode."""
|
||||
async def test_platform_not_found_recovery_mode(hass: HomeAssistant) -> None:
|
||||
"""Test no errors if platform not found in recovery_mode."""
|
||||
# Make sure they don't exist
|
||||
files = {YAML_CONFIG_FILE: BASE_CONFIG + "light:\n platform: beer"}
|
||||
hass.config.safe_mode = True
|
||||
hass.config.recovery_mode = True
|
||||
with patch("os.path.isfile", return_value=True), patch_yaml_files(files):
|
||||
res = await async_check_ha_config_file(hass)
|
||||
log_ha_config(res)
|
||||
|
|
|
@ -488,7 +488,7 @@ async def test_setup_hass(
|
|||
log_file=log_file,
|
||||
log_no_color=log_no_color,
|
||||
skip_pip=True,
|
||||
safe_mode=False,
|
||||
recovery_mode=False,
|
||||
),
|
||||
)
|
||||
|
||||
|
@ -547,7 +547,7 @@ async def test_setup_hass_takes_longer_than_log_slow_startup(
|
|||
log_file=log_file,
|
||||
log_no_color=log_no_color,
|
||||
skip_pip=True,
|
||||
safe_mode=False,
|
||||
recovery_mode=False,
|
||||
),
|
||||
)
|
||||
|
||||
|
@ -574,7 +574,7 @@ async def test_setup_hass_invalid_yaml(
|
|||
log_file="",
|
||||
log_no_color=False,
|
||||
skip_pip=True,
|
||||
safe_mode=False,
|
||||
recovery_mode=False,
|
||||
),
|
||||
)
|
||||
|
||||
|
@ -602,7 +602,7 @@ async def test_setup_hass_config_dir_nonexistent(
|
|||
log_file="",
|
||||
log_no_color=False,
|
||||
skip_pip=True,
|
||||
safe_mode=False,
|
||||
recovery_mode=False,
|
||||
),
|
||||
)
|
||||
is None
|
||||
|
@ -630,7 +630,7 @@ async def test_setup_hass_safe_mode(
|
|||
log_file="",
|
||||
log_no_color=False,
|
||||
skip_pip=True,
|
||||
safe_mode=True,
|
||||
recovery_mode=True,
|
||||
),
|
||||
)
|
||||
|
||||
|
@ -661,7 +661,7 @@ async def test_setup_hass_invalid_core_config(
|
|||
log_file="",
|
||||
log_no_color=False,
|
||||
skip_pip=True,
|
||||
safe_mode=False,
|
||||
recovery_mode=False,
|
||||
),
|
||||
)
|
||||
|
||||
|
@ -704,7 +704,7 @@ async def test_setup_safe_mode_if_no_frontend(
|
|||
log_file=log_file,
|
||||
log_no_color=log_no_color,
|
||||
skip_pip=True,
|
||||
safe_mode=False,
|
||||
recovery_mode=False,
|
||||
),
|
||||
)
|
||||
|
||||
|
|
|
@ -1449,7 +1449,7 @@ async def test_config_defaults() -> None:
|
|||
assert config.allowlist_external_dirs == set()
|
||||
assert config.allowlist_external_urls == set()
|
||||
assert config.media_dirs == {}
|
||||
assert config.safe_mode is False
|
||||
assert config.recovery_mode is False
|
||||
assert config.legacy_templates is False
|
||||
assert config.currency == "EUR"
|
||||
assert config.country is None
|
||||
|
@ -1487,7 +1487,7 @@ async def test_config_as_dict() -> None:
|
|||
"allowlist_external_urls": set(),
|
||||
"version": __version__,
|
||||
"config_source": ha.ConfigSource.DEFAULT,
|
||||
"safe_mode": False,
|
||||
"recovery_mode": False,
|
||||
"state": "RUNNING",
|
||||
"external_url": None,
|
||||
"internal_url": None,
|
||||
|
|
|
@ -690,9 +690,9 @@ async def test_get_mqtt(hass: HomeAssistant) -> None:
|
|||
assert mqtt["test_2"] == ["test_2/discovery"]
|
||||
|
||||
|
||||
async def test_get_custom_components_safe_mode(hass: HomeAssistant) -> None:
|
||||
"""Test that we get empty custom components in safe mode."""
|
||||
hass.config.safe_mode = True
|
||||
async def test_get_custom_components_recovery_mode(hass: HomeAssistant) -> None:
|
||||
"""Test that we get empty custom components in recovery mode."""
|
||||
hass.config.recovery_mode = True
|
||||
assert await loader.async_get_custom_components(hass) == {}
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue