Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rename safe mode to recovery mode #102580

Merged
merged 1 commit into from
Oct 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions homeassistant/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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,
)
Expand Down
22 changes: 11 additions & 11 deletions homeassistant/bootstrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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)

Expand All @@ -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 {}

Expand Down Expand Up @@ -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
Expand Down
6 changes: 3 additions & 3 deletions homeassistant/components/frontend/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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",
},
)
)
Expand Down
6 changes: 3 additions & 3 deletions homeassistant/components/http/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -445,7 +445,7 @@ def _create_ssl_context(self) -> ssl.SSLContext | None:
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}"
Expand All @@ -465,7 +465,7 @@ def _create_ssl_context(self) -> ssl.SSLContext | None:
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"
)
Expand Down Expand Up @@ -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
)
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/lovelace/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ async def reload_resources_service_handler(service_call: ServiceCall) -> None:
"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):
Expand Down
10 changes: 5 additions & 5 deletions homeassistant/components/lovelace/dashboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ async def async_get_info(self):

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:
Expand All @@ -127,8 +127,8 @@ async def async_load(self, force):

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()
Expand All @@ -138,8 +138,8 @@ async def async_save(self, config):

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
Expand Down
6 changes: 3 additions & 3 deletions homeassistant/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -2129,8 +2129,8 @@ def __init__(self, hass: HomeAssistant, config_dir: str) -> None:
# 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
Expand Down Expand Up @@ -2208,7 +2208,7 @@ def as_dict(self) -> dict[str, Any]:
"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,
Expand Down
4 changes: 2 additions & 2 deletions homeassistant/helpers/check_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ def _comp_error(ex: Exception, domain: str, config: ConfigType) -> None:
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:
Expand Down Expand Up @@ -216,7 +216,7 @@ def _comp_error(ex: Exception, domain: str, config: ConfigType) -> None:
)
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 (
Expand Down
4 changes: 2 additions & 2 deletions homeassistant/loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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]

Expand Down
2 changes: 1 addition & 1 deletion homeassistant/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
8 changes: 4 additions & 4 deletions tests/components/frontend/test_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"}
}


Expand Down
16 changes: 8 additions & 8 deletions tests/components/http/test_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
)

Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions tests/components/lovelace/test_dashboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
Expand Down
12 changes: 6 additions & 6 deletions tests/helpers/test_check_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down
Loading