Move core fundamental components into bootstrap (#105560)
Co-authored-by: Erik <erik@montnemery.com> Co-authored-by: Martin Hjelmare <marhje52@gmail.com>pull/108670/head
parent
31ef034c3f
commit
80207835d7
|
@ -39,7 +39,6 @@ from .helpers import (
|
|||
from .helpers.dispatcher import async_dispatcher_send
|
||||
from .helpers.typing import ConfigType
|
||||
from .setup import (
|
||||
DATA_SETUP,
|
||||
DATA_SETUP_STARTED,
|
||||
DATA_SETUP_TIME,
|
||||
async_notify_setup_error,
|
||||
|
@ -106,6 +105,52 @@ STAGE_1_INTEGRATIONS = {
|
|||
# Ensure supervisor is available
|
||||
"hassio",
|
||||
}
|
||||
DEFAULT_INTEGRATIONS = {
|
||||
# These integrations are set up unless recovery mode is activated.
|
||||
#
|
||||
# Integrations providing core functionality:
|
||||
"application_credentials",
|
||||
"frontend",
|
||||
"hardware",
|
||||
"logger",
|
||||
"network",
|
||||
"system_health",
|
||||
#
|
||||
# Key-feature:
|
||||
"automation",
|
||||
"person",
|
||||
"scene",
|
||||
"script",
|
||||
"tag",
|
||||
"zone",
|
||||
#
|
||||
# Built-in helpers:
|
||||
"counter",
|
||||
"input_boolean",
|
||||
"input_button",
|
||||
"input_datetime",
|
||||
"input_number",
|
||||
"input_select",
|
||||
"input_text",
|
||||
"schedule",
|
||||
"timer",
|
||||
}
|
||||
DEFAULT_INTEGRATIONS_RECOVERY_MODE = {
|
||||
# These integrations are set up if recovery mode is activated.
|
||||
"frontend",
|
||||
}
|
||||
DEFAULT_INTEGRATIONS_SUPERVISOR = {
|
||||
# These integrations are set up if using the Supervisor
|
||||
"hassio",
|
||||
}
|
||||
DEFAULT_INTEGRATIONS_NON_SUPERVISOR = {
|
||||
# These integrations are set up if not using the Supervisor
|
||||
"backup",
|
||||
}
|
||||
CRITICAL_INTEGRATIONS = {
|
||||
# Recovery mode is activated if these integrations fail to set up
|
||||
"frontend",
|
||||
}
|
||||
|
||||
|
||||
async def async_setup_hass(
|
||||
|
@ -165,11 +210,11 @@ async def async_setup_hass(
|
|||
_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 recovery mode")
|
||||
elif any(domain not in hass.config.components for domain in CRITICAL_INTEGRATIONS):
|
||||
_LOGGER.warning(
|
||||
"Detected that %s did not load. Activating recovery mode",
|
||||
",".join(CRITICAL_INTEGRATIONS),
|
||||
)
|
||||
# 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):
|
||||
|
@ -478,13 +523,18 @@ def _get_domains(hass: core.HomeAssistant, config: dict[str, Any]) -> set[str]:
|
|||
domain for key in config if (domain := cv.domain_key(key)) != core.DOMAIN
|
||||
}
|
||||
|
||||
# Add config entry domains
|
||||
# Add config entry and default domains
|
||||
if not hass.config.recovery_mode:
|
||||
domains.update(DEFAULT_INTEGRATIONS)
|
||||
domains.update(hass.config_entries.async_domains())
|
||||
else:
|
||||
domains.update(DEFAULT_INTEGRATIONS_RECOVERY_MODE)
|
||||
|
||||
# Make sure the Hass.io component is loaded
|
||||
# Add domains depending on if the Supervisor is used or not
|
||||
if "SUPERVISOR" in os.environ:
|
||||
domains.add("hassio")
|
||||
domains.update(DEFAULT_INTEGRATIONS_SUPERVISOR)
|
||||
else:
|
||||
domains.update(DEFAULT_INTEGRATIONS_NON_SUPERVISOR)
|
||||
|
||||
return domains
|
||||
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
"""Component providing default configuration for new users."""
|
||||
from homeassistant.components.hassio import is_hassio
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
from homeassistant.helpers.typing import ConfigType
|
||||
from homeassistant.setup import async_setup_component
|
||||
|
||||
DOMAIN = "default_config"
|
||||
|
||||
|
@ -12,7 +10,4 @@ CONFIG_SCHEMA = cv.empty_config_schema(DOMAIN)
|
|||
|
||||
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
||||
"""Initialize default configuration."""
|
||||
if not is_hassio(hass):
|
||||
await async_setup_component(hass, "backup", config)
|
||||
|
||||
return True
|
||||
|
|
|
@ -3,46 +3,25 @@
|
|||
"name": "Default Config",
|
||||
"codeowners": ["@home-assistant/core"],
|
||||
"dependencies": [
|
||||
"application_credentials",
|
||||
"assist_pipeline",
|
||||
"automation",
|
||||
"bluetooth",
|
||||
"cloud",
|
||||
"conversation",
|
||||
"counter",
|
||||
"dhcp",
|
||||
"energy",
|
||||
"frontend",
|
||||
"hardware",
|
||||
"history",
|
||||
"homeassistant_alerts",
|
||||
"input_boolean",
|
||||
"input_button",
|
||||
"input_datetime",
|
||||
"input_number",
|
||||
"input_select",
|
||||
"input_text",
|
||||
"logbook",
|
||||
"logger",
|
||||
"map",
|
||||
"media_source",
|
||||
"mobile_app",
|
||||
"my",
|
||||
"network",
|
||||
"person",
|
||||
"scene",
|
||||
"schedule",
|
||||
"script",
|
||||
"ssdp",
|
||||
"stream",
|
||||
"sun",
|
||||
"system_health",
|
||||
"tag",
|
||||
"timer",
|
||||
"usb",
|
||||
"webhook",
|
||||
"zeroconf",
|
||||
"zone"
|
||||
"zeroconf"
|
||||
],
|
||||
"documentation": "https://www.home-assistant.io/integrations/default_config",
|
||||
"integration_type": "system",
|
||||
|
|
|
@ -3,6 +3,7 @@ from unittest.mock import patch
|
|||
|
||||
import pytest
|
||||
|
||||
from homeassistant import bootstrap
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import recorder as recorder_helper
|
||||
from homeassistant.setup import async_setup_component
|
||||
|
@ -34,4 +35,9 @@ async def test_setup(
|
|||
) -> None:
|
||||
"""Test setup."""
|
||||
recorder_helper.async_initialize_recorder(hass)
|
||||
# default_config needs the homeassistant integration, assert it will be
|
||||
# automatically setup by bootstrap and set it up manually for this test
|
||||
assert "homeassistant" in bootstrap.CORE_INTEGRATIONS
|
||||
assert await async_setup_component(hass, "homeassistant", {"foo": "bar"})
|
||||
|
||||
assert await async_setup_component(hass, "default_config", {"foo": "bar"})
|
||||
|
|
|
@ -87,12 +87,21 @@ async def test_async_enable_logging(
|
|||
|
||||
|
||||
async def test_load_hassio(hass: HomeAssistant) -> None:
|
||||
"""Test that we load Hass.io component."""
|
||||
"""Test that we load the hassio integration when using Supervisor."""
|
||||
with patch.dict(os.environ, {}, clear=True):
|
||||
assert bootstrap._get_domains(hass, {}) == set()
|
||||
assert "hassio" not in bootstrap._get_domains(hass, {})
|
||||
|
||||
with patch.dict(os.environ, {"SUPERVISOR": "1"}):
|
||||
assert bootstrap._get_domains(hass, {}) == {"hassio"}
|
||||
assert "hassio" in bootstrap._get_domains(hass, {})
|
||||
|
||||
|
||||
async def test_load_backup(hass: HomeAssistant) -> None:
|
||||
"""Test that we load the backup integration when not using Supervisor."""
|
||||
with patch.dict(os.environ, {}, clear=True):
|
||||
assert "backup" in bootstrap._get_domains(hass, {})
|
||||
|
||||
with patch.dict(os.environ, {"SUPERVISOR": "1"}):
|
||||
assert "backup" not in bootstrap._get_domains(hass, {})
|
||||
|
||||
|
||||
@pytest.mark.parametrize("load_registries", [False])
|
||||
|
@ -784,6 +793,7 @@ async def test_setup_recovery_mode_if_no_frontend(
|
|||
|
||||
|
||||
@pytest.mark.parametrize("load_registries", [False])
|
||||
@patch("homeassistant.bootstrap.DEFAULT_INTEGRATIONS", set())
|
||||
async def test_empty_integrations_list_is_only_sent_at_the_end_of_bootstrap(
|
||||
hass: HomeAssistant,
|
||||
) -> None:
|
||||
|
@ -836,7 +846,7 @@ async def test_empty_integrations_list_is_only_sent_at_the_end_of_bootstrap(
|
|||
|
||||
assert integrations[0] != {}
|
||||
assert "an_after_dep" in integrations[0]
|
||||
assert integrations[-3] != {}
|
||||
assert integrations[-2] != {}
|
||||
assert integrations[-1] == {}
|
||||
|
||||
assert "normal_integration" in hass.config.components
|
||||
|
|
Loading…
Reference in New Issue