Rename safe mode to recovery mode (#102580)

This commit is contained in:
Erik Montnemery 2023-10-23 20:33:08 +02:00 committed by GitHub
parent 7a009ed6cd
commit c481fdb7d0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 67 additions and 65 deletions

View file

@ -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,
)

View file

@ -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

View file

@ -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",
},
)
)

View file

@ -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
)

View file

@ -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):

View file

@ -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

View file

@ -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,

View file

@ -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 (

View file

@ -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]

View file

@ -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

View file

@ -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"}
}

View file

@ -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

View file

@ -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"]

View file

@ -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)

View file

@ -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,
),
)

View file

@ -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,

View file

@ -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) == {}